You are not logged in.
Pages: 1
I - like many others - use FastReport for my reports but the exported PDF files - when pictures are embedded into them - look really bad.
Therefore I have decided to rework all my reports to use SynPDF.
A short introduction:
I have two webservice applications (both based on mORMot) that communicate with each other. One of them generates the picture files (*.png) which are inserted into reports by the second application.
All this can be handled by SynPDF alone. Instead of png files I plan to use the windows metafiles(*.emf) which the second application will render into resulting PDF pages.
I have tried to render my generated emf file and stumbled on some small issues in SynPDF that I would like to have fixed:
They are related to Canvas.SaveDC and Canvas.RestoreDC
procedure TPdfEnum.RestoreDC;
begin
Assert(nDC>0);
dec(nDC);
Canvas.GRestore; // <--- imho this line has to be added
end;
procedure TPdfEnum.SaveDC;
begin
Assert(nDC<high(DC));
DC[nDC+1] := DC[nDC];
inc(nDC);
Canvas.GSave; // <--- imho this line has to be added
end;
and to clipping - I have already read this topic from MtwStark https://synopse.info/forum/viewtopic.php?id=4276 , but I was not digging so deeply and not to such extent as he.
I was focused only on the EMR_SELECTCLIPPATH that is a part of my generated pictures - therefore my suggested change affects only the EMR_SELECTCLIPPATH.
function EnumEMFFunc(DC: HDC; var Table: THandleTable; R: PEnhMetaRecord;
NumObjects: DWord; E: TPdfEnum): LongBool; stdcall;
....
EMR_SELECTCLIPPATH:begin // <--- added EMF_record EMR_SELECTCLIPPATH
if PolyFillMode = ALTERNATE then
E.Canvas.EOClip
else
E.Canvas.Clip;
E.Canvas.NewPath;
end;
EMR_BEGINPATH: begin
E.InPath := true; // <--- added a path bracket flag := true;
E.Canvas.NewPath;
if not Moved then begin
E.Canvas.MoveToI(Position.X,Position.Y);
Moved := true;
end;
end;
EMR_ENDPATH:
begin
E.InPath := false; // <--- added a path bracket flag := false
E.Canvas.fNewPath := false;
end;
When the InPath flag is true, the path defined in path brackets (EMR_BEGINPATH .. EMR_ENDPATH) should not be Filled nor Stroked
procedure TPdfEnum.NeedBrushAndPen;
begin
if InPath then // <--- added a condition
begin
fStrokeColor := -1;
fPenWidth := -1;
fFillColor := -1;
fPenStyle := -1;
end
else begin
if fInlined then begin
fInlined := false;
Canvas.Stroke;
end;
NeedPen;
with DC[nDC] do
if not brush.null then
FillColor := brush.color;
end;
end;
procedure TPdfEnum.NeedPen;
begin
with DC[nDC] do
if not pen.null and not InPath then begin // <--- added a condition not InPath
StrokeColor := pen.color;
...
end else begin
// pen.null need reset values
fStrokeColor := -1;
fPenWidth := -1;
fPenStyle := -1;
end;
end;
and in EnumEMFFunc procedure an PolyPoly procedure
function EnumEMFFunc(DC: HDC; var Table: THandleTable; R: PEnhMetaRecord;
NumObjects: DWord; E: TPdfEnum): LongBool; stdcall;
...
EMR_POLYGON, EMR_POLYLINE, EMR_POLYGON16, EMR_POLYLINE16:
if not brush.null or not pen.null and not E.InPath then begin // <--- added a condition not InPath
...
end;
procedure TPdfEnum.PolyPoly(data: PEMRPolyPolygon; iType: Integer);
...
if not InPath then // <--- added a condition not InPath
begin
if iType in [EMR_POLYPOLYLINE, EMR_POLYPOLYLINE16] then begin // stroke
...
end;
end;
With these small changes applied my generated emf's are rendered correctly
Last edited by EvaF (2019-02-11 12:46:50)
Offline
I am continuing in the study of synPDF and mORMotReport and I have found out, that in some cases (when the font of pageNrs is not diffferent from the font of header (or footer))
then Adobe Acrobat notifies the error in generated PDF.
It can be fixed by swapping order of page draw and PageNr text:
procedure TGDIPages.EndDoc;
...
for i := 0 to n-1 do begin
Page := CreateMetaFile(fPages[i].SizePx.X,fPages[i].SizePx.Y);
try
fCanvas := CreateMetafileCanvas(Page);
//- fCanvas.Draw(0,0,GetMetaFileForPage(i)); // re-draw the original page
s := format(fPagesToFooterText,[i+1,n]); // add 'Page #/#' caption
aX := fPagesToFooterAt.X;
if aX<0 then
aX := fPages[i].SizePx.X-fPages[i].MarginPx.Right;
SavedState := fPagesToFooterState;
if TextAlign=taRight then
dec(aX,fCanvas.TextWidth(s));
with fPages[i] do
fCanvas.TextOut(aX,SizePx.Y-MarginPx.bottom-fFooterHeight+
fFooterGap+fPagesToFooterAt.Y,s);
fCanvas.Draw(0,0,GetMetaFileForPage(i)); //+ <-- swapping an order of commands
FreeAndNil(fCanvas);
SetMetaFileForPage(i,Page); // replace page content
finally
Page.Free;
end;
...
Offline
Pages: 1