Redth / ZXing.Net.Maui

Barcode Scanning for MAUI?
MIT License
437 stars 146 forks source link

Compatibility with some Android smart-phones #107

Open gyaccuzzi opened 1 year ago

gyaccuzzi commented 1 year ago

Here a solution to give compatibility to some models of smart-phones with Android. The problem is these modelos (like samsung A23) reports YUV format with another structure, so the processing of the picture fails. To solve it I had to change it to RGBA format and to apply a convertion:

// Frame by frame analyze
imageAnalyzer = new ImageAnalysis.Builder()
    .SetDefaultResolution(new Android.Util.Size(640, 480))
    .SetOutputImageFormat(ImageAnalysis.OutputImageFormatRgba8888)
    .SetBackpressureStrategy(ImageAnalysis.StrategyKeepOnlyLatest)
    .Build();

And into "public BarcodeResult[] Decode(PixelBufferHolder image)"

#if ANDROID
            Java.Nio.ByteBuffer imageData = Bitmap2Yuv420p(image.Data, w, h);

            ls = new ByteBufferYUVLuminanceSource(imageData, w, h, 0, 0, w, h);
#elif MACCATALYST || IOS
            ls = new CVPixelBufferBGRA32LuminanceSource(image.Data, w, h);
#endif

Here the function

#if ANDROID
        public static unsafe Java.Nio.ByteBuffer Bitmap2Yuv420p(Java.Nio.ByteBuffer buffer, int w, int h)
        {
            byte[] image = new byte[buffer.Remaining()];
            buffer.Get(image);

            byte[] imageYuv = new byte[w * h];

            fixed (byte* packet = image)
            {
                byte* pimage = packet;

                fixed (byte* packetOut = imageYuv)
                {
                    byte* pimageOut = packetOut;

                    for (int i = 0; i < (w * h); i++)
                    {
                        byte r = *pimage++;
                        byte g = *pimage++;
                        byte b = *pimage++;
                        pimage++;   // a
                        *pimageOut++ = (byte)(((66 * r + 129 * g + 25 * b) >> 8) + 16);
                    }
                }
            }

            return Java.Nio.ByteBuffer.Wrap(imageYuv);
        }
#endif
knocte commented 1 year ago

@gyaccuzzi hey, it seems you have mashed both a bug report and a solution together into the same issue.

I guess you could separate the bug from the solution by proposing the above code as a PR, and then give more details about this:

The problem is these modelos (like samsung A23) reports YUV format with another structure, so the processing of the picture fails

As in, what does "fails" mean exactly? An exception thrown? Please paste the whole exception (ex.ToString()) here.

gyaccuzzi commented 1 year ago

Hi, there's not an exception, the issue is in some models of smart-phones ImageAnalysis send the imagen in YUV format but with another standard, so when you analize the image the QR is not found because the image is malformed. A solution that I found was to convert YUV to RGB, surely you can found another better solution with less processing. This happened with two differente models, samsung and motorola.

knocte commented 1 year ago

Interesting, thanks for sharing.

SR84 commented 9 months ago

It happens with Xiaomi phones as well.

That's all very unfortunate, as I'm having difficulties converting my existing apps to Maui.

sbricchi commented 3 months ago

Hi @gyaccuzzi. It seems to be working ok! And your answer is somehow hidden in a third page of open issues. I hope more devs can reach here. Thanks!

knocte commented 3 months ago

@sbricchi can you propose a PR so that we all benefit from this fix?

sbricchi commented 3 months ago

@sbricchi can you propose a PR so that we all benefit from this fix?

I think, I need to do more testing. Also, as @gyaccuzzi mentioned, i'm not sure it's the FINAL solution for this issue. In the meantime you can re-fork and modify my fork at https://github.com/sbricchi/ZXing.Net.Maui.BAMinds.

sbricchi commented 3 months ago

@sbricchi can you propose a PR so that we all benefit from this fix?

Done: https://github.com/Redth/ZXing.Net.Maui/pull/180

Eskissimo commented 3 months ago

Hi all,

Thanks to @sbricchi & @gyaccuzzi for the work ! I suggest this additional code in order to get a good detection :

1- Add a constructor to handle orientation change :

    public CameraManager()
    {
        DeviceDisplay.MainDisplayInfoChanged += DeviceDisplay_MainDisplayInfoChanged;
    }

2- Update camera on orientation change :

    private void DeviceDisplay_MainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)
    {
        if (cameraPreview != null) UpdateCamera();
    }

3- Unregister event in Dispose :

    public void Dispose()
    {
        DeviceDisplay.MainDisplayInfoChanged -= DeviceDisplay_MainDisplayInfoChanged;

        cameraExecutor?.Shutdown();
        cameraExecutor?.Dispose();
    }

4- Configure camera preview with the same settings of the image analyzer :

            cameraPreview = new AndroidX.Camera.Core.Preview.Builder()
                .SetDefaultResolution(new Android.Util.Size(640, 480))
                .SetIsRgba8888SurfaceRequired(true)
                .Build();
            cameraPreview.SetSurfaceProvider(previewView.SurfaceProvider);

Tested on many Android phones/tablets including Samsung A23.

Regards.

knocte commented 3 months ago

@Eskissimo can you post your review in the PR please, not here :)