#1 2010-06-22 19:44:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Synopse PDF engine 1.8

Our PDF engine has been updated, it's now on version 1.8.

Two new features were added:
- font substitution if the font is not existing in the system (worse case will use "Arial" for any not available font);
- now handle ETO_GLYPH_INDEX in metafile rendering - see http://synopse.info/forum/viewtopic.php?id=3

Some obscure WinAnsi encoding / decoding to / from Unicode were also identified and fixed (in SynCommons.pas unit).

You can download the updated full source code of this unit, with other needed Synopse units, from synpdf.zip. Source code is licensed under a MPL/GPL/LGPL tri-license.

Offline

#2 2010-06-28 15:54:01

reddwarf
Member
Registered: 2010-06-28
Posts: 40
Website

Re: Synopse PDF engine 1.8

Thanks for the great PDF Library. I found 2 issues with the VCLCanvas functions. Please check my code:

procedure TForm1.Btn1Click(Sender: TObject);
var
  xPDF: TPdfDocumentGDI;
  xRect: TRect;
  xMF: TMetafile;
  xMFC: TMetaFileCanvas;

  procedure RotTextWithPoint(aC: TCanvas; aText: String; aAngle, aX, aY: Integer);
  var
    xLF: TLogFont;
    xF: TFont;
  begin
    xF := TFont.Create;
    try
      xF.Assign(aC.Font);
      GetObject(xF.Handle, SizeOf(xLF), @xLF);
      xLF.lfEscapement  := aAngle*10;
      xLF.lfOrientation := aAngle*10;
      SetBkMode(Handle, TRANSPARENT);
      xF.Handle := CreateFontIndirect(xLF);
      aC.Font.Assign(xF);
    finally
      xF.Free;
    end;
    aC.TextOut(aX, aY, aText);
    aC.MoveTo(aX-2, aY);
    aC.LineTo(aX+2,aY);
    aC.MoveTo(aX,aY-2);
    aC.LineTo(aX,aY+2);
  end;
  
begin
  xPDF := TPdfDocumentGDI.Create;
  xMF := TMetafile.Create;
  try
    xMF.Width := 500;
    xMF.Height := 500;
    
    xMFC := TMetafileCanvas.Create(xMF, 0);
    with xMFC do
    try
      Pen.Color := clBlue;
      Brush.Style := bsClear;
      Rectangle(0, 0, ClipRect.Right-1, ClipRect.Bottom-1);
      Pen.Color := clRed;
      xRect := Rect(100, 20, 150, 40);
      Rectangle(xRect);
      
      TextRect(xRect, xRect.Left, xRect.Top, 'long text is not clipped');

      RotTextWithPoint(xMFC, 'rotated text is misplaced', 90, 100, 200);
      RotTextWithPoint(xMFC, 'rotated text is misplaced', 180, 250, 200);
      RotTextWithPoint(xMFC, 'rotated text is misplaced', 270, 300, 200);
      RotTextWithPoint(xMFC, 'rotated text is misplaced', 45, 350, 200);
    finally
      Free;
    end;

    xMF.SaveToFile('a.emf');

    xPDF.AddPage;
    with xPDF.VCLCanvas do begin
      Draw(0, 0, xMF);
    end;

    xPDF.SaveToFile('a.pdf');
  finally
    xPDF.Free;
    xMF.Free;
  end;
end;

1. Rotated text is misplaced - there is a wrong sign in SynPDF.pas on line 6556. (procedure TPdfEnum.TextOut(var R: TEMRExtTextOut);)

Here is the corrected code:

(...)
    if font.spec.angle<>0 then begin
      a := font.spec.angle*(PI/180);
      acos := cos(a);
      asin := sin(a);
      with Canvas do
        SetTextMatrix(acos, asin, -asin, acos,
          I2X(R.emrtext.ptlReference.X+Round(W*acos-H*asin)),
          I2Y(R.emrtext.ptlReference.Y-Round(H*acos-W*asin))); // <- minus sign REDDWARF
    end else
(...)

2. Text is not cropped when using TextRect - unfortunately I did not find the solution on my own. I need this feature for drawing tables (text is clipped in a cell).

EDIT: Maybe I found a solution. This is the code:

procedure TPdfEnum.TextOut(var R: TEMRExtTextOut);
var W,H: integer;
    DX: PIntegerArray; // not handled during drawing yet
    ASize: single;
    tmp: array of WideChar; // R.emrtext is not #0 terminated -> use tmp[]
    a, acos, asin: single;
