Srv19
Srv19

Reputation: 3618

BitmapData size in windows mobile

I am trying to read image using native functions. To that end, i tried using this code:

        var result = new Bitmap((int)info.width,(int)info.height,PixelFormat.Format24bppRgb);
        var data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
        bool success = ReadFullImage(data.Scan0, ref info, ref png);
        result.UnlockBits(data);
        if (!success)
            return null;
        else
        {
            return result;
        }

where info contains height and width of an image, png is png_struct and ReadFullImage is wrapper around png_read_image. However, i was getting Access Violation (exception code 0xc0000005).

After that, i looked into the values data holds, i discovered this:

        data    {System.Drawing.Imaging.BitmapData} System.Drawing.Imaging.BitmapData
    Height  1557    int
        m_bmpdata   {Microsoft.AGL.Drawing.AGL_BITMAPDATA} Microsoft.AGL.Drawing.AGL_BITMAPDATA
    PixelFormat Format24bppRgb  System.Drawing.Imaging.PixelFormat
        Scan0   1638432 System.IntPtr
    Stride  1512    int
    Width   503 int

wherein seemingly lies th problem. The size of a row that is being written is 2012 bytes, yet there are only 1512 avaiable and before long there is a write attempt outside of allocated memory.

The question is, why the size of a row is only 1512=503*3+3, despite format being 24 bits per pixel, and how can sufficient memory be allocated and fed into a bitmap?

Alternatively, can png be read with libpng in the compabile way?

Update: ReadFullImage is a DllImport of

extern "C" void read_image_full( unsigned char * buffer,pngImageInfo* info,pngDataStructures* png)
{
    png_bytepp  row_pointers = new png_bytep[info->height];
    for (unsigned int i = 0;  i < info->height;  ++i)
        row_pointers[i] = buffer + i*info->rowbytes;
    png_read_image(png->png_struct_field, row_pointers);
    return true;
}

And rowbytes are retrieved via png_get_rowbytes.

Upvotes: 0

Views: 185

Answers (1)

Jigsore
Jigsore

Reputation: 61

First thing, as far as I know, 24/8 = 3, so 503*(24/8)=1509, then the Stride value is correct.

The other thing is that png_read_image uses an array of pointers and Scan0 is not an array of pointers. This means that png_read_image is reading data from Scan0 (but it's write-only) and interpreting this data as pointers.

You can try the following (not tested). You need to modify the first parameter of ReadFullImage (now it would be an int[]):

var result = new Bitmap((int)info.width,(int)info.height,PixelFormat.Format24bppRgb);
var data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
int y, ptr = data.Scan0.ToInt32();
int[] lines = new int[result.Height];
for (y = 0; y < lines.Length; y++)
{
    lines[y] = ptr;
    ptr += data.Stride;
}
bool success = ReadFullImage(lines, ref info, ref png);
result.UnlockBits(data);
if (!success)
    return null;
else
{
    return result;
}

I'm assuming this is a 32-bit application.

Upvotes: 2

Related Questions