-
Notifications
You must be signed in to change notification settings - Fork 311
Open
Labels
bugdocument-editingRelated to creating or editing/modifying documentsRelated to creating or editing/modifying documents
Description
Hi, First of all, I want to thank you for this awesome project. I have encountered a surprising behavior with the page operation list:
My setup is Windows 11 25H2 (26200.7623) Developping in .NET 8
I work on a project where I need to add some more data to PDF for production. Since my PDFs are Landscaped, I need to rotate them, append data at the desired location, then rotate back. Here is the code I am working with.
using (PdfDocument document = PdfDocument.Open(@"PathToFile"))
{
var page = document.GetPage(1);
string dest = @"OutputName";
if (System.IO.File.Exists(dest))
{
File.Delete(dest);
}
using (FileStream fileStream = new FileStream(dest, FileMode.CreateNew, FileAccess.ReadWrite))
using (PdfDocumentBuilder builder = new PdfDocumentBuilder(fileStream))
{
PdfDocumentBuilder.AddedFont font = builder.AddStandard14Font(Standard14Font.Helvetica);
PdfPageBuilder pageBuilder = builder.AddPage(document, page.Number);
pageBuilder.NewContentStreamBefore();
TransformationMatrix inversse = new TransformationMatrix();
if (page.Rotation.Value == 90)
{
TransformationMatrix rotationMatrix = TransformationMatrix.GetRotationMatrix(90);
TransformationMatrix translationMatrix = TransformationMatrix.GetTranslationMatrix(0, -page.Height);
TransformationMatrix matrix = translationMatrix.Multiply(rotationMatrix);
inversse = matrix.Inverse();
pageBuilder.CurrentStream.Operations.Add(new ModifyCurrentTransformationMatrix(new double[] { matrix.A, matrix.B, matrix.C, matrix.D, matrix.E, matrix.F }));
}
pageBuilder.SetStrokeColor(100, 100, 100);
pageBuilder.SetTextAndFillColor(100, 100, 100);
pageBuilder.SetTextRenderingMode(TextRenderingMode.Fill);
double scalingFactor = page.Width / (22 * 72);
PdfPoint textOrigin = new PdfPoint(0, 72 * 1.5 * scalingFactor);
var projectLetters = pageBuilder.MeasureText("16254", 24 * scalingFactor, textOrigin, font);
var textWidth = projectLetters.Max(x => x.GlyphRectangle.Right) - projectLetters.Min(x => x.GlyphRectangle.Left);
PdfPoint projectTextOrigin = textOrigin.Translate((page.Width / 2) - textWidth / 2, 0);
projectLetters = pageBuilder.MeasureText("16254", 24 * scalingFactor, projectTextOrigin, font);
var qtyLetters = pageBuilder.MeasureText($"Qte: {24}", 24 * scalingFactor, textOrigin, font);
var qtyWidth = qtyLetters.Max(x => x.GlyphRectangle.Right) - qtyLetters.Min(x => x.GlyphRectangle.Left);
PdfPoint qtyTextOrigin = textOrigin.Translate((page.Width / 2) - qtyWidth / 2, -(36 * scalingFactor));
qtyLetters = pageBuilder.MeasureText($"Qte: {24}", 24 * scalingFactor, qtyTextOrigin, font);
var bottomOfText = qtyLetters.Min(x => x.GlyphRectangle.Bottom);
var topOfText = projectLetters.Max(x => x.GlyphRectangle.Top);
var leftOfText = double.Min(projectLetters.Min(x => x.GlyphRectangle.Left), qtyLetters.Min(x => x.GlyphRectangle.Left));
var rightOfText = double.Max(projectLetters.Max(x => x.GlyphRectangle.Right), qtyLetters.Max(x => x.GlyphRectangle.Right));
//make the rectangle .125in away from the text
var rectangleOffset = (.125 * 72) * scalingFactor;
bottomOfText = bottomOfText - rectangleOffset;
topOfText = topOfText + rectangleOffset;
leftOfText = leftOfText - rectangleOffset;
rightOfText = rightOfText + rectangleOffset;
var boxWidth = rightOfText - leftOfText;
var boxHeight = topOfText - bottomOfText;
double lineWidth = 3 * scalingFactor;
PdfPoint rectangleOrigin = new PdfPoint(leftOfText, bottomOfText);
PdfPoint outerRectangleOrigin = rectangleOrigin.Translate(-rectangleOffset, -rectangleOffset);
double outerRectangleWidth = boxWidth + rectangleOffset * 2;
double outerRectangleHeight = boxHeight + rectangleOffset * 2;
var words = page.GetWords();
var docstrum = new DocstrumBoundingBoxes(new DocstrumBoundingBoxes.DocstrumBoundingBoxesOptions()
{
WithinLineBounds = new DocstrumBoundingBoxes.AngleBounds(-30, 30),
BetweenLineBounds = new DocstrumBoundingBoxes.AngleBounds(45, 135),
BetweenLineMultiplier = 0.1
});
PdfRectangle roi = new PdfRectangle(outerRectangleOrigin, new PdfPoint(outerRectangleOrigin.X + outerRectangleWidth, outerRectangleOrigin.Y + outerRectangleHeight));
var blocks = docstrum.GetBlocks(words).Where(x => x.BoundingBox.IntersectsWith(roi)).Select(x => x.BoundingBox).ToList();
if (blocks.Count > 0)
{
double[] pushRight = new double[blocks.Count];
double[] pushLeft = new double[blocks.Count];
double[] pushUp = new double[blocks.Count];
double[] pushDown = new double[blocks.Count];
//Border on C format starts at 0.5 inch from the bottom and 0.75 from the sides
//TitleBlock on C format is 8.824 inches wide, and 2.367 high
PdfPoint cartoucheBottomLeft = new((22.0 - 0.75 - 8.824) * 72.0 * scalingFactor, 0.5 * 72 * scalingFactor);
PdfPoint cartoucheTopRight = new((22.0 - 0.75) * 72 * scalingFactor, (0.5 + 2.367) * 72 * scalingFactor);
PdfRectangle cartouche = new PdfRectangle(cartoucheBottomLeft, cartoucheTopRight);
double rightLimit = roi.Bottom < cartouche.Top ? cartouche.Left : cartouche.Right;
double leftLimit = 0.75 * 72 * scalingFactor;
double bottomLimit = 0.5 * 72 * scalingFactor;
double topLimit = page.Height - (0.5 * 72 * scalingFactor);
for (int i = 0; i < blocks.Count; i++)
{
pushRight[i] = blocks[i].Right - roi.Left;
pushLeft[i] = roi.Right - blocks[i].Left;
pushUp[i] = blocks[i].Top - roi.Bottom;
pushDown[i] = roi.Top - blocks[i].Bottom;
}
double smallestDistance = double.MaxValue;
PdfPoint movementVector = new PdfPoint();
var minRight = pushRight.Min();
if (roi.Right + minRight <= rightLimit)
{
smallestDistance = minRight;
movementVector = new PdfPoint(minRight, 0);
}
var minLeft = pushLeft.Min();
if (roi.Left - minLeft >= leftLimit && minLeft < smallestDistance)
{
smallestDistance = minLeft;
movementVector = new PdfPoint(-minLeft, 0);
}
var minUp = pushUp.Min();
if (roi.Top + minUp <= topLimit && minUp < smallestDistance)
{
smallestDistance = minUp;
movementVector = new PdfPoint(0, minUp);
}
var minDown = pushDown.Min();
if (roi.Bottom - minDown >= bottomLimit && minDown < smallestDistance)
{
smallestDistance = minDown;
movementVector = new PdfPoint(0, -minDown);
}
rectangleOrigin = rectangleOrigin.Translate(movementVector.X, movementVector.Y);
outerRectangleOrigin = outerRectangleOrigin.Translate(movementVector.X, movementVector.Y);
qtyTextOrigin = qtyTextOrigin.Translate(movementVector.X, movementVector.Y);
projectTextOrigin = projectTextOrigin.Translate(movementVector.X, movementVector.Y);
}
pageBuilder.DrawRectangle(rectangleOrigin, boxWidth, boxHeight, lineWidth);
//add another rectangle
pageBuilder.DrawRectangle(outerRectangleOrigin, outerRectangleWidth, outerRectangleHeight, lineWidth);
var drawnQtyLetters = pageBuilder.AddText($"Qte: {24}", 24 * scalingFactor, qtyTextOrigin, font);
var drawnProjectLetters = pageBuilder.AddText("16254", 24 * scalingFactor, projectTextOrigin, font);
//pageBuilder.ResetColor(); //WILL NOT CAUSE PROBLEM
pageBuilder.CurrentStream.Operations.Add(new ModifyCurrentTransformationMatrix(new double[] { inversse.A, inversse.B, inversse.C, inversse.D, inversse.E, inversse.F }));
pageBuilder.ResetColor(); //THIS CAUSE BEHAVIOR ISSUE
builder.Build();
}
}As commented, If I call pageBuilder.ResetColor() before the last rotation operation, everything works as intended. If I place ResetColor() after the rotation, the last rotation is ignored?
Here is the resulting PDF if I place the ResetColor() after :
And this is when I place it before :
I have also attached the original PDF.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugdocument-editingRelated to creating or editing/modifying documentsRelated to creating or editing/modifying documents