The Synopse PDF engine features:
- Create PDF documents containing text, graphics, and bitmaps;
- Use a TCanvas instance to draw the page content with your VCL code, just as usual (you can even use the Handle property of the TCanvas to use low level GDI commands);
- Automatic document Compression;
- Embed JPG or BMP/GIF/PNG pictures (bitmaps are compressed into the PDF content);
- You can draw any EMF file or TMetaFile instance, which will be converted to vectorial;
- Fully handle Unicode text content;
- Embed TrueType fonts, as a whole, or as a subset (i.e. only used glyphs are stored into the PDF);
- Easily add outlines or change page format;
- PDF file content generation is very fast: after profiling, it appears that the creation time is mostly spent in compression, not in content generation;
- Works in Delphi 7 up to 2010;
- Whole engine is only one unit (i.e. no external dll is required), and doesn't require our SQLite3 database framework;
- Freeware Opensource unit, licensed under a MPL/GPL/LGPL tri-license.
There are two ways of using this framework.
1. Either directly (using the Canvas property, and its associated methods):
with TPdfDocument.Create doHere is the resulting file: testdirect.pdf
try
AddPage;
Canvas.SetFont('georgia',12,[fsItalic,fsBold]);
Canvas.TextOut(100,700,'Synopse PDF Engine Test');
Canvas.TextOut(100,680,'Testé en Français');
SaveToFile('testdirect.pdf');
finally
Free;
end;
2. Either by using a TCanvas, and VCL standard code:
with TPdfDocumentGDI.Create doHere is the resulting file: testvcl.pdf
try
for i := 1 to 9 do begin
AddPage;
with VCLCanvas do begin
Font.Name := 'Times new roman';
Font.Size := 150;
Font.Style := [fsBold,fsItalic];
Font.Color := clNavy;
TextOut(100,100,'Page '+IntToStr(i));
end;
end;
SaveToFile('testvcl.pdf');
finally
Free;
end;
Of course, both way of creating the PDF content can be used at the same time in your code, without any problem.
You can download the full source code of this unit, with other needed Synopse units, from synpdf.zip licensed under a MPL/GPL/LGPL tri-license.
Luiz Américo has made some sample code about Unicode, which can be downloaded from here.
I'm some kind of proud about this code, especially the fast low level CMAP4/TrueType part (for getting Unicode chars and their widths), the great TrueType subsetting trick (which works under XP and later, for once Micro$oft provided some useful API), and the way the TCanvas/EMF/TMetaFile features are implemented. Feedback welcome!
15 reactions
1 From Mohammed Nasman - 03/05/2010, 17:40
Nice work,
But when I try to compile the first example, I got this error:
[DCC Error] SynCommons.pas(1247): E2441 Inline function declared in interface section must not use local symbol 'WinAnsiTableSortedFind'
It worked, after I remove the inline from the WideCharToWinAnsi method.
Also it seems not working with RTL languages like Arabic, or is there an option to set the code page to 1256?
2 From Luiz Américo - 03/05/2010, 18:47
Opening both files (testdirect and testvcl) with adobe reader 9 gives an error about invalid font Georgia,BoldItalic.
Also i noticed that you are using WinAnsiEncoding (i.e., code page 1252). Some unicode characters can not be represented by such code page and in this case is necessary to use UTF16-LE encoding.
This library handle all unicode range?
3 From A.Bouchez - 03/05/2010, 19:04
I downloaded Acrobat Reader 9.
In fact, Acrobat Reader 9 doesn't handle the /flags item of the font definition as expected by the PDF Reference 1.3 official document §5.7.1... it expect this item to be equals to 32 (i.e. PDF_FONT_STD_CHARSET) whatever the font type is. Talk about standard and specifications!
Fixed with the newly uploaded version of the library.
Thanks for your feedback!
4 From A.Bouchez - 03/05/2010, 19:06
The engine is 100% unicode ready.
The PDFString is an AnsiString using the current code page. It is used internaly for most Ansi-Encoded values (like property names in PDF), and can be used safely from Delphi 7 to 2010.
See TPdfDocument.Create constructor code and CodePage/FCodePage variable in the unit. Override existing SysLocale.DefaultLCID value before calling this constructor.
Another possibility is to use Wide version of the API calls, together with the VCLCanvas property.
You could even use direct Unicode text output using:
- under Delphi 2009/2010, the TPdfCanvas.ShowText(const text: UnicodeString; NextLine: boolean) method
- with all versions of Delphi: the TPdfCanvas.ShowText(PW: PWideChar; NextLine: boolean=false) method
- with all versions of Delphi: the TPdfCanvas.TextOutW() method
- by using a PDFString and changing the current code page encoding
Both ShowText() methods (Unicode or Ansi) can be mixed, but must be embraced by BeginText/EndText methods:
with P.Canvas do begin
SetFont('georgia',12,[fsItalic,fsBold]);
SetLeading(Page.FontSize); // next line just below the current one
BeginText;
MoveTextPoint(20,P.DefaultPageHeight-40);
ShowText('Testé chez nous');
ShowText(pointer(WideChars),True);
EndText;
end;
I didn't test or implement RTL languages. Perhaps you could help me with your knowledge of both Delphi and Arabic!
5 From Luiz Américo - 04/05/2010, 03:51
Hi,
I tried without success creating a pdf with unicode. I sent to your email a Delphi 7 example.
6 From A.Bouchez - 04/05/2010, 11:22
The Unicode works well... You just forgot to use BeginText/EndText and MoveTextPoint/SetLeading methods as required by the PDF format.
I've release your example code, with the corrections, to be downloaded at http://synopse.info/files/pdf/synpd...
I've added the resulting testunicode.pdf file.
The resulting PDF is OK for Greek, but there is some problems with Right to Left languages:
- I had to reverse the chars manually, which is not the best option here (see parenthesis problems);
- Arabic Ligatures are not handled by the Acrobat Reader: they should be handled by the PDF producer. I think there are some low level Windows API for that, but I don't know them. Can anyone help about this?
Note that the TrueType subset font embedding works with these characters, without any problem. I've also modified the TPdfDocument constructor, in order to allow another codepage for the PDFString, if needed.
7 From Luiz Américo - 04/05/2010, 18:32
Thanks again. It's working now.
8 From A.Bouchez - 05/05/2010, 09:18
Reading text from pdf is not a difficult task. Since I could need such a feature for another project (http://roc-armees.info), I think I'll implement extracting text from a PDF file in a future version of SynPDF. This unit already knows the PDF structure, it will be not a big challenge to make the TPDFDocument class read a PDF content.
9 From Mohammed Nasman - 05/05/2010, 13:48
A,
Arnaud,
I think what do you need to support Arabic to check the if the language require "Glyph Shaping" which is needed for Arabic language, because the character change it's shape depend on his position on the word, you can check that using ScriptGetProperties as the following
http://msdn.microsoft.com/en-us/lib...).aspx
I posted a question on SO, to help translate the example to Delphi, because I'm not good in C++.
You can read more here:
http://www.xmlpdf.com/rtl.html
10 From d.carstensen - 05/05/2010, 15:55
Hi,
quite amazing, especially creating font subsets is well done!
One hint: Unicode.pdf is damaged because the /Type key is missing in Descendant font (/Type is required).
I test my PDFs with Acrobat full-version: When Acrobat ask for saving (without modification) the PDF is damaged and was repaired by Acrobat.
Another good syntax validation tool is the Acrobat-Preflight tool.
One profile can detect file format errors.
Best regards
Dirk Carstensen
11 From A.Bouchez - 06/05/2010, 07:28
To Dirk: I don't have the Acrobat application. Too much money for me: that's why I wrote this library
I've added the /Type key, as you suggested. Thanks for the feedback!
To Mohammed: Thanks for the "Glyph Shaping" reference. I'll use the ScriptGetProperties API to get the work done. I'll then need your feedback about the result!
I'll send a new article on this blog when I'm ready with the updated version.
In all cases, thanks for your feedback and very helpful comments. That's the beauty of OpenSource: sharing, sharing, sharing...
12 From A.Bouchez - 06/05/2010, 16:42
The unit has been updated, and now support Glyph Shaping. Arabic sample included.
See this article about the update to version 1.7.2.
13 From A.Bouchez - 21/06/2010, 11:21