将EMF文件转换为位图并获得正确的大小

时间:2013-03-12 05:27:34

标签: delphi bitmap

情况是我有一个打印机EMF文件。我想在将数据发送到打印机之前覆盖一些数据。打印机文件为300dpi。保持相同的打印质量非常重要。

我正在使用此代码转换emf文件...

  b:=TBitmap.create;
  MyMetaFile.LoadFromFile(emf);
  MyCanvas:= TMetafileCanvas.Create(MyMetaFile, 0);
  try
    Width:=MyMetaFile.Width;
    Height:=MyMetaFile.Height;

    b.width:=width;
    b.height:=height;
    b.Canvas.Draw(0, 0, MyMetaFile);
    b.SaveToFile('c:\emftest.bmp');

除了你只得到emf文件的左上角之外,这种作品。如果你在windows中查看EMF文件的属性,它会显示2551x3301。但这里的宽度和高度设置为613x792。如果我用这些值覆盖b.width和b.height就可以了,但我显然不想这样做。 EMF文件为300dpi,屏幕dpi约为100,但错误是4.16。知道这里发生了什么吗?

由于 特里

2 个答案:

答案 0 :(得分:2)

您必须在此处使用StrechDraw而不是Draw才能将内容扩展到预期的位图大小。

例如:

function MetafileToBitmap(Source: TMetafile; ScaleX,ScaleY: integer): TBitmap;
var R: TRect;
begin
  result := nil;
  if Source=nil then // self=nil is OK below
    Exit;
  R.Left := 0;
  R.Right := (Source.Width*ScaleX)div 100;
  R.Top := 0;
  R.Bottom := (Source.Height*ScaleY)div 100;
  result := TBitmap.Create;
  result.Width := R.Right;
  result.Height := R.Bottom;
  Dec(R.Right);  // Metafile rect includes right and bottom coords
  Dec(R.Bottom);
  PlayEnhMetaFile(Result.Canvas.Handle,Source.Handle,R);
end;

如果您想使用GDI +进行抗锯齿绘制,则需要枚举图元文件内容,然后使用our Open Source SynGdiPlus unit进行渲染:

function LoadFrom(const MetaFile: TMetaFile): TBitmap;

答案 1 :(得分:1)

(感谢Arnaud的评论。)

使用matafiles时,除非使用Windows GDI方法渲染(或播放)矢量内容,否则只有在加载文件时才会呈现位图数据。我使用第三方库(GDI +)为我做的工作。每当我处理图像时,我也会使用Graphics32。

GDI +

作者的网站似乎不再有源代码了。但是,我通过搜索gdipobj.pas找到了here。我也在code.google.com上找到了它(包含在几个项目like this one中)。

Graphics32

Graphics32的源代码位于SourceForge here上。 SVN命令是:

svn co https://graphics32.svn.sourceforge.net/svnroot/graphics32/trunk graphics32

我的解决方案

花了一段时间才弄清楚如何正确渲染元文件,大小合适等等。这是我使用的功能。

uses
  GR32, GDIPOBJ, ActiveX;

procedure RenderWMF(var WMF: TMemoryStream; OutputBitmap: TBitmap32; const ScreenResolution: Integer = 96);
var
  gph: TGPGraphics;
  img: TGPImage;
  bmap: TBitmap;
  ms: IStream;
  pLi: PLongint;
  iPos: Int64;
  tmpms: TMemoryStream;
begin
  WMF.Position := 0;
  ms := TStreamAdapter.Create(WMF, soReference);
  try
    pLi := nil;
    ms.Write(WMF.Memory, WMF.Size, pLi);
    bmap := TBitmap.Create;
    try
      ms.Seek(0, soFromBeginning, iPos);
      img := TGPImage.Create(ms);
      try
        bmap.width := Trunc(img.GetWidth / img.GetHorizontalResolution * ScreenResolution + 0.5);
        bmap.height := Trunc(img.GetHeight / img.GetVerticalResolution * ScreenResolution + 0.5);
        gph := TGPGraphics.Create(bmap.Canvas.Handle);
        try
          gph.DrawImage(img, 0, 0, bmap.Width, bmap.Height);
          tmpms := TMemoryStream.Create;
          try
            bmap.SaveToStream(tmpms);
            tmpms.Position := 0;
            OutputBitmap.LoadFromStream(tmpms);
          finally
            tmpms.Free;
          end;
        finally
          gph.Free;
        end;
      finally
        img.Free;
      end;
    finally
      bmap.Free;
    end;
  finally
    ms := nil;
  end;
end;

我用这样的代码调用它:

var
  bm32: TBitmap32;
  wmf: TMemoryStream;
begin
  bm32 := TBitmap32.Create;
  try
    wmf := TMemoryStream.Create;
    try
      wmf.LoadFromFile('metafile.emf');
      RenderWMF(wmf, bm32, Screen.PixelsPerInch);
      // Do something with 'bm32'
    finally
      wmf.Free;
    end;
  finally
    bm32.Free;
  end;
end;

我知道这个答案比how to properly set the canvas size宽得多。我希望它有所帮助。