khoren93 / flutter_zxing

Flutter plugin for scanning and generating QR codes using the ZXing library, supporting Android, iOS, and desktop platforms
https://pub.dev/packages/flutter_zxing
MIT License
89 stars 50 forks source link

QR code in large image is not scanned #74

Open kaboc opened 1 year ago

kaboc commented 1 year ago

readBarcodeImagePathString() fails to scan a QR code in an image taken from slightly off to the side, while ReaderWidget can successfully scan the same QR from the same position. Do you have any idea why there is such a difference?

To reproduce it, please try scanning the QR code below with ReaderWidget and readBarcodeImagePathString() (or it may be reproduced with other similar methods like readBarcodeImagePath(). I'm not sure about it as I haven't used them.)

khoren93 commented 1 year ago

I think one way to potentially address this issue would be to resize the image before attempting to scan it with readBarcodeImagePathString(). This could involve resizing the image to a specific width and height. By adjusting the size of the image in this way, it might be possible to improve the performance of readBarcodeImagePathString() when scanning QR codes from images taken at an angle.

kaboc commented 1 year ago

I hadn't noticed that the image was huge (3,096 x 3,553), and you were right! The QR code above was read successfully after it was shrunk to 1/10 its original size. However, it was not read if the size was 1/5 (620 x 711). It is not that big.

If it is difficult to support larger images on the package side, I'll improve my app myself to resize an image depending on the size.

khoren93 commented 1 year ago

I'll definitely keep your feedback in mind and will research this issue further. If there are any updates or solutions, I'll be sure to let you know.

In the meantime, if you are able to find a workaround by resizing the images in your app, that would be greatly appreciated.

kaboc commented 1 year ago

Proposal for improvement

Currently, I can check if scanning has failed with isValid, but there is no way to know the reason. I think it would be better if an exception was thrown or there was another property having the error information.

khoren93 commented 1 year ago

I wanted to let you know that i've now implemented image resizing in the plugin side. It's now possible to set the maxSize parameter in the DecodeParams object, which will resize the image to fit within the specified dimensions while maintaining the aspect ratio. The default value for maxSize is 512, but you can set it to any value you like. This should help to improve performance and reduce memory usage in situations where large images are being processed.

kaboc commented 1 year ago

Great, thanks! But I can't build my app with the new version 1.0.0-beta.3 of the package.

Error log ``` FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':flutter_zxing:configureCMakeDebug[arm64-v8a]'. > [CXX1405] error when building with cmake using D:\xxxxxx\dart\pub_cache\hosted\pub.dartlang.org\flutter_zxing-1.0.0-beta.3\src\CMakeLists.txt: Build command failed. Error while executing process D:\xxxxxx\android\sdk\cmake\3.18.1\bin\cmake.exe with arguments {-HD:\xxxxxx\dart\pub_cache\hosted\pub.dartlang.org\flutter_zxing-1.0.0-beta.3\src -DCMAKE_SYSTEM_NAME=Android -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_SYSTEM_VERSION=21 -DANDROID_PLATFORM=android-21 -DANDROID_ABI=arm64-v8a -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DANDROID_NDK=D:\xxxxxx\android\sdk\ndk\21.1.6352462 -DCMAKE_ANDROID_NDK=D:\xxxxxx\android\sdk\ndk\21.1.6352462 -DCMAKE_TOOLCHAIN_FILE=D:\xxxxxx\android\sdk\ndk\21.1.6352462\build\cmake\android.toolchain.cmake -DCMAKE_MAKE_PROGRAM=D:\xxxxxx\android\sdk\cmake\3.18.1\bin\ninja.exe -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\xxxxxx\build\flutter_zxing\intermediates\cxx\Debug\1c725b35\obj\arm64-v8a -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=D:\xxxxxx\build\flutter_zxing\intermediates\cxx\Debug\1c725b35\obj\arm64-v8a -DCMAKE_BUILD_TYPE=Debug -BD:\xxxxxx\dart\pub_cache\hosted\pub.dartlang.org\flutter_zxing-1.0.0-beta.3\android\.cxx\Debug\1c725b35\arm64-v8a -GNinja} -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: D:/xxxxxx/android/sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: D:/xxxxxx/android/sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring incomplete, errors occurred! See also "D:/xxxxxx/dart/pub_cache/hosted/pub.dartlang.org/flutter_zxing-1.0.0-beta.3/android/.cxx/Debug/1c725b35/arm64-v8a/CMakeFiles/CMakeOutput.log". CMake Error at CMakeLists.txt:14 (add_subdirectory): The source directory D:/xxxxxx/dart/pub_cache/hosted/pub.dartlang.org/flutter_zxing-1.0.0-beta.3/src/zxing does not contain a CMakeLists.txt file. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 14s Exception: Gradle task assembleDevDebug failed with exit code 1 ```
  CMake Error at CMakeLists.txt:14 (add_subdirectory):
    The source directory

      D:/xxxxxx/dart/pub_cache/hosted/pub.dartlang.org/flutter_zxing-1.0.0-beta.3/src/zxing

    does not contain a CMakeLists.txt file.

