Rank: Newbie
Groups: Registered
Joined: 4/9/2024(UTC) Posts: 2
|
A page normalization function is required. If the page is displayed rotated in the Viewer, this is very bad. Here is an example of how to do this, rewrite it and add it to the library. And it is necessary that when opening a document, normalization occurs. Otherwise, very complex processing always occurs. Now it is extremely inconvenient to work with the library; you always need to check the page rotation and write 4 versions of the code. Quote: function TQuickPDF.NormalizePage(NormalizeOptions: Integer): Integer; var OldWidth: Double; OldHeight: Double; OldRotation: Integer; OldOrigin: Integer; OldScale: Double; NewWidth: Double; NewHeight: Double; CropXOffset: Double; CropYOffset: Double; CropWidth: Double; CropHeight: Double; Transform: AnsiString; AnnotIndex: Integer; AnnotRect: TPDFArray; PDFRect: TPDFRectangle; AnnotLeft: Double; AnnotTop: Double; AnnotRight: Double; AnnotBottom: Double; AnnotRotation: Integer; Balancer: TPDFContentStreamStackBalancer; CS: AnsiString; Obj: TPDFObject; Dict: TPDFDictionary; I: Integer;
procedure ResetMatrixEntries(Obj: TPDFObject; Rotation: Integer); const R: Array[1..16] of Integer = ( 1, 0, 0, 1, // 0 0, -1, 1, 0, // 90 -1, 0, 0, -1, // 180 0, 1, -1, 0 // 270 ); var Offset: Integer; A: TPDFArray; begin Offset := (((Rotation + 360) mod 360) div 90) * 4;
if Obj is TPDFIndRef then Obj := TPDFIndRef(Obj).Obj; if (Obj is TPDFArray) and (TPDFArray(Obj).Count = 6) then begin A := TPDFArray(Obj); if (A.Item[0] is TPDFNumeric) then TPDFNumeric(A.Item[0]).SetTo(R[Offset + 1]); if (A.Item[1] is TPDFNumeric) then TPDFNumeric(A.Item[1]).SetTo(R[Offset + 2]); if (A.Item[2] is TPDFNumeric) then TPDFNumeric(A.Item[2]).SetTo(R[Offset + 3]); if (A.Item[3] is TPDFNumeric) then TPDFNumeric(A.Item[3]).SetTo(R[Offset + 4]); end; end;
begin Result := 0; if ((NormalizeOptions >= 0) and (NormalizeOptions <= 3)) then begin
// Reset the origin and scale OldOrigin := FSelDoc.Origin; OldScale := FSelDoc.Scale; FSelDoc.Origin := 0; FSelDoc.Scale := 1;
// Get the CropBox offset and size CropXOffset := GetPageBox(2, 0); CropWidth := GetPageBox(2, 2); CropHeight := GetPageBox(2, 3); CropYOffset := GetPageBox(2, 5); OldWidth := CropWidth; OldHeight := CropHeight;
// Get the page's rotation OldRotation := PageRotation;
// Normalize the rotation OldRotation := ((OldRotation div 90) mod 4) * 90; if (OldRotation < 0) then OldRotation := 360 + OldRotation;
// Determine the new width/height based on the rotation if (OldRotation = 90) or (OldRotation = 270) then begin NewWidth := OldHeight; NewHeight := OldWidth; end else begin NewWidth := OldWidth; NewHeight := OldHeight; end;
// Remove the page rotation attribute RotatePage(0);
// Set all the page boxes to be the same SetPageBox(1, 0, NewHeight, NewWidth, NewHeight); SetPageBox(2, 0, NewHeight, NewWidth, NewHeight); SetPageBox(3, 0, NewHeight, NewWidth, NewHeight); SetPageBox(4, 0, NewHeight, NewWidth, NewHeight); SetPageBox(5, 0, NewHeight, NewWidth, NewHeight);
// Calculate an appropriate transformation Transform := ''; case OldRotation of 0: begin Transform := '1 0 0 1 ' + QPLDoubleToStrConst(-CropXOffset, 4) + ' ' + QPLDoubleToStrConst(-CropYOffset, 4) + ' cm'; end; 90: begin Transform := '0 -1 1 0 0 ' + QPLDoubleToStrConst(NewHeight, 4) + ' cm ' + '1 0 0 1 ' + QPLDoubleToStrConst(-CropXOffset, 4) + ' ' + QPLDoubleToStrConst(-CropYOffset, 4) + ' cm'; end; 180: begin Transform := '-1 0 0 -1 ' + QPLDoubleToStrConst(NewWidth, 4) + ' ' + QPLDoubleToStrConst(NewHeight, 4) + ' cm ' + '1 0 0 1 ' + QPLDoubleToStrConst(-CropXOffset, 4) + ' ' + QPLDoubleToStrConst(-CropYOffset, 4) + ' cm'; end; 270: begin Transform := '0 1 -1 0 ' + QPLDoubleToStrConst(NewWidth, 4) + ' 0 cm ' + '1 0 0 1 ' + QPLDoubleToStrConst(-CropXOffset, 4) + ' ' + QPLDoubleToStrConst(-CropYOffset, 4) + ' cm'; end; end;
if (NormalizeOptions = 1) or (NormalizeOptions = 3) then begin // Balance the save/restore state commands Balancer := TPDFContentStreamStackBalancer.Create(0); try CS := GetPageContentToString; Balancer.Process(CS);
NewContentStream; SetContentStreamFromString('q ' + Transform + ' '); MoveContentStream(ContentStreamCount, 1);
NewContentStream; SetContentStreamFromString(' Q ' + Balancer.GetBalancingSuffix); finally Balancer.Free; end; end else begin if (NewContentStream <> 0) then begin SetContentStreamFromString('q ' + Transform + ' '); MoveContentStream(ContentStreamCount, 1);
NewContentStream; SetContentStreamFromString(' Q ') end else Exit; end;
if (OldRotation <> 0) then begin
// Adjust the annotations for AnnotIndex := 0 to FSelDoc.PageTree.Annots.Count - 1 do begin AnnotRect := FSelDoc.PageTree.Annots.GetAnnotRect(AnnotIndex);
AnnotRotation := FSelDoc.PageTree.Annots.GetRotation(AnnotIndex); FSelDoc.PageTree.Annots.SetRotation(AnnotIndex, AnnotRotation - OldRotation);
if (Assigned(AnnotRect) and (AnnotRect.Count = 4)) then begin
PDFRect := TPDFRectangle.Create(AnnotRect); AnnotLeft := PDFRect.Left; AnnotTop := PDFRect.Top; AnnotRight := PDFRect.Right; AnnotBottom := PDFRect.Bottom; try case OldRotation of 0: begin PDFRect.Left := AnnotLeft - CropXOffset; PDFRect.Top := AnnotTop - CropYOffset; PDFRect.Right := AnnotRight - CropXOffset; PDFRect.Bottom := AnnotBottom - CropYOffset; end;
90: begin PDFRect.Left := CropHeight - ((CropYOffset + CropHeight) - AnnotTop); PDFRect.Top := CropWidth - (AnnotRight - CropXOffset); PDFRect.Right := CropHeight - ((CropYOffset + CropHeight) - AnnotBottom); PDFRect.Bottom := CropWidth - (AnnotLeft - CropXOffset); end;
180: begin PDFRect.Left := (CropXOffset + CropWidth) - AnnotRight; PDFRect.Top := (CropYOffset + CropHeight) - AnnotBottom; PDFRect.Right := (CropXOffset + CropWidth) - AnnotLeft; PDFRect.Bottom := (CropYOffset + CropHeight) - AnnotTop; end;
270: begin PDFRect.Left := CropHeight - (AnnotBottom - CropYOffset); PDFRect.Top := CropWidth - ((CropXOffset + CropWidth) - AnnotLeft); PDFRect.Right := CropHeight - (AnnotTop - CropYOffset); PDFRect.Bottom := CropWidth - ((CropXOffset + CropWidth) - AnnotRight); end; end; finally PDFRect.Free; end; end;
Obj := FSelDoc.PageTree.Annots.GetAnnotRef(AnnotIndex); if Obj is TPDFIndRef then Obj := TPDFIndRef(Obj).Obj; if (Obj is TPDFDictionary) then begin if (TPDFDictionary(Obj).FindValueByKeyName('MK') = nil) then begin Obj := TPDFDictionary(Obj).FindValueByKeyName('AP', True); if (Obj is TPDFDictionary) then begin Obj := TPDFDictionary(Obj).FindValueByKeyName('N'); if Obj is TPDFIndRef then Obj := TPDFIndRef(Obj).Obj; if (Obj is TPDFStream) then begin Obj := TPDFStream(Obj).Dictionary.FindValueByKeyName('Matrix', True); if (Obj is TPDFArray) then ResetMatrixEntries(Obj, OldRotation); end; if (Obj is TPDFDictionary) then begin Dict := TPDFDictionary(Obj); for I := 0 to Dict.Count do begin Obj := Dict.Entry[I].Value; if Obj is TPDFIndRef then Obj := TPDFIndRef(Obj).Obj;
if (Obj is TPDFStream) then begin Obj := TPDFStream(Obj).Dictionary.FindValueByKeyName('Matrix', True); if (Obj is TPDFArray) then begin ResetMatrixEntries(Obj, OldRotation); end; end; end; end; end; end; end; end;
if FSelDoc.HasFormData then begin for AnnotIndex := 0 to FSelDoc.AcroForm.Count - 1 do begin AnnotRotation := FSelDoc.AcroForm.Field[AnnotIndex].GetRotation; FSelDoc.AcroForm.Field[AnnotIndex].SetRotation(AnnotRotation - OldRotation); end; end; end; // Rotation <> 0
FSelDoc.Origin := OldOrigin; FSelDoc.Scale := OldScale; FSelDoc.ReloadFormData;
Result := 1; end; end;
|