Размер BitmapData в Windows Mobile

Я пытаюсь прочитать изображение, используя собственные функции. С этой целью я попытался использовать этот код:

        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;
        }

где info содержит высоту и ширину изображения, png — это png_struct, а ReadFullImage является оболочкой вокруг png_read_image. Однако я получал нарушение прав доступа (код исключения 0xc0000005).

После этого я изучил значения, которые содержит data, и обнаружил следующее:

        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

в чем, казалось бы, кроется проблема. Размер записываемой строки составляет 2012 байт, но доступно только 1512, и вскоре происходит попытка записи за пределы выделенной памяти.

Вопрос в том, почему размер строки составляет всего 1512=503*3+3, несмотря на то, что формат 24 бита на пиксель, и как можно выделить достаточно памяти и передать ее в растровое изображение?

В качестве альтернативы, можно ли читать png с libpng совместимым способом?

Обновление: ReadFullImage — это DllImport из

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;
}

А байты строк извлекаются через png_get_rowbytes.


person Srv19    schedule 30.10.2012    source источник


Ответы (1)


Во-первых, насколько мне известно, 24/8 = 3, поэтому 503*(24/8)=1509, затем шаг значение правильное.

Другое дело, что png_read_image использует массив указателей, а Scan0 не является массивом указателей. Это означает, что png_read_image считывает данные из Scan0 (но только для записи) и интерпретирует эти данные как указатели.

Вы можете попробовать следующее (не проверено). Вам нужно изменить первый параметр ReadFullImage (теперь это будет 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;
}

Я предполагаю, что это 32-разрядное приложение.

person Jigsore    schedule 30.10.2012
comment
Я знаю, что png_read_image принимает массив указателей (см. обновление с кодом оболочки), но, как вы указали, 24/8 действительно 3 (и другие 3 байта должны быть заполнены, поскольку строки должны делиться на 4)) и, вполне возможно, у меня не получилось как в базовой арифметике, так и в настройке формата пикселей аналогично в .NET code и libpng. - person Srv19; 30.10.2012
comment
Если libpng требуется 2012 байт для чтения строки в 503 пикселя, я думаю, вам следует использовать PixelFormat.Format32bppRgb или декодировать построчно (используя png_read_row), но это может быть сложно.. . - person Jigsore; 30.10.2012
comment
Что ж, вся цель использования libpng для меня состоит в том, чтобы использовать png_read_row и читать его построчно; изменение формата на 32 бита на пиксель работает как шарм. - person Srv19; 30.10.2012