0

We have some bitmap images which actually in RAW format but it uses a windows bitmap format, however if not using the camera provided lib to decode it you cannot have a good result.

The following is the code that works fine:

    public static Bitmap DecodeImage(Bitmap raw_image)
    {
        if (raw_image == null || raw_image.PixelFormat != PixelFormat.Format8bppIndexed) 
            return null;

        BitmapData data_in, data_out;
        Bitmap rgb_image = new Bitmap(raw_image.Width, raw_image.Height, PixelFormat.Format24bppRgb);
        data_in = raw_image.LockBits(new Rectangle(0, 0, raw_image.Width, raw_image.Height), ImageLockMode.ReadWrite, raw_image.PixelFormat);
        data_out = rgb_image.LockBits(new Rectangle(0, 0, rgb_image.Width, rgb_image.Height), ImageLockMode.ReadWrite, rgb_image.PixelFormat);
        try
        {
            DecodeImageRaw(raw_image.Width, raw_image.Height, data_in.Scan0, data_out.Scan0);
            return rgb_image;
        }
        finally
        {
            raw_image.UnlockBits(data_in);
            rgb_image.UnlockBits(data_out);
        }
    }

Here DecodeImageRaw is a method that uses the camera lib to decode the image. The above works fine for us.

The new version of the same code that uses windows imaging component:

    public static BitmapSource DecodeImage(BitmapSource raw_image)
    {
        if (raw_image == null || raw_image.Format != PixelFormats.Indexed8) 
            return null;

        var w = raw_image.PixelWidth;
        var h = raw_image.PixelHeight;
        var dx = raw_image.DpiX;
        var dy = raw_image.DpiY;
        var in_image = new WriteableBitmap(w, h, dx, dy, PixelFormats.Indexed8, raw_image.Palette);
        var out_image = new WriteableBitmap(w, h, dx, dy, PixelFormats.Rgb24, null);

        in_image.Lock();
        out_image.Lock();

        var bufin = in_image.BackBuffer;
        var bufout = out_image.BackBuffer;
        var s = in_image.BackBufferStride;
        try
        {
            raw_image.CopyPixels(Int32Rect.Empty, bufin, h*s, s);

            out_image.AddDirtyRect(new Int32Rect(0, 0, w, h));
            DecodeImageRaw(w, h, bufin, bufout);
            return out_image;
        }
        finally
        {
            in_image.Unlock();
            out_image.Unlock();
        }
    }

The above actually outputs a image with the same shape, but the color is wrong (for example, the background should be "blue" for the sky, but it becomes brown.

So what is wrong with the new code? How to make it equivalent with the original one? Also I want to know explanation of the reason.

Good image

The decoded image should look like this

Bad image

But it was decoded with the new code like this

EDIT

There are some little adjustment since the first edit to the code to make it easier to read and rule out some unrelated detail. For example, there was a bool flag to select between algorithms, but was removed now. However, the behavior remains the same.

Earth Engine
  • 10,048
  • 5
  • 48
  • 78

1 Answers1

2

You have the channels backwards: RGB vs BGR.

I recognized the effect. To confirm it i opened your decoded image in Photoshop, and manually swapped the Red and Blue channels. I then got the image (of whatever the hell that is) that you expected:

enter image description here

I don't understand your code, but try PixelFormats.Bgr24, rather than PixelFormats.Rgb24.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 1
    The WIC naming convention for pixel formats is to order the components by the way they appear in the file (least significant first), which is the opposite of GDI+'s naming convention. – Esme Povirk Jun 17 '14 at 22:14