⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 updfwriter.pas

📁 DelphiDoc is a program for automatic generation of documentation on a Delphi-Project. At the momen
💻 PAS
📖 第 1 页 / 共 5 页
字号:
 FStream.WriteBuffer(Pointer(Text)^, Length(Text));  //write the text

 if NewLine then                                     //wants line break
  FStream.WriteBuffer(Pointer(UPDFWriter.NewLine)^,    //write it
                      Length(UPDFWriter.NewLine));
end;

{Writes some formatted text into the stream.
~param Fmt     the format of the text to write
~param Args    the arguments for the format to include in the text to be
               written
~param NewLine whether an end-of-line sequence should also be written }
procedure TPDFWriter.WriteFormatted(const Fmt: String;
                                    const Args: array of const;
                                    NewLine: Boolean = True);
begin
 Write(Format(Fmt, Args), NewLine);     //format and write the text
end;

{Writes some text into the page.
~param S       the text to write
~param NewLine if an end-of-line sequence should also be written }
procedure TPDFWriter.WritePage(const S: String; NewLine: Boolean = True);
begin
 FPageStream.WriteBuffer(Pointer(S)^, Length(S));      //write the text
 if NewLine then                                       //wants line break
  FPageStream.WriteBuffer(Pointer(UPDFWriter.NewLine)^,  //write it
                          Length(UPDFWriter.NewLine));
end;


{Writes a PDF number value as part of a command into the page. The value of the
 number has to be below 20 million and is written with two digits after the
 decimal point.
~param Number the value to be written }
procedure TPDFWriter.WritePageCommandNumber(const Number: TPDFValue);
const     BufferSize = 15;  //size of the buffer to convert the number
var       S         :String[BufferSize];  //used to convert
          TheValue  :Integer;             //number * 100 as an integer
          pS        :PChar;               //runner through the buffer
          AbsValue  :Cardinal;            //positiv number * 100 as an integer
begin
 TheValue := Round(Number * 100);         //get the number to be written
 pS := PChar(@S[BufferSize]);             //initialize buffer

 if TheValue = 0 then                     //number is zero?
  ps^ := '0'                                //write the zero
 else
  begin
   AbsValue := Abs(TheValue);               //first write positive number

   ps^ := Char(Ord('0') + AbsValue mod 10); //add last digit
   AbsValue := AbsValue div 10;

   if (AbsValue = 0) or (pS^ <> '0') then   //is relevant?
    Dec(pS);

   ps^ := Char(Ord('0') + AbsValue mod 10); //add "tenth"-digit
   AbsValue := AbsValue div 10;
   if (pS^ <> '0') or (pS <> PChar(@S[BufferSize])) then //is relevant?
    begin
     Dec(pS);
     pS^ := '.';                              //add decimal point
     Dec(pS);
    end;

   repeat                                   //add all other digits
     ps^ := Char(Ord('0') + AbsValue mod 10);
     Dec(pS);
     AbsValue := AbsValue div 10;
   until AbsValue = 0;

   if TheValue < 0 then                     //value was negative?
    pS^ := '-'                                //prepend signum
   else
    Inc(pS);
  end;

 FPageStream.WriteBuffer(pS^, @S[BufferSize] - pS + 1);  //write the number

{

 Str2Ext(Number, 1, 2, S);                      //get number as text
// Str(Number:1:2, S);                             //get number as text
 FPageStream.WriteBuffer(S[1], Length(S));       //write the text
}
end;







{Ends the current page. }
procedure TPDFWriter.EndPage;
var       PObj      :TPDFObjectNumber;  //index of the PDF object of the page
          Parent    :TPDFObjectNumber;  //parent object of list (tree) of pages
          Obj       :TPDFObjectNumber;  //index of a new PDF object
          i         :Integer;           //general counter
          AliasInd  :Integer;           //counter through destination aliases
          TmpStream :TMemoryStream;     //compressed content of the page
