delphi (
DelphiUnit.pas) –
the last “Hello World!” example, which uses the
Delphi interface.
It's basically the same as the example for the C++ Builder, but completely written
in the Pascal. It also contains Delphi version of
attachments
,
docinfo
,
drawtoresource
,
encrypt
,
fromdoc
,
pagesperpage
and
sign
examples,
in a simplified form.
1 unit DelphiUnit;
2
3 {*
4 * (c) 2013-2016 http://www.litePDF.cz
5 * (c) 2017 zyx [@:] zyx gmx [dot] us
6 *
7 * This software is provided 'as-is', without any express or implied
8 * warranty. In no event will the authors be held liable for any damages
9 * arising from the use of this software.
10 *
11 * Permission is granted to anyone to use this software for any purpose,
12 * including commercial applications, and to alter it and redistribute it
13 * freely, subject to the following restrictions:
14 *
15 * 1. The origin of this software must not be misrepresented; you must not
16 * claim that you wrote the original software. If you use this software
17 * in a product, an acknowledgment in the product documentation would be
18 * appreciated but is not required.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
21 * 3. This notice may not be removed or altered from any source distribution.
22 *}
23
24 interface
25
26 uses
27 Winapi.Windows, Winapi.Messages, Winapi.ShellAPI, System.SysUtils,
28 System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms,
29 Vcl.Dialogs, Vcl.StdCtrls, litePDF, Vcl.ExtCtrls;
30
31 type
32 TDelphiFrm = class(TForm)
33 HelloWorldBtn: TButton;
34 OpenHelloWorldBtn: TButton;
35 DivideBvl: TBevel;
36 AttachmentsBtn: TButton;
37 DocinfoBtn: TButton;
38 DrawtoresourceBtn: TButton;
39 EncryptBtn: TButton;
40 FromdocBtn: TButton;
41 PagesperpageBtn: TButton;
42 SignManualBtn: TButton;
43 procedure HelloWorldBtnClick(Sender: TObject);
44 procedure OpenHelloWorldBtnClick(Sender: TObject);
45 procedure AttachmentsBtnClick(Sender: TObject);
46 procedure DocinfoBtnClick(Sender: TObject);
47 procedure DrawtoresourceBtnClick(Sender: TObject);
48 procedure EncryptBtnClick(Sender: TObject);
49 procedure FromdocBtnClick(Sender: TObject);
50 procedure PagesperpageBtnClick(Sender: TObject);
51 procedure SignManualBtnClick(Sender: TObject);
52 private
53 { Private declarations }
54 procedure AddPage(lpdf: TLitePDF; pageWidthMM, pageHeightMM : UInt;
55 text: String);
56 public
57 { Public declarations }
58 end;
59
60 var
61 DelphiFrm: TDelphiFrm;
62
63 implementation
64
65 {$R *.dfm}
66
67 var crlf : String = AnsiString(Chr(13)) + AnsiString(Chr(10));
68
69 //----------------------------------------------------------------------------
70 // helloworld example
71 //----------------------------------------------------------------------------
72
73 procedure TDelphiFrm.HelloWorldBtnClick(Sender: TObject);
74 var lpdf : TLitePDF;
75 canvas : TCanvas;
76 hdc : THandle;
77 begin
78 // create a TLitePDF instance
79 lpdf := TLitePDF.Create;
80 try
81 try
82 // create a new PDF document
83 lpdf.CreateMemDocument;
84
85 // create a canvas to draw to
86 canvas := TCanvas.Create;
87 if canvas = nil then
88 begin
89 raise Exception.Create('Low memory!');
90 end;
91
92 try
93 // add a page, with large-enough pixel scale
94 hdc := lpdf.AddPage(Trunc(lpdf.MMToUnit(210)),
95 Trunc(lpdf.MMToUnit(297)),
96 2100, 2970, LongWord(LitePDFDrawFlag_None));
97
98 // initialize the canvas
99 canvas.Handle := hdc;
100
101 // prepare text print
102 canvas.Font.Name := 'Arial';
103 canvas.Font.Size := -240;
104 canvas.Font.Color := clGreen;
105
106 // print text
107 canvas.TextOut(100, 100, 'Hello World!');
108
109 canvas.Font.Size := -100;
110 canvas.Font.Color := clBlack;
111 canvas.TextOut(100, 450, 'from Delphi');
112
113 // prepare a pen
114 canvas.Pen.Width := 10;
115 canvas.Pen.Style := psSolid;
116
117 // draw three lines
118 canvas.Pen.Color := clRed;
119 canvas.MoveTo(1800, 100);
120 canvas.LineTo(1800, 550);
121
122 canvas.Pen.Color := clGreen;
123 canvas.MoveTo(1810, 100);
124 canvas.LineTo(1810, 550);
125
126 canvas.Pen.Color := clBlue;
127 canvas.MoveTo(1820, 100);
128 canvas.LineTo(1820, 550);
129 finally
130 canvas.Destroy;
131 end;
132
133 if hdc <> THandle(0) then
134 begin
135 // finish drawing
136 lpdf.FinishPage(hdc);
137
138 // save the document
139 lpdf.SaveToFile('delphi-1.pdf');
140 end;
141
142 // close the document
143 lpdf.Close();
144 except
145 // do something on TLitePDFException exception
146 on ex : TLitePDFException do raise;
147 end;
148 finally
149 // destroy the TLitePDF instance
150 lpdf.Destroy;
151 end;
152 end;
153
154 procedure TDelphiFrm.OpenHelloWorldBtnClick(Sender: TObject);
155 var errCode : Integer;
156 begin
157 errCode := Integer(ShellExecute(HWND(nil), 'open', 'delphi-1.pdf',
158 nil, nil, SW_SHOW));
159 if errCode < 32 then
160 begin
161 raise Exception.Create('Failed to open PDF file');
162 end;
163 end;
164
165 //----------------------------------------------------------------------------
166 // Helper function
167 //----------------------------------------------------------------------------
168
169 procedure TDelphiFrm.AddPage(lpdf: TLitePDF; pageWidthMM, pageHeightMM : UInt;
170 text: String);
171 var hDC : THandle;
172 canvas : TCanvas;
173 begin
174 // add a new page to it, with large-enough pixel scale
175 hDC := lpdf.AddPage(Trunc(lpdf.MMToUnit(pageWidthMM)),
176 Trunc(lpdf.MMToUnit(pageHeightMM)),
177 pageWidthMM * 10, pageHeightMM * 10,
178 LongWord(LitePDFDrawFlag_SubstituteFonts));
179
180 // some examples need an empty page, thus test for it
181 if Length(text) > 0 then
182 begin
183 // prepare drawing
184 canvas := TCanvas.Create;
185 try
186 canvas.Handle := hdc;
187 canvas.Font.Name := 'Helvetica';
188 canvas.Font.Size := -50; // ~5mm
189 canvas.Font.Color := clBlack;
190
191 // print the text
192 canvas.TextOut(100, 100, text);
193 finally
194 canvas.Destroy;
195 end;
196 end;
197
198 // finish drawing
199 lpdf.FinishPage(hDC);
200 end;
201
202 //----------------------------------------------------------------------------
203 // attachments example
204 //----------------------------------------------------------------------------
205
206 procedure TDelphiFrm.AttachmentsBtnClick(Sender: TObject);
207 var lpdf : TLitePDF;
208 customData : PAnsiChar;
209 ii, sz : Integer;
210 fileName : AnsiString;
211 dataLength : LongWord;
212 data : PByte;
213 msg : String;
214 begin
215 lpdf := TLitePDF.Create;
216
217 try
218 // create a document
219 lpdf.CreateMemDocument();
220
221 // check expected counts
222 if lpdf.GetEmbeddedFileCount <> 0 then
223 begin
224 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
225 'Newly created document reports non-zero embedded files');
226 end;
227
228 // create a page
229 AddPage(lpdf, 210, 297, 'Document with two attachments');
230
231 // embed data and file
232 customData := 'This is' + Chr(13) + Chr(10) + 'a multiline' +
233 Chr(13) + Chr(10) + 'custom data.';
234 lpdf.EmbedData('custom data.txt', PByte(customData), Length(customData));
235 lpdf.EmbedFile('..\\examples\\delphi\\delphi.dpr');
236
237 // check expected counts
238 if lpdf.GetEmbeddedFileCount <> 2 then
239 begin
240 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
241 'Newly created document reports other than two embedded files');
242 end;
243
244 // save to file
245 lpdf.SaveToFile('delphi-attachments-1.pdf');
246
247 // close the document
248 lpdf.Close;
249
250 //-----------------------------------------------------------------
251
252 // load from file
253 lpdf.LoadFromFile('delphi-attachments-1.pdf', '', True);
254
255 // check expected counts
256 if lpdf.GetEmbeddedFileCount <> 2 then
257 begin
258 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
259 'Loaded document reports other than two embedded files');
260 end;
261
262 sz := lpdf.GetEmbeddedFileCount;
263 for ii := 0 to sz - 1 do
264 begin
265 fileName := lpdf.GetEmbeddedFileName(ii);
266 msg := msg + '[' + IntToStr(ii) + '] fileName: ''' + String(fileName) + '''';
267
268 dataLength := 0;
269 if not lpdf.GetEmbeddedFileData(ii, nil, dataLength) then
270 begin
271 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
272 'Failed to get attachment data length');
273 end;
274
275 GetMem(data, dataLength);
276
277 if not lpdf.GetEmbeddedFileData(ii, data, dataLength) then
278 begin
279 FreeMem(data);
280 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
281 'Failed to get attachment data');
282 end;
283
284 msg := msg + ' dataLength: ' + IntToStr(dataLength) + crlf;
285
286 FreeMem(data);
287 end;
288
289 // close the document
290 lpdf.Close;
291 finally
292 // destroy the TLitePDF instance
293 lpdf.Destroy;
294 end;
295
296 ShowMessage(msg);
297 end;
298
299 //----------------------------------------------------------------------------
300 // docinfo example
301 //----------------------------------------------------------------------------
302
303 procedure TDelphiFrm.DocinfoBtnClick(Sender: TObject);
304 type MDocInfos = record
305 key : AnsiString;
306 value : WideString;
307 end;
308 var lpdf : TLitePDF;
309 docinfo : array[0..9] of MDocInfos;
310 ii : Integer;
311 value : WideString;
312 msg : String;
313 begin
314 // initialzie the array with items
315 docinfo[0].key := LitePDFDocumentInfo_Author;
316 docinfo[0].value := 'Document''s Author ěščřžýáíéúůöĚŠČŘŽÝÁÍÉÚŮÖ §';
317 docinfo[1].key := LitePDFDocumentInfo_Creator;
318 docinfo[1].value := 'Document''s Creator';
319 docinfo[2].key := LitePDFDocumentInfo_Keywords;
320 docinfo[2].value := 'Keyword1;Keyword2';
321 docinfo[3].key := LitePDFDocumentInfo_Subject;
322 docinfo[3].value := 'Document''s subject ěščřžýáíéúůöĚŠČŘŽÝÁÍÉÚŮÖ §';
323 docinfo[4].key := LitePDFDocumentInfo_Title;
324 docinfo[4].value := 'Document''s Title ěščřžýáíéúůöĚŠČŘŽÝÁÍÉÚŮÖ §';
325 docinfo[5].key := 'CustomProperty';
326 docinfo[5].value := 'CustomPropertyValue';
327 docinfo[6].key := LitePDFDocumentInfo_Producer;
328 docinfo[6].value := ''; // cannot be written
329 docinfo[7].key := LitePDFDocumentInfo_Trapped;
330 docinfo[7].value := '';
331 docinfo[8].key := LitePDFDocumentInfo_CreationDate;
332 docinfo[8].value := ''; // this is set automatically on save
333 docinfo[9].key := LitePDFDocumentInfo_ModificationDate;
334 docinfo[9].value := ''; // this is set automatically on save
335
336 lpdf := TLitePDF.Create;
337
338 try
339 // create a document
340 lpdf.CreateMemDocument();
341
342 // create a page
343 AddPage(lpdf, 210, 297, 'Document with set information about an author and such');
344
345 for ii := 0 to 9 do
346 begin
347 if Length(docinfo[ii].value) > 0 then
348 begin
349 lpdf.SetDocumentInfo(docinfo[ii].key, docinfo[ii].value);
350 end;
351 end;
352
353 // save to file
354 lpdf.SaveToFile('delphi-docinfo-1.pdf');
355
356 // close the document
357 lpdf.Close;
358
359 //-----------------------------------------------------------------
360
361 // load from file
362 lpdf.LoadFromFile('delphi-docinfo-1.pdf', '', False);
363
364 for ii := 0 to 9 do
365 begin
366 if lpdf.GetDocumentInfoExists(docinfo[ii].key) then
367 begin
368 value := lpdf.GetDocumentInfo(docinfo[ii].key);
369
370 msg := msg + '"' + String(docinfo[ii].key) + '" = "' + value + '"';
371
372 if Length(docinfo[ii].value) > 0 then
373 begin
374 if docinfo[ii].value = value then
375 msg := msg + ', as expected'
376 else
377 msg := msg + ', unexpected!';
378 end;
379 end else begin
380 msg := msg + 'key "' + String(docinfo[ii].key) + '" not found';
381 end;
382
383 msg := msg + crlf;
384 end;
385
386 // close the document
387 lpdf.Close;
388 finally
389 // destroy the TLitePDF instance
390 lpdf.Destroy;
391 end;
392
393 ShowMessage(msg);
394 end;
395
396 //----------------------------------------------------------------------------
397 // drawtoresource example
398 //----------------------------------------------------------------------------
399
400 procedure TDelphiFrm.DrawtoresourceBtnClick(Sender: TObject);
401 function createResource(lpdf : TLitePDF) : LongWord;
402 var hDC : THandle;
403 canvas : TCanvas;
404 begin
405 // create a resource
406 hDC := lpdf.AddResource(Trunc(lpdf.MMToUnit(100)),
407 Trunc(lpdf.MMToUnit(100)),
408 Trunc(lpdf.MMToUnit(100)),
409 Trunc(lpdf.MMToUnit(100)),
410 LongWord(LitePDFDrawFlag_None));
411
412 canvas := TCanvas.Create;
413 try
414 canvas.Handle := hDC;
415 canvas.Pen.Style := psSolid;
416 canvas.Pen.Color := clBlack;
417 canvas.Pen.Width := 1;
418
419 canvas.MoveTo(0, 0);
420 canvas.LineTo(0, 10);
421 canvas.LineTo(45, 50);
422 canvas.LineTo(0, 90);
423 canvas.LineTo(0, 100);
424 canvas.LineTo(10, 100);
425 canvas.LineTo(50, 55);
426 canvas.LineTo(90, 100);
427 canvas.LineTo(100, 100);
428 canvas.LineTo(100, 90);
429 canvas.LineTo(55, 50);
430 canvas.LineTo(100, 10);
431 canvas.LineTo(100, 0);
432 canvas.LineTo(90, 0);
433 canvas.LineTo(50, 45);
434 canvas.LineTo(10, 0);
435 canvas.LineTo(0, 0);
436 finally
437 canvas.Destroy;
438 end;
439
440 // finish drawing into the resource
441 Result := lpdf.FinishResource(hDC);
442 end;
443 var lpdf : TLitePDF;
444 resourceID : LongWord;
445 hDC : THandle;
446 begin
447 lpdf := TLitePDF.Create;
448
449 try
450 // create a document
451 lpdf.CreateMemDocument();
452
453 // create the resource
454 resourceID := createResource(lpdf);
455
456 // add an empty page, with large-enough pixel scale
457 hDC := lpdf.AddPage(Trunc(lpdf.MMToUnit(210)),
458 Trunc(lpdf.MMToUnit(297)),
459 2100, 2970, LongWord(LitePDFDrawFlag_None));
460 lpdf.FinishPage(hDC);
461
462 // draw the resource
463 lpdf.DrawResource(resourceID, 0,
464 LitePDFUnit_1000th_mm, // for better accuracy
465 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
466 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
467 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 1.0)),
468 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 1.0)));
469 lpdf.DrawResource(resourceID, 0,
470 LitePDFUnit_1000th_mm, // for better accuracy
471 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 150)),
472 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
473 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 1.0)),
474 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 1.0)));
475 lpdf.DrawResource(resourceID, 0,
476 LitePDFUnit_1000th_mm, // for better accuracy
477 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 150)),
478 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 120)),
479 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 0.3)),
480 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 0.3)));
481 lpdf.DrawResource(resourceID, 0,
482 LitePDFUnit_1000th_mm, // for better accuracy
483 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
484 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 150)),
485 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 0.5)),
486 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 1.5)));
487
488 lpdf.DrawResourceWithMatrix(resourceID, 0, 1.0, 0.3, -0.3, 1.2, 123, 153);
489
490 // save to file
491 lpdf.SaveToFile('delphi-drawtoresource-1.pdf');
492
493 // close the document
494 lpdf.Close;
495 finally
496 // destroy the TLitePDF instance
497 lpdf.Destroy;
498 end;
499 end;
500
501 //----------------------------------------------------------------------------
502 // encrypt example
503 //----------------------------------------------------------------------------
504
505 procedure TDelphiFrm.EncryptBtnClick(Sender: TObject);
506 // helper function
507 procedure createEncryptedFiles;
508 var lpdf : TLitePDF;
509 begin
510 lpdf := TLitePDF.Create;
511
512 try
513 //-----------------------------------------------------------------
514
515 // setup encryption to be used when creating the document
516 lpdf.PrepareEncryption('', 'owner',
517 LongWord(LitePDFEncryptPermission_All),
518 LongWord(LitePDFEncryptAlgorithm_RC4V1));
519
520 // begin write-only PDF file
521 lpdf.CreateFileDocument('delphi-encrypt-rc4v1-no-user-pass.pdf');
522
523 // fill a page
524 AddPage(lpdf, 210, 297, 'Encrypted, without user password, RC4 V1');
525
526 // close the document
527 lpdf.Close;
528
529 //-----------------------------------------------------------------
530
531 // setup encryption to be used when creating the document
532 lpdf.PrepareEncryption('user', 'owner',
533 LongWord(LitePDFEncryptPermission_All),
534 LongWord(LitePDFEncryptAlgorithm_RC4V2));
535
536 // begin memory-based PDF document
537 lpdf.CreateMemDocument;
538
539 // fill a page
540 AddPage(lpdf, 210, 297, 'Encrypted, with user and owner password, RC4 V2');
541
542 // save to file
543 lpdf.SaveToFile('delphi-encrypt-rc4v2.pdf');
544
545 // close the document
546 lpdf.Close;
547
548 //-----------------------------------------------------------------
549
550 // setup encryption to be used when creating the document
551 lpdf.PrepareEncryption('user', 'owner',
552 LongWord(LitePDFEncryptPermission_All),
553 LongWord(LitePDFEncryptAlgorithm_AESV2));
554
555 // begin memory-based PDF document
556 lpdf.CreateMemDocument;
557
558 // fill a page
559 AddPage(lpdf, 210, 297, 'Encrypted, with user and owner password, AES V2');
560
561 // save to file
562 lpdf.SaveToFile('delphi-encrypt-aesv2.pdf');
563
564 // close the document
565 lpdf.Close;
566
567 //-----------------------------------------------------------------
568
569 // setup encryption to be used when creating the document
570 lpdf.PrepareEncryption('user', 'owner',
571 LongWord(LitePDFEncryptPermission_All),
572 LongWord(LitePDFEncryptAlgorithm_AESV3));
573
574 // begin memory-based PDF document
575 lpdf.CreateMemDocument;
576
577 // fill a page
578 AddPage(lpdf, 210, 297, 'Encrypted, with user and owner password, AES V3');
579
580 // save to file
581 lpdf.SaveToFile('delphi-encrypt-aesv3.pdf');
582
583 // close the document
584 lpdf.Close;
585 finally
586 // destroy the TLitePDF instance
587 lpdf.Destroy;
588 end;
589 end;
590
591 var lpdf : TLitePDF;
592 begin
593 lpdf := TLitePDF.Create;
594
595 try
596 // create the files
597 createEncryptedFiles;
598
599 //-----------------------------------------------------------------
600 // now try to open them
601 //-----------------------------------------------------------------
602
603 // no user password, then open it as a user
604 lpdf.LoadFromFile('delphi-encrypt-rc4v1-no-user-pass.pdf', '', False);
605
606 // close the document
607 lpdf.Close;
608
609 //-----------------------------------------------------------------
610
611 try
612 // this should fail, because no password was provided
613 lpdf.LoadFromFile('delphi-encrypt-rc4v2.pdf', '', False);
614
615 raise TLitePDFException.Create(ERROR_CANNOT_MAKE,
616 'Should fail to open encrypted file without provided password');
617 except
618 on ex : TLitePDFException do
619 begin
620 if ex.getCode <> ERROR_WRONG_PASSWORD then
621 begin
622 raise;
623 end;
624
625 // re-try with user's password
626 lpdf.LoadFromFile('delphi-encrypt-rc4v2.pdf', 'user', False);
627 end;
628 end;
629
630 // close the document
631 lpdf.Close;
632
633 //-----------------------------------------------------------------
634
635 // try to open as owner
636 lpdf.LoadFromFile('delphi-encrypt-rc4v1-no-user-pass.pdf', 'owner', False);
637
638 // close the document
639 lpdf.Close;
640
641 //-----------------------------------------------------------------
642
643 // try to open as user
644 lpdf.LoadFromFile('delphi-encrypt-rc4v2.pdf', 'user', False);
645
646 // close the document
647 lpdf.Close;
648
649 //-----------------------------------------------------------------
650
651 // try to open as owner
652 lpdf.LoadFromFile('delphi-encrypt-rc4v2.pdf', 'owner', False);
653
654 // close the document
655 lpdf.Close;
656
657 //-----------------------------------------------------------------
658
659 // try to open as user
660 lpdf.LoadFromFile('delphi-encrypt-aesv2.pdf', 'user', False);
661
662 // close the document
663 lpdf.Close;
664
665 //-----------------------------------------------------------------
666
667 // try to open as owner
668 lpdf.LoadFromFile('delphi-encrypt-aesv2.pdf', 'owner', False);
669
670 // close the document
671 lpdf.Close;
672
673 //-----------------------------------------------------------------
674
675 // try to open as user
676 lpdf.LoadFromFile('delphi-encrypt-aesv3.pdf', 'user', False);
677
678 // close the document
679 lpdf.Close;
680
681 //-----------------------------------------------------------------
682
683 // try to open as owner
684 lpdf.LoadFromFile('delphi-encrypt-aesv3.pdf', 'owner', False);
685
686 // close the document
687 lpdf.Close;
688 finally
689 // destroy the TLitePDF instance
690 lpdf.Destroy;
691 end;
692 end;
693
694 //----------------------------------------------------------------------------
695 // fromdoc example
696 //----------------------------------------------------------------------------
697
698 procedure TDelphiFrm.FromdocBtnClick(Sender: TObject);
699 var lpdfFrom, lpdfTo : TLitePDF;
700 resourceID : LongWord;
701 begin
702 lpdfFrom := TLitePDF.Create;
703 lpdfTo := TLitePDF.Create;
704
705 try
706 // create a document
707 lpdfFrom.CreateMemDocument;
708
709 // create the source document's pages
710 AddPage(lpdfFrom, 210, 297, 'Page 1');
711 AddPage(lpdfFrom, 210, 297, 'Page 2');
712 AddPage(lpdfFrom, 210, 297, 'Page 3');
713
714 // save to file
715 lpdfFrom.SaveToFile('delphi-fromdoc-1.pdf');
716
717 // close the document
718 lpdfFrom.Close;
719
720 //-----------------------------------------------------------------
721
722 // load from file
723 lpdfFrom.LoadFromFile('delphi-fromdoc-1.pdf', '', False);
724
725 //-----------------------------------------------------------------
726
727 // create a new document
728 lpdfTo.CreateMemDocument;
729
730 // copy all, but the first page
731 lpdfTo.AddPagesFrom(lpdfFrom, 1, lpdfFrom.GetPageCount - 1);
732
733 // save to file
734 lpdfTo.SaveToFile('delphi-fromdoc-2.pdf');
735
736 // close the document
737 lpdfTo.Close;
738
739 //-----------------------------------------------------------------
740
741 // create a new document
742 lpdfTo.CreateMemDocument;
743
744 // copy all, but the first page
745 lpdfTo.AddPagesFrom(lpdfFrom, 1, lpdfFrom.GetPageCount - 1);
746
747 // insert page 0 as page 1 - note, page inserting is PDF-resource hungry
748 lpdfTo.InsertPageFrom(1, lpdfFrom, 0);
749
750 // save to file
751 lpdfTo.SaveToFile('delphi-fromdoc-3.pdf');
752
753 // close the document
754 lpdfTo.Close;
755
756 //-----------------------------------------------------------------
757
758 // create a new document
759 lpdfTo.CreateMemDocument;
760
761 // copy the third page
762 lpdfTo.AddPagesFrom(lpdfFrom, 2, 1);
763
764 // add new empty page, it has index 1
765 AddPage(lpdfTo, 210, 297, '');
766
767 // copy page 2 as a resource
768 resourceID := lpdfTo.AddPageFromAsResource(lpdfFrom, 1);
769
770 // draw the added page (twice)
771 lpdfTo.DrawResource(resourceID, 1,
772 LitePDFUnit_1000th_mm, // for better accuracy
773 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
774 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 10)),
775 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 0.3)),
776 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 0.3)));
777 lpdfTo.DrawResource(resourceID, 1,
778 LitePDFUnit_1000th_mm, // for better accuracy
779 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 150)),
780 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 150)),
781 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 0.2)),
782 Trunc(lpdfTo.MMToUnitEx(LitePDFUnit_1000th_mm, 0.2)));
783
784 // insert page 0 as page 1 - note, page inserting is PDF-resource hungry
785 lpdfTo.InsertPageFrom(1, lpdfFrom, 0);
786
787 // save to file
788 lpdfTo.SaveToFile('delphi-fromdoc-4.pdf');
789
790 // close the document
791 lpdfTo.Close;
792
793 //-----------------------------------------------------------------
794
795 // close the source document
796 lpdfFrom.Close;
797 finally
798 // destroy the TLitePDF instances
799 lpdfFrom.Destroy;
800 lpdfTo.Destroy;
801 end;
802 end;
803
804 //----------------------------------------------------------------------------
805 // pagesperpage example
806 //----------------------------------------------------------------------------
807
808 procedure TDelphiFrm.PagesperpageBtnClick(Sender: TObject);
809 // helper function
810 procedure AddPage2(lpdf: TLitePDF;
811 pageWidthMM, pageHeightMM : Integer;
812 text: String;
813 center : Boolean;
814 insertPos : Integer);
815 var hDC : THandle;
816 canvas : TCanvas;
817 len : Integer;
818 begin
819 // add a new page to it, with large-enough pixel scale
820 if insertPos = -1 then
821 hDC := lpdf.AddPage(Trunc(lpdf.MMToUnit(pageWidthMM)),
822 Trunc(lpdf.MMToUnit(pageHeightMM)),
823 pageWidthMM * 10, pageHeightMM * 10,
824 LongWord(LitePDFDrawFlag_SubstituteFonts))
825 else
826 hDC := lpdf.InsertPage(insertPos,
827 Trunc(lpdf.MMToUnit(pageWidthMM)),
828 Trunc(lpdf.MMToUnit(pageHeightMM)),
829 pageWidthMM * 10, pageHeightMM * 10,
830 LongWord(LitePDFDrawFlag_SubstituteFonts));
831
832 // prepare drawing
833 canvas := TCanvas.Create;
834 try
835 canvas.Handle := hdc;
836 canvas.Font.Name := 'Helvetica';
837 canvas.Font.Size := -50; // ~5mm
838 if center then
839 canvas.Font.Size := -150; // ~15mm
840 canvas.Font.Color := clBlack;
841
842 // print the text
843 if center then
844 begin
845 len := Length(text);
846 canvas.TextOut(Trunc((pageWidthMM - 5 * len) * 10 / 2),
847 Trunc((pageHeightMM - 15) * 10 / 2), text);
848 end else begin
849 canvas.TextOut(100, 100, text);
850 end;
851 finally
852 canvas.Destroy;
853 end;
854
855 // finish drawing
856 lpdf.FinishPage(hDC);
857 end;
858
859 // helper function
860 procedure DrawPageRect(lpdf: TLitePDF; pageIndex : LongWord);
861 var hDC : THandle;
862 canvas : TCanvas;
863 width_mm, height_mm : LongWord;
864 begin
865 lpdf.GetPageSize(pageIndex, width_mm, height_mm);
866
867 // the conversion is not needed here, because the current
868 // unit set on the lpdf is in millimeters, but done anyway,
869 // to show the usage of the conversion routine
870 width_mm := Trunc(lpdf.UnitToMM(width_mm));
871 height_mm := Trunc(lpdf.UnitToMM(height_mm));
872
873 // use the same scale as the AddPage2() function
874 hDC := lpdf.UpdatePage(pageIndex,
875 width_mm * 10, height_mm * 10,
876 LongWord(LitePDFDrawFlag_None));
877
878 // prepare drawing
879 canvas := TCanvas.Create;
880 try
881 canvas.Handle := hdc;
882 canvas.Pen.Style := psSolid;
883 canvas.Pen.Color := clBlack;
884 canvas.Pen.Width := 1;
885
886 canvas.MoveTo(10, 10);
887 canvas.LineTo(width_mm * 10 - 10, 10);
888 canvas.LineTo(width_mm * 10 - 10, height_mm * 10 - 10);
889 canvas.LineTo(10, height_mm * 10 - 10);
890 canvas.LineTo(10, 10);
891 finally
892 canvas.Destroy;
893 end;
894
895 // finish drawing
896 lpdf.FinishPage(hDC);
897 end;
898
899 type MSize = record
900 cx, cy : LongWord;
901 end;
902 var lpdf : TLitePDF;
903 sizes : array[0..4] of MSize;
904 resources : array[0..4] of LongWord;
905 ii, idx, pages, width_mm, height_mm : LongWord;
906 pageSzX, pageSzY : LongWord;
907 scaleX, scaleY, offsetY : Real;
908 hDC : THandle;
909 begin
910 sizes[0].cx := 210;
911 sizes[0].cy := 297;
912 sizes[1].cx := 210;
913 sizes[1].cy := 297;
914 sizes[2].cx := 210;
915 sizes[2].cy := 297;
916 sizes[3].cx := 297;
917 sizes[3].cy := 210;
918 sizes[4].cx := 297;
919 sizes[4].cy := 210;
920
921 lpdf := TLitePDF.Create;
922
923 try
924 // create a to-be-multipage document
925 lpdf.CreateMemDocument;
926
927 // add pages
928 idx := 0;
929 for ii := 0 to 3 do
930 begin
931 AddPage2(lpdf, sizes[idx].cx, sizes[idx].cy, 'Page ' + IntToStr(idx + 1), True, -1);
932
933 pages := idx;
934 if pages > 1 then
935 Dec(pages);
936
937 // draw page rectangle
938 DrawPageRect(lpdf, pages);
939
940 // skip the third page, it'll be inserted
941 if ii = 1 then
942 Inc(idx);
943
944 // add one the same as for 'ii'
945 Inc(idx);
946 end;
947
948 // insert the third page
949 AddPage2(lpdf, sizes[2].cx, sizes[2].cy, 'Page 3 [inserted]', True, 2);
950
951 // draw page rectangle
952 DrawPageRect(lpdf, 2);
953
954 // test stored page sizes
955 for ii := 0 to 4 do
956 begin
957 width_mm := 0;
958 height_mm := 0;
959
960 lpdf.GetPageSize(ii, width_mm, height_mm);
961
962 // the conversion is not needed here, because the current
963 // unit set on the lpdf is in millimeters, but done anyway,
964 // to show the usage of the conversion routine
965 width_mm := Trunc(lpdf.UnitToMM(width_mm));
966 height_mm := Trunc(lpdf.UnitToMM(height_mm));
967
968 if (width_mm <> sizes[ii].cx) or (height_mm <> sizes[ii].cy) then
969 begin
970 raise TLitePDFException.Create(ERROR_CANNOT_MAKE, AnsiString(
971 'page[' + IntToStr(ii) + '] size doesn''t match; expected ' +
972 IntToStr(sizes[ii].cx) + ' x ' + IntToStr(sizes[ii].cy) +
973 ', but got ' + IntToStr(width_mm) + ' x ' + IntToStr(height_mm)));
974 end;
975 end;
976
977 // save to file
978 lpdf.SaveToFile('delphi-pagesperpage-1.pdf');
979
980 // close the document
981 lpdf.Close;
982
983 //-----------------------------------------------------------------
984
985 // load from file
986 lpdf.LoadFromFile('delphi-pagesperpage-1.pdf', '', True);
987
988 // check the opened file has correct page count
989 pages := lpdf.GetPageCount;
990 if pages <> 5 then
991 begin
992 raise TLitePDFException.Create(ERROR_CANNOT_MAKE, AnsiString(
993 'The opened document doesn''t have 5 pages, but ' + IntToStr(pages)));
994 end;
995
996 // convert pages to resources
997 for ii := 0 to 4 do
998 begin
999 width_mm := 0;
1000 height_mm := 0;
1001
1002 lpdf.GetPageSize(ii, width_mm, height_mm);
1003
1004 // the conversion is not needed here, because the current
1005 // unit set on the lpdf is in millimeters, but done anyway,
1006 // to show the usage of the conversion routine
1007 width_mm := Trunc(lpdf.UnitToMM(width_mm));
1008 height_mm := Trunc(lpdf.UnitToMM(height_mm));
1009
1010 if (width_mm <> sizes[ii].cx) or (height_mm <> sizes[ii].cy) then
1011 begin
1012 raise TLitePDFException.Create(ERROR_CANNOT_MAKE, AnsiString(
1013 'page[' + IntToStr(ii) + '] size doesn''t match; expected ' +
1014 IntToStr(sizes[ii].cx) + ' x ' + IntToStr(sizes[ii].cy) +
1015 ', but got ' + IntToStr(width_mm) + ' x ' + IntToStr(height_mm)));
1016 end;
1017
1018 resources[ii] := lpdf.PageToResource(ii);
1019
1020 width_mm := 0;
1021 height_mm := 0;
1022
1023 lpdf.GetResourceSize(resources[ii], width_mm, height_mm);
1024
1025 // the conversion is not needed here, because the current
1026 // unit set on the lpdf is in millimeters, but done anyway,
1027 // to show the usage of the conversion routine
1028 width_mm := Trunc(lpdf.UnitToMM(width_mm));
1029 height_mm := Trunc(lpdf.UnitToMM(height_mm));
1030
1031 if (width_mm <> sizes[ii].cx) or (height_mm <> sizes[ii].cy) then
1032 begin
1033 raise TLitePDFException.Create(ERROR_CANNOT_MAKE, AnsiString(
1034 'resource ID ' + IntToStr(resources[ii]) + ' from ' +
1035 'page[' + IntToStr(ii) + '] size doesn''t match; expected ' +
1036 IntToStr(sizes[ii].cx) + ' x ' + IntToStr(sizes[ii].cy) +
1037 ', but got ' + IntToStr(width_mm) + ' x ' + IntToStr(height_mm)));
1038 end;
1039 end;
1040
1041 // delete pages
1042 for ii := 0 to 4 do
1043 begin
1044 lpdf.DeletePage(0);
1045 end;
1046
1047 // there should be no pages now
1048 pages := lpdf.GetPageCount;
1049 if pages <> 0 then
1050 begin
1051 raise TLitePDFException.Create(ERROR_CANNOT_MAKE, AnsiString(
1052 'The opened document doesn''t have 0 pages, but ' + IntToStr(pages)));
1053 end;
1054
1055 // draw resources (former pages) into new pages
1056 ii := 0;
1057 while ii <= 4 do
1058 begin
1059 pageSzX := sizes[ii].cy;
1060 pageSzY := sizes[ii].cx;
1061
1062 // create a new page without drawing into it
1063 hDC := lpdf.AddPage(Trunc(lpdf.MMToUnit(pageSzX)),
1064 Trunc(lpdf.MMToUnit(pageSzY)),
1065 pageSzX, pageSzY,
1066 LongWord(LitePDFDrawFlag_None));
1067 lpdf.FinishPage(hDC);
1068
1069 offsetY := 0.0;
1070 lpdf.GetResourceSize(resources[ii], width_mm, height_mm);
1071
1072 // the conversion is not needed here, because the current
1073 // unit set on the lpdf is in millimeters, but done anyway,
1074 // to show the usage of the conversion routine
1075 width_mm := Trunc(lpdf.UnitToMM(width_mm));
1076 height_mm := Trunc(lpdf.UnitToMM(height_mm));
1077
1078 scaleX := pageSzX / 2.0 / width_mm;
1079 scaleY := pageSzY / height_mm;
1080
1081 if width_mm > height_mm then
1082 begin
1083 scaleY := scaleY / 2.0;
1084 scaleX := scaleX * 2.0;
1085 offsetY := pageSzY / 2.0;
1086 end;
1087
1088 // draw the first page on the left part
1089 lpdf.DrawResourceWithMatrix(resources[ii], lpdf.GetPageCount - 1,
1090 scaleX, 0.0, 0.0, scaleY, 0.0, offsetY);
1091
1092 if ii + 1 < 5 then
1093 begin
1094 lpdf.GetResourceSize(resources[ii + 1], width_mm, height_mm);
1095
1096 // the conversion is not needed here, because the current
1097 // unit set on the lpdf is in millimeters, but done anyway,
1098 // to show the usage of the conversion routine
1099 width_mm := Trunc(lpdf.UnitToMM(width_mm));
1100 height_mm := Trunc(lpdf.UnitToMM(height_mm));
1101
1102 scaleX := pageSzX / 2.0 / width_mm;
1103 scaleY := pageSzY / height_mm;
1104
1105 if width_mm > height_mm then
1106 begin
1107 scaleY := scaleY / 2.0;
1108 end;
1109
1110 // draw the second page on the right part
1111 lpdf.DrawResource(resources[ii + 1], lpdf.GetPageCount - 1,
1112 LitePDFUnit_1000th_mm, // for better accuracy
1113 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, pageSzX / 2)),
1114 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, 0.0)),
1115 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, scaleX)),
1116 Trunc(lpdf.MMToUnitEx(LitePDFUnit_1000th_mm, scaleY)));
1117 end;
1118
1119 ii := ii + 2;
1120 end;
1121
1122 // save to file
1123 lpdf.SaveToFile('delphi-pagesperpage-2.pdf');
1124
1125 // close the document
1126 lpdf.Close;
1127 finally
1128 // destroy the TLitePDF instance
1129 lpdf.Destroy;
1130 end;
1131 end;
1132
1133 //----------------------------------------------------------------------------
1134 // helper definitions for sign example
1135 //----------------------------------------------------------------------------
1136
1137 {$IFDEF WIN64}
1138 {$ALIGN ON}
1139 {$ELSE}
1140 {$ALIGN 4}
1141 {$ENDIF}
1142
1143 {$MINENUMSIZE 4}
1144
1145 type
1146 PCRYPT_DATA_BLOB = ^CRYPT_DATA_BLOB;
1147 CRYPT_DATA_BLOB = record
1148 cbData : DWORD;
1149 pbData : PByte;
1150 end;
1151
1152 {$EXTERNALSYM CRYPT_DATA_BLOB}
1153 CRYPT_OBJID_BLOB = CRYPT_DATA_BLOB;
1154 {$EXTERNALSYM CRYPT_OBJID_BLOB}
1155
1156 PCCERT_CONTEXT = Pointer;
1157 {$EXTERNALSYM PCCERT_CONTEXT}
1158
1159 HCERTSTORE = Pointer;
1160 {$EXTERNALSYM HCERTSTORE}
1161
1162 PCRYPT_ALGORITHM_IDENTIFIER = ^CRYPT_ALGORITHM_IDENTIFIER;
1163 CRYPT_ALGORITHM_IDENTIFIER = record
1164 pszObjId : LPSTR;
1165 Parameters : CRYPT_OBJID_BLOB;
1166 end;
1167 {$EXTERNALSYM CRYPT_ALGORITHM_IDENTIFIER}
1168
1169 PCRYPT_SIGN_MESSAGE_PARA = ^CRYPT_SIGN_MESSAGE_PARA;
1170 CRYPT_SIGN_MESSAGE_PARA = record
1171 cbSize : DWORD;
1172 dwMsgEncodingType : DWORD;
1173 pSigningCert : PCCERT_CONTEXT;
1174 HashAlgorithm : CRYPT_ALGORITHM_IDENTIFIER;
1175 pvHashAuxInfo : Pointer;
1176 cMsgCert : DWORD;
1177 rgpMsgCert : ^PCCERT_CONTEXT;
1178 cMsgCrl : DWORD;
1179 rgpMsgCrl : ^Pointer;
1180 cAuthAttr : DWORD;
1181 rgAuthAttr : Pointer; // PCRYPT_ATTRIBUTE
1182 cUnauthAttr : DWORD;
1183 rgUnauthAttr : Pointer; // PCRYPT_ATTRIBUTE
1184 dwFlags : DWORD;
1185 dwInnerContentType : DWORD;
1186 end;
1187 {$EXTERNALSYM CRYPT_SIGN_MESSAGE_PARA}
1188
1189 PPByte = ^PByte;
1190
1191 const
1192 PKCS_7_ASN_ENCODING = $00010000;
1193 X509_ASN_ENCODING = $00000001;
1194 CERT_FIND_ANY = 0;
1195
1196 function PFXIsPFXBlob(
1197 pPFX : PCRYPT_DATA_BLOB) : BOOL; stdcall;
1198 external 'crypt32.dll' name 'PFXIsPFXBlob';
1199
1200 function PFXImportCertStore(
1201 pPFX: PCRYPT_DATA_BLOB;
1202 szPassword: PWideChar;
1203 dwFlags : DWORD) : HCERTSTORE; stdcall;
1204 external 'crypt32.dll' name 'PFXImportCertStore';
1205
1206 function CertFindCertificateInStore(
1207 ppCertStore : HCERTSTORE;
1208 dwCertEncodingType : DWORD;
1209 dwFindFlags : DWORD;
1210 dwFindType : DWORD;
1211 pvFindPara : Pointer;
1212 pPrevCertContext : PCCERT_CONTEXT) : PCCERT_CONTEXT; stdcall;
1213 external 'crypt32.dll' name 'CertFindCertificateInStore';
1214
1215 function CryptSignMessage(
1216 pSignPara : PCRYPT_SIGN_MESSAGE_PARA;
1217 fDetachedSignature : BOOL;
1218 cToBeSigned : DWORD;
1219 rgpbToBeSigned : PPByte;
1220 rgcbToBeSigned : PDWORD;
1221 pbSignedBlob : PByte;
1222 pcbSignedBlob : PLongWord) : BOOL; stdcall;
1223 external 'crypt32.dll' name 'CryptSignMessage';
1224
1225 function CertFreeCertificateContext(
1226 ppCertContext : PCCERT_CONTEXT) : BOOL; stdcall;
1227 external 'crypt32.dll' name 'CertFreeCertificateContext';
1228
1229 function CertCloseStore(
1230 ppCertStore : HCERTSTORE;
1231 dwFlags : DWORD) : BOOL; stdcall;
1232 external 'crypt32.dll' name 'CertCloseStore';
1233
1234 //----------------------------------------------------------------------------
1235 // helper class for sign example
1236 //----------------------------------------------------------------------------
1237
1238 type MPdfSigner = class
1239 protected
1240 m_bytes : Pointer;
1241 m_bytes_len : LongWord;
1242 m_lastSignatureIndex : LongWord;
1243
1244 procedure loadCertificateStore(var hStore : HCERTSTORE);
1245 procedure AddData(pBytes : PByte; pBytes_len : LongWord);
1246 procedure Finish(signature : PByte; signature_len : PLongWord);
1247 function CreateSignatureField(lpdf : TLitePDF;
1248 signatureName : AnsiString;
1249 dateOfSign : TDateTime;
1250 annotationResourceID : LongWord;
1251 annotationPageIndex : LongWord;
1252 annotationPosition_mm : TRect;
1253 annotationFlags : LongWord;
1254 signatureLen : Integer) : LongWord;
1255 public
1256 constructor Create;
1257 destructor Destroy; override;
1258
1259 procedure Clear;
1260
1261 procedure SignToFile(lpdf : TLitePDF;
1262 fileName : AnsiString;
1263 signatureName : AnsiString);
1264
1265 procedure SignToFileEx(lpdf : TLitePDF;
1266 fileName : AnsiString;
1267 signatureName : AnsiString;
1268 annotationResourceID : LongWord;
1269 annotationPageIndex : LongWord;
1270 annotationPosition_mm : TRect;
1271 annotationFlags : LongWord);
1272
1273 function SignToData(lpdf : TLitePDF;
1274 data : PByte;
1275 var dataLength : LongWord;
1276 signatureName : AnsiString) : Boolean;
1277 end;
1278
1279 procedure appendSignatureData(bytes : PByte; bytes_len : LongWord; user_data : Pointer); stdcall;
1280 var signer : MPdfSigner;
1281 begin
1282 signer := MPdfSigner(user_data);
1283 signer.AddData(bytes, bytes_len);
1284 end;
1285
1286 procedure finishSignature(signature : PByte; signature_len : PLongWord; user_data : Pointer); stdcall;
1287 var signer : MPdfSigner;
1288 begin
1289 signer := MPdfSigner(user_data);
1290 signer.Finish(signature, signature_len);
1291 end;
1292
1293 constructor MPdfSigner.Create;
1294 begin
1295 m_bytes := nil;
1296 m_bytes_len := 0;
1297 m_lastSignatureIndex := $FFFFFFFF;
1298 end;
1299
1300 destructor MPdfSigner.Destroy;
1301 begin
1302 Clear;
1303 end;
1304
1305 procedure MPdfSigner.Clear;
1306 begin
1307 if m_bytes <> nil then
1308 begin
1309 FreeMem(m_bytes);
1310 m_bytes := nil;
1311 end;
1312 m_bytes_len := 0;
1313 m_lastSignatureIndex := $FFFFFFFF;
1314 end;
1315
1316 procedure MPdfSigner.loadCertificateStore(var hStore : HCERTSTORE);
1317 var certFile : TMemoryStream;
1318 blob : CRYPT_DATA_BLOB;
1319 begin
1320 certFile := TMemoryStream.Create;
1321 try
1322 certFile.LoadFromFile('cert.pfx');
1323
1324 blob.cbData := certFile.Size;
1325 blob.pbData := certFile.Memory;
1326 if PFXIsPFXBlob(@blob) then
1327 hStore := PFXImportCertStore(@blob, '', 0);
1328 finally
1329 certFile.Destroy;
1330 end;
1331 end;
1332
1333 procedure MPdfSigner.AddData(pBytes : PByte; pBytes_len : LongWord);
1334 var shifted_bytes : PByte;
1335 ii : LongWord;
1336 begin
1337 if m_bytes = nil then
1338 GetMem(m_bytes, SizeOf(Byte) * pBytes_len * 2)
1339 else
1340 ReallocMem(m_bytes, SizeOf(Byte) * (m_bytes_len + pBytes_len));
1341
1342 shifted_bytes := PByte(m_bytes) + m_bytes_len;
1343 for ii := 0 to pBytes_len - 1 do
1344 begin
1345 shifted_bytes[ii] := pBytes[ii];
1346 end;
1347 m_bytes_len := m_bytes_len + pBytes_len;
1348 end;
1349
1350 procedure MPdfSigner.Finish(signature : PByte; signature_len : PLongWord);
1351 var hStore : HCERTSTORE;
1352 hCertContext : PCCERT_CONTEXT;
1353 MessageArray : PByte;
1354 MessageSizeArray : LongWord;
1355 SigParams : CRYPT_SIGN_MESSAGE_PARA;
1356 begin
1357 hStore := nil;
1358 hCertContext := nil;
1359
1360 MessageArray := m_bytes;
1361 MessageSizeArray := m_bytes_len;
1362
1363 loadCertificateStore(hStore);
1364 if hStore = nil then
1365 begin
1366 raise TLitePDFException.Create(GetLastError, AnsiString(
1367 'Failed to open a temporary store: ' +
1368 SysErrorMessage(GetLastError)));
1369 end;
1370
1371 hCertContext := CertFindCertificateInStore(hStore,
1372 PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, 0, CERT_FIND_ANY,
1373 nil, nil);
1374 if hCertContext = nil then
1375 begin
1376 CertCloseStore(hStore, 0);
1377 raise TLitePDFException.Create(GetLastError, AnsiString(
1378 'Failed to find certificate in the store: ' +
1379 SysErrorMessage(GetLastError)));
1380 end;
1381
1382 FillChar(SigParams, SizeOf(CRYPT_SIGN_MESSAGE_PARA), 0);
1383
1384 SigParams.cbSize := SizeOf(CRYPT_SIGN_MESSAGE_PARA);
1385 SigParams.dwMsgEncodingType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;
1386 SigParams.pSigningCert := hCertContext;
1387 SigParams.HashAlgorithm.pszObjId := '1.2.840.113549.1.1.5'; // szOID_RSA_SHA1RSA
1388 SigParams.HashAlgorithm.Parameters.pbData := nil;
1389 SigParams.HashAlgorithm.Parameters.cbData := 0;
1390 SigParams.pvHashAuxInfo := nil;
1391 SigParams.cMsgCert := 1;
1392 SigParams.rgpMsgCert := @hCertContext;
1393 SigParams.cMsgCrl := 0;
1394 SigParams.rgpMsgCrl := nil;
1395 SigParams.cAuthAttr := 0;
1396 SigParams.rgAuthAttr := nil;
1397 SigParams.cUnauthAttr := 0;
1398 SigParams.rgUnauthAttr := nil;
1399 SigParams.dwFlags := 0;
1400 SigParams.dwInnerContentType := 0;
1401
1402 if not CryptSignMessage(
1403 @SigParams, // Signature parameters
1404 TRUE, // detached ?
1405 1, // Number of messages
1406 @MessageArray, // Messages to be signed
1407 @MessageSizeArray, // Size of messages
1408 signature, // Buffer for signed message
1409 signature_len) then
1410 begin
1411 CertFreeCertificateContext(hCertContext);
1412 CertCloseStore(hStore, 0);
1413
1414 raise TLitePDFException.Create(GetLastError, AnsiString (
1415 'Failed to sign data: ' + SysErrorMessage(GetLastError)));
1416 end;
1417
1418 CertFreeCertificateContext(hCertContext);
1419 CertCloseStore(hStore, 0);
1420 end;
1421
1422 function MPdfSigner.CreateSignatureField(lpdf : TLitePDF;
1423 signatureName : AnsiString;
1424 dateOfSign : TDateTime;
1425 annotationResourceID : LongWord;
1426 annotationPageIndex : LongWord;
1427 annotationPosition_mm : TRect;
1428 annotationFlags : LongWord;
1429 signatureLen : Integer) : LongWord;
1430 var signatureIndex : LongWord;
1431 begin
1432 lpdf.SetSignatureSize(signatureLen);
1433
1434 signatureIndex := lpdf.CreateSignature(signatureName,
1435 annotationPageIndex,
1436 annotationPosition_mm,
1437 annotationFlags);
1438
1439 lpdf.SetSignatureReason(signatureIndex, 'litePDF example');
1440 lpdf.SetSignatureDate(signatureIndex, dateOfSign);
1441
1442 if annotationResourceID and annotationPageIndex < lpdf.GetPageCount() then
1443 begin
1444 lpdf.SetSignatureAppearance(signatureIndex, LitePDFAppearance_Normal, annotationResourceID, 0, 0);
1445 end;
1446
1447 Result := signatureIndex;
1448 end;
1449
1450 procedure MPdfSigner.SignToFile(lpdf : TLitePDF;
1451 fileName : AnsiString;
1452 signatureName : AnsiString);
1453 var rect_mm : TRect;
1454 begin
1455 rect_mm := Rect(0, 0, 0, 0);
1456
1457 SignToFileEx(lpdf, fileName, signatureName, 0, 0, rect_mm, 0);
1458 end;
1459
1460 procedure MPdfSigner.SignToFileEx(lpdf : TLitePDF;
1461 fileName : AnsiString;
1462 signatureName : AnsiString;
1463 annotationResourceID : LongWord;
1464 annotationPageIndex : LongWord;
1465 annotationPosition_mm : TRect;
1466 annotationFlags : LongWord);
1467 var signatureIndex : LongWord;
1468 begin
1469 signatureIndex := CreateSignatureField(lpdf,
1470 signatureName,
1471 System.SysUtils.EncodeDate(1970, 1, 1), { works as today }
1472 annotationResourceID,
1473 annotationPageIndex,
1474 annotationPosition_mm,
1475 annotationFlags,
1476 0);
1477
1478 lpdf.SaveToFileWithSignManual(fileName,
1479 signatureIndex,
1480 appendSignatureData, self,
1481 finishSignature, self);
1482 end;
1483
1484 function MPdfSigner.SignToData(lpdf : TLitePDF;
1485 data : PByte;
1486 var dataLength : LongWord;
1487 signatureName : AnsiString) : Boolean;
1488 var rect_mm : TRect;
1489 signatureIndex : LongWord;
1490 begin
1491 rect_mm := Rect(0, 0, 0, 0);
1492
1493 if m_lastSignatureIndex = $FFFFFFFF then
1494 begin
1495 signatureIndex := CreateSignatureField(lpdf,
1496 signatureName,
1497 System.SysUtils.EncodeDate(1970, 1, 1),
1498 0, 0, rect_mm, 0, 0);
1499 // remember the used signature index for the second call,
1500 // when populating the 'data'
1501 m_lastSignatureIndex := signatureIndex;
1502 end else begin
1503 signatureIndex := m_lastSignatureIndex;
1504 end;
1505
1506 Result := lpdf.SaveToDataWithSignManual(signatureIndex,
1507 appendSignatureData, self,
1508 finishSignature, self,
1509 data, dataLength);
1510 end;
1511
1512 //----------------------------------------------------------------------------
1513 // sign example
1514 //----------------------------------------------------------------------------
1515
1516 procedure TDelphiFrm.SignManualBtnClick(Sender: TObject);
1517 // helper function
1518 function createResource(lpdf : TLitePDF) : LongWord;
1519 var hDC : THandle;
1520 w, h : Integer;
1521 canvas : TCanvas;
1522 begin
1523 w := 25;
1524 h := 8;
1525
1526 // create a new resource
1527 hDC := lpdf.AddResource(Trunc(lpdf.MMToUnit(w)),
1528 Trunc(lpdf.MMToUnit(h)),
1529 w * 20, h * 20,
1530 LongWord(LitePDFDrawFlag_SubstituteFonts));
1531
1532 canvas := TCanvas.Create;
1533 try
1534 // prepare canvas
1535 canvas.Handle := hDC;
1536 canvas.Pen.Style := psDot;
1537 canvas.Pen.Color := clGray;
1538 canvas.Pen.Width := 1;
1539 canvas.Font.Name := 'Helvetica';
1540 canvas.Font.Size := -40;
1541
1542 // rectangle on boundaries
1543 canvas.MoveTo(0, 0);
1544 canvas.LineTo(w * 20, 0);
1545 canvas.LineTo(w * 20, h * 20);
1546 canvas.LineTo(0, h * 20);
1547 canvas.LineTo(0, 0);
1548
1549 // draw the text
1550 canvas.TextOut(50, 20, 'litePDF example');
1551 canvas.TextOut(50, 70, 'Signature');
1552 finally
1553 canvas.Destroy;
1554 end;
1555
1556 // finish drawing
1557 result := lpdf.FinishResource(hDC);
1558 end;
1559
1560 var lpdf : TLitePDF;
1561 signer : MPdfSigner;
1562 where_mm : TRect;
1563 begin
1564 lpdf := TLitePDF.Create;
1565 signer := MPdfSigner.Create;
1566
1567 try
1568 // create a document
1569 lpdf.CreateMemDocument;
1570
1571 // create some pages
1572 AddPage(lpdf, 210, 297, 'Digitally signed document');
1573 AddPage(lpdf, 210, 297, 'Page 2');
1574
1575 // create also visual appearance for this signature, on the second page
1576 where_mm := Rect(Trunc(lpdf.MMToUnit(90)), Trunc(lpdf.MMToUnit(5)),
1577 Trunc(lpdf.MMToUnit(90 + 25)), Trunc(lpdf.MMToUnit(5 + 8)));
1578
1579 // save signed to a file
1580 signer.Clear;
1581 signer.SignToFileEx(lpdf, 'delphi-sign-1.pdf', 'Sig1',
1582 createResource(lpdf),
1583 1,
1584 where_mm,
1585 LongWord(LitePDFAnnotationFlag_None));
1586
1587 // close the document
1588 lpdf.Close;
1589 finally
1590 // destroy the TLitePDF and MPdfSigner instances
1591 lpdf.Destroy;
1592 signer.Destroy;
1593 end;
1594 end;
1595
1596 end.