0

I'm using a list of InteropBitmap in order to display a set of image frames within Image control which is customized with a datatemplate.

What I'm lookin for is to export set of images in a single image, however what I get is a bad/partial image with wrong colors.

The following is the code snippet I'm using to convert set of InteropBitmap in a single image:

 var firstInterop = this.InteropBitmapList[0]; // Get info from first frame, all other one are the same format.

  int width = firstInterop .PixelWidth;
            int height = firstInterop.PixelHeight;
            int bpp = firstInterop Format.BitsPerPixel;

            int stride = width * (bpp / 8);
            int count = this.InteropBitmapList.Count;

            byte[] buffer = new byte[stride * height * count];

            for (int i = 0; i < count; i++)
            {
                var wb = this.InteropBitmapList[i];
                wb.CopyPixels(buffer, stride, width * height * i);
            }

Finally, I use buffer array to achieve my jpeg image through GDI+ or else wpf instruments. Unfortunately, both the way doesn't work as I expected.

Is there something to wrong in my code?

@@EDIT Well, thanks to Clemens answers, now I'm able to obtain a correct image, except only for its color (all colors are altered). The issue is true only when I try to create an Image through GDI+, instead, if I use something of WPF susch as JpegBitmapEncoder all works fine.

The following code snippet allow me to achieve the right image:

byte[] buffer = MyFunc.GetBuffer();
// ...
    var bitmap = System.Windows.Media.Imaging.BitmapSource.Create(width, height, 300, 300,
       System.Windows.Media.PixelFormats.Rgb24, null, buffer, stride);
            System.IO.FileStream stream = new System.IO.FileStream("example.jpg", System.IO.FileMode.Create);
            JpegBitmapEncoder encoder = new JpegBitmapEncoder();

            encoder.QualityLevel = 100;

            encoder.Frames.Add(BitmapFrame.Create(bitmap));
            encoder.Save(stream);

Instead, the following code return me an image with wrong colors (the red become blue and so on)

byte[] buffer = MyFunc.GetBuffer(); 
// ...
IntPtr unmanagedPointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(buffer.Length);
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, unmanagedPointer, buffer.Length);

System.Drawing.Imaging.PixelFormat format = System.Drawing.Imaging.PixelFormat.Format24bppRgb (the equivalent of WPF format..)

System.Drawing.Image myImg = new System.Drawing.Bitmap(Width, Height, stride, format, unmanagedPointer);

myImg.Save("example.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

I haven't idea why it doesn't work when I use System.Drawing classes.

bit
  • 934
  • 1
  • 11
  • 32
  • Shouldn't the offset in CopyPixels be `stride * height * i`? – Clemens Jul 22 '14 at 14:04
  • And stride should better be calculated as `width * (bpp + 7) / 8`, just in case `bpp` is not an integer multiple of 8. – Clemens Jul 22 '14 at 14:07
  • You are right. Now, my image seems uniform, but its colors are not correct. My original frame contains colors like red, orange and black. After exporting image appear with color blue.. – bit Jul 22 '14 at 14:08
  • You have to use the right bitmap format during creation of the result image. See [here](http://msdn.microsoft.com/en-us/library/system.windows.media.pixelformats.aspx) for possible formats. – Clemens Jul 22 '14 at 14:11
  • I think format is correct. My original frames come from PixelFormat = Rgb24. Since I'm using GDI+ to create a single image, when I export my image, I convert that System.Windows.Media.PixelFormat to equivalent System.Drawing.Imaging.PixelFormat.Format24bppRgb... – bit Jul 22 '14 at 14:17
  • And now you expect me to guess what else *exactly* you did? – Clemens Jul 22 '14 at 14:24
  • If you see the right image, but with just wrong colors, it's very likely a problem with the format. – Clemens Jul 22 '14 at 14:30
  • `Format24bppRgb` *is not* the equivalent of `Bgr24`. The one is R-G-B, the other B-G-R. That's why red and blue are interchanged. – Clemens Jul 23 '14 at 15:23
  • Ok, so, how can I achieve the right color? Is there some solution? – bit Jul 23 '14 at 16:56
  • Just go through the buffer and swap each pixel's red and blue byte, or don't use GDI. Or try to get the InteropBitmaps in a format supported by GDI in the first place. – Clemens Jul 23 '14 at 17:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/57868/discussion-between-bit-and-clemens). – bit Jul 23 '14 at 17:47
  • I'd like swap blue byte with red byte. Could you give me an example about it? – bit Jul 23 '14 at 17:58
  • Well, you loop over your buffer with an index variable (say `i`) that you increment by 3 in each loop cycle. In each loop cycle you exchange the buffer values at positions `i` and `i+2`. This is very basic programming knowledge. – Clemens Jul 23 '14 at 19:15
  • Excuse me. It'm my error. WPF format is Rgb24. I've just edit again my code snippet, so, again, I haven't idea why my colors are Exchanged. – bit Jul 24 '14 at 12:07

1 Answers1

1

The error is in the calculation of the buffer offset for the ith image. Instead of width * height * i it has to calculated as stride * height * i:

wb.CopyPixels(buffer, stride, stride * height * i);

In order to also support bits-per-pixel values that are not an integer multiples of 8, you should calculate the stride like this:

int stride = (width * bpp + 7) / 8;
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • @bit This post clearly answers your question "is there something wrong in my code?". If you have another problem, ask another question, or edit this one and be more specific. – Clemens Jul 22 '14 at 14:56
  • Yeah, but from your current question it is impossible to say why. – Clemens Jul 22 '14 at 15:40
  • Please, see my @@EDIT on original question. – bit Jul 23 '14 at 15:19