Search code examples
c#exceptionbitmapgrayscalepixelformat

Acess Violation Exception When saving a Bitmap


I need to save a intraoral x-ray image, I'm try to use the 8bppIndexed pixel format, and using this code to save:

 private void SaveImage(short[] data, int widht, int height)
        {
            try
            {
                Bitmap pic = new Bitmap(widht, height, PixelFormat.Format8bppIndexed);

                Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
                BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat);

                IntPtr pixelStartAddress = picData.Scan0;

                Marshal.Copy(data, 0, pixelStartAddress, data.Length);

                pic.UnlockBits(picData);

                pic = ConvertToGrayscale(pic);

                pic.Save("C:\\Users\\WIM\\Desktop\\teste\\teste\\teste.jpeg");
                pic.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

And with this line Marshal.Copy(data, 0, pixelStartAddress, data.Length); I receive the AcessViolationException.

I'm not used to c# so I really don't undertand why I got this error. What I read is that maybe the ptr has been in use, but if I use other pixelFormat, like 16bppRgb565, I can capture the image and transform to grayScale, but the image return deformed. Like this

I'm using an array of short because It's the data I received from the sdk I received from the company we bought the sensor;

In my researches, I found the 16bppGrayScale is a good option, but the GDI+ don't have it encoded yet. But we can make a DICOM for this, but we need to run the application on nootbooks with a hardware not that good, so for that I'm trying to use the 8bppIndexed pixel format.


Solution

  • I dicided to answer my own question to make the post more easy to read.

    I managed to find a solution through this post: Generate 16-bit grayscale BitmapData and save to file

    So please vote on the answer to make more people find the solution more easily.

    And the code I'm using now is like this now:

           private void SaveImage(short[] data, int widht, int height)
            {
                try
                {
                    Bitmap pic = new Bitmap(widht, height, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);
    
                    Rectangle dimension = new Rectangle(0, 0, pic.Width, pic.Height);
                    BitmapData picData = pic.LockBits(dimension, ImageLockMode.ReadWrite, pic.PixelFormat);
    
                    IntPtr pixelStartAddress = picData.Scan0;
    
                    //Marshal.Copy(data, 0, pixelStartAddress, data.Length);
                    Marshal.Copy(data, 0, pixelStartAddress, data.Length);
    
                    pic.UnlockBits(picData);
    
    
                    //SaveBmp(pic, Path.Combine(Directory.GetCurrentDirectory(), "imagem"));
    
                    SaveBmp(pic, "C:\\Users\\WIM\\Desktop\\teste\\teste\\teste.bmp");
                    pic.Dispose();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
    
            private static void SaveBmp(Bitmap bmp, string path)
            {
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    
                BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
    
                var pixelFormats = ConvertBmpPixelFormat(bmp.PixelFormat);
    
                BitmapSource source = BitmapSource.Create(bmp.Width,
                                                          bmp.Height,
                                                          bmp.HorizontalResolution,
                                                          bmp.VerticalResolution,
                                                          pixelFormats,
                                                          null,
                                                          bitmapData.Scan0,
                                                          bitmapData.Stride * bmp.Height,
                                                          bitmapData.Stride);
    
                bmp.UnlockBits(bitmapData);
    
    
                FileStream stream = new FileStream(path, FileMode.Create);
    
                TiffBitmapEncoder encoder = new TiffBitmapEncoder();
    
                encoder.Compression = TiffCompressOption.Zip;
                encoder.Frames.Add(BitmapFrame.Create(source));
                encoder.Save(stream);
    
                stream.Close();
            }
    
    
            private static System.Windows.Media.PixelFormat ConvertBmpPixelFormat(System.Drawing.Imaging.PixelFormat pixelformat)
            {
                System.Windows.Media.PixelFormat pixelFormats = System.Windows.Media.PixelFormats.Default;
    
                switch (pixelformat)
                {
                    case System.Drawing.Imaging.PixelFormat.Format32bppArgb:
                        pixelFormats = PixelFormats.Bgr32;
                        break;
    
                    case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
                        pixelFormats = PixelFormats.Gray8;
                        break;
    
                    case System.Drawing.Imaging.PixelFormat.Format16bppGrayScale:
                        pixelFormats = PixelFormats.Gray16;
                        break;
                }
    
                return pixelFormats;
            }
    

    So now we change the 16bppGrayScale to Gray16.

    To use that, you will need to add the reference to the "PresentationCore" on your project.

    That you can use then

    System.Windows.Media.Format
    

    And anothers objects like BitmapSource.