GDI + & Delphi, ресурс PNG, DrawImage, ColorConversion -> Недостаточно памяти - PullRequest
4 голосов
/ 12 марта 2010

Я начал играть с GDI + в Delphi 2009. Среди прочего я хотел загрузить PNG-ресурс и применить преобразование цветов к нему при рисовании его в объекте Graphics. Я использую код, предоставленный в http://www.bilsen.com/gdiplus/.. Для этого я просто добавил новый конструктор в TGPBitmap, который использует тот же код, что и в /KB/GDI-plus/cgdiplusbitmap.aspx (C ++ ) или /board/index.php?topic=10191.0 (MASM) преобразован в Delphi.

Для справки, преобразованный код выглядит следующим образом:

constructor TGPBitmap.Create(const Instance: HInst; const PngName: String; dummy : PngResource_t);
const
    cPngType : string = 'PNG';

var
    hResource : HRSRC;
    imageSize : DWORD;
    pResourceData : Pointer;
    hBuffer : HGLOBAL;
    pBuffer : Pointer;
    pStream : IStream;

begin
    inherited Create;

    hResource := FindResource(Instance, PWideChar(PngName), PWideChar(cPngType));
    if hResource = 0 then Exit;

    imageSize := SizeofResource(Instance, hResource);
    if imageSize = 0 then Exit;

    pResourceData := LockResource(LoadResource(Instance, hResource));
    if pResourceData = nil then Exit;

    hBuffer := GlobalAlloc(GMEM_MOVEABLE, imageSize);

    if hBuffer <> 0 then
    begin
        try
            pBuffer := GlobalLock(hBuffer);

            if pBuffer <> nil then
            begin
                try
                    CopyMemory(pBuffer, pResourceData, imageSize);

                    if CreateStreamOnHGlobal(hBuffer, FALSE, pStream) = S_OK then
                    begin
                        GdipCheck(GdipCreateBitmapFromStream(pStream, FNativeHandle));
                    end;
                finally
                    GlobalUnlock(hBuffer);
                    pStream := nil;
                end;
            end;
        finally
            GlobalFree(hBuffer);
        end;
    end;
end;

Код работает нормально, так как я могу нарисовать загруженное изображение без проблем. Однако, если я пытаюсь применить преобразование цветов при рисовании, я получаю прекрасную ошибку: (GDI + ошибка) Недостаточно памяти.

Если я загружаю растровое изображение из файла, или если я создаю временное изображение, к которому я рисую исходное растровое изображение, а затем использую временное изображение, то оно работает просто отлично.

Что меня беспокоит, так это то, что если я беру проект C ++ из codeproject , добавляю тот же PNG, что и ресурс, и использую такое же преобразование цветов (другими словами, делайте то же самое, что я делаю в Delphi) в том же порядке и с теми же вызовами функций, которые попадают в одну и ту же DLL), тогда это работает.

Код C ++ выглядит так:

    const Gdiplus::ColorMatrix cTrMatrix = {
        {
            {1.0, 0.0, 0.0, 0.0, 0.0},
            {0.0, 1.0, 0.0, 0.0, 0.0},
            {0.0, 0.0, 1.0, 0.0, 0.0},
            {0.0, 0.0, 0.0, 0.5, 0.0},
            {0.0, 0.0, 0.0, 0.0, 1.0}
        }
    };

    Gdiplus::ImageAttributes imgAttrs;
    imgAttrs.SetColorMatrix(&cTrMatrix, Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap);
    graphics.DrawImage(*pBitmap, Gdiplus::Rect(0, 0, pBitmap->m_pBitmap->GetWidth(), pBitmap->m_pBitmap->GetHeight()), 0, 0, pBitmap->m_pBitmap->GetWidth(), pBitmap->m_pBitmap->GetHeight(), Gdiplus::UnitPixel, &imgAttrs);

Аналог Delphi:

const
  cTrMatrix: TGPColorMatrix = (
    M: ((1.0, 0.0, 0.0, 0.0, 0.0),
        (0.0, 1.0, 0.0, 0.0, 0.0),
        (0.0, 0.0, 1.0, 0.0, 0.0),
        (0.0, 0.0, 0.0, 0.5, 0.0),
        (0.0, 0.0, 0.0, 0.0, 1.0)));

var
    lImgAttrTr : IGPImageAttributes;
    lBitmap : IGPBitmap;

begin
    // ...
    lImgAttrTr := TGPImageAttributes.Create;
    lImgAttrTr.SetColorMatrix(cTrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);

        aGraphics.DrawImage
        (
            lBitmap,
            TGPRect.Create
            (
                0, 0, lBitmap.Width, lBitmap.Height
            ),
            0, 0, lBitmap.Width, lBitmap.Height,
            UnitPixel,
            lImgAttrTr
        );

Я совершенно не понимаю, что может быть причиной проблемы, и Google не помог. Любые идеи, комментарии и объяснения высоко ценятся.

Ответы [ 2 ]

1 голос
/ 12 марта 2010

У меня была такая же проблема. Пиксельный формат изображения, загруженного из ресурса, на самом деле НЕ является PixelFormat32bppARGB. Должно быть, но кажется, что это не так. Мое решение, которое работает:

// Create local bimap with PixelFormat32bppARGB flag
Gdiplus::Bitmap local_bmp(WIDTH, HEIGHT, PixelFormat32bppARGB);
Gdiplus::Graphics gfx(&local_bmp);

// Redraw the original bitmap on the local without transformation.
gfx.DrawImage(&resource_bmp, 0, 0);

// ... set the matrix and attributes

// Do the transformation on the local_bmp
screenGfx.DrawImage(&local_bmp,Rect(0, 0, WIDTH, HEIGHT), 0, 0, WIDTH, HEIGHT, Gdiplus::UnitPixel, &imgAttrs);
1 голос
/ 12 марта 2010

Я не могу полностью следовать вашему коду, поэтому рассмотрим это более общее утверждение: ошибка «Недостаточно памяти» часто наблюдается при преобразовании цветов, если не исходное, и целевое растровое изображение не 32 ГБ.

...