0

I have the following code which takes an array of bytes which i generated and writes them out to this bitmap. If i set the pixel format to Format4bppIndexed, then i get a readable image repeating width wise 4 times, if i set it to Format1bppIndexed(which is the correct setting) then i get one big unreadable image.

The image was a decoded Jbig2 image , i know the bytes are correct i can't seem to figure out how to get it into a 1bpp readable format.

Does anyone have any advice on that matter

        Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);

        //Create a BitmapData and Lock all pixels to be written           
        BitmapData bmpData = bitmap.LockBits(
                             new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                             ImageLockMode.WriteOnly, bitmap.PixelFormat);

        //Copy the data from the byte array into BitmapData.Scan0
        Marshal.Copy(newarray, 0, bmpData.Scan0, newarray.Length);
        //Unlock the pixels
        bitmap.UnlockBits(bmpData);
DevTeamExpress
  • 183
  • 2
  • 9
  • Sounds like it should be 16 bits per pixel based on the "4 times repetition". Not sure why you think your data would only be 1 bit black/white... Note: Converting to 1 bpp would come after decoding if it's not already 1bpp. –  Nov 13 '13 at 16:36
  • is it bit per pixel or Byte per pixel? – Stefan Nov 13 '13 at 16:36
  • @Stefan I can't think of many things that would still be repeating 4 times at 4 bytes per pixel (what's that 32 bits with alpha?) –  Nov 13 '13 at 16:37
  • @ebyrob: you are right. And yes, 32-bit per pixel is an A(lpha)RGB format. For bitmaps it's usually XRGB (32 bit as well, but the first byte being ignored). The later is just an optimization for 32-bit systems. – Stefan Nov 13 '13 at 16:41
  • Why do you believe 1bpp is the "correct setting"? Just asking, as I rarely come across 1bpp images when I'm looking at proprietary image formats. Though considering that it's marketed as a very efficient way to store text images...1bpp would be pretty nice. – MxLDevs Nov 13 '13 at 16:55
  • I'm porting over something from Java and there it uses 1 bit per pixel. – DevTeamExpress Nov 13 '13 at 17:10
  • 1bpp is for indexed images, like tiff. I am not sure if you can use it with other formats, it needs an index table in the image header to decode what indexes mean. – Alex Nov 13 '13 at 18:46
  • @DevTeamExpress Can you provide a screenshot from the two phenomena you mentioned? (with 4bpp image is repeated 4 times, and how does that big unreadable image looks like? I'm asking because screenshots can give hints what happens). – Csaba Toth Nov 13 '13 at 23:19

2 Answers2

0

The following may work although, if I remember correctly, Stride sometimes has an effect and a simple block-copy won't suffice (line by line must be used instead).

Bitmap bitmap = new Bitmap(
    width, 
    height, 
    System.Drawing.PixelFormat.Format16bppGrayScale
    );

To handle the Stride you'd want:

    BitmapData^ data = bitmap->LockBits(oSize, 
        ImageLockMode::ReadOnly, bitmap->PixelFormat);
    try {
        unsigned char *pData = (unsigned char *)data->Scan0.ToPointer();

        for( int x = 0; x < bmpImage->Width; ++x )
        {
            for( int y = 0; y < bmpImage->Height; ++y )
            {
                // Note: Stride is data width of scan line rounded up
                //       to 4 byte boundary.  
                // Requires use of Stride, not (width * pixelWidth)
                int ps = y*bmpImage->Width*(nBitsPerPixel / 8)
                         + x * (nBitsPerPixel / 8);
                int p = y * data->Stride + x * (nBitsPerPixel / 8);
                Byte lo = newarray[ps + 1];
                Byte hi = newarray[ps + 0];
                pData[p + 1] = lo;
                pData[p + 0] = hi;
            }
        }
    } finally {
        bmpImage->UnlockBits(data);
    }

Note: This was written in C++/CLI. Let me know if you need C# equivalents for any of the operations here. (Also, I pulled it from a read from bitmap rather than a write to bitmap so it may yet be a bit rough, but should hopefully give you the idea...)

  • I had to implement 16bpp through the WPF namespace because the GDI doesn't support saving it. But when i do it looks all skewed unreadable. Code looks like this var bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.Gray16, null); bitmap.Lock(); Marshal.Copy(newarray,0, bitmap.BackBuffer, newarray.Length); bitmap.Unlock(); – DevTeamExpress Nov 13 '13 at 17:09
  • @DevTeamExpress I bet that's the Stride, issue sorry for the slow response, I'll see if I can dig up that code sample I had... To be clear you kinda see the image but it's distorted right?! –  Nov 13 '13 at 18:38
  • @DevTeamExpress The simple thing may be to first compare stride with (width * pixelWidth). PS - knowing width here might help a lot. –  Nov 13 '13 at 19:02
  • I'm gonna give this a try and let you know what happens. It sounds like this could be the problem. Thanks – DevTeamExpress Nov 13 '13 at 23:01
  • The Width is 2550px, Stride is 320, Height 3299 assuming 1bpp which i am still pretty sure it must be. When running your code i receive a memory out of bounds error any ideas why. – DevTeamExpress Nov 14 '13 at 07:57
  • @DevTeamExpress probably out of bounds because you really had 1bpp data. Looks like you solved your stride problem by letting WriteableBitmap handle it. –  Nov 14 '13 at 14:37
0

I figured this out Although i'm still not sure why it should matter.

Based on this stackoverflow posting How can I load the raw data of a 48bpp image into a Bitmap?

I used the WPF classes instead of the GDI and wrote the code like this

var bitmap = new WriteableBitmap(width, height, 96, 96,           System.Windows.Media.PixelFormats.BlackWhite, null);
bitmap.WritePixels(new System.Windows.Int32Rect(0, 0, width, height), newarray, stride, 0);     
MemoryStream stream3 = new MemoryStream();
var encoder = new TiffBitmapEncoder ();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream3);

This correctly creates the image.

If anyone has any insight into why this might be the case please comment below

The port which now mostly works(lots of cleanup code) was based on a java implementation of JPedal Big2 Decoder to .NET. If anyone knows anyone interested send them here https://github.com/devteamexpress/JBig2Decoder.NET

Community
  • 1
  • 1
DevTeamExpress
  • 183
  • 2
  • 9