I have CmakeLists.txt in src/ and src/zxing/core/ but not in src/zxing/. The directory has only the "core" folder and no files at all.

khoren93 commented 1 year ago

Could you check version 1.0.0-beta.6?

kaboc commented 1 year ago

The build issue is gone. Thank you!

Original
3,096 x 3,553
1/5
620 x 711
1/10
310 x 356
1.0.0 ✔️
1.0.0-beta.6 ✔️ ✔️

It's getting better, but scanning of the original size still fails sadly... Could you check it with the QR code image I pasted earlier please?

khoren93 commented 1 year ago

I was able to resolve this problem by increasing the maximum image size from 512 to 768. Please consider upgrading to version 1.0.0-beta.7 to take advantage of this fix.

kaboc commented 1 year ago

Thanks again! The original image is now read correctly.

In fact, the image I pasted earlier is not the real original. It was too big with large black space, so I uploaded a trimmed one. I shouldn't have done so, my apologies. Below is the actual unedited image:

The QR code in this image is not read successfully, so the change in the default maxSize you made is effective for some images but not for others.

https://github.com/khoren93/flutter_zxing/blob/b8f002b4328e8ea08d917fcfb1bd6980a2631b54/lib/src/utils/image_converter.dart#L74-L78

This resizing doesn't look wrong. I'm wondering why...

kaboc commented 1 year ago

The image size is 3,096 (width) x 5,504 (height), whereas an album app on my phone shows its width is 5,504. It may be related, but I doubt copyResize() cannot correctly handle it.

kaboc commented 1 year ago

I tried saving the resized image as a JPEG file to see what it looked like.

It is rotated 90 degrees and looks much coarser than the original.

If the failure of scanning was initially due to the huge data size and is now due to the quality degradation, it may be better to resize the image only to some degree and then lower the quality; e.g. encodeJpg(image, quality: 50). It is just my guess, so it can eventually turn out to be little effective. I'm sorry if that's the case.

Size: not changed
Quality: 60
Size: 1/2
Quality: 60
Size: 1/2
Quality: 50
Size: 1/3
Quality: 50

3,060 KB

804 KB

717 KB

346 KB

I think it depends on the image how much it should be shrunk and whether lowering the quality is necessary. I imagine the implementation will be a little complicated if all of them have to be done properly.

kaboc commented 1 year ago

I think the coarseness (so-called moiré pattern?) is only because I took a photo of a QR code shown on a PC monitor, and don't think there are many cases where the image quality becomes so bad by a resize. But it can still happen, like when someone sends an image of a QR code taken from a TV screen and the receiver wants to read it.

@khoren93 I'm feeling that many issue reports I've made for the past few days have caused you to work very hard, so I can't force you to do more. I'll leave it to you to decide on the necessity to fix this one. Thank you very much indeed.

axxel commented 7 months ago

Just came across this by chance and it seems you are not aware of the tryDownscale property of the ReaderOptions (former DecodeHints). If you enable that, it will try different resolutions internally, no need to do some external image scaling.