8

PNG を透過的に MetaFileCanvas に描画する必要があります。これは、ビットマップ (画面に表示するときに使用する) に描画するときは問題なく動作しますが、印刷するには MetaFile が必要です。どうすればこれを達成できますか?

問題を示すコードを次に示します。添付の PNG をどこかに置き、コード内のパスを更新します。

procedure TForm1.Test;
var
  vPNG : TPNGImage;

  vBMP : TBitmap;
  vMeta : TMetafile;
  vMetaCanvas : TMetafileCanvas;
  LDC : HDC;
begin
  vPNG := TPNGImage.Create;
  try
    vPNG.LoadFromFile('c:\temp\pic\pic.png'); 

    //1. Draw to bitmap. Draw stuff behind PNG to demonstrate transparency
    vBMP := TBitmap.Create;
    try
      vBMP.SetSize(vPNG.Width + 20,vPNG.Height + 20);
      vBMP.Canvas.Pen.Color := clLime;
      vBMP.Canvas.Pen.Width := 5;
      vBMP.Canvas.MoveTo(0,0);
      vBMP.Canvas.LineTo(vBMP.Width,vBMP.Height);
      vBMP.Canvas.MoveTo(vBMP.Width,0);
      vBMP.Canvas.LineTo(0,vBMP.Height);
      vBMP.Canvas.Draw(10,10,vPNG);  //This is drawn correctly and transparently

      Canvas.Draw(10,10,vBMP); //Draw to demo form
    finally
      vBMP.Free;
    end;

    //2. Draw to metafile
    vMeta := TMetaFile.Create;
    try
      LDC := GetDC(0);
      vMetaCanvas := TMetafileCanvas.Create(vMeta,LDC);
      try
        vMetaCanvas.Pen.Color := clLime;
        vMetaCanvas.Pen.Width := 5;
        vMetaCanvas.MoveTo(0,0);
        vMetaCanvas.LineTo(vPNG.Width+20,vPNG.Height+20);
        vMetaCanvas.MoveTo(vPNG.Width+20,0);
        vMetaCanvas.LineTo(0,vPNG.Height+20);

        vMetaCanvas.Draw(10,10,vPNG); //Not correct. Can't see the green line
      finally
        vMetaCanvas.Free;
      end;

      //Demonstrate that resizing works fine:
      Canvas.Draw(10,130,vMeta);
      vMeta.MMWidth := vMeta.MMWidth * 2;
      Canvas.Draw(150,130,vMeta);
      vMeta.MMHeight := vMeta.MMHeight * 2;
      Canvas.Draw(400,130,vMeta);
    finally
      vMeta.Free;
      ReleaseDC(0,LDC);
    end;
  finally
    vPNG.Free;
  end;
end;

透明部分のあるサンプル画像

4

2 に答える 2

0

おそらくこれを行う唯一の方法は、AlphaBlend () ウィンドウ関数を使用することです。PNG を 32 ビット RGBA ファイルに変換する場合。するべきこと:

  1. PNG を 32 ビット BMP にロードする

  2. ビットマップの A 値で RGB 値を事前に乗算します (AlphaBlend 呼び出しの前提条件です)。

              for y := 0 to FHeight - 1 do begin
                Src  := BM.ScanLine[ y ];
                Dest := FBitmap.ScanLine[ y ];
                for x := 0 to FWidth - 1 do begin
                  A := Src^; Inc( Src );
                  Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest );
                  Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest );
                  Dest^ := MulDiv( Dest^, A, 255 ); Inc( Dest );
                  Dest^ := A;                       Inc( Dest );
                end;
              end;
    
  3. あらかじめ乗算されたビットマップの Canvas.Handle としてソース HDC を指定し、メタファイル キャンバス ハンドルとして宛先ハンドルを指定して、Alphablend を呼び出します。

    BF.BlendOp             := AC_SRC_OVER;
    BF.BlendFlags          := 0;
    BF.SourceConstantAlpha := 255;
    BF.AlphaFormat         := AC_SRC_ALPHA;
    AlphaBlend( Bitmap.Canvas.Handle, X, Y, BM.Width, BM.Height, BM.Canvas.Handle, 0, 0, BM.Width, BM.Height, BF );
    
于 2012-04-06T13:42:29.720 に答える