0

I have an application that is reading registration plates of an image. I have a simple UI where user can select image to scan using FilePicker.

So scenario where the problem occurs

  1. Select image A
  2. Scan image A --> Success
  3. Select image B
  4. Scan image B --> Success
  5. Select image A
  6. Scan image A --> Fail

Error I receive

System.Runtime.InteropServices.ExternalException: 'A generic error occurred in GDI+.'

I'm using WPF so Image component is using SourceImage as source. I then do conversion. I couldn't find anything to convert SourceImage --> SoftwareBitmap so I use Bitmap as proxy object

SourceImage --> Bitmap --> SoftwareImage (used by Microsoft OCR)

Code samples

File Picker

OpenFileDialog openFileDialog = new OpenFileDialog()
        {
            InitialDirectory = @"c:\Temp",
            Filter = "Image files (*.jpg;*.jpeg;*.png)|*.jpg;*.jpeg;*.png",
            FilterIndex = 0,
            RestoreDirectory = true,
            Multiselect = false
        };
        
        if (openFileDialog.ShowDialog() == true)
        {
            img = new BitmapImage();
            img.BeginInit();
            img.CacheOption = BitmapCacheOption.OnLoad;
            img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
            img.UriSource = new Uri(openFileDialog.FileName);
            img.EndInit();

            if(img != null)
            {
                ANPR_image.Source = img;
            }

        }

Convert to Bitmap

Bitmap bmp = new Bitmap(
          source.PixelWidth,
          source.PixelHeight,
          System.Drawing.Imaging.PixelFormat.Format32bppArgb
          );

        BitmapData data = bmp.LockBits(
          new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size),
          ImageLockMode.WriteOnly,
          System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

        source.CopyPixels(
          Int32Rect.Empty,
          data.Scan0,
          data.Height * data.Stride,
          data.Stride);

        bmp.UnlockBits(data);

        return bmp;

Convert to SoftwareBitmap and OCR

using (Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream())
        {
            if(newBitmap != null)
            {
               
                newBitmap.Save(stream.AsStream(), ImageFormat.Tiff); //choose the specific image format by your own bitmap source
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
                using (SoftwareBitmap s_Bitmap = await decoder.GetSoftwareBitmapAsync())
                {
                    try
                    {
                        result = await ocr.RecognizeAsync(s_Bitmap);
                        newBitmap.Dispose();
                        image.Dispose();
                        
                        return result is null ? "" : result.Text;
                    }
                    catch(Exception e)
                    {
                        return "Error";
                    }
                
                }
            }
            else
            {
                return "Image is null";
            }

The error occurs here newBitmap.Save(stream.AsStream(), ImageFormat.Tiff); //choose the specific image format by your own bitmap source

I read online about this error and it seems there may be a lock somewhere but I can't figure out where... I tried disposing of all possible images, I wrapped everything with using statements. Nothing works...

Any ideas, suggestion would be appreciated!

Thanks

aberforth
  • 72
  • 11
  • Why do you set `img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;`? – mm8 May 31 '22 at 12:16
  • Have you tried loading the BitmapImage from a FileStream, as shown [here](https://stackoverflow.com/a/12867281/1136211)? – Clemens May 31 '22 at 12:22
  • @mm8 I found a solution somewhere to do it this way but didn't help – aberforth May 31 '22 at 12:46
  • @Clemens that improved the rate error gets generated greatly! Thanks. However when I change images around (I have samples of like 10 images) eventually the error returns... – aberforth May 31 '22 at 12:51

1 Answers1

2

You may simplify your code by creating both bitmaps from a single MemoryStream. Pass stream.AsRandomAccessStream() to the BitmapDecoder.

var buffer = await File.ReadAllBytesAsync(openFileDialog.FileName);

using (var stream = new MemoryStream(buffer))
{
    ANPR_image.Source = BitmapFrame.Create(
        stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

    using (var randomAccessStream = stream.AsRandomAccessStream())
    {
        Windows.Graphics.Imaging.BitmapDecoder decoder =
            await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(
                randomAccessStream);

        using (var softwareBitmap = await decoder.GetSoftwareBitmapAsync())
        {
            // ...
        }
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Now I'm getting error `System.Runtime.InteropServices.COMException: 'The image is unrecognized. (0x88982F60)'` in line `using (var softwareBitmap = await decoder.GetSoftwareBitmapAsync())` It happens on various images, no pattern – aberforth May 31 '22 at 12:59
  • Didn't help... still the same error – aberforth May 31 '22 at 13:14
  • No idea, it seems to work for me. At least I could access some properties of the SoftwareBitmap. Anyway, this is the direction you should go. Maybe try to create the IRandomAccessStream from the buffer in a different way. There are plenty of examples on the internet. – Clemens May 31 '22 at 13:28
  • I mean it works, but throws error after x tries... thanks for the direction. I will accept your answer – aberforth May 31 '22 at 13:32
  • decided to untick your answer as an answer so others can contribute. If no one replies I'll flag it back – aberforth May 31 '22 at 13:41
  • You may perhaps also create the SoftwareBitmap from the raw pixel buffer of the WPF BitmapFrame, instead of decoding the MemoryStream twice. – Clemens Jun 01 '22 at 09:15