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是否存储绘图缓冲区以及位图?怎么预防呢?
答案 0 :(得分:2)
至于为什么你的尺寸可能会有所不同 - 一旦你绘制到图元文件,你就会将责任交给元文件来保存数据。您的位深度可能会在输出中有所不同。我不确定,但我也想知道StretchDraw调用是否最终保存了原始输入,或者它是否保存了具有新像素数的位图。如果图像小于拉伸绘制调用的大小,可以解释差异。您还将在元文件中有一些开销,这些开销不会在保存的位图中,尽管这应该是最小的。
您可能需要查看MetaFile Explorer。它是一个工具,它将向您显示嵌入在图元文件中的不同绘图命令。我尝试了你的代码并在MetaFileExplorer中查看了生成的图像。嵌入式图像的大小对我来说很合适。查看EMR_STRETCHBLT.cbBitsSrc大小。但是,我确实看到你报告的尺寸差异,所以有些东西占据了这个空间。
你说:
原因是Word内部保存了Metafile格式的图像的缩放预览(以及原始图像),这个缩放版本被复制并粘贴到RTF,显然RTF在RichText编辑器中缩放时可以平滑地呈现MetaFile图像。
我对这个假设有点质疑。位图(任何光栅图像)将根据缩放的执行方式显示不同的缩放伪像。 Image Scaling Wikipedia page有一些很好的例子。
当您将位图写入图元文件时,您可以在图像绘制到屏幕时让图元文件执行缩放。元文件绘图代码与RTF绘图代码使用的不同算法将导致输出看起来不同。但是,使用普通位图无法实现的元文件没有什么特别之处。在这两种情况下,原始像素都需要调整大小/重新采样。
图元文件的确用于与嵌入单个位图图像不同的东西。这是一个很好的Windows Metafile FAQ,它解释了一些不同之处。基本上,如果您定义线条,形状和文本,您可以获得非常平滑的缩放,因为您正在描述绘图,而不是存储单个像素。
获得好看的缩放图像的关键部分是选择正确的缩放程序。我在我的应用程序中使用了Graphics32 library。标准的StretchDraw例程设计得很快 - 而不是高质量。当准备好绘制到屏幕时,我选择了一个Graphics32重采样器,它可以提供我想要的结果。这可能会根据尺寸而改变。例如,您的最终输出大于或小于输入图像。我将图像调整为最终输出大小,然后只绘制Draw而不是StretchDraw。
答案 1 :(得分:1)
在mf.SaveToFile('C:\4MB_MetaFile_Why.wmf');
mf.MMHeight := Round(mf.Height / Screen.PixelsPerInch * 2540);
mf.MMWidth := Round(mf.Width / Screen.PixelsPerInch * 2540);