0

私が変更しているプログラムは、EMF ファイルを別の形式 (SVG) に変換します。これは、EMF の各レコードに対してプログラムの解析ルーチンを呼び出す EnumEnhMetaFile() で行われます。それはベクトルのものに最適です。ただし、EMR_STRETCHDIBITS にヒットしたときにビットマップを引き出すことができる必要もあります。(最終的なターゲットは、実際には base64 でエンコードされた PNG ですが、問題はビットマップを取得することです。) Microsoft は、この時点で画像を引き出すための機能をどこかに提供していますか? ビットマップを EMF に追加する逆の操作は abitmap.Draw です。必要なのは、EnumEnhMetaFile データ処理内から操作できる abitmap.Read の一種です。

EMR_STRETCHDIBITS が提供するデータ オフセット フィールドから Windows ビットマップに変換する関数はありますか? EMF をビットマップにレンダリングしたくないことに注意してください。EMF に格納されている元のビットマップが必要です。

ありがとう。

4

3 に答える 3

0

私が発見したことの 1 つは、HBM が CreateDIBitmap で作成された場合、GetObjectA は NULL bmbits ポインターを返すことです。bm.bmbits がデータを指すようにするには、代わりに CreateDIBSection を使用する必要があります。問題は、2 番目の関数が明らかに EMR_STRETCHDIBITS レコードからデータを読み取る方法がないことです! したがって、あなたの選択肢は次のとおりです。

  1. データはファイルから HBM に読み取られましたが、このメカニズムを介してそのデータへのポインターはありません
  2. HBM は正しいサイズを作成しましたが、ファイルからデータを読み取れませんでした。メカニズムはポインターを返しますが、ゼロ値でいっぱいのバッファーを指しています!

GDI+ ファイルへの保存関数は、JPEG 品質 = 100 モードまたは PNG のいずれかで利用可能なすべてのデータを保持していないため、これを再検討していました。これは、私の 2 つのファイル タイプ オプションのみです。データを GDK::Pixbuf に取り込もうとしています。おそらく、Bitmap または HBitmap オブジェクト内のどこかにポインタが存在します。

于 2012-04-17T18:24:47.780 に答える
0

いいえ。

ただし、Wine の PlayEnhMetaFile がレコードを描画するために使用するコードへのリンクは次のとおりです

これは驚くほど単純で、StretchDIBits 呼び出しにはビット、BITMAPINFO、および iUsage が含まれます。HBITMAP を取得するために CreateDIBSection と SetDIBits にプラグインする必要があるすべての情報です。(CreateDIBitmap を使用した場合、現在の表示モードによっては、処理中に情報が失われる可能性があります。ビットが RLE 圧縮されている可能性があるため、ビットを DIB に直接コピーすることはできません。SetDIBits はそれを適切に処理します。 )

高さを取得して SetDIBits に渡す必要があります。実際には異なる構造を持つ BITMAPCOREINFO である可能性があるため、BITMAPINFO からそれを引き出すことには問題があります。最初に 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;
}
于 2012-04-14T03:07:53.057 に答える
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);
于 2012-04-16T18:08:12.713 に答える