testfppdf.lpr 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. { This program generates a multi-page PDF document and tests various
  2. functionality on each of the 5 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. typinfo;
  22. type
  23. TPDFTestApp = class(TCustomApplication)
  24. private
  25. Fpg: integer;
  26. FRawJPEG,
  27. FImageCompression,
  28. FTextCompression,
  29. FFontCompression: boolean;
  30. FDoc: TPDFDocument;
  31. function SetUpDocument: TPDFDocument;
  32. procedure SaveDocument(D: TPDFDocument);
  33. procedure EmptyPage;
  34. procedure SimpleText(D: TPDFDocument; APage: integer);
  35. procedure SimpleLinesRaw(D: TPDFDocument; APage: integer);
  36. procedure SimpleLines(D: TPDFDocument; APage: integer);
  37. procedure SimpleImage(D: TPDFDocument; APage: integer);
  38. procedure SimpleShapes(D: TPDFDocument; APage: integer);
  39. procedure SampleMatrixTransform(D: TPDFDocument; APage: integer);
  40. procedure SampleLandscape(D: TPDFDocument; APage: integer);
  41. protected
  42. procedure DoRun; override;
  43. public
  44. procedure WriteHelp;
  45. end;
  46. var
  47. Application: TPDFTestApp;
  48. function TPDFTestApp.SetUpDocument: TPDFDocument;
  49. var
  50. P: TPDFPage;
  51. S: TPDFSection;
  52. i: integer;
  53. lPageCount: integer;
  54. lOpts: TPDFOptions;
  55. begin
  56. Result := TPDFDocument.Create(Nil);
  57. Result.Infos.Title := Application.Title;
  58. Result.Infos.Author := 'Graeme Geldenhuys';
  59. Result.Infos.Producer := 'fpGUI Toolkit 0.8';
  60. Result.Infos.ApplicationName := ApplicationName;
  61. Result.Infos.CreationDate := Now;
  62. lOpts := [];
  63. if FFontCompression then
  64. Include(lOpts, poCompressFonts);
  65. if FTextCompression then
  66. Include(lOpts,poCompressText);
  67. if FImageCompression then
  68. Include(lOpts,poCompressImages);
  69. if FRawJPEG then
  70. Include(lOpts,poUseRawJPEG);
  71. Result.Options := lOpts;
  72. Result.StartDocument;
  73. S := Result.Sections.AddSection; // we always need at least one section
  74. lPageCount := 7;
  75. if Fpg <> -1 then
  76. lPageCount := 1;
  77. for i := 1 to lPageCount do
  78. begin
  79. P := Result.Pages.AddPage;
  80. P.PaperType := ptA4;
  81. P.UnitOfMeasure := uomMillimeters;
  82. S.AddPage(P); // Add the Page to the Section
  83. end;
  84. end;
  85. procedure TPDFTestApp.SaveDocument(D : TPDFDocument);
  86. var
  87. F: TFileStream;
  88. begin
  89. F := TFileStream.Create('test.pdf',fmCreate);
  90. try
  91. D.SaveToStream(F);
  92. Writeln('Document used ',D.ObjectCount,' PDF objects/commands');
  93. finally
  94. F.Free;
  95. end;
  96. end;
  97. procedure TPDFTestApp.EmptyPage;
  98. var
  99. D: TPDFDocument;
  100. begin
  101. D := SetupDocument;
  102. try
  103. SaveDocument(D);
  104. finally
  105. D.Free;
  106. end;
  107. end;
  108. { all units of measure are in millimeters }
  109. procedure TPDFTestApp.SimpleText(D: TPDFDocument; APage: integer);
  110. var
  111. P : TPDFPage;
  112. FtTitle, FtText1, FtText2, FtText3: integer;
  113. begin
  114. P := D.Pages[APage];
  115. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  116. FtTitle := D.AddFont('Helvetica', clRed);
  117. FtText1 := D.AddFont('FreeSans.ttf', 'FreeSans', clGreen); // TODO: this color value means nothing - not used at all
  118. FtText2 := D.AddFont('Times-BoldItalic', clBlack);
  119. // FtText3 := D.AddFont('arial.ttf', 'Arial', clBlack);
  120. FtText3 := FtText1; // to reduce font dependecies, but above works too if you have arial.ttf available
  121. { Page title }
  122. P.SetFont(FtTitle, 23);
  123. P.SetColor(clBlack, false);
  124. P.WriteText(25, 20, 'Sample Text');
  125. // -----------------------------------
  126. // Write text using PDF standard fonts
  127. P.SetFont(FtTitle, 12);
  128. P.SetColor(clBlue, false);
  129. P.WriteText(25, 50, '(25mm,50mm) Helvetica: The quick brown fox jumps over the lazy dog.');
  130. P.SetFont(ftText2,16);
  131. P.SetColor($c00000, false);
  132. P.WriteText(60, 100, '(60mm,100mm) Times-BoldItalic: Big text at absolute position');
  133. // -----------------------------------
  134. // TrueType testing purposes
  135. P.SetFont(ftText3, 13);
  136. P.SetColor(clBlack, false);
  137. P.WriteText(15, 120, 'Languages: English: Hello, World!');
  138. P.WriteText(40, 130, 'Greek: Γειά σου κόσμος');
  139. P.WriteText(40, 140, 'Polish: Witaj świecie');
  140. P.WriteText(40, 150, 'Portuguese: Olá mundo');
  141. P.WriteText(40, 160, 'Russian: Здравствуйте мир');
  142. P.WriteText(40, 170, 'Vietnamese: Xin chào thế giới');
  143. P.SetFont(ftText1, 13);
  144. P.WriteText(15, 185, 'Box Drawing: ╠ ╣ ╦ ╩ ├ ┤ ┬ ┴');
  145. P.WriteText(15, 200, 'Typography: “What’s wrong?”');
  146. P.WriteText(40, 210, '£17.99 vs £17·99');
  147. P.WriteText(40, 220, '€17.99 vs €17·99');
  148. P.WriteText(40, 230, 'OK then… (êçèûÎÐð£¢ß) \\//{}()#<>');
  149. P.WriteText(25, 280, 'B субботу двадцать третьего мая приезжает твоя любимая теща.');
  150. end;
  151. procedure TPDFTestApp.SimpleLinesRaw(D: TPDFDocument; APage: integer);
  152. var
  153. P: TPDFPage;
  154. FtTitle: integer;
  155. lPt1, lPt2: TPDFCoord;
  156. begin
  157. P:=D.Pages[APage];
  158. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  159. FtTitle := D.AddFont('Helvetica', clBlack);
  160. { Page title }
  161. P.SetFont(FtTitle,23);
  162. P.SetColor(clBlack, False);
  163. P.WriteText(25, 20, 'Sample Line Drawing (DrawLine)');
  164. P.SetColor(clBlack, True);
  165. P.SetPenStyle(ppsSolid);
  166. lPt1.X := 30; lPt1.Y := 100;
  167. lPt2.X := 150; lPt2.Y := 150;
  168. P.DrawLine(lPt1, lPt2, 0.2);
  169. P.SetColor(clBlue, True);
  170. P.SetPenStyle(ppsDash);
  171. lPt1.X := 50; lPt1.Y := 70;
  172. lPt2.X := 180; lPt2.Y := 100;
  173. P.DrawLine(lPt1, lPt2, 0.1);
  174. { we can also use coordinates directly, without TPDFCoord variables }
  175. P.SetColor(clRed, True);
  176. P.SetPenStyle(ppsDashDot);
  177. P.DrawLine(40, 140, 160, 80, 1);
  178. P.SetColor(clBlack, True);
  179. P.SetPenStyle(ppsDashDotDot);
  180. P.DrawLine(60, 50, 60, 120, 1.5);
  181. P.SetColor(clBlack, True);
  182. P.SetPenStyle(ppsDot);
  183. P.DrawLine(10, 80, 130, 130, 0.5);
  184. end;
  185. procedure TPDFTestApp.SimpleLines(D: TPDFDocument; APage: integer);
  186. var
  187. P: TPDFPage;
  188. FtTitle: integer;
  189. TsThinBlack, TsThinBlue, TsThick, TsThinRed, TsThinBlackDot: Integer;
  190. lPt1, lPt2: TPDFCoord;
  191. begin
  192. P:=D.Pages[APage];
  193. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  194. FtTitle := D.AddFont('Helvetica', clRed);
  195. { Page title }
  196. P.SetFont(FtTitle,23);
  197. P.SetColor(clBlack, false);
  198. P.WriteText(25, 20, 'Sample Line Drawing (DrawLineStyle)');
  199. // write the text at position 100 mm from left and 120 mm from top
  200. TsThinBlack := D.AddLineStyleDef(0.2, clBlack, ppsSolid);
  201. TsThinBlue := D.AddLineStyleDef(0.1, clBlue, ppsDash);
  202. TsThinRed := D.AddLineStyleDef(1, clRed, ppsDashDot);
  203. TsThick := D.AddLineStyleDef(1.5, clBlack, ppsDashDotDot);
  204. TsThinBlackDot := D.AddLineStyleDef(0.5, clBlack, ppsDot);
  205. lPt1.X := 30; lPt1.Y := 100;
  206. lPt2.X := 150; lPt2.Y := 150;
  207. P.DrawLineStyle(lPt1, lPt2, tsThinBlack);
  208. lPt1.X := 50; lPt1.Y := 70;
  209. lPt2.X := 180; lPt2.Y := 100;
  210. P.DrawLineStyle(lPt1, lPt2, tsThinBlue);
  211. { we can also use coordinates directly, without TPDFCoord variables }
  212. P.DrawLineStyle(40, 140, 160, 80, tsThinRed);
  213. P.DrawLineStyle(60, 50, 60, 120, tsThick);
  214. P.DrawLineStyle(10, 80, 130, 130, tsThinBlackDot);
  215. end;
  216. procedure TPDFTestApp.SimpleImage(D: TPDFDocument; APage: integer);
  217. Var
  218. P: TPDFPage;
  219. FtTitle: integer;
  220. IDX: Integer;
  221. W, H: Integer;
  222. begin
  223. P := D.Pages[APage];
  224. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  225. FtTitle := D.AddFont('Helvetica', clBlack);
  226. { Page title }
  227. P.SetFont(FtTitle,23);
  228. P.SetColor(clBlack, false);
  229. P.WriteText(25, 20, 'Sample Image Support');
  230. P.SetFont(FtTitle,10);
  231. P.SetColor(clBlack, false);
  232. IDX := D.Images.AddFromFile('poppy.jpg',False);
  233. W := D.Images[IDX].Width;
  234. H := D.Images[IDX].Height;
  235. { full size image }
  236. P.DrawImageRawSize(25, 130, W, H, IDX); // left-bottom coordinate of image
  237. P.WriteText(145, 90, '[Full size (defined in pixels)]');
  238. { half size image }
  239. P.DrawImageRawSize(25, 190, W shr 1, H shr 1, IDX); // could also have used: Integer(W div 2), Integer(H div 2)
  240. P.WriteText(90, 165, '[Quarter size (defined in pixels)]');
  241. { scalled image to 2x2 centimeters }
  242. P.DrawImage(25, 230, 20.0, 20.0, IDX); // left-bottom coordinate of image
  243. P.WriteText(50, 220, '[2x2 cm scaled image]');
  244. end;
  245. procedure TPDFTestApp.SimpleShapes(D: TPDFDocument; APage: integer);
  246. var
  247. P: TPDFPage;
  248. FtTitle: integer;
  249. lPt1: TPDFCoord;
  250. begin
  251. P:=D.Pages[APage];
  252. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  253. FtTitle := D.AddFont('Helvetica', clBlack);
  254. { Page title }
  255. P.SetFont(FtTitle,23);
  256. P.SetColor(clBlack);
  257. P.WriteText(25, 20, 'Basic Shapes');
  258. // ========== Rectangles ============
  259. { PDF origin coordinate is Bottom-Left, and we want to use Image Coordinate of Top-Left }
  260. lPt1.X := 30;
  261. lPt1.Y := 60+20; // origin + height
  262. P.SetColor(clRed, true);
  263. P.SetColor($37b344, false); // some green color
  264. P.DrawRect(lPt1.X, lPt1.Y, 40, 20, 3, true, true);
  265. lPt1.X := 20;
  266. lPt1.Y := 50+20; // origin + height
  267. P.SetColor(clBlue, true);
  268. P.SetColor($b737b3, false); // some purple color
  269. P.DrawRect(lPt1.X, lPt1.Y, 40, 20, 1, true, true);
  270. P.SetPenStyle(ppsDashDot);
  271. P.SetColor(clBlue, true);
  272. P.DrawRect(110, 70+20 {origin+height}, 40, 20, 1, false, true);
  273. P.SetPenStyle(ppsDash);
  274. P.SetColor($37b344, true); // some green color
  275. P.DrawRect(100, 60+20 {origin+height}, 40, 20, 2, false, true);
  276. P.SetPenStyle(ppsSolid);
  277. P.SetColor($b737b3, true); // some purple color
  278. P.DrawRect(90, 50+20 {origin+height}, 40, 20, 4, false, true);
  279. // ========== Ellipses ============
  280. P.SetPenStyle(ppsSolid);
  281. P.SetColor($c00000, True);
  282. P.DrawEllipse(60, 150, -40, 20, 3, False, True);
  283. lPt1.X := 60;
  284. lPt1.Y := 150;
  285. P.SetColor(clBlue, true);
  286. P.SetColor($b737b3, false); // some purple color
  287. P.DrawEllipse(lPt1, 10, 10, 1, True, True);
  288. P.SetPenStyle(ppsDashDot);
  289. P.SetColor($b737b3, True);
  290. P.DrawEllipse(140, 150, 35, 20, 1, False, True);
  291. // ========== Lines Pen Styles ============
  292. P.SetPenStyle(ppsSolid);
  293. P.SetColor(clBlack, True);
  294. P.DrawLine(30, 200, 70, 200, 1);
  295. P.SetPenStyle(ppsDash);
  296. P.SetColor(clBlack, True);
  297. P.DrawLine(30, 210, 70, 210, 1);
  298. P.SetPenStyle(ppsDot);
  299. P.SetColor(clBlack, True);
  300. P.DrawLine(30, 220, 70, 220, 1);
  301. P.SetPenStyle(ppsDashDot);
  302. P.SetColor(clBlack, True);
  303. P.DrawLine(30, 230, 70, 230, 1);
  304. P.SetPenStyle(ppsDashDotDot);
  305. P.SetColor(clBlack, True);
  306. P.DrawLine(30, 240, 70, 240, 1);
  307. // ========== Line Attribute ============
  308. P.SetPenStyle(ppsSolid);
  309. P.SetColor(clBlack, True);
  310. P.DrawLine(100, 170, 140, 170, 0.2);
  311. P.DrawLine(100, 180, 140, 180, 0.3);
  312. P.DrawLine(100, 190, 140, 190, 0.5);
  313. P.DrawLine(100, 200, 140, 200, 1);
  314. P.SetColor(clRed, True);
  315. P.DrawLine(100, 210, 140, 210, 2);
  316. P.SetColor($37b344, True);
  317. P.DrawLine(100, 220, 140, 220, 3);
  318. P.SetColor(clBlue, True);
  319. P.DrawLine(100, 230, 140, 230, 4);
  320. P.SetColor($b737b3, True);
  321. P.DrawLine(100, 240, 140, 240, 5);
  322. end;
  323. procedure TPDFTestApp.SampleMatrixTransform(D: TPDFDocument; APage: integer);
  324. var
  325. P: TPDFPage;
  326. FtTitle: integer;
  327. procedure OutputSample;
  328. var
  329. b: boolean;
  330. begin
  331. b := P.Matrix._11 = -1;
  332. P.SetFont(FtTitle, 10);
  333. P.WriteText(10, 10, 'Matrix transform: ' + BoolToStr(b, True));
  334. P.DrawLine(0, 0, 100, 100, 1);
  335. P.WriteText(100, 100, '(line end point)');
  336. end;
  337. begin
  338. P:=D.Pages[APage];
  339. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  340. FtTitle := D.AddFont('Helvetica', clBlack);
  341. { Page title }
  342. P.SetFont(FtTitle,23);
  343. P.SetColor(clBlack);
  344. P.WriteText(75, 20, 'Matrix Transform');
  345. OutputSample;
  346. // enables Cartesian coordinate system for the page
  347. P.Matrix.SetYScalation(1);
  348. P.Matrix.SetYTranslation(0);
  349. OutputSample;
  350. end;
  351. procedure TPDFTestApp.SampleLandscape(D: TPDFDocument; APage: integer);
  352. var
  353. P: TPDFPage;
  354. FtTitle: integer;
  355. function PaperTypeToString(AEnum: TPDFPaperType): string;
  356. begin
  357. result := GetEnumName(TypeInfo(TPDFPaperType), Ord(AEnum));
  358. end;
  359. function PixelsToMM(AValue: integer): integer;
  360. begin
  361. Result := Round((AValue / 72) * 25.4);
  362. end;
  363. begin
  364. P:=D.Pages[APage];
  365. P.Orientation := ppoLandscape;
  366. // create the fonts to be used (use one of the 14 Adobe PDF standard fonts)
  367. FtTitle := D.AddFont('Helvetica', clBlack);
  368. { Page title }
  369. P.SetFont(FtTitle,23);
  370. P.SetColor(clBlack);
  371. P.WriteText(25, 20, 'Landscape Page');
  372. P.SetFont(FtTitle, 12);
  373. P.WriteText(100, 80, 'Page PaperType:');
  374. P.WriteText(145, 80, PaperTypeToString(P.PaperType));
  375. P.WriteText(100, 90, 'Page Size:');
  376. P.WriteText(145, 90, Format('%d x %d (pixels)', [P.Paper.W, P.Paper.H]));
  377. P.WriteText(145, 95, Format('%d x %d (mm)', [PixelsToMM(P.Paper.W), PixelsToMM(P.Paper.H)]));
  378. end;
  379. { TPDFTestApp }
  380. procedure TPDFTestApp.DoRun;
  381. Function BoolFlag(C : Char;ADefault : Boolean) : Boolean;
  382. Var
  383. V : Integer;
  384. begin
  385. Result:=ADefault;
  386. if HasOption(C, '') then
  387. begin
  388. v := StrToIntDef(GetOptionValue(C,''),-1);
  389. if Not (V in [0,1]) then
  390. Raise Exception.Create('Error in -'+C+' parameter. Valid range is 0-1.');
  391. Result:=(v=1);
  392. end
  393. end;
  394. var
  395. ErrorMsg: String;
  396. begin
  397. StopOnException:=True;
  398. inherited DoRun;
  399. // quick check parameters
  400. ErrorMsg := CheckOptions('hp:f:t:i:j:', '');
  401. if ErrorMsg <> '' then
  402. begin
  403. WriteLn('ERROR: ' + ErrorMsg);
  404. Writeln('');
  405. Terminate;
  406. Exit;
  407. end;
  408. // parse parameters
  409. if HasOption('h', '') then
  410. begin
  411. WriteHelp;
  412. Terminate;
  413. Exit;
  414. end;
  415. Fpg := -1;
  416. if HasOption('p', '') then
  417. begin
  418. Fpg := StrToInt(GetOptionValue('p', ''));
  419. if (Fpg < 1) or (Fpg > 7) then
  420. begin
  421. Writeln('Error in -p parameter. Valid range is 1-7.');
  422. Writeln('');
  423. Terminate;
  424. Exit;
  425. end;
  426. end;
  427. FFontCompression := BoolFlag('f',true);
  428. FTextCompression := BoolFlag('t',False);
  429. FImageCompression := BoolFlag('i',False);
  430. FRawJPEG:=BoolFlag('j',False);
  431. FDoc := SetupDocument;
  432. try
  433. FDoc.FontDirectory := 'fonts';
  434. if Fpg = -1 then
  435. begin
  436. SimpleText(FDoc, 0);
  437. SimpleShapes(FDoc, 1);
  438. SimpleLines(FDoc, 2);
  439. SimpleLinesRaw(FDoc, 3);
  440. SimpleImage(FDoc, 4);
  441. SampleMatrixTransform(FDoc, 5);
  442. SampleLandscape(FDoc, 6);
  443. end
  444. else
  445. begin
  446. case Fpg of
  447. 1: SimpleText(FDoc, 0);
  448. 2: SimpleShapes(FDoc, 0);
  449. 3: SimpleLines(FDoc, 0);
  450. 4: SimpleLinesRaw(FDoc, 0);
  451. 5: SimpleImage(FDoc, 0);
  452. 6: SampleMatrixTransform(FDoc, 0);
  453. 7: SampleLandscape(FDoc, 0);
  454. end;
  455. end;
  456. SaveDocument(FDoc);
  457. finally
  458. FDoc.Free;
  459. end;
  460. // stop program loop
  461. Terminate;
  462. end;
  463. procedure TPDFTestApp.WriteHelp;
  464. begin
  465. writeln('Usage:');
  466. writeln(' -h Show this help.');
  467. writeln(' -p <n> Generate only one page. Valid range is 1-7.' + LineEnding +
  468. ' If this option is not specified, then all 7 pages are' + LineEnding +
  469. ' generated.');
  470. writeln(' -f <0|1> Toggle embedded font compression. A value of 0' + LineEnding +
  471. ' disables compression. A value of 1 enables compression.');
  472. writeln(' -t <0|1> Toggle text compression. A value of 0' + LineEnding +
  473. ' disables compression. A value of 1 enables compression.');
  474. writeln(' -i <0|1> Toggle image compression. A value of 0' + LineEnding +
  475. ' disables compression. A value of 1 enables compression.');
  476. writeln(' -j <0|1> Toggle use of JPEG. A value of 0' + LineEnding +
  477. ' disables use of JPEG images. A value of 1 writes jpeg file as-is');
  478. writeln('');
  479. end;
  480. begin
  481. Application := TPDFTestApp.Create(nil);
  482. Application.Title := 'fpPDF Test Application';
  483. Application.Run;
  484. Application.Free;
  485. end.