将图片保存为各种文件格式

7
我有一个例程procedure DrawStuff(ACanvas: TCanvas; const ARect: TRect),用于在TCanvas的指定矩形上绘制内容。目前我使用PaintBox的画布调用DrawStuff。现在我要添加一个“另存为”选项,让用户可以选择多种文件格式(如bmp、wmf、jpg等)将DrawStuff的结果保存到文件中(最好尽可能多地使用TGraphic的派生类)。
将绘图内容绘制到TMetafile并将其保存为“bla.bmp”或将其分配给TPicture不起作用-例如,它会生成扩展名为“.bmp”的文件,但实际上不是位图。目前,我无法想到不涉及每个文件格式的特殊情况的解决方案:
  • bmp-使用TBitmap.Canvas
  • wmf/emf-使用TMetafileCanvas
  • 等等。
你有什么想法吗?

2
制作一个“统一”的例程来保存BMP、PNG、GIF、JPG等格式非常容易,但如果还要包括WMF或EMF,则要困难得多,因为后者是矢量图像格式,而前者是光栅图像格式。当然,除非您选择将图像保存为嵌入在EMF/WMF中的光栅位图,但在这种情况下,使用EMF/WMF格式就是纯粹的愚蠢... - Andreas Rejbrand
特别处理wmf/emf应该没问题。你能给我提到的统一例程的指针吗? - Uli Gerhardt
PS:我认为将绘图到元文件,然后将其分配给TPicture可能有效,因为它似乎是一组记录的GDI调用。 - Uli Gerhardt
特殊情况是正确的解决方案。你为什么不想这样做呢?PNG与JPG不同,WMF也不同。如果没有一些变化,你如何保存它们中的每一个呢? - David Heffernan
它如何为您节省工作?创建所有图像的代码必须不同。为什么要将它们塞进 TPicture 然后再保存呢?直接保存,省去一步,获得高质量的结果。很抱歉我误解了问题,它真的让我措手不及。 - David Heffernan
显示剩余2条评论
1个回答

11

我猜一种“简单”转换可能就像这样:

type
  TGraphicTypeEnum = (gteBMP, gteJPG, gteTIF, gtePNG);

procedure SaveGraphicAs(AGraphic : TGraphic; AGraphicType : TGraphicTypeEnum; AFileName : String);
var vGraphicClass : TGraphicClass;
    vTargetGraphic : TGraphic;
    vBmp : TBitmap;
begin

  case AGraphicType of
    gteBMP : vGraphicClass := TBitmap;
    gtejpg : vGraphicClass := TJPEGImage;
    gtetif : vGraphicClass := TWICImage;
    gtepng : vGraphicClass := TPngImage;
  else
    // EXIT; or raise...
  end;
  if aGraphic is vGraphicClass then //As suggested by Rob Kennedy
    AGraphic.SaveToFile(AFileName)
  else
  begin
    vBmp := nil;
    vTargetGraphic := vGraphicClass.Create;
    try
      vBmp := TBitmap.Create;
      vBmp.Assign(AGraphic);
      vTargetGraphic.Assign(vBmp);
      vTargetGraphic.SaveToFile(aFileName);
    finally
      vTargetGraphic.Free;
      vBmp.Free;
    end;
  end;
end;

当你给一个TPicture赋值时,它会将图形转换为你要赋值的类。因此给TPicture赋值是无效的。

需要注意的是,在我的示例中,有两层转换,原始图像被转换成位图然后再转换成最终格式。这个过程中可能会损失很多信息。大多数(或全部?)图形类型知道如何转换到TBitmap和从TBitmap转换回去,但TJPEGImage不知道如何转换到TPngImage,反之亦然。

可以开发更高效的转换方法,以保留与文件格式特定的透明度和其他效果,但这超出了我的知识范围。但根据你的需求,这可能足够了。


如果 AGraphicvGraphicClass,那么跳过位图转换可能是值得的。否则,即使将 JPEG 保存为 JPEG,您也会失去图像质量。 - Rob Kennedy
或者根本不调用SaveGraphicAs函数,直接调用AGraphic.SaveToFile。还有一些其他问题可能会出现。第三方可能会注册自己的PNG类(DevExpress就是这样做的)。所以你最终会得到TdxPNGImage is TPNGImage(这将是错误的)。很遗憾,目前无法获取给定扩展名的当前注册类(QC57402在2008-01-24提出...仍然未解决)。对于调用者来说,确定图形是否已经处于正确的格式可能更容易。但是,我猜这样优化也不会有坏处。 - Ken Bourassa
[dcc32 警告] main.pas(101): W1036 变量 'vGraphicClass' 可能未被初始化。如何解决? - Xel Naga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接