我正在修改的程序将EMF文件转换为其他格式(SVG)。它是这样做的 EnumEnhMetaFile(),它为EMF的每个记录调用程序的解析例程。这适用于矢量的东西。但是,当它到达EMR_STRETCHDIBITS时,它还需要能够拉出位图。 (最终目标实际上是一个base64编码的PNG,但是关键点在于抓住Bitmap。)Microsoft是否在此处提供了一个用于拉出图像的功能?向EMF添加位图的逆操作是abitmap.Draw,我需要的是某种可以在EnumEnhMetaFile数据处理中操作的abitmap.Read。
是否有一个函数可以将EMR_STRETCHDIBITS提供的数据偏移字段转换为Windows位图?注意,我不想将EMF渲染成位图,我想要存储在EMF中的原始位图。
感谢。
答案 0 :(得分:0)
没有
但是这里是Wine的PlayEnhMetaFile用于绘制记录的代码的链接:http://source.winehq.org/source/dlls/gdi32/enhmetafile.c?v=wine-1.5.2#L1111
它非常简单,并且StretchDIBits调用具有位,BITMAPINFO和iUsage - 您需要插入CreateDIBSection和SetDIBits以获取HBITMAP所需的所有信息。 (如果你使用CreateDIBitmap,你可能会在进程中丢失信息,具体取决于当前的显示模式。呃。你不能直接将这些位复制到DIB中,因为这些位可能是RLE压缩的.SetDIBits会正确处理它。 )
好的,所以你需要获得传递给SetDIBits的高度。将它从BITMAPINFO中拉出是有问题的,因为它实际上可能是具有不同结构的BITMAPCOREINFO。可能最容易创建HBITMAP然后检查它的高度。
我认为如果使用DIB_PAL_COLORS,调色板将不会在BITMAPINFO中,而是通过之前的记录选择到HDC中,因此您最好播放那些操纵DC并使用您给出的HDC的记录。
所以,把它们放在一起,这样的事情(未经测试,缺乏错误检查)应该有效:
HBITMAP bitmap_from_stretchdibits(HDC hdc, const ENHMETARECORD *lpEMFR)
{
const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)lpEMFR;
BITMAP bm;
HBITMAP hbm;
hbm = CreateDIBitmap(
hdc,
(const BITMAPINFO *)((const BYTE *)lpEMFR + pStretchDIBits->offBmiSrc),
pStretchDIBits->iUsageSrc,
NULL,
NULL,
0);
if (hbm)
{
GetObjectA(hbm, sizeof(bm), &bm);
SetDIBits(
hdc,
hbm,
1,
abs(bm.bmHeight),
(const BYTE *)lpEMFR + pStretchDIBits->offBitsSrc,
(const BITMAPINFO *)((const BYTE *)lpEMFR + pStretchDIBits->offBmiSrc),
pStretchDIBits->iUsageSrc);
}
return hbm;
}
答案 1 :(得分:0)
这样做 - 但它保存的PNG是压缩的。
BITMAPINFO *pbitmapinfo = (BITMAPINFO *)((char *)lpEMFR + pEmr->offBmiSrc);
void *pBitsInMem = (char *)lpEMFR + pEmr->offBitsSrc;
HBITMAP hbm;
HDC tmpDC = CreateDC("DISPLAY", "", NULL, NULL);
hbm = CreateDIBitmap(
tmpDC,
&(pbitmapinfo->bmiHeader),
CBM_INIT,
pBitsInMem,
pbitmapinfo,
DIB_RGB_COLORS);
if(hbm){
Gdiplus::Bitmap *pbmp = NULL;
pbmp = Gdiplus::Bitmap::FromHBITMAP(hbm,NULL);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
pbmp->Save(L"C:\\Temp\\scratch.png",&pngClsid, NULL);
delete pbmp;
}
(void) DeleteObject(hbm);
(void) DeleteDC(tmpDC);
答案 2 :(得分:0)
我刚发现的一件事是,如果使用CreateDIBitmap创建HBM,GetObjectA将返回NULL bmbits指针。为了使bm.bmbits指向数据,必须使用CreateDIBSection。问题是第二个函数显然无法从EMR_STRETCHDIBITS记录中读取数据!所以你的选择是:
我正在重新审视这一点,因为GDI +保存到文件函数并不保留JPEG质量= 100模式或PNG中的所有可用数据,这是我唯一的两种文件类型选项。试图将数据转换为GDK :: Pixbuf。据推测,Bitmap或HBitmap对象中的某个地方有一个指向它的指针。