0

RTF 图像支持非常有限(Windows 支持,不仅在 Delphi 中),位图和元文件以外的其他格式也可以工作,但 RichEdit 控件不能正确显示。

我注意到的一件事是,当 Microsoft Word 图像被复制并粘贴到 RTF 中时,它可以平滑地缩放,而不是手动粘贴图像(作为位图)。原因是 Word 在内部保留 Metafile 格式的图像的缩放预览(以及原始图像),并且此缩放版本被复制并粘贴到 RTF 中,显然 RTF 在 RichText 编辑器中缩放时可以平滑地呈现 MetaFile 图像。

似乎是一个很好的解决方法,在 WPF 函数中实现嵌入 BMP 后,我注意到一个我无法解决的问题:生成的 WMF 是位图大小的两倍。看起来 WMF 存储了绘制缓冲区或图像的第二个副本。

编码:

  procedure DoCopyImage(AGraphic: TGraphic; AWidth, AHeight: Integer);
  var
    mf: TMetafile;
    mfc: TMetafileCanvas;
    r: Cardinal;
  begin
    mf := TMetafile.Create;
    try
      mf.Enhanced := True;
      mf.SetSize(AWidth, AHeight);
      mfc := TMetafileCanvas.Create(mf, 0);
      try
        // set clipping region to a whole image
        r := CreateRectRgn(0, 0, AWidth, AHeight);
        try
          SelectClipRgn(mfc.Handle, r)
        finally
          DeleteObject(r);
        end;

        if (AGraphic.Width = AWidth) and (AGraphic.Height = AHeight) then
          mfc.Draw(0, 0, AGraphic)
        else
          mfc.StretchDraw(Rect(0, 0, AWidth, AHeight), AGraphic);
      finally
        mfc.Free;
      end;
      // Clipboard.Assign(mf);
      mf.SaveToFile('C:\4MB_MetaFile_Why.wmf');
    finally
      mf.Free;
    end;
  end;

我使用 TBitmap 作为 TGraphic 来调用它:

  pic := TPicture.Create;
  pic.LoadFromFile('C:\2MB_24bpp_Bitmap.bmp');
  bmp := Graphics.TBitmap.Create;
  bmp.Assign(pic.Graphic);
  bmp.Dormant; // experimentation
  bmp.FreeImage; // experimentation
  DoCopyImage(bmp, bmp.Width, bmp.Height);

有人可以找到这种行为的解释吗?WMF 是否将绘画缓冲区与位图一起存储?如何预防?

4

2 回答 2

2

至于为什么您的大小可能不同 - 一旦您绘制到元文件,您就将责任移交给元文件以保存数据。您的位深度可能在输出中有所不同。我不确定,但我也想知道 StretchDraw 调用是否最终保存了原始输入,或者它是否保存了具有新像素数的位图。如果图像小于可以解释差异的大小拉伸绘制调用。您还将在元文件中产生一些不会出现在已保存位图中的开销,尽管这应该是最小的。

您可能想查看MetaFile Explorer。它是一个向您展示嵌入在元文件中的不同绘图命令的工具。我尝试了您的代码并在 MetaFileExplorer 中查看了生成的图像。嵌入图像的大小对我来说看起来不错。查看 EMR_STRETCHBLT.cbBitsSrc 大小。但是,我确实看到了您报告的大小差异,所以有些东西正在占用那个空间。

你说:

原因是 Word 在内部保留 Metafile 格式的图像的缩放预览(以及原始图像),并且此缩放版本被复制并粘贴到 RTF 中,显然 RTF 在 RichText 编辑器中缩放时可以平滑地呈现 MetaFile 图像。

我对这个假设有点怀疑。位图(任何光栅图像)将根据缩放的执行方式显示不同的缩放伪影。Image Scaling Wikipedia 页面有一些很好的差异示例。

当您将位图写入图元文件时,您就是在将图像绘制到屏幕上时让图元文件执行缩放。图元文件绘制代码与 RTF 绘制代码使用的不同算法将导致输出看起来不同。然而,元文件并没有什么特别之处,不能用普通的位图来完成。在这两种情况下,都需要调整原始像素的大小/重新采样。

元文件的真正用途不仅仅是嵌入单个位图图像。这是一个很好的Windows 图元文件常见问题解答,它解释了一些差异。基本上,如果您定义线条、形状和文本,您可以获得非常平滑的缩放,因为您是在描述绘图,而不是存储单个像素。

获得好看的缩放图像的关键部分是选择正确的缩放例程。我在我的应用程序中为此使用了Graphics32 库。标准的 StretchDraw 例程被设计为快速而不是高质量。当准备在屏幕上绘制时,我选择了一个 Graphics32 重采样器,它可以提供我想要的结果。这可以根据大小而改变。例如,您的最终输出是否大于或小于输入图像。我将图像调整为最终输出大小,然后只使用 Draw 而不是 StretchDraw。

于 2013-06-10T22:07:49.933 回答
1

在您之前添加此代码mf.SaveToFile('C:\4MB_MetaFile_Why.wmf');

  mf.MMHeight := Round(mf.Height / Screen.PixelsPerInch * 2540);
  mf.MMWidth := Round(mf.Width / Screen.PixelsPerInch * 2540);
于 2013-06-10T13:58:01.497 回答