Blit of image with bit depth of 8

Feb 9, 2012 at 11:47 AM

hi!

I am starting on a project where I use WBX to render geographic maps. I need to be able to render different data sources into the map. One of these is tiles like those of openstreetmap with 8 bit depth:

http://a.tile.openstreetmap.org/0/0/0.png

When I load this tile in a WriteableBitmap and Blit this into the WriteableBitmap which is the main map the image gets messed up. This is probably because the Blit method only support 32 bit depth. 

My question. Do you see a way to deal with this? Should I convert to 32 bits? How to do this? Or initialize the WriteableBitmap differently? Rewrite the Blit method perhaps? Any pointers are appreciated.

thanks,

Paul

Coordinator
Feb 9, 2012 at 1:48 PM

How do you read the PNG in (Step from PNG to WriteableBitmap)?

How does the original WriteableBitmap look, how does the overlay WriteableBitmap look? Just read both in and attach them to the Source of an Image control.

How do you call the Blit method? A code snippet might be a good idea. 

 

- Rene Schulte

Feb 9, 2012 at 2:59 PM
Edited Feb 9, 2012 at 2:59 PM

I read it in from web and from disk with different apps with the same result. I think the easiest way to reproduce it is to modify the WriteableBitmapExBlitSample. What I changed is, in MainWindow.Xaml.cs load the osm image I pointed to above, and change these lines:

         particleBmp = LoadBitmap("/WriteableBitmapExBlitSample.Wpf;component/Data/osmSampleImage.png");
         particleSourceRect = new Rect(0, 0, 256, 256);

In ParticleEmitter.cs I changed the source rect:

      Rect sourceRect = new Rect(0, 0, 256, 256);

And changed the blit line:

      var color = Color.FromArgb((byte)Convert.ToInt32(255 * 0.5), 255, 255, 255);           

      TargetBitmap.Blit(new Rect(0, 0, 256, 256), ParticleBitmap, sourceRect,       color, WriteableBitmapExtensions.BlendMode.Alpha);

This shows an image on the top left. In case of a 32 bit image this is what I expect. In the case of 8 bit image like the above I get this:

http://yfrog.com/5rg2ip

I think the main code involved is in WriteableBitmapBlitExtensions.cs

if (BlendMode == BlendMode.Alpha) 

{                                       

    destPixel = ((sa + (((da * (255 - sa)) * 0x8081) >> 23)) << 24) |   

    ((sr + (((dr * (255 - sa)) * 0x8081) >> 23)) << 16) | 

    ((sg + (((dg * (255 - sa)) * 0x8081) >> 23)) << 8) | 

    ((sb + (((db * (255 - sa)) * 0x8081) >> 23)));

}

btw there seems to be a problem with codeplex' Insert code snippets.

Coordinator
Feb 9, 2012 at 4:03 PM

You should try to only visualize that certain image without blitting. So load it into a WBmp and then assign it to the Source property of an Image control. What is the result.

Also, convert it to a 32 bit PNG and see if that works as expected. 

 

- Rene Schulte

Feb 9, 2012 at 4:56 PM
Edited Feb 10, 2012 at 7:56 AM

Directly assigning the image to a WBmp works correct (tried that before my first post)

I just converted the 8 bit image to 32, by simply opening it in paint.net and saving it as 32 bit, this also works correct.

Then I suspected there might be a difference between Wpf and Silverlight (since it seems Silverlight's WBmp is always initialized with 32 bits). So I ran the same sample in Silverlight and it worked correct also there. 

My theory is the Silverlight version converts the image to a 32 bit internal representation but the Wpf version maintains the 8 bit representation which is not compatible with the Blit implementation. 

btw is use the WBX_1.0_BitmapContext branch.

Coordinator
Feb 9, 2012 at 6:50 PM

You're right. Didn't know you were using WPF.

That's the problem. WriteableBitmapEx only supports 32 bpp images. I might add a functionality to automatically convert a different pixel format input WB to 32 in one of the next versions. But I'm quite busy ATM.

For now you should manually convert it. Here's the class you need 
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.formatconvertedbitmap.aspx

 

- Rene Schulte

Feb 10, 2012 at 11:28 AM
Edited Feb 10, 2012 at 1:00 PM

Thank you very much, this solved this issue for me. I now use the method below. I do not fully understand the remark about the DecodePixelWidth in the sample you refer to.

 

    public static class BitmapFactory
    {
        public static WriteableBitmap New(BitmapSource source)
        {
#if SILVERLIGHT
          return new WriteableBitmap(source);
#elif WPF
          FormatConvertedBitmap formatedBitmapSource = new FormatConvertedBitmap();
          formatedBitmapSource.BeginInit();
          formatedBitmapSource.Source = source;
          formatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;
          formatedBitmapSource.EndInit();

          return new WriteableBitmap(formatedBitmapSource);
#endif
        }
    }
Coordinator
Feb 10, 2012 at 11:52 AM

You can ignore the DecodePixel* properties. It can be used to optimize the size. If you set it, the image will only be decoded at the desired size in order to save memory. So if you only use a 100x100 Image control, you can set DecodePixel* to that size and the returned bitmap will only be 100x100.

 

- Rene Schulte

Coordinator
Apr 23, 2012 at 9:36 PM

I added a check and a helper method to r89620 which make this easier.

Sorry for the late reply.

- Rene Schulte