testfppdf.lpr 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. { This program generates a multi-page PDF document and tests various
  2. functionality on each of the pages.
  3. You can also specify to generate single pages by using the -p <n>
  4. command line parameter.
  5. eg: testfppdf -p 1
  6. testfppdf -p 2
  7. Use -h to see more command line parameter options.
  8. }
  9. program testfppdf;
  10. {$mode objfpc}{$H+}
  11. {$codepage utf8}
  12. uses
  13. {$ifdef unix}cwstring,{$endif} // required for UnicodeString handling.
  14. classes,
  15. sysutils,
  16. custapp,
  17. fpimage,
  18. fpreadjpeg,
  19. fppdf,
  20. fpparsettf,
  21. fpttf,
  22. typinfo;
  23. type
  24. { TPDFTestApp }
  25. TPDFTestApp = class(TCustomApplication)
  26. private
  27. FPage: integer;
  28. FRawJPEG,
  29. FImageCompression,
  30. FTextCompression,
  31. FFontCompression,
  32. FImageTransparency: boolean;
  33. FNoFontEmbedding: boolean;
  34. FAddMetadata : Boolean;
  35. FSubsetFontEmbedding: boolean;
  36. FDoc: TPDFDocument;
  37. function SetUpDocument: TPDFDocument;
  38. procedure SaveDocument(D: TPDFDocument);
  39. procedure EmptyPage;
  40. procedure TableOfContents(D: TPDFDocument; APage: integer);
  41. procedure SimpleText(D: TPDFDocument; APage: integer);
  42. procedure SimpleLinesRaw(D: TPDFDocument; APage: integer);
  43. procedure SimpleLines(D: TPDFDocument; APage: integer);
  44. procedure SimpleImage(D: TPDFDocument; APage: integer);
  45. procedure SimpleShapes(D: TPDFDocument; APage: integer);
  46. procedure AdvancedShapes(D: TPDFDocument; APage: integer);
  47. procedure SampleMatrixTransform(D: TPDFDocument; APage: integer);
  48. procedure SampleLandscape(D: TPDFDocument; APage: integer);
  49. procedure TextInABox(const APage: TPDFPage; const AX, AY: TPDFFloat; const APointSize: integer; const ABoxColor: TARGBColor; const AFontName: string; const AText: UTF8String);
  50. protected
  51. procedure DoRun; override;
  52. public
  53. procedure WriteHelp;
  54. end;
  55. var
  56. Application: TPDFTestApp;
  57. const
  58. cPageCount: integer = 9;
  59. function TPDFTestApp.SetUpDocument: TPDFDocument;
  60. var
  61. P: TPDFPage;
  62. S: TPDFSection;
  63. i: integer;
  64. lPageCount: integer;
  65. lOpts: TPDFOptions;
  66. begin
  67. Result := TPDFDocument.Create(Nil);
  68. Result.Infos.Title := Application.Title;
  69. Result.Infos.Author := 'Graeme Geldenhuys';
  70. Result.Infos.Producer := 'fpGUI Toolkit 1.4.1';
  71. Result.Infos.ApplicationName := ApplicationName;
  72. Result.Infos.CreationDate := Now;
  73. Result.Infos.KeyWords:='fcl-pdf demo PDF support Free Pascal';
  74. lOpts := [poPageOriginAtTop];
  75. if FSubsetFontEmbedding then
  76. Include(lOpts, poSubsetFont);
  77. if FNoFontEmbedding then
  78. begin
  79. Include(lOpts, poNoEmbeddedFonts);
  80. Exclude(lOpts, poSubsetFont);
  81. end;
  82. if FFontCompression then
  83. Include(lOpts, poCompressFonts);
  84. if FTextCompression then
  85. Include(lOpts,poCompressText);
  86. if FImageCompression then
  87. Include(lOpts,poCompressImages);
  88. if FImageTransparency then
  89. Include(lOpts,poUseImageTransparency);
  90. if FRawJPEG then
  91. Include(lOpts,poUseRawJPEG);
  92. if FAddMetadata then
  93. Include(lOpts,poMetadataEntry);
  94. Result.Options := lOpts;
  95. Result.StartDocument;
  96. S := Result.Sections.AddSection; // we always need at least one section
  97. lPageCount := cPageCount;
  98. if FPage <> -1 then
  99. lPageCount := 1;
  100. for i := 1 to lPageCount do
  101. begin
  102. P := Result.Pages.AddPage;
  103. P.PaperType := ptA4;
  104. P.UnitOfMeasure := uomMillimeters;
  105. S.AddPage(P); // Add the Page to the Section
  106. end;
  107. end;
  108. procedure TPDFTestApp.SaveDocument(D : TPDFDocument);
  109. var
  110. F: TFileStream;
  111. begin
  112. F := TFileStream.Create('test.pdf',fmCreate);
  113. try
  114. D.SaveToStream(F);
  115. Writeln('Document used ',D.ObjectCount,' PDF objects/commands');
  116. finally
  117. F.Free;
  118. end;
  119. end;
  120. procedure TPDFTestApp.EmptyPage;
  121. var
  122. D: TPDFDocument;
  123. begin
  124. D := SetupDocument;
  125. try
  126. SaveDocument(D);
  127. finally
  128. D.Free;
  129. end;
  130. end;
  131. procedure TPDFTestApp.TableOfContents(D: TPDFDocument; APage: integer);
  132. const
  133. pagesarr: array [1..8] of String = ('Sample Text', 'Basic Shapes', 'Advanced Drawing',
  134. 'Sample Line Drawing (DrawLineStyle)', 'Sample Line Drawing (DrawLine)', 'Sample Image Support',
  135. 'Matrix transform', 'Landscape Page');
  136. var
  137. P : TPDFPage;
  138. FtTitle, FtText, i: integer;
  139. begin
  140. P := D.Pages[APage];
  141. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  142. FtTitle := D.AddFont('Helvetica');
  143. FtText := D.AddFont('Courier');
  144. { Page title }
  145. P.SetFont(FtTitle, 23);
  146. P.SetColor(clBlack, false);
  147. P.WriteText(25, 20, 'Table of contents');
  148. // -----------------------------------
  149. { references to document pages }
  150. P.SetFont(FtText, 12);
  151. P.SetColor(clBlack, false);
  152. for i := Low(pagesarr) to High(pagesarr) do
  153. begin
  154. P.WriteText(25, 40 + 10 * i, pagesarr[i] + StringOfChar('.', 60 - Length(pagesarr[i])) + IntToStr(i));
  155. P.AddInternalLink(25, 40 + 10 * i, 160, 5, i, false);
  156. end;
  157. end;
  158. { all units of measure are in millimeters }
  159. procedure TPDFTestApp.SimpleText(D: TPDFDocument; APage: integer);
  160. var
  161. P : TPDFPage;
  162. FtTitle, FtText1, FtText2: integer;
  163. FtWaterMark: integer;
  164. begin
  165. P := D.Pages[APage];
  166. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  167. FtTitle := D.AddFont('Helvetica');
  168. FtText1 := D.AddFont('FreeSans.ttf', 'FreeSans');
  169. FtText2 := D.AddFont('Times-BoldItalic');
  170. FtWaterMark := D.AddFont('Helvetica-Bold');
  171. { Page title }
  172. P.SetFont(FtTitle, 23);
  173. P.SetColor(clBlack, false);
  174. P.WriteText(25, 20, 'Sample Text');
  175. P.SetFont(FtWaterMark, 120);
  176. P.SetColor(clWaterMark, false);
  177. P.WriteText(55, 190, 'Sample', 45);
  178. // -----------------------------------
  179. // Write text using PDF standard fonts
  180. P.SetFont(FtTitle, 12);
  181. P.SetColor(clBlue, false);
  182. P.WriteText(25, 50, '(25mm,50mm) Helvetica: The quick brown fox jumps over the lazy dog.');
  183. P.SetColor(clBlack, false);
  184. P.WriteText(25, 57, 'Click the URL: http://www.freepascal.org');
  185. P.AddExternalLink(54, 58, 49, 5, 'http://www.freepascal.org', false);
  186. // strike-through text
  187. P.WriteText(25, 64, 'Strike-Through text', 0, false, true);
  188. // underline text
  189. P.WriteText(65, 64, 'Underlined text', 0, true);
  190. // underline and strikethrough text
  191. P.WriteText(120, 64, 'Underlined and strikethrough text', 0, true, true);
  192. // rotated text
  193. P.SetColor(clBlue, false);
  194. P.WriteText(25, 100, 'Rotated text at 30 degrees', 30);
  195. P.SetFont(ftText2,16);
  196. P.SetColor($C00000, false);
  197. P.WriteText(50, 100, '(50mm,100mm) Times-BoldItalic: Big text at absolute position');
  198. // -----------------------------------
  199. // TrueType testing purposes
  200. P.SetFont(FtText1, 13);
  201. P.SetColor(clBlack, false);
  202. P.WriteText(15, 120, 'Languages: English: Hello, World!');
  203. P.WriteText(40, 130, 'Greek: Γειά σου κόσμος');
  204. P.WriteText(40, 140, 'Polish: Witaj świecie');
  205. P.WriteText(40, 150, 'Portuguese: Olá mundo');
  206. P.WriteText(40, 160, 'Russian: Здравствуйте мир');
  207. P.WriteText(40, 170, 'Vietnamese: Xin chào thế giới');
  208. P.WriteText(15, 185, 'Box Drawing: ╠ ╣ ╦ ╩ ├ ┤ ┬ ┴');
  209. P.WriteText(15, 200, 'Typography: “What’s wrong?”');
  210. P.WriteText(40, 210, '£17.99 vs £17·99');
  211. P.WriteText(40, 220, '€17.99 vs €17·99');
  212. P.WriteText(40, 230, 'OK then… (êçèûÎÐð£¢ß) \\//{}()#<>');
  213. P.WriteText(25, 280, 'B субботу двадцать третьего мая приезжает твоя любимая теща.');
  214. { draw a rectangle around the text }
  215. TextInABox(P, 25, 255, 23, clRed, 'FreeSans', '“Text in a Box gyj?”');
  216. { lets make a hyperlink more prominent }
  217. TextInABox(P, 100, 255, 12, clMagenta, 'FreeSans', 'http://www.freepascal.org');
  218. P.AddExternalLink(99, 255, 49, 5, 'http://www.freepascal.org', false);
  219. end;
  220. procedure TPDFTestApp.SimpleLinesRaw(D: TPDFDocument; APage: integer);
  221. var
  222. P: TPDFPage;
  223. FtTitle: integer;
  224. lPt1, lPt2: TPDFCoord;
  225. begin
  226. P:=D.Pages[APage];
  227. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  228. FtTitle := D.AddFont('Helvetica');
  229. { Page title }
  230. P.SetFont(FtTitle,23);
  231. P.SetColor(clBlack, False);
  232. P.WriteText(25, 20, 'Sample Line Drawing (DrawLine)');
  233. P.SetColor(clBlack, True);
  234. P.SetPenStyle(ppsSolid, 1);
  235. lPt1.X := 30; lPt1.Y := 100;
  236. lPt2.X := 150; lPt2.Y := 150;
  237. P.DrawLine(lPt1, lPt2, 1);
  238. P.SetColor(clBlue, True);
  239. P.SetPenStyle(ppsDash, 1);
  240. lPt1.X := 50; lPt1.Y := 70;
  241. lPt2.X := 180; lPt2.Y := 100;
  242. P.DrawLine(lPt1, lPt2, 1);
  243. { we can also use coordinates directly, without TPDFCoord variables }
  244. P.SetColor(clRed, True);
  245. P.SetPenStyle(ppsDashDot, 1);
  246. P.DrawLine(40, 140, 160, 80, 1);
  247. P.SetColor(clBlack, True);
  248. P.SetPenStyle(ppsDashDotDot, 1);
  249. P.DrawLine(60, 50, 60, 120, 1);
  250. P.SetColor(clBlack, True);
  251. P.SetPenStyle(ppsDot, 1);
  252. P.DrawLine(10, 80, 130, 130, 1);
  253. end;
  254. procedure TPDFTestApp.SimpleLines(D: TPDFDocument; APage: integer);
  255. var
  256. P: TPDFPage;
  257. FtTitle: integer;
  258. TsThinBlack, TsThinBlue, TsThick, TsThinRed, TsThinBlackDot: Integer;
  259. lPt1, lPt2: TPDFCoord;
  260. begin
  261. P:=D.Pages[APage];
  262. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  263. FtTitle := D.AddFont('Helvetica');
  264. { Page title }
  265. P.SetFont(FtTitle,23);
  266. P.SetColor(clBlack, false);
  267. P.WriteText(25, 20, 'Sample Line Drawing (DrawLineStyle)');
  268. // write the text at position 100 mm from left and 120 mm from top
  269. TsThinBlack := D.AddLineStyleDef(1, clBlack, ppsSolid);
  270. TsThinBlue := D.AddLineStyleDef(1, clBlue, ppsDash);
  271. TsThinRed := D.AddLineStyleDef(1, clRed, ppsDashDot);
  272. TsThick := D.AddLineStyleDef(1, clBlack, ppsDashDotDot);
  273. TsThinBlackDot := D.AddLineStyleDef(1, clBlack, ppsDot);
  274. lPt1.X := 30; lPt1.Y := 100;
  275. lPt2.X := 150; lPt2.Y := 150;
  276. P.DrawLineStyle(lPt1, lPt2, tsThinBlack);
  277. lPt1.X := 50; lPt1.Y := 70;
  278. lPt2.X := 180; lPt2.Y := 100;
  279. P.DrawLineStyle(lPt1, lPt2, tsThinBlue);
  280. { we can also use coordinates directly, without TPDFCoord variables }
  281. P.DrawLineStyle(40, 140, 160, 80, tsThinRed);
  282. P.DrawLineStyle(60, 50, 60, 120, tsThick);
  283. P.DrawLineStyle(10, 80, 130, 130, tsThinBlackDot);
  284. end;
  285. procedure TPDFTestApp.SimpleImage(D: TPDFDocument; APage: integer);
  286. Var
  287. P: TPDFPage;
  288. FtTitle: integer;
  289. IDX, IDX_Diamond: Integer;
  290. W, H: Integer;
  291. begin
  292. P := D.Pages[APage];
  293. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  294. FtTitle := D.AddFont('Helvetica');
  295. { Page title }
  296. P.SetFont(FtTitle,23);
  297. P.SetColor(clBlack, false);
  298. P.WriteText(25, 20, 'Sample Image Support');
  299. P.SetFont(FtTitle,10);
  300. P.SetColor(clBlack, false);
  301. IDX := D.Images.AddFromFile('poppy.jpg',False);
  302. W := D.Images[IDX].Width;
  303. H := D.Images[IDX].Height;
  304. { full size image }
  305. P.DrawImageRawSize(25, 130, W, H, IDX); // left-bottom coordinate of image
  306. P.WriteText(145, 90, '[Full size (defined in pixels)]');
  307. P.WriteText(145, 95, '+alpha-transparent overlay (if enabled)');
  308. IDX_Diamond := D.Images.AddFromFile('diamond.png',False);
  309. P.DrawImageRawSize(30, 125, D.Images[IDX_Diamond].Width, D.Images[IDX_Diamond].Height, IDX_Diamond);
  310. { quarter size image }
  311. P.DrawImageRawSize(25, 190, W shr 1, H shr 1, IDX); // could also have used: Integer(W div 2), Integer(H div 2)
  312. P.WriteText(85, 180, '[Quarter size (defined in pixels)]');
  313. { rotated image }
  314. P.DrawImageRawSize(150, 190, W shr 1, H shr 1, IDX, 30);
  315. { scalled image to 2x2 centimeters }
  316. P.DrawImage(25, 230, 20.0, 20.0, IDX); // left-bottom coordinate of image
  317. P.WriteText(50, 220, '[2x2 cm scaled image]');
  318. { rotatedd image }
  319. P.DrawImage(120, 230, 20.0, 20.0, IDX, 30);
  320. end;
  321. procedure TPDFTestApp.SimpleShapes(D: TPDFDocument; APage: integer);
  322. var
  323. P: TPDFPage;
  324. FtTitle: integer;
  325. lPt1: TPDFCoord;
  326. lPoints: array of TPDFCoord;
  327. i: integer;
  328. lLineWidth: TPDFFloat;
  329. begin
  330. P:=D.Pages[APage];
  331. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  332. FtTitle := D.AddFont('Helvetica');
  333. { Page title }
  334. P.SetFont(FtTitle,23);
  335. P.SetColor(clBlack);
  336. P.WriteText(25, 20, 'Basic Shapes');
  337. // ========== Rectangles ============
  338. { PDF origin coordinate is Bottom-Left. }
  339. lPt1.X := 30;
  340. lPt1.Y := 75;
  341. P.SetColor($c00000, true);
  342. P.SetColor(clLtGray, false);
  343. P.DrawRect(lPt1.X, lPt1.Y, 40, 20, 3, true, true);
  344. lPt1.X := 20;
  345. lPt1.Y := 65;
  346. P.SetColor(clBlue, true);
  347. P.SetColor($ffff80, false); // pastel yellow
  348. P.DrawRect(lPt1.X, lPt1.Y, 40, 20, 1, true, true);
  349. P.SetPenStyle(ppsDashDot);
  350. P.SetColor(clBlue, true);
  351. P.DrawRect(110, 75, 40, 20, 1, false, true);
  352. P.SetPenStyle(ppsDash);
  353. P.SetColor($37b344, true); // some green color
  354. P.DrawRect(100, 70, 40, 20, 2, false, true);
  355. P.SetPenStyle(ppsSolid);
  356. P.SetColor($c00000, true);
  357. P.DrawRect(90, 65, 40, 20, 4, false, true);
  358. P.SetPenStyle(ppsSolid);
  359. P.SetColor(clBlack, true);
  360. P.DrawRect(170, 75, 30, 15, 1, false, true, 30);
  361. // ========== Rounded Rectangle ===========
  362. lPt1.X := 30;
  363. lPt1.Y := 120;
  364. P.SetColor($c00000, true);
  365. P.SetColor(clLtGray, false);
  366. P.DrawRoundedRect(lPt1.X, lPt1.Y, 40, 20, 5, 2, true, true);
  367. lPt1.X := 20;
  368. lPt1.Y := 110;
  369. P.SetColor(clBlue, true);
  370. P.SetColor($ffff80, false); // pastel yellow
  371. P.DrawRoundedRect(lPt1.X, lPt1.Y, 40, 20, 2.4, 1, true, true);
  372. P.SetPenStyle(ppsDashDot);
  373. P.SetColor(clBlue, true);
  374. P.DrawRoundedRect(110, 120, 40, 20, 1.5, 1, false, true);
  375. P.SetPenStyle(ppsDash);
  376. P.SetColor($37b344, true); // some green color
  377. P.DrawRoundedRect(100, 115, 40, 20, 3, 2, false, true);
  378. P.SetPenStyle(ppsSolid);
  379. P.SetColor($c00000, true);
  380. P.DrawRoundedRect(90, 110, 40, 20, 5, 3, false, true);
  381. P.SetPenStyle(ppsSolid);
  382. P.SetColor(clBlack, true);
  383. P.DrawRoundedRect(170, 120, 30, 15, 5, 1, false, true, 30);
  384. // ========== Ellipses ============
  385. P.SetPenStyle(ppsSolid);
  386. P.SetColor($c00000, True);
  387. P.DrawEllipse(60, 150, -40, 20, 3, False, True);
  388. lPt1.X := 60;
  389. lPt1.Y := 150;
  390. P.SetColor(clBlue, true);
  391. P.SetColor($ffff80, false); // pastel yellow
  392. P.DrawEllipse(lPt1, 10, 10, 1, True, True);
  393. P.SetPenStyle(ppsDashDot);
  394. P.SetColor($b737b3, True);
  395. P.DrawEllipse(73, 150, 10, 20, 1, False, True);
  396. P.SetPenStyle(ppsSolid);
  397. P.SetColor(clBlack, True);
  398. P.DrawEllipse(170, 150, 30, 15, 1, False, True, 30);
  399. // ========== Lines Pen Styles ============
  400. lLineWidth := 1;
  401. P.SetPenStyle(ppsSolid, lLineWidth);
  402. P.SetColor(clBlack, True);
  403. P.DrawLine(30, 170, 70, 170, lLineWidth);
  404. P.SetPenStyle(ppsDash, lLineWidth);
  405. P.SetColor(clBlack, True);
  406. P.DrawLine(30, 175, 70, 175, lLineWidth);
  407. P.SetPenStyle(ppsDot, lLineWidth);
  408. P.SetColor(clBlack, True);
  409. P.DrawLine(30, 180, 70, 180, lLineWidth);
  410. P.SetPenStyle(ppsDashDot, lLineWidth);
  411. P.SetColor(clBlack, True);
  412. P.DrawLine(30, 185, 70, 185, lLineWidth);
  413. P.SetPenStyle(ppsDashDotDot, lLineWidth);
  414. P.SetColor(clBlack, True);
  415. P.DrawLine(30, 190, 70, 190, lLineWidth);
  416. // ========== Line Attribute ============
  417. P.SetPenStyle(ppsSolid);
  418. P.SetColor(clBlack, True);
  419. P.DrawLine(100, 170, 140, 170, 0.2);
  420. P.DrawLine(100, 175, 140, 175, 0.3);
  421. P.DrawLine(100, 180, 140, 180, 0.5);
  422. P.DrawLine(100, 185, 140, 185, 1);
  423. P.SetColor(clRed, True);
  424. P.DrawLine(100, 190, 140, 190, 2);
  425. P.SetColor($37b344, True);
  426. P.DrawLine(100, 195, 140, 195, 3);
  427. P.SetColor(clBlue, True);
  428. P.DrawLine(100, 200, 140, 200, 4);
  429. P.SetColor($b737b3, True);
  430. P.DrawLine(100, 205, 140, 205, 5);
  431. // ========== PolyLines and Polygons ============
  432. P.Matrix.SetYTranslation(70);
  433. P.Matrix.SetXTranslation(20);
  434. P.SetPenStyle(ppsSolid);
  435. P.SetColor(clBlack, true);
  436. P.DrawRect(0, 10, 50, -50, 1, false, true);
  437. P.SetColor($c00000, true);
  438. P.ResetPath;
  439. SetLength(lPoints, 10);
  440. for i := 0 to 9 do
  441. begin
  442. lPoints[i].X := Random(50);
  443. lPoints[i].Y := Random(50) + 10.5;
  444. end;
  445. P.DrawPolyLine(lPoints, 1);
  446. P.StrokePath;
  447. P.Matrix.SetXTranslation(80);
  448. P.SetPenStyle(ppsSolid);
  449. P.SetColor(clBlack, true);
  450. P.DrawRect(0, 10, 50, -50, 1, false, true);
  451. P.SetColor($ffff80, false); // pastel yellow
  452. P.SetColor(clBlue, true);
  453. P.ResetPath;
  454. P.DrawPolygon(lPoints, 1);
  455. P.FillStrokePath;
  456. p.SetPenStyle(ppsSolid);
  457. P.SetFont(FtTitle, 8);
  458. P.SetColor(clBlack, false);
  459. P.WriteText(0, 8, 'Fill using the nonzero winding number rule');
  460. P.Matrix.SetXTranslation(140);
  461. P.SetPenStyle(ppsSolid);
  462. P.SetColor(clBlack, true);
  463. P.DrawRect(0, 10, 50, -50, 1, false, true);
  464. P.SetColor($ffff80, false); // pastel yellow
  465. P.SetColor(clBlue, true);
  466. P.ResetPath;
  467. P.DrawPolygon(lPoints, 1);
  468. P.FillEvenOddStrokePath;
  469. p.SetPenStyle(ppsSolid);
  470. P.SetFont(FtTitle, 8);
  471. P.SetColor(clBlack, false);
  472. P.WriteText(0, 8, 'Fill using the even-odd rule');
  473. end;
  474. { Each curve uses the exact same four coordinates, just with different CubicCurveToXXX
  475. method calls. I also use the page Maxtix Y-Translation to adjust the coordinate
  476. system before I draw each curve. I could also refactor each curves drawing
  477. code into a single parametised procedure - simply to show that each of the
  478. curves really do use the same code and coordinates. }
  479. procedure TPDFTestApp.AdvancedShapes(D: TPDFDocument; APage: integer);
  480. var
  481. P: TPDFPage;
  482. FtTitle: integer;
  483. lPt1, lPt2, lPt3, lPt4: TPDFCoord;
  484. begin
  485. P:=D.Pages[APage];
  486. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  487. FtTitle := D.AddFont('Helvetica');
  488. { Page title }
  489. P.SetFont(FtTitle,23);
  490. P.SetColor(clBlack);
  491. P.WriteText(25, 20, 'Advanced Drawing');
  492. // ========== Cubic Bezier curve ===========
  493. // PDF c operator curve ===========
  494. lPt1 := PDFCoord(75, 70);
  495. lPt2 := PDFCoord(78, 40);
  496. lPt3 := PDFCoord(100, 35);
  497. lPt4 := PDFCoord(140, 60);
  498. p.SetColor(clBlack, true);
  499. p.SetPenStyle(ppsSolid);
  500. p.MoveTo(lPt1);
  501. p.CubicCurveTo(lPt2, lPt3, lPt4, 1);
  502. // for fun, lets draw the control points as well
  503. P.SetColor(clLtGray, True);
  504. P.SetColor(clLtGray, false);
  505. P.DrawEllipse(lPt2.X-0.5, lPt2.Y, 1, 1, 1, True, True);
  506. P.DrawEllipse(lPt3.X-0.8, lPt3.Y, 1, 1, 1, True, True);
  507. P.SetPenStyle(ppsDot);
  508. P.DrawLine(lPt1, lPt2, 1);
  509. P.DrawLine(lPt3, lPt4, 1);
  510. p.SetPenStyle(ppsSolid);
  511. P.SetFont(FtTitle, 8);
  512. P.SetColor(clBlack, false);
  513. P.WriteText(lPt1.X+1, lPt1.Y, '(current point)');
  514. p.WriteText(lPt2.X+1, lPt2.Y, '(x1, y1)');
  515. p.WriteText(lPt3.X+1, lPt3.Y, '(x2, y2)');
  516. p.WriteText(lPt4.X+1, lPt4.Y, '(xTo, yTo)');
  517. P.SetFont(FtTitle, 10);
  518. P.WriteText(20, 50, 'CubicCurveTo(...)');
  519. // PDF v operator curve ===========
  520. P.Matrix.SetYTranslation(220);
  521. p.SetColor(clBlack, true);
  522. p.SetPenStyle(ppsSolid);
  523. p.MoveTo(lPt1);
  524. p.CubicCurveToV(lPt3, lPt4, 1);
  525. // for fun, lets draw the control points as well
  526. P.SetColor(clLtGray, True);
  527. P.SetColor(clLtGray, false);
  528. P.DrawEllipse(lPt3.X-0.8, lPt3.Y, 1, 1, 1, True, True);
  529. P.SetPenStyle(ppsDot);
  530. P.DrawLine(lPt3, lPt4, 1);
  531. p.SetPenStyle(ppsSolid);
  532. P.SetFont(FtTitle,8);
  533. P.SetColor(clBlack, false);
  534. P.WriteText(lPt1.X+1, lPt1.Y, '(current point)');
  535. p.WriteText(lPt3.X+1, lPt3.Y, '(x2, y2)');
  536. p.WriteText(lPt4.X+1, lPt4.Y, '(xTo, yTo)');
  537. P.SetFont(FtTitle, 10);
  538. P.WriteText(20, 50, 'CubicCurveToV(...)');
  539. // PDF y operator curve ===========
  540. P.Matrix.SetYTranslation(140);
  541. p.SetColor(clBlack, true);
  542. p.SetPenStyle(ppsSolid);
  543. p.MoveTo(lPt1);
  544. p.CubicCurveToY(lPt2, lPt4, 1);
  545. // for fun, lets draw the control points as well
  546. P.SetColor(clLtGray, True);
  547. P.SetColor(clLtGray, false);
  548. P.DrawEllipse(lPt2.X-0.5, lPt2.Y, 1, 1, 1, True, True);
  549. P.SetPenStyle(ppsDot);
  550. P.DrawLine(lPt1, lPt2, 1);
  551. p.SetPenStyle(ppsSolid);
  552. P.SetFont(FtTitle,8);
  553. P.SetColor(clBlack, false);
  554. P.WriteText(lPt1.X+1, lPt1.Y, '(current point)');
  555. p.WriteText(lPt2.X+1, lPt2.Y, '(x1, y1)');
  556. p.WriteText(lPt4.X+1, lPt4.Y, '(xTo, yTo)');
  557. P.SetFont(FtTitle, 10);
  558. P.WriteText(20, 50, 'CubicCurveToY(...)');
  559. end;
  560. procedure TPDFTestApp.SampleMatrixTransform(D: TPDFDocument; APage: integer);
  561. var
  562. P: TPDFPage;
  563. FtTitle: integer;
  564. procedure OutputSample;
  565. var
  566. b: boolean;
  567. begin
  568. b := P.Matrix._11 = -1;
  569. P.SetFont(FtTitle, 10);
  570. P.WriteText(10, 10, 'Matrix transform: ' + BoolToStr(b, True));
  571. P.DrawLine(0, 0, 100, 100, 1);
  572. P.WriteText(100, 100, '(line end point)');
  573. end;
  574. begin
  575. P:=D.Pages[APage];
  576. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  577. FtTitle := D.AddFont('Helvetica');
  578. { Page title }
  579. P.SetFont(FtTitle,23);
  580. P.SetColor(clBlack);
  581. P.WriteText(75, 20, 'Matrix Transform');
  582. OutputSample;
  583. // enables Cartesian coordinate system for the page
  584. P.Matrix.SetYScalation(1);
  585. P.Matrix.SetYTranslation(0);
  586. OutputSample;
  587. end;
  588. procedure TPDFTestApp.SampleLandscape(D: TPDFDocument; APage: integer);
  589. var
  590. P: TPDFPage;
  591. FtTitle: integer;
  592. function PaperTypeToString(AEnum: TPDFPaperType): string;
  593. begin
  594. result := GetEnumName(TypeInfo(TPDFPaperType), Ord(AEnum));
  595. end;
  596. function PixelsToMM(AValue: integer): integer;
  597. begin
  598. Result := Round((AValue / 72) * 25.4);
  599. end;
  600. begin
  601. P:=D.Pages[APage];
  602. P.Orientation := ppoLandscape;
  603. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  604. FtTitle := D.AddFont('Helvetica');
  605. { Page title }
  606. P.SetFont(FtTitle,23);
  607. P.SetColor(clBlack);
  608. P.WriteText(25, 20, 'Landscape Page');
  609. P.SetFont(FtTitle, 12);
  610. P.WriteText(100, 80, 'Page PaperType:');
  611. P.WriteText(145, 80, PaperTypeToString(P.PaperType));
  612. P.WriteText(100, 90, 'Page Size:');
  613. P.WriteText(145, 90, Format('%d x %d (pixels)', [P.Paper.W, P.Paper.H]));
  614. P.WriteText(145, 95, Format('%d x %d (mm)', [PixelsToMM(P.Paper.W), PixelsToMM(P.Paper.H)]));
  615. end;
  616. procedure TPDFTestApp.TextInABox(const APage: TPDFPage; const AX, AY: TPDFFloat; const APointSize: integer;
  617. const ABoxColor: TARGBColor; const AFontName: string; const AText: UTF8String);
  618. var
  619. lFontIdx: integer;
  620. lFC: TFPFontCacheItem;
  621. lHeight: single;
  622. lDescenderHeight: single;
  623. lTextHeightInMM: single;
  624. lWidth: single;
  625. lTextWidthInMM: single;
  626. lDescenderHeightInMM: single;
  627. i: integer;
  628. begin
  629. for i := 0 to APage.Document.Fonts.Count-1 do
  630. begin
  631. if APage.Document.Fonts[i].Name = AFontName then
  632. begin
  633. lFontIdx := i;
  634. break;
  635. end;
  636. end;
  637. APage.SetFont(lFontIdx, APointSize);
  638. APage.SetColor(clBlack, false);
  639. APage.WriteText(AX, AY, AText);
  640. lFC := gTTFontCache.Find(AFontName, False, False);
  641. if not Assigned(lFC) then
  642. raise Exception.Create(AFontName + ' font not found');
  643. lHeight := lFC.TextHeight(AText, APointSize, lDescenderHeight);
  644. { convert the Font Units to mm as our PDFPage.UnitOfMeasure is set to mm. }
  645. lTextHeightInMM := (lHeight * 25.4) / gTTFontCache.DPI;
  646. lDescenderHeightInMM := (lDescenderHeight * 25.4) / gTTFontCache.DPI;
  647. lWidth := lFC.TextWidth(AText, APointSize);
  648. { convert the Font Units to mm as our PDFPage.UnitOfMeasure is set to mm. }
  649. lTextWidthInMM := (lWidth * 25.4) / gTTFontCache.DPI;
  650. { adjust the Y coordinate for the font Descender, because
  651. WriteText() draws on the baseline. Also adjust the TextHeight
  652. because CapHeight doesn't take into account the Descender. }
  653. APage.SetColor(ABoxColor, true);
  654. APage.DrawRect(AX, AY+lDescenderHeightInMM, lTextWidthInMM,
  655. lTextHeightInMM+lDescenderHeightInMM, 1, false, true);
  656. end;
  657. { TPDFTestApp }
  658. procedure TPDFTestApp.DoRun;
  659. Function BoolFlag(C : Char;ADefault : Boolean) : Boolean;
  660. Var
  661. V : Integer;
  662. begin
  663. Result:=ADefault;
  664. if HasOption(C, '') then
  665. begin
  666. v := StrToIntDef(GetOptionValue(C,''),-1);
  667. if Not (V in [0,1]) then
  668. Raise Exception.Create('Error in -'+C+' parameter. Valid range is 0-1.');
  669. Result:=(v=1);
  670. end
  671. end;
  672. var
  673. ErrorMsg: String;
  674. begin
  675. StopOnException:=True;
  676. inherited DoRun;
  677. // quick check parameters
  678. ErrorMsg := CheckOptions('hp:f:t:i:j:nsm:', '');
  679. if ErrorMsg <> '' then
  680. begin
  681. WriteLn('ERROR: ' + ErrorMsg);
  682. Writeln('');
  683. Terminate;
  684. Exit;
  685. end;
  686. // parse parameters
  687. if HasOption('h', '') then
  688. begin
  689. WriteHelp;
  690. Terminate;
  691. Exit;
  692. end;
  693. FPage := -1;
  694. if HasOption('p', '') then
  695. begin
  696. FPage := StrToInt(GetOptionValue('p', ''));
  697. if (FPage < 1) or (FPage > cPageCount) then
  698. begin
  699. Writeln(Format('Error in -p parameter. Valid range is 1-%d.', [cPageCount]));
  700. Writeln('');
  701. Terminate;
  702. Exit;
  703. end;
  704. end;
  705. FNoFontEmbedding := HasOption('n', '');
  706. FSubsetFontEmbedding := HasOption('s', '');
  707. FFontCompression := BoolFlag('f',true);
  708. FTextCompression := BoolFlag('t',False);
  709. FImageCompression := BoolFlag('i',False);
  710. FImageTransparency := BoolFlag('t',False);
  711. FAddMetadata := BoolFlag('m',False);
  712. FRawJPEG:=BoolFlag('j',False);
  713. gTTFontCache.SearchPath.Add(ExtractFilePath(ParamStr(0)) + 'fonts');
  714. gTTFontCache.BuildFontCache;
  715. FDoc := SetupDocument;
  716. try
  717. FDoc.FontDirectory := 'fonts';
  718. if FPage = -1 then
  719. begin
  720. TableOfContents(FDoc, 0);
  721. SimpleText(FDoc, 1);
  722. SimpleShapes(FDoc, 2);
  723. AdvancedShapes(FDoc, 3);
  724. SimpleLines(FDoc, 4);
  725. SimpleLinesRaw(FDoc, 5);
  726. SimpleImage(FDoc, 6);
  727. SampleMatrixTransform(FDoc, 7);
  728. SampleLandscape(FDoc, 8);
  729. end
  730. else
  731. begin
  732. case FPage of
  733. 1: SimpleText(FDoc, 0);
  734. 2: SimpleShapes(FDoc, 0);
  735. 3: AdvancedShapes(FDoc, 0);
  736. 4: SimpleLines(FDoc, 0);
  737. 5: SimpleLinesRaw(FDoc, 0);
  738. 6: SimpleImage(FDoc, 0);
  739. 7: SampleMatrixTransform(FDoc, 0);
  740. 8: SampleLandscape(FDoc, 0);
  741. end;
  742. end;
  743. SaveDocument(FDoc);
  744. finally
  745. FDoc.Free;
  746. end;
  747. // stop program loop
  748. Terminate;
  749. end;
  750. procedure TPDFTestApp.WriteHelp;
  751. begin
  752. writeln('Usage:');
  753. writeln(' -h Show this help.');
  754. writeln(Format(
  755. ' -p <n> Generate only one page. Valid range is 1-%d.' + LineEnding +
  756. ' If this option is not specified, then all %0:d pages are' + LineEnding +
  757. ' generated.', [cPageCount]));
  758. writeln(' -n If specified, no fonts will be embedded.');
  759. writeln(' -s If specified, subset TTF font embedding will occur.');
  760. writeln(' -m <0|1> Toggle metadata generation.');
  761. writeln(' -f <0|1> Toggle embedded font compression. A value of 0' + LineEnding +
  762. ' disables compression. A value of 1 enables compression.' + LineEnding +
  763. ' If -n is specified, this option is ignored.');
  764. writeln(' -t <0|1> Toggle text compression. A value of 0' + LineEnding +
  765. ' disables compression. A value of 1 enables compression.');
  766. writeln(' -i <0|1> Toggle image compression. A value of 0' + LineEnding +
  767. ' disables compression. A value of 1 enables compression.');
  768. writeln(' -j <0|1> Toggle use of JPEG. A value of 0' + LineEnding +
  769. ' disables use of JPEG images. A value of 1 writes jpeg file as-is');
  770. writeln(' -t <0|1> Toggle image transparency support. A value of 0' + LineEnding +
  771. ' disables transparency. A value of 1 enables transparency.');
  772. writeln('');
  773. end;
  774. begin
  775. Randomize;
  776. Application := TPDFTestApp.Create(nil);
  777. Application.Title := 'fpPDF Test Application';
  778. Application.Run;
  779. Application.Free;
  780. end.