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.