begin
  with DC[nDC] do begin
    SetLength(tmp,R.emrtext.nChars+1); // faster than WideString for our purpose
    move(pointer(PtrUInt(@R)+R.emrtext.offString)^,tmp[0],R.emrtext.nChars*2);
    // guess the font size
    if font.LogFont.lfHeight<0 then
      ASize := -font.LogFont.lfHeight*Canvas.fFactorY else
      ASize := font.spec.cell*Canvas.fFactorY;
    // ensure this font is selected (very fast if was already selected)
    Canvas.SetFont(Canvas.FDoc.FDC,font.LogFont,ASize);
    // calculate coordinates
    if R.emrtext.offDx=0 then begin
       if R.emrtext.fOptions and ETO_GLYPH_INDEX<>0 then
         W := 0 else
         W := Round(Canvas.UnicodeTextWidth(pointer(tmp))/Canvas.fFactorX);
    end else  begin
      DX := pointer(cardinal(@R)+R.emrtext.offDx);
      W := DXTextWidth(DX,R.emrText.nChars);
    end;
    if font.Align and TA_CENTER=TA_CENTER then
      W := W shr 1 else
    if font.Align and TA_RIGHT=0 then
      W := 0;
    if font.Align and TA_BASELINE<>0 then
      H := 0 else
    if font.Align and TA_BOTTOM<>0 then
      H := font.spec.descent else
      H := -font.spec.ascent;
    // draw background (if any)
    if (R.emrtext.fOptions and ETO_OPAQUE<>0) and not brush.null and
       (font.spec.angle=0) then begin
      // don't handle BkMode, since global to the page, but only specific text
      // don't handle rotation here, since should not be used much
      NormalizeRect(R.rclBounds);
      FillRectangle(R.rclBounds);
    end;
    // draw text
    FillColor := font.color;
{$ifdef USE_UNISCRIBE}
    Canvas.RightToLeftText := R.emrtext.fOptions and ETO_RTLREADING<>0;
{$endif}

    //REDDWARF BEGIN CLIPPING
    with Canvas do begin
      GSave;
      with R.emrtext.rcl do begin
        MoveTo(I2X(Left), I2Y(Top));
        LineTo(I2X(Left), I2Y(Bottom-1));
        LineTo(I2X(Right-1), I2Y(Bottom-1));
        LineTo(I2X(Right-1), I2Y(Top));
      end;
      ClosePath;
      Clip;
      NewPath;
    end;
    //REDDWARF END CLIPPING

    Canvas.BeginText;
    if font.spec.angle<>0 then begin
      a := font.spec.angle*(PI/180);
      acos := cos(a);
      asin := sin(a);
      with Canvas do
        SetTextMatrix(acos, asin, -asin, acos,
          I2X(R.emrtext.ptlReference.X+Round(W*acos-H*asin)),
          I2Y(R.emrtext.ptlReference.Y-Round(H*acos-W*asin))); // <- minus REDDWARF
    end else
      Canvas.MoveTextPoint(
        Canvas.I2X(R.emrtext.ptlReference.X-W),
        Canvas.I2Y(R.emrtext.ptlReference.Y-H));
    if R.emrtext.fOptions and ETO_GLYPH_INDEX<>0 then
      Canvas.ShowGlyph(pointer(tmp),R.emrtext.nChars) else
      Canvas.ShowText(pointer(tmp));
    Canvas.EndText;

    Canvas.GRestore;//REDDWARF CLIPPING RESTORE
  end;
end;

Last edited by reddwarf (2010-06-28 17:03:00)

Offline

#3 2010-06-28 21:02:26

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Synopse PDF engine 1.8

Thanks for your tips. I'll try and implement them to the main source code!

That's GREAT!!!

Offline

#4 2010-06-29 00:58:58

reddwarf
Member
Registered: 2010-06-28
Posts: 40
Website

Re: Synopse PDF engine 1.8

I worked on your PDF library and corrected some other issues (all concerning VCLCanvas):

  • Error when drawing multiple images

  • Automatical JPEG compression for graphics

  • UNDERLINE + STRIKEOUT support (also in RICH TEXT and rotated text !)

  • Because some developers may prefer to use the default JPEG unit in Delphi I added the directive USE_SYNGDIPLUS that can switch between GDIPLUS / JPEG

  • PenWidth changed to Single -> better precision (f.e. for underlined text)

  • ... maybe some other minor corrections

I don't see where I could save an attachment, therefore I send you the whole SynPdf.pas unit in an email. All my code changes (I hope that I haven't forgotten something) are marked with ONDREJ comment.

Offline

#5 2010-06-29 06:53:36

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Synopse PDF engine 1.8

You are welcome to register to our source code repository, and push the modifications directly!

See http://synopse.info/forum/viewtopic.php?id=29

Thanks for all that!

Offline

#6 2010-06-29 16:38:09

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,660
Website

Re: Synopse PDF engine 1.8

I reviewed then uploaded to the source code repository the reddwarf's modifications.
See also http://synopse.info/forum/viewtopic.php?id=36

Hope everything is now OK.

Great work indeed!

Offline

Board footer

Powered by FluxBB