begin
 DoDrawCommands;                        //draw everything that has been drawn

 //get future index of the PDF object of the page
 PObj := FObjPositions.Count + 1 + FDestinations.Count + FAnnotations.Count;
 //register the page reference (might change it) and get parent entry
 Parent := RegisterPageNumber(PObj);

 AliasInd := 0;                                 //start with first alias
 for i := 0 to FDestinations.Count - 1 do //for each destination in the page
  begin
   Obj := GetAddObjPosNumber;               //create a new object for it
   Write(IntToStr(Obj) + ' 0 obj <<');      //write the PDF object for it
   Write('/D [' + IntToStr(PObj) + ' 0 R /XYZ ' +  //write destination
         FDestinations[i] +  ' 0.00 ]');
   Write('>> endobj');
   //add destination to name tree of the destinations
   FDestNameTreeItems.AddObject(FDestinationNames[i], Pointer(Obj));

   //check whether aliases exist for that destination
   while (AliasInd < FDestinationAliases.Count) and
         (Integer(FDestinationAliases.Objects[AliasInd]) = i) do
    begin
     //add destination with the alias to name tree of the destinations
     FDestNameTreeItems.AddObject(FDestinationAliases[AliasInd], Pointer(Obj));
     Inc(AliasInd);                           //resume with next alias
    end;
  end;
 Assert(AliasInd = FDestinationAliases.Count);
 FDestinations.Clear;                     //clear lists of the destinations
 FDestinationNames.Clear;
 FDestinationAliases.Clear;



 for i := 0 to FAnnotations.Count - 1 do  //for each annotation
  begin
   Obj := GetAddObjPosNumber;               //create a new object for it
   FAnnotations.Objects[i] := Pointer(Obj); //save the index
   Write(IntToStr(Obj) + ' 0 obj <<');      //create a PDF object for it

   Write('/Type /Annot');
   Write('/Subtype /Link');                 //write the annotation

   Write(FAnnotations[i]);                  //write data of link target

   Write('/Border [0 0 0 ]');

   Write('>> endobj');
  end;






 Obj := GetAddObjPosNumber;               //create PDF object for the page
 assert(PObj = Obj);


 Write(IntToStr(Obj) + ' 0 obj <<');      //start PDF object for the page
 Write('/Type /Page');
 Write(Format('/Parent %d 0 R', [Parent])); //parent in the tree of the pages

 //write size of the pages of the file
 Write('/MediaBox [0 0 ' + PDFNumberToStr(FPageWidth) + ' ' +
       PDFNumberToStr(FPageHeight) + ' ]');

 if FImageReferences.Count <> 0 then      //some images drawn in the page?
  begin
   WriteResources(FImageReferences);        //use them as resource
   FImageReferences.Clear;                  //clear for the next page
  end;


 if FAnnotations.Count <> 0 then          //annotations in the page?
  begin
   Write('/Annots [', False);               //create entry for them
   for i := 0 to FAnnotations.Count - 1 do  //write references to annotations
    Write(IntToStr(Integer(FAnnotations.Objects[i])) + ' 0 R ', False);
   Write(']');
   FAnnotations.Clear;
  end;
 //the directly following object contains the content of the page
 Write('/Contents ' + IntToStr(Obj + 1) + ' 0 R');
 Write('>> endobj');


 //create the PDF object for the content of the page
 Write(IntToStr(GetAddObjPosNumber) + ' 0 obj <<');


 if FImageDrawCommands <> '' then        //some images should be drawn?
  begin
   //set new and final size
   FPageStream.Size := FPageStream.Position + Length(FImageDrawCommands);
   //move the whole stream to free some space for this commands for the images
   Move(FPageStream.Memory^,
        Pointer(Integer(FPageStream.Memory) + Length(FImageDrawCommands))^,
        FPageStream.Position);
   //write the commands to draw the images at the beginning
   Move(Pointer(FImageDrawCommands)^, FPageStream.Memory^,
        Length(FImageDrawCommands));
   FPageStream.Position := FPageStream.Size;   //move to the end
   FImageDrawCommands := '';
  end;


 TmpStream := FPageStream;                //use stream for content of page
 try
   FPageStream.Size := FPageStream.Position; //copy only valid data
   if FCompression then                      //compression enabled?
    begin
     //create stream for compressed content
     TmpStream := TMemoryStream.Create;
     with TCompressionStream.Create(clMax, TmpStream) do //create compressor
      try
        CopyFrom(FPageStream, 0);                        //compress content
      finally
       Free;                                             //free compressor
      end;
    end; //if FCompression

   //write length of the (compressed) content
   Write('/Length ' + IntToStr(TmpStream.Size));
   if FCompression then                      //compression enabled?
    Write('/Filter [/FlateDecode ]')           //write the decompressor to use
   else
    Write('/Filter []');
   Write('>>');
   Write('stream' + NewLine, False);         //start the content of the page

   TmpStream.Position := 0;
   Stream.CopyFrom(TmpStream, 0);            //copy the content of the page
 finally
  if TmpStream <> FPageStream then           //compression enabled?
   TmpStream.Free;                             //free the stream
 end;

 Write(#10'endstream endobj');               //end the content of the page
end;




{Registers a page number and returns its parent object in the tree of pages.
~param Page the number of a (not yet written) page to register into the tree of
            pages, might be modified (incremented) slightly in case new objects
            have to be inserted
~result the number of the parent entry in the tree }
function TPDFWriter.RegisterPageNumber(
                                 var Page: TPDFObjectNumber): TPDFObjectNumber;

 //Write the current node of the specified level of the tree of pages.
 procedure WritePagesNode(Level, PageCount: Integer); forward;
 //Adds a new node into the tree of pages.
 procedure AddPagesNode(Level, PageCount: Integer); forward;


 {Write the current node of the specified level of the tree of pages.
 ~param Level     the level in the tree to write the current node of
 ~param PageCount the number of pages in the node }
 procedure WritePagesNode(Level, PageCount: Integer);
 var       ObjNum        :TPDFObjectNumber; //number of the object of the node
           Parent        :TPDFObjectNumber; //the number of the parent's object
           i             :Integer;          //counter through child entries
 begin
  Assert(Length(FPageTreeObjectsCounter) > Level);

  //is the first node on this level?
  if FPageTreeObjectsCounter[Level] = 1 then
   //we need a new parent node, so add (register) it
   AddPagesNode(Level + 1, PageCount * FPagesTreeNumberInNodes);

  //get number of the object
  ObjNum := FPageTreeObjects[Level][FPageTreeObjectsCounter[Level] - 1];
  //get number of the object of the parent entry
  Parent := FPageTreeObjects[Level + 1][FPageTreeObjectsCounter[Level + 1] -
                                        1];

  //save position of the pages-object
  FObjPositions[ObjNum - 1] := Pointer(FStream.Position);

  Write(Format('%d 0 obj <<', [ObjNum]));    //start the object
  Write('/Type /Pages');                     //a node in the tree of pages
  Write(Format('/Parent %d 0 R', [Parent])); //reference to parent node
  //write the references to the child nodes
  Write('/Kids [', False);
  for i := 0 to FPagesTreeNumberInNodes - 1 do
   Write(Format('%d 0 R ', [FPageTreeObjects[Level - 1][i]]), False);
  Write(']');
  Write(Format('/Count %d', [PageCount]));   //write number of pages
  Write('>> endobj');                        //end the object

  FPageTreeObjectsCounter[Level - 1] := 0;   //clear list of child nodes
 end;

 {Adds a new node into the tree of pages.
 ~param Level     the level in the tree to add a new node to
 ~param PageCount the number of pages in the node }
 procedure AddPagesNode(Level, PageCount: Integer);
 begin
  Assert(Length(FPageTreeObjectsCounter) >= Level);

  //is the first node on the level?
  if Length(FPageTreeObjectsCounter) = Level then
   begin
    SetLength(FPageTreeObjects, Level + 1);          //add the new level
    SetLength(FPageTreeObjects[Level], FPagesTreeNumberInNodes);
    SetLength(FPageTreeObjectsCounter, Level + 1);
    FPageTreeObjectsCounter[Level] := 0;             //no nodes in it so far
   end
  else                                             //level is already filled?
   if FPageTreeObjectsCounter[Level] = FPagesTreeNumberInNodes then
    //write references to all the nodes (i.e. write their parent node) and
    //clear

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -