logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Maratovich  
#1 Posted : Sunday, November 16, 2025 7:40:15 AM(UTC)
Maratovich

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;

Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.