用fastreport来打印Trichedit的内容。文字正常,但图片在打印预览的时候出现失真模糊现象。文字很清晰,就图片不行,会颜色失真变得模糊。
调整前:
调整后
查看fastreport的代码,发现是生成的TMetafile图元文件里面文字和图片很大,这样在StretchDraw缩小到预览画面的时候出现了颜色失真。
调整metafile文件的Width宽高或者mmWidth也不行,调小了哪怕预览半页,文字还是那么大。猜测可能是richedit在渲染的时候根据图片的原始宽高与屏幕上显示的宽高的比率自动进行了页面放大。(因为粘贴图片到richedit后,对图片做了拖拉调整,屏幕闪显示的会比实际图片要小)
如果是richedit自动根据图片尺寸调整了图元文件的尺寸,那就不好搞了,于是将TMetafile改为Tbitmap来作为渲染目标。图片果然清晰了。
只是这样改后有一个问题,就是矢量图变成了点阵图。那么在默认预览环境下是很清晰的,但如果放大或者缩小很多以后,文字就不如原先使用TMetafile时清晰了。TMetafile是矢量图,不论放大多少倍,文字都是很清晰的。改成tbitmap后,对预览图放大缩小太多,文字就会有锯齿。
不过总体上还是直接看默认预览效果的占绝大多数。去手动再放大缩小的人不多。并且打印预览时图片失真肯定是不行,必须要改。
另外还有一个就是fastreport默认预览是100%,可以根据显示器DPI放大比率,在预览时自动放大相应倍数,不然预览的会比实际的看起来小。代码如下,在frxReport1控件的Preview事件里添加一行。
procedure TForm_report.frxReport1Preview(Sender: TObject);
begin
TfrxPreview(frxReport1.Preview).Zoom:= frxReport1.Preview.ScaleValue(1.0);
end;
预览richedit图片模糊的修改方法
把frxRich单元内的CreateMetafile 和 Draw 两个过程进行修改,完整代码如下
注意:CreateMetafile的申明的地方大概在78行的位置,也要把返回类型改为tbitmap
function TfrxRichView.CreateMetafile: Tbitmap;
var
Range: TFormatRange;
//EMFCanvas: TMetafileCanvas;
PrinterHandle: TfrHandle;
aScaleX, aScaleY: Extended;
h: hdc;
begin
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Enter;
{$ENDIF}
try
if UsePrinterCanvas then
PrinterHandle := frxPrinters.Printer.Canvas.Handle
else
PrinterHandle := GetDC(0);
finally
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Leave;
{$ENDIF}
end;
FillChar(Range, SizeOf(TFormatRange), 0);
Range.rc := Rect(Round(GapX * 1440 / 96), Round(GapY * 1440 / 96),
Round((Width - GapX) * 1440 / 96), Round((Height - GapY) * 1440 / 96));
Range.rcPage := Range.rc;
//Result := TMetafile.Create;
Result := Tbitmap.Create;
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Enter;
{$ENDIF}
try
// GetDisplayScale(PrinterHandle, UsePrinterCanvas, aScaleX, aScaleY);
h:= getdc(0);
aScaleX := GetDeviceCaps(h,LOGPIXELSX)/96;
aScaleY := aScaleX;
ReleaseDC(0, h);
finally
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Leave;
{$ENDIF}
end;
Result.Width := Round(Width * aScaleX);
Result.Height := Round(Height * aScaleY);
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Enter;
{$ENDIF}
//EMFCanvas := TMetafileCanvas.Create(Result, PrinterHandle);
//EMFCanvas.Lock;
try
//Range.hdc := EMFCanvas.Handle;
Range.hdc := result.Canvas.Handle;
Range.hdcTarget := Range.hdc;
Range.chrg.cpMax := -1;
Range.chrg.cpMin := 0;
FRichEdit.SendSynchMessage(EM_FORMATRANGE, 1, frInteger(@Range), True);
if not UsePrinterCanvas then
ReleaseDC(0, PrinterHandle);
FRichEdit.SendSynchMessage(EM_FORMATRANGE, 0, 0, True);
finally
//EMFCanvas.Unlock;
//EMFCanvas.Free;
{$IFNDEF NO_CRITICAL_SECTION}
frxCSRich.Leave;
{$ENDIF}
end;
end;
procedure TfrxRichView.Draw(Canvas: TCanvas; ScaleX, ScaleY, OffsetX,
OffsetY: Extended);
var
//EMF: TMetafile;
EMF: tbitmap;
begin
if Height < 0 then Height := Height * (-1);
BeginDraw(Canvas, ScaleX, ScaleY, OffsetX, OffsetY);
DrawBackground;
EMF := CreateMetafile;
try
Canvas.StretchDraw(Rect(FX, FY, FX1, FY1), EMF);
finally
EMF.Free;
end;
if not FObjAsMetafile then
begin
DrawFrameEdges;
DrawFrame;
end;
end;
经如此修改后,渲染设备从图元文件改成了位图文件。图片打印预览正常了。
不过这样改以后有个问题,就是导出为pdf的话,内容成为图片格式的了。于是用了个简单粗暴的方法,保留原函数,修改的作为新增返回bitmap函数。然后新增一个全局变量,如果是预览模式就使用返回bitmap的函数,否则使用返回tmetafile的函数。这样问题解决了,而且导出pdf时还能多一个选项,就是即可以导出文本类型的也可以导出图片类型的PDF。
另外,如果StretchDraw能选择缩放算法使用高精度算法,或者用gdi+图片处理库,也许能在原先的代码上实现不失真的预览。