简体   繁体   English

GDI +和Delphi,PNG资源,DrawImage,ColorConversion->内存不足

[英]GDI+ & Delphi, PNG resource, DrawImage, ColorConversion -> Out of Memory

I have started to toy around with GDI+ in Delphi 2009. Among the things that I wanted to do was to load a PNG resource and apply a Color Conversion to it when drawing it to the Graphics object. 我已经开始在Delphi 2009中使用GDI +玩弄。我要做的事情之一就是加载PNG资源,并在将其绘制到Graphics对象时对其进行颜色转换。 I am using the code provided in http://www.bilsen.com/gdiplus/ . 我正在使用http://www.bilsen.com/gdiplus/中提供的代码。 To do that I just added a new constructor to TGPBitmap that uses the same code found in <www.codeproject.com>/KB/GDI-plus/cgdiplusbitmap.aspx (C++) or <www.masm32.com>/board/index.php?topic=10191.0 (MASM) converted to Delphi. 为此,我只是向TGPBitmap添加了一个新的构造函数,该构造函数使用<www.codeproject.com> /KB/GDI-plus/cgdiplusbitmap.aspx(C ++)或<www.masm32.com> / board / index中找到的相同代码.php?topic = 10191.0(MASM)转换为Delphi。

For reference, the converted code is as follows: 供参考,转换后的代码如下:

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;

The code seems to work fine as I am able to draw the loaded image without any problems. 该代码似乎可以正常工作,因为我能够绘制加载的图像而没有任何问题。 However, if I try to apply a Color Conversion when drawing it, then I get a lovely error: (GDI+ Error) Out of Memory. 但是,如果在绘制时尝试应用颜色转换,则会收到一个可爱的错误:(GDI +错误)内存不足。

If I load the bitmap from a file, or if I create a temporary to which I draw the initial bitmap and then use the temporary, then it works just fine. 如果我从文件中加载位图,或者创建了一个临时图,将初始位图绘制到该临时图上,然后使用该临时图,那么它就可以正常工作。

What bugs me is that if I take the C++ project from codeproject , add the same PNG as resource and use the same color conversion (in other words, do the exact same thing I am doing in Delphi in the same order and with the same function calls that happen to go to the same DLL), then it works. 让我感到烦恼的是,如果我从codeproject中获取C ++项目,添加相同的PNG作为资源并使用相同的颜色转换(换句话说,就是以相同的顺序和相同的功能执行我在Delphi中所做的完全相同的事情恰好转到同一个DLL的调用),然后它起作用了。

The C++ code looks like this: 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);

The Delphi counterpart is: 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
        );

I am completely clueless as to what may be causing the issue, and Google has not been of any help. 对于可能导致此问题的原因,我一无所知,而Google并没有任何帮助。 Any ideas, comments and explanations are highly appreciated. 任何想法,评论和解释都受到高度赞赏。

我无法完全遵循您的代码,因此请考虑以下更一般的说法:如果源位图和目标位图都不都是32bbp,则颜色转换通常会出现内存不足错误。

I had the same problem. 我有同样的问题。 The pixel format of the image loaded from resource in fact is NOT PixelFormat32bppARGB. 从资源加载的图像的像素格式实际上不是PixelFormat32bppARGB。 Should be, but seems that it's not. 应该是,但似乎不是。 My solution that works is: 我有效的解决方案是:

// 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM