diff --git a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs index 18346cd5..915bbc5b 100644 --- a/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs +++ b/src/foundation/src/PDFsharp/src/PdfSharp/Pdf.IO/PdfWriter.cs @@ -236,7 +236,14 @@ public void Write(PdfLiteral value) /// public void Write(PdfRectangle rect) { - const string format = Config.SignificantDecimalPlaces3; + // With three decimal places, writing an existing page rounds its /MediaBox + // (e.g. 595.2756 -> 595.276). That is a change of the page geometry, which a validator + // reports as a changed page for every digital signature the document already contains. + // + // Note that the coordinates are written as they are, while Write(double) converts a real + // number to a single first. Doing that here would defeat the purpose: the single nearest to + // 595.2756 is 595.27557, which does not round-trip either. + const string format = Config.SignificantDecimalPlaces7; WriteSeparator(CharCat.Delimiter); WriteRaw(PdfEncoders.Format("[{0:" + format + "} {1:" + format + "} {2:" + format + "} {3:" + format + "}]", rect.X1, rect.Y1, rect.X2, rect.Y2)); } diff --git a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs index 3af04c71..2b1b37b1 100644 --- a/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs +++ b/src/foundation/src/PDFsharp/tests/PdfSharp.Tests/IO/WriterTests.cs @@ -29,5 +29,32 @@ public void Write_import_file() Action save = () => doc.Save(filename); save.Should().Throw(); } + + [Fact] + public void Write_rectangle_with_the_precision_of_a_real_number() + { + // ISO A4 in points. The values have four decimal places, which must survive a round-trip, + // because a changed /MediaBox is a changed page for every digital signature of the document. + const double width = 595.2756, height = 841.8898; + + using var stream = new MemoryStream(); + using (var document = new PdfDocument()) + { + var page = document.AddPage(); + page.MediaBox = new PdfRectangle(new XPoint(0, 0), new XPoint(width, height)); + document.Save(stream, false); + } + + var pdf = stream.ToArray(); + var chars = new char[pdf.Length]; + for (int idx = 0; idx < pdf.Length; idx++) + chars[idx] = (char)pdf[idx]; + new String(chars).Should().Contain("[0 0 595.2756 841.8898]"); + + using var writtenDocument = PdfReader.Open(new MemoryStream(pdf), PdfDocumentOpenMode.Import); + var mediaBox = writtenDocument.Pages[0].MediaBox; + mediaBox.X2.Should().Be(width); + mediaBox.Y2.Should().Be(height); + } } }