0

I have a question about BitmapSource.Create. I have the following code, and it's not behaving as expected:

  reader.BaseStream.Position += BytesInMetadata;

  var rawData = new UInt16[NumberOfPixels];

  // Read in the raw image data in 16 bit format.
  NumberOfPixels.Times((Action<int>)(i => rawData[i] = reader.ReadUInt16()));

  var stats = new MsiStats()
  {
    Mean = rawData.Average(v => (Double)v),
    StdDev = rawData.StandardDeviation(v => (Double)v),
    Min = rawData.Min(),
    Max = rawData.Max()
  };

  // Convert the 16-bit image to an 8-bit image that can actually be displayed.
  var scaledData = ScaleData(rawData, 4.0f, CType);

  GCHandle handle = GCHandle.Alloc(scaledData, GCHandleType.Pinned);
  using (var bmp = new Bitmap(2048, 2048, 2048, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, handle.AddrOfPinnedObject()))
  {
    bmp.Save(@"C:\Users\icyr\Work Folders\COBRA_I-3\CAST Data\myOGBitmap.bmp");
  }
  handle.Free();

  var src = BitmapSource.Create(NumberOfColumns, NumberOfRows,
                                96, 96,
                                PixelFormats.Gray8, null,
                                scaledData,
                                NumberOfRows);

  using (var fileStream = new FileStream(@"C:\<somefolder>\myBitmap.bmp", FileMode.OpenOrCreate))
  {
    BitmapEncoder enc = new BmpBitmapEncoder();
    enc.Frames.Add(BitmapFrame.Create(src));
    enc.Save(fileStream);
  }

I'm reading a 12 bit value from an proprietary image file, converting it to 8 bits, and then saving it as a bitmapsource object. However, when I read it back (or save it, as I do below) it saves it... wrong. I'm not even sure how to describe it. When I read the saved images in Matlab, the file saved from the Bitmapsource object only has pixel values that are multiples of 17. The saved file from the scaledData object has the full range of values.

What's going on here? Unfortuantely I'm working within a framework of code that I didn't write, and unless I want to overhaul the entire project (which I don't, nor do I have the time to) I need to continue to be able to use BitmapSource objects for my data storage purposes.

I'm at a loss of what to do here, so I'm hoping that you guys might have a better understanding of why this is occuring, and how to prevent it from doing so with minimal changes.

Ian Cyr
  • 23
  • 5
  • Probibly not related to your problem but you are not disposing the bitmap you created in `var bmp = new Bitmap(...`, when working with GDI you really need to dispose all IDisposeable objects because they use a lot of unmanaged handlels that need to be released. Also `scaledData` appears to be a GCPinned object but I don't see you unpinning it. – Scott Chamberlain Nov 10 '15 at 20:20
  • No, I'm not disposing the bmp at the moment. It was thrown in as debug code, but thanks for the reminder to clean that up properly. As far as the GCPinned issue, I'm not even sure I know what that is, so I have no idea if it is pinned, and if it's ever unpinned. I'll look into that as well. edit: I don't think scaled is GCPinned - it's created in ScaledData(), and I don't see anything in there about pinning it. So unless it's pinned as part of the BitmapSource.Create() function, it shouldn't be pinned and the GC should be able to dispose it correctly. – Ian Cyr Nov 10 '15 at 20:40
  • Ah, I see now why you were talking about scaledData being pinned. I took that code from here: http://stackoverflow.com/questions/21555394/how-to-create-bitmap-from-byte-array, just as an attempt to save the array as a bitmap so I could see if it was exhibiting the same weird behavior as the BitmapSource object. So yeah, it's probably not correct and needs to be adjusted, but it appears to work as expected for the moment, which is all I need. – Ian Cyr Nov 10 '15 at 20:50
  • I've disposed of the BMP, and pinned/unpinned the scaled data. The results are still the same though, as expected - the scaledData bitmap contains the full range, the BitmapSource bitmap contains only multiples of 17 as pixel values. – Ian Cyr Nov 10 '15 at 20:56

1 Answers1

1

Apparently the issue was the use of the PixelFormat.Gray8. I changed it to PixelFormat.Indexed8, using BitmapPallettes.Gray256 for my pallette, and that seemed to fix my issue.

var src = BitmapSource.Create(NumberOfColumns, NumberOfRows,
                                96, 96,
                                PixelFormats.Indexed8, BitmapPalettes.Gray256,
                                scaledData,
                                NumberOfRows);

Still don't understand what was going on.

Ian Cyr
  • 23
  • 5