flutter(dart)

flutter - Null check operator used on a null value 오류 해결하기

칠구의 스터디 2024. 1. 21. 19:48

 

ocr을 사용한 앱을 개발 중인데 갤러리에서 가져온 이미지는 ocr이 잘 적용하는데 카메라로 찍은 이미지는 ocr이 되지 않고  Null check operator used on a null value 이 오류가 자꾸 발생했다 ㅠㅠ

GPT , POE , 구글링 등등으로도 해결이 안 되다가 이번에 드디어 해결했다.

참고로 난 tesseractocr을 사용했고 이 오류 때문에 엄청 애먹었는데

이 글을 보고 조금이나마 도움이 됐으면 좋겠다

 

 

 

 

한 줄 요약 : 카메라로 찍은 사진이 갤러리에 저장되게 하고 여기서 이미지를 가져와 OCR 수행시킴

 


오류

먼저 오류가 나던 코드다 

import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';

//생략

//바텀바 부분
class BottomNavBar extends StatefulWidget {
  const BottomNavBar({super.key});

  @override
  _BottomNavBarState createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  final ImagePicker _imagePicker = ImagePicker();
  final _qrBarCodeScannerDialogPlugin = QrBarCodeScannerDialog();
  String? code;
  String parsedText = '';

  late File? pickedImage;
  late XFile? pickedFile;
  late String img64;
  
//생략
  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
//생략
                  // 카메라 부분
                  Expanded(
                    child: ElevatedButton(
                      onPressed: () async {
                        Navigator.pop(context);

                        final pickedFile = await _imagePicker.pickImage(
                          source: ImageSource.camera,
                        );

                        if (pickedFile != null) {
                          var ocrText = await FlutterTesseractOcr.extractText(
                            pickedFile.path,
                            language: 'kor',
                          );

                          if (mounted) {
                            await Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (BuildContext context) => Information(
                                  image: File(pickedFile.path),
                                  parsedText: ocrText,
                                ),
                              ),
                            );
                          }
                        }
                      },
                      child: Text('Camera'),
                    ),
                  ),

                  // 갤러리 부분
                  Expanded(
                    child: ElevatedButton(
                      onPressed: () async {
                        final pickedFile = await _imagePicker.pickImage(
                            source: ImageSource.gallery);

                        if (pickedFile != null) {
                          // OCR 수행
                          var ocrText = await FlutterTesseractOcr.extractText(
                            pickedFile.path,
                            language: 'kor',
                          );

                          // Information 화면으로 이동하여 OCR 결과값 전달
                          await Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (BuildContext context) => Information(
                                image: File(pickedFile.path),
                                parsedText: ocrText,
                              ),
                            ),
                          );
                        }
                      },
                      child: Text('Gallery'),
                    ),
                  ),
//생략

나는 바텀바의 렌즈를 클릭하면 카메라, 갤러리, QR/바코드를 선택할 수 있는 버튼이 나오는데 여기의 카메라와 갤러리를 클릭하여 OCR이 적용되도록 하였다

OCR 결과는 Information이라는 화면으로 전환해서 보여지도록 함

 

밑의 코드는 OCR결과가 보여지는 Information화면의 코드이다 

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_banergy/mypage/mypage.dart';
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';


class Information extends StatefulWidget {
  final String imagePath;

 
  const camerainformation({super.key, required this.imagePath});

  @override
  _InformationState createState() => _InformationState();
}


class InformationState extends State<Information> {
  String parsedText = '';
  bool isOcrInProgress = true;

  @override
  void initState() {
    super.initState();
    _performOCR();
  }

  void _performOCR() async {
    try {
      var ocrText = await FlutterTesseractOcr.extractText(
        widget.imagePath,
        language: 'kor',
      );

      setState(() {
        parsedText = ocrText;
      });
    } finally {
      setState(() {
        isOcrInProgress = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('상품 정보'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () {
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (context) => const MypageApp()),
            );
          },
        ),
      ),
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: SizedBox(
                width: 150,
                height: 150,
                child: Image.file(File(widget.imagePath)),
              ),
            ),
            const Divider(
              color: Colors.grey,
              thickness: 2.0,
              height: 5.0,
            ),
            const Center(
              child: Text(
                'OCR 결과',
                style: TextStyle(
                  fontSize: 24.0,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            if (isOcrInProgress)
              const CircularProgressIndicator()
            else
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: Text(parsedText.isNotEmpty
                    ? ' $parsedText'
                    : 'No text detected'),
              ),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context); // 현재 화면 닫기
              },
              child: const Text('닫기'),
            ),
          ],
        ),
      ),
    );
  }
}

 

해결

매번 문제를 못고치다가 문득 카메라로 찍은 사진이 갤러리에 저장이 안 된다는 사실을 알게 되었다.....

카메라로 찍은 사진/갤러리에서 가져오는 사진 둘 다 imagePicker를 통해 사진을 통해 사진을 가져오는데

카메라로 찍은 사진은 저장이 안되니 imagePicker을 통해 사진을 가져올 수 없어서 오류가 뜬다고 생각했다

 

그래서 갤러리 저장 함수인 saveImageToGallery를 사용해서 카메라로 찍은 이미지가 갤러리에 저장되도록 하였고

그 후 해당 이미지를 대상으로 OCR을 실행시킨 후 해당결과를 Information화면으로 전환되도록 하였다.

//카메라 부분 수정 및 추가된 부분 

//사진을 찍은 후 갤러리에 저장

  Future<void> _saveImageToGallery(
      XFile pickedFile, BuildContext context) async {
    final File imageFile = File(pickedFile.path);

    try {
      // OCR 수행
      final String imagePath = await _performOCR(imageFile);

      // 다음 화면으로 이동
      if (mounted) {
        final NavigatorState navigator = Navigator.of(context);
        navigator.pushReplacement(
          MaterialPageRoute(
            builder: (BuildContext context) => camerainformation(
              imagePath: imagePath,
            ),
          ),
        );
      }
    } catch (e) {
      print('OCR failed: $e');
      // OCR 오류 시
    }
  }

//카메라 찍은 거
  Future<String> _performOCR(File imageFile) async {
    try {
      return imageFile.path;
    } catch (e) {
      //오류 떴을때 확인
      print('OCR failed: $e');
      throw e;
    }
  }
  
  //생략
  
   Expanded(
                    child: ElevatedButton(
                      onPressed: () async {
                        final pickedFile = await _imagePicker.pickImage(
                          source: ImageSource.camera,
                        );

                        if (pickedFile != null) {
                            // OCR 수행
                            _saveImageToGallery(pickedFile, context);
                          
                        }
                      },
                      child: const Text('Camera'),
                    ),
                  ),

그 결과.... 성공적으로 카메라로 찍은 사진이 갤러리에 저장되었고 OCR도 잘 작동하였다 ㅜㅜㅜ

 

https://github.com/kimnambin/banergy

 

GitHub - kimnambin/banergy

Contribute to kimnambin/banergy development by creating an account on GitHub.

github.com

이거에 대한 깃허브인데 필요하면 참고하기~~~