diff --git a/src/UglyToad.PdfPig.Tests/Integration/Documents/inherited_mediabox.pdf b/src/UglyToad.PdfPig.Tests/Integration/Documents/inherited_mediabox.pdf
new file mode 100644
index 00000000..2d4468c4
--- /dev/null
+++ b/src/UglyToad.PdfPig.Tests/Integration/Documents/inherited_mediabox.pdf
@@ -0,0 +1,61 @@
+%PDF-1.1
+1 0 obj
+<>
+endobj
+2 0 obj
+<>
+endobj
+3 0 obj
+<<
+ /Type/Page
+ /Parent 2 0 R
+ /Resources <<
+ /XObject << /SomeImage 4 0 R >>
+ >>
+ /Contents 5 0 R
+>>
+endobj
+4 0 obj
+<<
+ /Type/XObject
+ /Subtype/Image
+ /Width 200 % The width or height directly affects the image's file size.
+ /Height 100
+ /ColorSpace/DeviceRGB
+ /DecodeParms [] % Forces NativeImageDecoder.isSupported to return false.
+ /BitsPerComponent 8
+ /Length 580
+ /Filter [ /ASCIIHexDecode /DCTDecode ]
+>>
+% convert -size 1x1 xc:red jpeg:- | xxd -p -c40
+stream
+ffd8ffe000104a46494600010100000100010000ffdb004300030202020202030202020303030304
+060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c
+12131210130f101010ffdb00430103030304030408040408100b090b101010101010101010101010
+1010101010101010101010101010101010101010101010101010101010101010101010101010ffc0
+0011080001000103011100021101031101ffc40014000100000000000000000000000000000008ff
+c40014100100000000000000000000000000000000ffc40015010101000000000000000000000000
+00000709ffc40014110100000000000000000000000000000000ffda000c03010002110311003f00
+3a03154dffd9
+endstream
+endobj
+5 0 obj
+<>
+stream
+500 0 0 400 0 0 cm
+/SomeImage Do
+endstream
+endobj
+xref
+0 6
+0000000000 65535 f
+0000000008 00000 n
+0000000054 00000 n
+0000000128 00000 n
+0000000246 00000 n
+0000001201 00000 n
+trailer
+<>
+startxref
+1281
+%%EOF
diff --git a/src/UglyToad.PdfPig.Tests/Integration/Documents/steam_in_page_dict.pdf b/src/UglyToad.PdfPig.Tests/Integration/Documents/steam_in_page_dict.pdf
new file mode 100644
index 00000000..721018a7
Binary files /dev/null and b/src/UglyToad.PdfPig.Tests/Integration/Documents/steam_in_page_dict.pdf differ
diff --git a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs
index 6b163ee7..a9ca12da 100644
--- a/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Writer/PdfDocumentBuilderTests.cs
@@ -1,6 +1,6 @@
namespace UglyToad.PdfPig.Tests.Writer
{
- using System.IO;
+ using System.IO;
using System.Linq;
using Content;
using Integration;
@@ -9,8 +9,8 @@
using PdfPig.Tokens;
using PdfPig.Writer;
using Tests.Fonts.TrueType;
- using Xunit;
-
+ using Xunit;
+
public class PdfDocumentBuilderTests
{
[Fact]
@@ -53,953 +53,1001 @@
Assert.Equal("Small page.", page1.Text);
}
- }
-
+ }
+
[Fact]
- public void CanReadSingleBlankPage()
+ public void CanFastAddPageAndInheritProps()
{
- var result = CreateSingleBlankPage();
+ var first = IntegrationHelpers.GetDocumentPath("inherited_mediabox.pdf");
+ var contents = File.ReadAllBytes(first);
- using (var document = PdfDocument.Open(result, new ParsingOptions { UseLenientParsing = false }))
- {
- Assert.Equal(1, document.NumberOfPages);
-
- var page = document.GetPage(1);
-
- Assert.Equal(PageSize.A4, page.Size);
-
- Assert.Empty(page.Letters);
-
- Assert.NotNull(document.Structure.Catalog);
-
- foreach (var offset in document.Structure.CrossReferenceTable.ObjectOffsets)
- {
- var obj = document.Structure.GetObject(offset.Key);
-
- Assert.NotNull(obj);
- }
+
+ byte[] results = null;
+ using (var existing = PdfDocument.Open(contents, ParsingOptions.LenientParsingOff))
+ using (var output = new PdfDocumentBuilder())
+ {
+ output.AddPage(existing, 1);
+ results = output.Build();
+ }
+
+ using (var rewritted = PdfDocument.Open(results, ParsingOptions.LenientParsingOff))
+ {
+ var pg = rewritted.GetPage(1);
+ Assert.Equal(200, pg.MediaBox.Bounds.Width);
+ Assert.Equal(100, pg.MediaBox.Bounds.Height);
}
- }
-
- private static byte[] CreateSingleBlankPage()
- {
- var builder = new PdfDocumentBuilder();
-
- builder.AddPage(PageSize.A4);
-
- var result = builder.Build();
-
- return result;
- }
-
+ }
+
[Fact]
- public void CanWriteSinglePageStandard14FontHelloWorld()
+ public void CanFastAddPageWithStreamSubtype()
{
- var builder = new PdfDocumentBuilder();
+ var first = IntegrationHelpers.GetDocumentPath("steam_in_page_dict.pdf");
+ var contents = File.ReadAllBytes(first);
- PdfPageBuilder page = builder.AddPage(PageSize.A4);
-
- PdfDocumentBuilder.AddedFont font = builder.AddStandard14Font(Standard14Font.Helvetica);
-
- page.AddText("Hello World!", 12, new PdfPoint(25, 520), font);
-
- var b = builder.Build();
-
- WriteFile(nameof(CanWriteSinglePageStandard14FontHelloWorld), b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal(new[] {"Hello", "World!"}, page1.GetWords().Select(x => x.Text));
+
+ byte[] results = null;
+ using (var existing = PdfDocument.Open(contents, ParsingOptions.LenientParsingOff))
+ using (var output = new PdfDocumentBuilder())
+ {
+ output.AddPage(existing, 1);
+ results = output.Build();
+ }
+
+ using (var rewritted = PdfDocument.Open(results, ParsingOptions.LenientParsingOff))
+ {
+ // really just checking for no exception...
+ var pg = rewritted.GetPage(1);
+ Assert.NotNull(pg.Content);
}
- }
-
- [Fact]
- public void CanWriteSinglePageHelloWorld()
- {
- var builder = new PdfDocumentBuilder();
-
- var page = builder.AddPage(PageSize.A4);
-
- page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520));
- page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250));
-
- page.SetStrokeColor(250, 132, 131);
- page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3);
- page.ResetColor();
- page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m);
- page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
-
- var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
-
- var font = builder.AddTrueTypeFont(file);
-
- var letters = page.AddText("Hello World!", 12, new PdfPoint(30, 50), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- var b = builder.Build();
-
- WriteFile(nameof(CanWriteSinglePageHelloWorld), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("Hello World!", page1.Text);
-
- var h = page1.Letters[0];
-
- Assert.Equal("H", h.Value);
- Assert.Equal("Andada-Regular", h.FontName);
-
- var comparer = new DoubleComparer(0.01);
- var pointComparer = new PointComparer(comparer);
-
- for (int i = 0; i < page1.Letters.Count; i++)
- {
- var readerLetter = page1.Letters[i];
- var writerLetter = letters[i];
-
- Assert.Equal(readerLetter.Value, writerLetter.Value);
- Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
- Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
- }
- }
- }
-
- [Fact]
- public void CanWriteRobotoAccentedCharacters()
- {
- var builder = new PdfDocumentBuilder();
-
- builder.DocumentInformation.Title = "Hello Roboto!";
-
- var page = builder.AddPage(PageSize.A4);
-
- var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
-
- page.AddText("eé", 12, new PdfPoint(30, 520), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- var b = builder.Build();
-
- WriteFile(nameof(CanWriteRobotoAccentedCharacters), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("eé", page1.Text);
- }
- }
-
- [Fact]
- public void WindowsOnlyCanWriteSinglePageAccentedCharactersSystemFont()
- {
- var builder = new PdfDocumentBuilder();
-
- builder.DocumentInformation.Title = "Hello Windows!";
-
- var page = builder.AddPage(PageSize.A4);
-
- var file = @"C:\Windows\Fonts\Calibri.ttf";
-
- if (!File.Exists(file))
- {
- return;
- }
-
- byte[] bytes;
- try
- {
- bytes = File.ReadAllBytes(file);
- }
- catch
- {
- return;
- }
-
- var font = builder.AddTrueTypeFont(bytes);
-
- page.AddText("eé", 12, new PdfPoint(30, 520), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- var b = builder.Build();
-
- WriteFile(nameof(WindowsOnlyCanWriteSinglePageAccentedCharactersSystemFont), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("eé", page1.Text);
- }
- }
-
- [Fact]
- public void WindowsOnlyCanWriteSinglePageHelloWorldSystemFont()
- {
- var builder = new PdfDocumentBuilder();
-
- builder.DocumentInformation.Title = "Hello Windows!";
-
- var page = builder.AddPage(PageSize.A4);
-
- var file = @"C:\Windows\Fonts\BASKVILL.TTF";
-
- if (!File.Exists(file))
- {
- return;
- }
-
- byte[] bytes;
- try
- {
- bytes = File.ReadAllBytes(file);
- }
- catch
- {
- return;
- }
-
- var font = builder.AddTrueTypeFont(bytes);
-
- var letters = page.AddText("Hello World!", 16, new PdfPoint(30, 520), font);
- page.AddText("This is some further text continuing to write", 12, new PdfPoint(30, 500), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- var b = builder.Build();
-
- WriteFile(nameof(WindowsOnlyCanWriteSinglePageHelloWorldSystemFont), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.StartsWith("Hello World!", page1.Text);
-
- var h = page1.Letters[0];
-
- Assert.Equal("H", h.Value);
- Assert.Equal("BaskOldFace", h.FontName);
-
- var comparer = new DoubleComparer(0.01);
- var pointComparer = new PointComparer(comparer);
-
- for (int i = 0; i < letters.Count; i++)
- {
- var readerLetter = page1.Letters[i];
- var writerLetter = letters[i];
-
- Assert.Equal(readerLetter.Value, writerLetter.Value);
- Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
- Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
- }
- }
- }
-
- [Fact]
- public void CanWriteSinglePageWithAccentedCharacters()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- var file = TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf");
-
- var font = builder.AddTrueTypeFont(file);
-
- page.AddText("é (lower case, upper case É).", 9,
- new PdfPoint(30, page.PageSize.Height - 50), font);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWriteSinglePageWithAccentedCharacters), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("é (lower case, upper case É).", page1.Text);
- }
- }
-
- [Fact]
- public void CanWriteTwoPageDocument()
- {
- var builder = new PdfDocumentBuilder();
- var page1 = builder.AddPage(PageSize.A4);
- var page2 = builder.AddPage(PageSize.A4);
-
- var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
-
- var topLine = new PdfPoint(30, page1.PageSize.Height - 60);
- var letters = page1.AddText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", 9, topLine, font);
- page1.AddText("incididunt ut labore et dolore magna aliqua.", 9, new PdfPoint(30, topLine.Y - letters.Max(x => x.GlyphRectangle.Height) - 5), font);
-
- var page2Letters = page2.AddText("The very hungry caterpillar ate all the apples in the garden.", 12, topLine, font);
- var left = (decimal)page2Letters[0].GlyphRectangle.Left;
- var bottom = (decimal)page2Letters.Min(x => x.GlyphRectangle.Bottom);
- var right = (decimal)page2Letters[page2Letters.Count - 1].GlyphRectangle.Right;
- var top = (decimal)page2Letters.Max(x => x.GlyphRectangle.Top);
- page2.SetStrokeColor(10, 250, 69);
- page2.DrawRectangle(new PdfPoint(left, bottom), right - left, top - bottom);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWriteTwoPageDocument), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1Out = document.GetPage(1);
-
- Assert.StartsWith("Lorem ipsum dolor sit", page1Out.Text);
-
- var page2Out = document.GetPage(2);
-
- Assert.StartsWith("The very hungry caterpillar", page2Out.Text);
- }
- }
-
- [Fact]
- public void CanWriteSinglePageWithCzechCharacters()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
-
- page.AddText("Hello: řó", 9,
- new PdfPoint(30, page.PageSize.Height - 50), font);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWriteSinglePageWithCzechCharacters), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("Hello: řó", page1.Text);
- }
- }
-
- [Fact]
- public void CanWriteSinglePageWithJpeg()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- var font = builder.AddStandard14Font(Standard14Font.Helvetica);
-
- page.AddText("Smile", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
-
- var img = IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false);
-
- var expectedBounds = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
-
- var imageBytes = File.ReadAllBytes(img);
-
- page.AddJpeg(imageBytes, expectedBounds);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWriteSinglePageWithJpeg), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("Smile", page1.Text);
-
- var image = Assert.Single(page1.GetImages());
-
- Assert.NotNull(image);
-
- Assert.Equal(expectedBounds.BottomLeft, image.Bounds.BottomLeft);
- Assert.Equal(expectedBounds.TopRight, image.Bounds.TopRight);
-
- Assert.Equal(imageBytes, image.RawBytes);
- }
- }
-
- [Fact]
- public void CanWrite2PagesSharingJpeg()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- var font = builder.AddStandard14Font(Standard14Font.Helvetica);
-
- page.AddText("Smile", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
-
- var img = IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false);
-
- var expectedBounds1 = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
-
- var imageBytes = File.ReadAllBytes(img);
-
- var expectedBounds2 = new PdfRectangle(25, 600, 75, 650);
-
- var jpeg = page.AddJpeg(imageBytes, expectedBounds1);
- page.AddJpeg(jpeg, expectedBounds2);
-
- var expectedBounds3 = new PdfRectangle(30, 500, 130, 550);
-
- var page2 = builder.AddPage(PageSize.A4);
- page2.AddJpeg(jpeg, expectedBounds3);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWrite2PagesSharingJpeg), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("Smile", page1.Text);
-
- var page1Images = page1.GetImages().ToList();
- Assert.Equal(2, page1Images.Count);
-
- var image1 = page1Images[0];
- Assert.Equal(expectedBounds1, image1.Bounds);
-
- var image2 = page1Images[1];
- Assert.Equal(expectedBounds2, image2.Bounds);
-
- var page2Doc = document.GetPage(2);
-
- var image3 = Assert.Single(page2Doc.GetImages());
-
- Assert.NotNull(image3);
-
- Assert.Equal(expectedBounds3, image3.Bounds);
-
- Assert.Equal(imageBytes, image1.RawBytes);
- Assert.Equal(imageBytes, image2.RawBytes);
- Assert.Equal(imageBytes, image3.RawBytes);
- }
- }
-
- [Theory]
- [InlineData(PdfAStandard.A1B)]
- [InlineData(PdfAStandard.A1A)]
- [InlineData(PdfAStandard.A2B)]
- [InlineData(PdfAStandard.A2A)]
- public void CanGeneratePdfAFile(PdfAStandard standard)
- {
- var builder = new PdfDocumentBuilder
- {
- ArchiveStandard = standard
- };
-
- var page = builder.AddPage(PageSize.A4);
-
- var imgBytes = File.ReadAllBytes(IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false));
- page.AddJpeg(imgBytes, new PdfRectangle(50, 70, 150, 130));
-
- var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
-
- page.AddText($"Howdy PDF/{standard}!", 10, new PdfPoint(25, 700), font);
-
- var bytes = builder.Build();
-
- WriteFile(nameof(CanGeneratePdfAFile) + standard, bytes);
-
- using (var pdf = PdfDocument.Open(bytes, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(1, pdf.NumberOfPages);
-
- Assert.True(pdf.TryGetXmpMetadata(out var xmp));
-
- Assert.NotNull(xmp.GetXDocument());
- }
- }
-
- [Fact]
- public void CanWriteSinglePageWithPng()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- var font = builder.AddStandard14Font(Standard14Font.Helvetica);
-
- page.AddText("Piggy", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
-
- var img = IntegrationHelpers.GetDocumentPath("pdfpig.png", false);
-
- var expectedBounds = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
-
- var imageBytes = File.ReadAllBytes(img);
-
- page.AddPng(imageBytes, expectedBounds);
-
- var bytes = builder.Build();
- WriteFile(nameof(CanWriteSinglePageWithPng), bytes);
-
- using (var document = PdfDocument.Open(bytes))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("Piggy", page1.Text);
-
- var image = Assert.Single(page1.GetImages());
-
- Assert.NotNull(image);
-
- Assert.Equal(expectedBounds.BottomLeft, image.Bounds.BottomLeft);
- Assert.Equal(expectedBounds.TopRight, image.Bounds.TopRight);
-
- Assert.True(image.TryGetPng(out var png));
- Assert.NotNull(png);
-
- WriteFile(nameof(CanWriteSinglePageWithPng) + "out", png, "png");
- }
- }
-
- [Fact]
- public void CanCreateDocumentInformationDictionaryWithNonAsciiCharacters()
- {
- const string littlePig = "маленький поросенок";
- var builder = new PdfDocumentBuilder();
- builder.DocumentInformation.Title = littlePig;
- var page = builder.AddPage(PageSize.A4);
- var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
- page.AddText(littlePig, 12, new PdfPoint(120, 600), font);
-
- var file = builder.Build();
- WriteFile(nameof(CanCreateDocumentInformationDictionaryWithNonAsciiCharacters), file);
- using (var document = PdfDocument.Open(file))
- {
- Assert.Equal(littlePig, document.Information.Title);
- }
- }
-
- [Fact]
- public void CanCreateDocumentWithFilledRectangle()
- {
- var builder = new PdfDocumentBuilder();
- var page = builder.AddPage(PageSize.A4);
-
- page.SetTextAndFillColor(255, 0, 0);
- page.SetStrokeColor(0, 0, 255);
-
- page.DrawRectangle(new PdfPoint(20, 100), 200, 100, 1.5m, true);
-
- var file = builder.Build();
- WriteFile(nameof(CanCreateDocumentWithFilledRectangle), file);
- }
-
- [Fact]
- public void CanGeneratePageWithMultipleStream()
- {
- var builder = new PdfDocumentBuilder();
-
- var page = builder.AddPage(PageSize.A4);
-
- var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
-
- var font = builder.AddTrueTypeFont(file);
-
- var letters = page.AddText("Hello", 12, new PdfPoint(30, 50), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- page.NewContentStreamAfter();
-
- page.AddText("World!", 12, new PdfPoint(50, 50), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
-
- var b = builder.Build();
-
- WriteFile(nameof(CanGeneratePageWithMultipleStream), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("HelloWorld!", page1.Text);
-
- var h = page1.Letters[0];
-
- Assert.Equal("H", h.Value);
- Assert.Equal("Andada-Regular", h.FontName);
- }
- }
-
- [Fact]
- public void CanCopyPage()
- {
-
- byte[] b;
- {
- var builder = new PdfDocumentBuilder();
-
- var page1 = builder.AddPage(PageSize.A4);
-
- var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
-
- var font = builder.AddTrueTypeFont(file);
-
- page1.AddText("Hello", 12, new PdfPoint(30, 50), font);
-
- Assert.NotEmpty(page1.CurrentStream.Operations);
-
-
- using (var readDocument = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("bold-italic.pdf")))
- {
- var rpage = readDocument.GetPage(1);
-
- var page2 = builder.AddPage(PageSize.A4);
- page2.CopyFrom(rpage);
- }
-
- b = builder.Build();
- Assert.NotEmpty(b);
- }
-
- WriteFile(nameof(CanCopyPage), b);
-
- using (var document = PdfDocument.Open(b))
- {
- Assert.Equal( 2, document.NumberOfPages);
-
- var page1 = document.GetPage(1);
-
- Assert.Equal("Hello", page1.Text);
-
- var page2 = document.GetPage(2);
-
- Assert.Equal("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", page2.Text);
- }
- }
-
- [Fact]
- public void CanAddHelloWorldToSimplePage()
- {
- var path = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
- var doc = PdfDocument.Open(path);
- var builder = new PdfDocumentBuilder();
-
- var page = builder.AddPage(doc, 1);
-
- page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520));
- page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250));
-
- page.SetStrokeColor(250, 132, 131);
- page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3);
- page.ResetColor();
- page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m);
- page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
-
- var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
-
- var font = builder.AddTrueTypeFont(file);
-
- var letters = page.AddText("Hello World!", 12, new PdfPoint(30, 50), font);
-
- Assert.NotEmpty(page.CurrentStream.Operations);
-
- var b = builder.Build();
-
- WriteFile(nameof(CanAddHelloWorldToSimplePage), b);
-
- Assert.NotEmpty(b);
-
- using (var document = PdfDocument.Open(b))
- {
- var page1 = document.GetPage(1);
-
- Assert.Equal("I am a simple pdf.Hello World!", page1.Text);
-
- var h = page1.Letters[18];
-
- Assert.Equal("H", h.Value);
- Assert.Equal("Andada-Regular", h.FontName);
-
- var comparer = new DoubleComparer(0.01);
- var pointComparer = new PointComparer(comparer);
-
- for (int i = 0; i < letters.Count; i++)
- {
- var readerLetter = page1.Letters[i+18];
- var writerLetter = letters[i];
-
- Assert.Equal(readerLetter.Value, writerLetter.Value);
- Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
- Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
- Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
- }
- }
- }
-
- [Fact]
- public void CanMerge2SimpleDocumentsReversed_Builder()
- {
- var one = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
- var two = IntegrationHelpers.GetDocumentPath("Single Page Simple - from inkscape.pdf");
-
-
- using (var docOne = PdfDocument.Open(one))
- using (var docTwo = PdfDocument.Open(two))
- {
- var builder = new PdfDocumentBuilder();
- builder.AddPage(docOne, 1);
- builder.AddPage(docTwo, 1);
- var result = builder.Build();
- PdfMergerTests.CanMerge2SimpleDocumentsAssertions(new MemoryStream(result), "I am a simple pdf.", "Write something inInkscape", false);
- }
- }
-
- [Fact]
- public void CanMerge2SimpleDocuments_Builder()
- {
- var one = IntegrationHelpers.GetDocumentPath("Single Page Simple - from inkscape.pdf");
- var two = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
-
- using (var docOne = PdfDocument.Open(one))
- using (var docTwo = PdfDocument.Open(two))
- using (var builder = new PdfDocumentBuilder())
- {
-
- builder.AddPage(docOne, 1);
- builder.AddPage(docTwo, 1);
- var result = builder.Build();
- PdfMergerTests.CanMerge2SimpleDocumentsAssertions(new MemoryStream(result), "Write something inInkscape", "I am a simple pdf.", false);
- }
-
-
- }
-
- [Fact]
- public void CanDedupObjectsFromSameDoc_Builder()
- {
- var one = IntegrationHelpers.GetDocumentPath("Multiple Page - from Mortality Statistics.pdf");
-
- using (var doc = PdfDocument.Open(one))
- {
- var builder = new PdfDocumentBuilder();
- builder.AddPage(doc, 1);
- builder.AddPage(doc, 1);
-
- var result = builder.Build();
-
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(2, document.NumberOfPages);
- Assert.True(document.Structure.CrossReferenceTable.ObjectOffsets.Count <= 29,
- "Expected object count to be lower than 30"); // 45 objects with duplicates, 29 with correct re-use
- }
- }
- }
-
- [Fact]
- public void CanDedupObjectsFromDifferentDoc_HashBuilder()
- {
- var one = IntegrationHelpers.GetDocumentPath("Multiple Page - from Mortality Statistics.pdf");
- using (var doc = PdfDocument.Open(one))
- using (var doc2 = PdfDocument.Open(one))
- using (var builder = new PdfDocumentBuilder(new MemoryStream(), true, PdfWriterType.ObjectInMemoryDedup))
- {
- builder.AddPage(doc, 1);
- builder.AddPage(doc2, 1);
-
- var result = builder.Build();
-
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(2, document.NumberOfPages);
- Assert.True(document.Structure.CrossReferenceTable.ObjectOffsets.Count <= 29,
- "Expected object count to be lower than 30"); // 45 objects with duplicates, 29 with correct re-use
- }
- }
- }
-
- [Fact]
- public void CanCreatePageTree()
- {
- var count = 25 * 25 * 25 + 1;
- using (var builder = new PdfDocumentBuilder())
- {
- for (var i = 0; i < count;i++)
- {
- builder.AddPage(PageSize.A4);
- }
- var result = builder.Build();
- WriteFile(nameof(CanCreatePageTree), result);
-
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(count, document.NumberOfPages);
- }
- }
- }
-
- [Fact]
- public void CanWriteEmptyContentStream()
- {
- using (var builder = new PdfDocumentBuilder())
- {
- builder.AddPage(PageSize.A4);
- var result = builder.Build();
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(1, document.NumberOfPages);
- var pg = document.GetPage(1);
- // single empty page should result in single content stream
- Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
- }
- }
- }
-
- [Fact]
- public void CanWriteSingleContentStream()
- {
- using (var builder = new PdfDocumentBuilder())
- {
- var pb = builder.AddPage(PageSize.A4);
- pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
- var result = builder.Build();
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(1, document.NumberOfPages);
- var pg = document.GetPage(1);
- // single empty page should result in single content stream
- Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
- }
- }
- }
-
- [Fact]
- public void CanWriteAndIgnoreEmptyContentStream()
- {
- using (var builder = new PdfDocumentBuilder())
- {
- var pb = builder.AddPage(PageSize.A4);
- pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
- pb.NewContentStreamAfter();
- var result = builder.Build();
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(1, document.NumberOfPages);
- var pg = document.GetPage(1);
- // empty stream should be ignored and resulting single stream should be written
- Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
- }
- }
- }
-
- [Fact]
- public void CanWriteMultipleContentStream()
- {
- using (var builder = new PdfDocumentBuilder())
- {
- var pb = builder.AddPage(PageSize.A4);
- pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
- pb.NewContentStreamAfter();
- pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
- var result = builder.Build();
- using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- Assert.Equal(1, document.NumberOfPages);
- var pg = document.GetPage(1);
- // multiple streams should be written to array
- var streams = pg.Dictionary.Data[NameToken.Contents] as ArrayToken;
- Assert.NotNull(streams);
- Assert.Equal(2, streams.Length);
- }
- }
- }
-
- [InlineData("Single Page Simple - from google drive.pdf")]
- [InlineData("Old Gutnish Internet Explorer.pdf")]
- [InlineData("68-1990-01_A.pdf")]
- [InlineData("Multiple Page - from Mortality Statistics.pdf")]
- [Theory]
- public void CopiedPagesResultInSameData(string name)
- {
- var docPath = IntegrationHelpers.GetDocumentPath(name);
-
- using (var doc = PdfDocument.Open(docPath, ParsingOptions.LenientParsingOff))
- using (var builder = new PdfDocumentBuilder())
- {
- var count1 = GetCounts(doc);
-
- for (var i = 1; i <= doc.NumberOfPages; i++)
- {
- builder.AddPage(doc, i);
- }
- var result = builder.Build();
- WriteFile(nameof(CopiedPagesResultInSameData) + "_" + name, result);
-
- using (var doc2 = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
- {
- var count2 = GetCounts(doc2);
- Assert.Equal(count1.Item1, count2.Item1);
- Assert.Equal(count1.Item2, count2.Item2);
- }
- }
-
-
- (int, double) GetCounts(PdfDocument toCount)
- {
- int letters = 0;
- double location = 0;
- foreach (var page in toCount.GetPages())
- {
- foreach (var letter in page.Letters)
- {
-
- unchecked { letters += 1; }
- unchecked {
- location += letter.Location.X;
- location += letter.Location.Y;
- location += letter.Font.Name.Length;
- }
- }
- }
-
- return (letters, location);
- }
- }
-
- private static void WriteFile(string name, byte[] bytes, string extension = "pdf")
- {
- try
- {
- if (!Directory.Exists("Builder"))
- {
- Directory.CreateDirectory("Builder");
- }
-
- var output = Path.Combine("Builder", $"{name}.{extension}");
-
- File.WriteAllBytes(output, bytes);
- }
- catch
- {
- // ignored.
- }
- }
- }
+ }
+
+
+ [Fact]
+ public void CanReadSingleBlankPage()
+ {
+ var result = CreateSingleBlankPage();
+
+ using (var document = PdfDocument.Open(result, new ParsingOptions { UseLenientParsing = false }))
+ {
+ Assert.Equal(1, document.NumberOfPages);
+
+ var page = document.GetPage(1);
+
+ Assert.Equal(PageSize.A4, page.Size);
+
+ Assert.Empty(page.Letters);
+
+ Assert.NotNull(document.Structure.Catalog);
+
+ foreach (var offset in document.Structure.CrossReferenceTable.ObjectOffsets)
+ {
+ var obj = document.Structure.GetObject(offset.Key);
+
+ Assert.NotNull(obj);
+ }
+ }
+ }
+
+ private static byte[] CreateSingleBlankPage()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ builder.AddPage(PageSize.A4);
+
+ var result = builder.Build();
+
+ return result;
+ }
+
+ [Fact]
+ public void CanWriteSinglePageStandard14FontHelloWorld()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ PdfPageBuilder page = builder.AddPage(PageSize.A4);
+
+ PdfDocumentBuilder.AddedFont font = builder.AddStandard14Font(Standard14Font.Helvetica);
+
+ page.AddText("Hello World!", 12, new PdfPoint(25, 520), font);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(CanWriteSinglePageStandard14FontHelloWorld), b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal(new[] { "Hello", "World!" }, page1.GetWords().Select(x => x.Text));
+ }
+ }
+
+ [Fact]
+ public void CanWriteSinglePageHelloWorld()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ var page = builder.AddPage(PageSize.A4);
+
+ page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520));
+ page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250));
+
+ page.SetStrokeColor(250, 132, 131);
+ page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3);
+ page.ResetColor();
+ page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m);
+ page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
+
+ var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
+
+ var font = builder.AddTrueTypeFont(file);
+
+ var letters = page.AddText("Hello World!", 12, new PdfPoint(30, 50), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(CanWriteSinglePageHelloWorld), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Hello World!", page1.Text);
+
+ var h = page1.Letters[0];
+
+ Assert.Equal("H", h.Value);
+ Assert.Equal("Andada-Regular", h.FontName);
+
+ var comparer = new DoubleComparer(0.01);
+ var pointComparer = new PointComparer(comparer);
+
+ for (int i = 0; i < page1.Letters.Count; i++)
+ {
+ var readerLetter = page1.Letters[i];
+ var writerLetter = letters[i];
+
+ Assert.Equal(readerLetter.Value, writerLetter.Value);
+ Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
+ Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteRobotoAccentedCharacters()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ builder.DocumentInformation.Title = "Hello Roboto!";
+
+ var page = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
+
+ page.AddText("eé", 12, new PdfPoint(30, 520), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(CanWriteRobotoAccentedCharacters), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("eé", page1.Text);
+ }
+ }
+
+ [Fact]
+ public void WindowsOnlyCanWriteSinglePageAccentedCharactersSystemFont()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ builder.DocumentInformation.Title = "Hello Windows!";
+
+ var page = builder.AddPage(PageSize.A4);
+
+ var file = @"C:\Windows\Fonts\Calibri.ttf";
+
+ if (!File.Exists(file))
+ {
+ return;
+ }
+
+ byte[] bytes;
+ try
+ {
+ bytes = File.ReadAllBytes(file);
+ }
+ catch
+ {
+ return;
+ }
+
+ var font = builder.AddTrueTypeFont(bytes);
+
+ page.AddText("eé", 12, new PdfPoint(30, 520), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(WindowsOnlyCanWriteSinglePageAccentedCharactersSystemFont), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("eé", page1.Text);
+ }
+ }
+
+ [Fact]
+ public void WindowsOnlyCanWriteSinglePageHelloWorldSystemFont()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ builder.DocumentInformation.Title = "Hello Windows!";
+
+ var page = builder.AddPage(PageSize.A4);
+
+ var file = @"C:\Windows\Fonts\BASKVILL.TTF";
+
+ if (!File.Exists(file))
+ {
+ return;
+ }
+
+ byte[] bytes;
+ try
+ {
+ bytes = File.ReadAllBytes(file);
+ }
+ catch
+ {
+ return;
+ }
+
+ var font = builder.AddTrueTypeFont(bytes);
+
+ var letters = page.AddText("Hello World!", 16, new PdfPoint(30, 520), font);
+ page.AddText("This is some further text continuing to write", 12, new PdfPoint(30, 500), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(WindowsOnlyCanWriteSinglePageHelloWorldSystemFont), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.StartsWith("Hello World!", page1.Text);
+
+ var h = page1.Letters[0];
+
+ Assert.Equal("H", h.Value);
+ Assert.Equal("BaskOldFace", h.FontName);
+
+ var comparer = new DoubleComparer(0.01);
+ var pointComparer = new PointComparer(comparer);
+
+ for (int i = 0; i < letters.Count; i++)
+ {
+ var readerLetter = page1.Letters[i];
+ var writerLetter = letters[i];
+
+ Assert.Equal(readerLetter.Value, writerLetter.Value);
+ Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
+ Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteSinglePageWithAccentedCharacters()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ var file = TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf");
+
+ var font = builder.AddTrueTypeFont(file);
+
+ page.AddText("é (lower case, upper case É).", 9,
+ new PdfPoint(30, page.PageSize.Height - 50), font);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWriteSinglePageWithAccentedCharacters), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("é (lower case, upper case É).", page1.Text);
+ }
+ }
+
+ [Fact]
+ public void CanWriteTwoPageDocument()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page1 = builder.AddPage(PageSize.A4);
+ var page2 = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
+
+ var topLine = new PdfPoint(30, page1.PageSize.Height - 60);
+ var letters = page1.AddText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", 9, topLine, font);
+ page1.AddText("incididunt ut labore et dolore magna aliqua.", 9, new PdfPoint(30, topLine.Y - letters.Max(x => x.GlyphRectangle.Height) - 5), font);
+
+ var page2Letters = page2.AddText("The very hungry caterpillar ate all the apples in the garden.", 12, topLine, font);
+ var left = (decimal)page2Letters[0].GlyphRectangle.Left;
+ var bottom = (decimal)page2Letters.Min(x => x.GlyphRectangle.Bottom);
+ var right = (decimal)page2Letters[page2Letters.Count - 1].GlyphRectangle.Right;
+ var top = (decimal)page2Letters.Max(x => x.GlyphRectangle.Top);
+ page2.SetStrokeColor(10, 250, 69);
+ page2.DrawRectangle(new PdfPoint(left, bottom), right - left, top - bottom);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWriteTwoPageDocument), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1Out = document.GetPage(1);
+
+ Assert.StartsWith("Lorem ipsum dolor sit", page1Out.Text);
+
+ var page2Out = document.GetPage(2);
+
+ Assert.StartsWith("The very hungry caterpillar", page2Out.Text);
+ }
+ }
+
+ [Fact]
+ public void CanWriteSinglePageWithCzechCharacters()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
+
+ page.AddText("Hello: řó", 9,
+ new PdfPoint(30, page.PageSize.Height - 50), font);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWriteSinglePageWithCzechCharacters), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Hello: řó", page1.Text);
+ }
+ }
+
+ [Fact]
+ public void CanWriteSinglePageWithJpeg()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddStandard14Font(Standard14Font.Helvetica);
+
+ page.AddText("Smile", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
+
+ var img = IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false);
+
+ var expectedBounds = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
+
+ var imageBytes = File.ReadAllBytes(img);
+
+ page.AddJpeg(imageBytes, expectedBounds);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWriteSinglePageWithJpeg), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Smile", page1.Text);
+
+ var image = Assert.Single(page1.GetImages());
+
+ Assert.NotNull(image);
+
+ Assert.Equal(expectedBounds.BottomLeft, image.Bounds.BottomLeft);
+ Assert.Equal(expectedBounds.TopRight, image.Bounds.TopRight);
+
+ Assert.Equal(imageBytes, image.RawBytes);
+ }
+ }
+
+ [Fact]
+ public void CanWrite2PagesSharingJpeg()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddStandard14Font(Standard14Font.Helvetica);
+
+ page.AddText("Smile", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
+
+ var img = IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false);
+
+ var expectedBounds1 = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
+
+ var imageBytes = File.ReadAllBytes(img);
+
+ var expectedBounds2 = new PdfRectangle(25, 600, 75, 650);
+
+ var jpeg = page.AddJpeg(imageBytes, expectedBounds1);
+ page.AddJpeg(jpeg, expectedBounds2);
+
+ var expectedBounds3 = new PdfRectangle(30, 500, 130, 550);
+
+ var page2 = builder.AddPage(PageSize.A4);
+ page2.AddJpeg(jpeg, expectedBounds3);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWrite2PagesSharingJpeg), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Smile", page1.Text);
+
+ var page1Images = page1.GetImages().ToList();
+ Assert.Equal(2, page1Images.Count);
+
+ var image1 = page1Images[0];
+ Assert.Equal(expectedBounds1, image1.Bounds);
+
+ var image2 = page1Images[1];
+ Assert.Equal(expectedBounds2, image2.Bounds);
+
+ var page2Doc = document.GetPage(2);
+
+ var image3 = Assert.Single(page2Doc.GetImages());
+
+ Assert.NotNull(image3);
+
+ Assert.Equal(expectedBounds3, image3.Bounds);
+
+ Assert.Equal(imageBytes, image1.RawBytes);
+ Assert.Equal(imageBytes, image2.RawBytes);
+ Assert.Equal(imageBytes, image3.RawBytes);
+ }
+ }
+
+ [Theory]
+ [InlineData(PdfAStandard.A1B)]
+ [InlineData(PdfAStandard.A1A)]
+ [InlineData(PdfAStandard.A2B)]
+ [InlineData(PdfAStandard.A2A)]
+ public void CanGeneratePdfAFile(PdfAStandard standard)
+ {
+ var builder = new PdfDocumentBuilder
+ {
+ ArchiveStandard = standard
+ };
+
+ var page = builder.AddPage(PageSize.A4);
+
+ var imgBytes = File.ReadAllBytes(IntegrationHelpers.GetDocumentPath("smile-250-by-160.jpg", false));
+ page.AddJpeg(imgBytes, new PdfRectangle(50, 70, 150, 130));
+
+ var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
+
+ page.AddText($"Howdy PDF/{standard}!", 10, new PdfPoint(25, 700), font);
+
+ var bytes = builder.Build();
+
+ WriteFile(nameof(CanGeneratePdfAFile) + standard, bytes);
+
+ using (var pdf = PdfDocument.Open(bytes, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(1, pdf.NumberOfPages);
+
+ Assert.True(pdf.TryGetXmpMetadata(out var xmp));
+
+ Assert.NotNull(xmp.GetXDocument());
+ }
+ }
+
+ [Fact]
+ public void CanWriteSinglePageWithPng()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ var font = builder.AddStandard14Font(Standard14Font.Helvetica);
+
+ page.AddText("Piggy", 12, new PdfPoint(25, page.PageSize.Height - 52), font);
+
+ var img = IntegrationHelpers.GetDocumentPath("pdfpig.png", false);
+
+ var expectedBounds = new PdfRectangle(25, page.PageSize.Height - 300, 200, page.PageSize.Height - 200);
+
+ var imageBytes = File.ReadAllBytes(img);
+
+ page.AddPng(imageBytes, expectedBounds);
+
+ var bytes = builder.Build();
+ WriteFile(nameof(CanWriteSinglePageWithPng), bytes);
+
+ using (var document = PdfDocument.Open(bytes))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Piggy", page1.Text);
+
+ var image = Assert.Single(page1.GetImages());
+
+ Assert.NotNull(image);
+
+ Assert.Equal(expectedBounds.BottomLeft, image.Bounds.BottomLeft);
+ Assert.Equal(expectedBounds.TopRight, image.Bounds.TopRight);
+
+ Assert.True(image.TryGetPng(out var png));
+ Assert.NotNull(png);
+
+ WriteFile(nameof(CanWriteSinglePageWithPng) + "out", png, "png");
+ }
+ }
+
+ [Fact]
+ public void CanCreateDocumentInformationDictionaryWithNonAsciiCharacters()
+ {
+ const string littlePig = "маленький поросенок";
+ var builder = new PdfDocumentBuilder();
+ builder.DocumentInformation.Title = littlePig;
+ var page = builder.AddPage(PageSize.A4);
+ var font = builder.AddTrueTypeFont(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.ttf"));
+ page.AddText(littlePig, 12, new PdfPoint(120, 600), font);
+
+ var file = builder.Build();
+ WriteFile(nameof(CanCreateDocumentInformationDictionaryWithNonAsciiCharacters), file);
+ using (var document = PdfDocument.Open(file))
+ {
+ Assert.Equal(littlePig, document.Information.Title);
+ }
+ }
+
+ [Fact]
+ public void CanCreateDocumentWithFilledRectangle()
+ {
+ var builder = new PdfDocumentBuilder();
+ var page = builder.AddPage(PageSize.A4);
+
+ page.SetTextAndFillColor(255, 0, 0);
+ page.SetStrokeColor(0, 0, 255);
+
+ page.DrawRectangle(new PdfPoint(20, 100), 200, 100, 1.5m, true);
+
+ var file = builder.Build();
+ WriteFile(nameof(CanCreateDocumentWithFilledRectangle), file);
+ }
+
+ [Fact]
+ public void CanGeneratePageWithMultipleStream()
+ {
+ var builder = new PdfDocumentBuilder();
+
+ var page = builder.AddPage(PageSize.A4);
+
+ var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
+
+ var font = builder.AddTrueTypeFont(file);
+
+ var letters = page.AddText("Hello", 12, new PdfPoint(30, 50), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ page.NewContentStreamAfter();
+
+ page.AddText("World!", 12, new PdfPoint(50, 50), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+
+ var b = builder.Build();
+
+ WriteFile(nameof(CanGeneratePageWithMultipleStream), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("HelloWorld!", page1.Text);
+
+ var h = page1.Letters[0];
+
+ Assert.Equal("H", h.Value);
+ Assert.Equal("Andada-Regular", h.FontName);
+ }
+ }
+
+ [Fact]
+ public void CanCopyPage()
+ {
+
+ byte[] b;
+ {
+ var builder = new PdfDocumentBuilder();
+
+ var page1 = builder.AddPage(PageSize.A4);
+
+ var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
+
+ var font = builder.AddTrueTypeFont(file);
+
+ page1.AddText("Hello", 12, new PdfPoint(30, 50), font);
+
+ Assert.NotEmpty(page1.CurrentStream.Operations);
+
+
+ using (var readDocument = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("bold-italic.pdf")))
+ {
+ var rpage = readDocument.GetPage(1);
+
+ var page2 = builder.AddPage(PageSize.A4);
+ page2.CopyFrom(rpage);
+ }
+
+ b = builder.Build();
+ Assert.NotEmpty(b);
+ }
+
+ WriteFile(nameof(CanCopyPage), b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ Assert.Equal(2, document.NumberOfPages);
+
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("Hello", page1.Text);
+
+ var page2 = document.GetPage(2);
+
+ Assert.Equal("Lorem ipsum dolor sit amet, consectetur adipiscing elit. ", page2.Text);
+ }
+ }
+
+ [Fact]
+ public void CanAddHelloWorldToSimplePage()
+ {
+ var path = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
+ var doc = PdfDocument.Open(path);
+ var builder = new PdfDocumentBuilder();
+
+ var page = builder.AddPage(doc, 1);
+
+ page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520));
+ page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250));
+
+ page.SetStrokeColor(250, 132, 131);
+ page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3);
+ page.ResetColor();
+ page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m);
+ page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
+
+ var file = TrueTypeTestHelper.GetFileBytes("Andada-Regular.ttf");
+
+ var font = builder.AddTrueTypeFont(file);
+
+ var letters = page.AddText("Hello World!", 12, new PdfPoint(30, 50), font);
+
+ Assert.NotEmpty(page.CurrentStream.Operations);
+
+ var b = builder.Build();
+
+ WriteFile(nameof(CanAddHelloWorldToSimplePage), b);
+
+ Assert.NotEmpty(b);
+
+ using (var document = PdfDocument.Open(b))
+ {
+ var page1 = document.GetPage(1);
+
+ Assert.Equal("I am a simple pdf.Hello World!", page1.Text);
+
+ var h = page1.Letters[18];
+
+ Assert.Equal("H", h.Value);
+ Assert.Equal("Andada-Regular", h.FontName);
+
+ var comparer = new DoubleComparer(0.01);
+ var pointComparer = new PointComparer(comparer);
+
+ for (int i = 0; i < letters.Count; i++)
+ {
+ var readerLetter = page1.Letters[i + 18];
+ var writerLetter = letters[i];
+
+ Assert.Equal(readerLetter.Value, writerLetter.Value);
+ Assert.Equal(readerLetter.Location, writerLetter.Location, pointComparer);
+ Assert.Equal(readerLetter.FontSize, writerLetter.FontSize, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Width, writerLetter.GlyphRectangle.Width, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.Height, writerLetter.GlyphRectangle.Height, comparer);
+ Assert.Equal(readerLetter.GlyphRectangle.BottomLeft, writerLetter.GlyphRectangle.BottomLeft, pointComparer);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanMerge2SimpleDocumentsReversed_Builder()
+ {
+ var one = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
+ var two = IntegrationHelpers.GetDocumentPath("Single Page Simple - from inkscape.pdf");
+
+
+ using (var docOne = PdfDocument.Open(one))
+ using (var docTwo = PdfDocument.Open(two))
+ {
+ var builder = new PdfDocumentBuilder();
+ builder.AddPage(docOne, 1);
+ builder.AddPage(docTwo, 1);
+ var result = builder.Build();
+ PdfMergerTests.CanMerge2SimpleDocumentsAssertions(new MemoryStream(result), "I am a simple pdf.", "Write something inInkscape", false);
+ }
+ }
+
+ [Fact]
+ public void CanMerge2SimpleDocuments_Builder()
+ {
+ var one = IntegrationHelpers.GetDocumentPath("Single Page Simple - from inkscape.pdf");
+ var two = IntegrationHelpers.GetDocumentPath("Single Page Simple - from open office.pdf");
+
+ using (var docOne = PdfDocument.Open(one))
+ using (var docTwo = PdfDocument.Open(two))
+ using (var builder = new PdfDocumentBuilder())
+ {
+
+ builder.AddPage(docOne, 1);
+ builder.AddPage(docTwo, 1);
+ var result = builder.Build();
+ PdfMergerTests.CanMerge2SimpleDocumentsAssertions(new MemoryStream(result), "Write something inInkscape", "I am a simple pdf.", false);
+ }
+
+
+ }
+
+ [Fact]
+ public void CanDedupObjectsFromSameDoc_Builder()
+ {
+ var one = IntegrationHelpers.GetDocumentPath("Multiple Page - from Mortality Statistics.pdf");
+
+ using (var doc = PdfDocument.Open(one))
+ {
+ var builder = new PdfDocumentBuilder();
+ builder.AddPage(doc, 1);
+ builder.AddPage(doc, 1);
+
+ var result = builder.Build();
+
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(2, document.NumberOfPages);
+ Assert.True(document.Structure.CrossReferenceTable.ObjectOffsets.Count <= 29,
+ "Expected object count to be lower than 30"); // 45 objects with duplicates, 29 with correct re-use
+ }
+ }
+ }
+
+ [Fact]
+ public void CanDedupObjectsFromDifferentDoc_HashBuilder()
+ {
+ var one = IntegrationHelpers.GetDocumentPath("Multiple Page - from Mortality Statistics.pdf");
+ using (var doc = PdfDocument.Open(one))
+ using (var doc2 = PdfDocument.Open(one))
+ using (var builder = new PdfDocumentBuilder(new MemoryStream(), true, PdfWriterType.ObjectInMemoryDedup))
+ {
+ builder.AddPage(doc, 1);
+ builder.AddPage(doc2, 1);
+
+ var result = builder.Build();
+
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(2, document.NumberOfPages);
+ Assert.True(document.Structure.CrossReferenceTable.ObjectOffsets.Count <= 29,
+ "Expected object count to be lower than 30"); // 45 objects with duplicates, 29 with correct re-use
+ }
+ }
+ }
+
+ [Fact]
+ public void CanCreatePageTree()
+ {
+ var count = 25 * 25 * 25 + 1;
+ using (var builder = new PdfDocumentBuilder())
+ {
+ for (var i = 0; i < count; i++)
+ {
+ builder.AddPage(PageSize.A4);
+ }
+ var result = builder.Build();
+ WriteFile(nameof(CanCreatePageTree), result);
+
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(count, document.NumberOfPages);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteEmptyContentStream()
+ {
+ using (var builder = new PdfDocumentBuilder())
+ {
+ builder.AddPage(PageSize.A4);
+ var result = builder.Build();
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(1, document.NumberOfPages);
+ var pg = document.GetPage(1);
+ // single empty page should result in single content stream
+ Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteSingleContentStream()
+ {
+ using (var builder = new PdfDocumentBuilder())
+ {
+ var pb = builder.AddPage(PageSize.A4);
+ pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
+ var result = builder.Build();
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(1, document.NumberOfPages);
+ var pg = document.GetPage(1);
+ // single empty page should result in single content stream
+ Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteAndIgnoreEmptyContentStream()
+ {
+ using (var builder = new PdfDocumentBuilder())
+ {
+ var pb = builder.AddPage(PageSize.A4);
+ pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
+ pb.NewContentStreamAfter();
+ var result = builder.Build();
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(1, document.NumberOfPages);
+ var pg = document.GetPage(1);
+ // empty stream should be ignored and resulting single stream should be written
+ Assert.NotNull(pg.Dictionary.Data[NameToken.Contents] as IndirectReferenceToken);
+ }
+ }
+ }
+
+ [Fact]
+ public void CanWriteMultipleContentStream()
+ {
+ using (var builder = new PdfDocumentBuilder())
+ {
+ var pb = builder.AddPage(PageSize.A4);
+ pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
+ pb.NewContentStreamAfter();
+ pb.DrawLine(new PdfPoint(1, 1), new PdfPoint(2, 2));
+ var result = builder.Build();
+ using (var document = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ Assert.Equal(1, document.NumberOfPages);
+ var pg = document.GetPage(1);
+ // multiple streams should be written to array
+ var streams = pg.Dictionary.Data[NameToken.Contents] as ArrayToken;
+ Assert.NotNull(streams);
+ Assert.Equal(2, streams.Length);
+ }
+ }
+ }
+
+ [InlineData("Single Page Simple - from google drive.pdf")]
+ [InlineData("Old Gutnish Internet Explorer.pdf")]
+ [InlineData("68-1990-01_A.pdf")]
+ [InlineData("Multiple Page - from Mortality Statistics.pdf")]
+ [Theory]
+ public void CopiedPagesResultInSameData(string name)
+ {
+ var docPath = IntegrationHelpers.GetDocumentPath(name);
+
+ using (var doc = PdfDocument.Open(docPath, ParsingOptions.LenientParsingOff))
+ using (var builder = new PdfDocumentBuilder())
+ {
+ var count1 = GetCounts(doc);
+
+ for (var i = 1; i <= doc.NumberOfPages; i++)
+ {
+ builder.AddPage(doc, i);
+ }
+ var result = builder.Build();
+ WriteFile(nameof(CopiedPagesResultInSameData) + "_" + name, result);
+
+ using (var doc2 = PdfDocument.Open(result, ParsingOptions.LenientParsingOff))
+ {
+ var count2 = GetCounts(doc2);
+ Assert.Equal(count1.Item1, count2.Item1);
+ Assert.Equal(count1.Item2, count2.Item2);
+ }
+ }
+
+
+ (int, double) GetCounts(PdfDocument toCount)
+ {
+ int letters = 0;
+ double location = 0;
+ foreach (var page in toCount.GetPages())
+ {
+ foreach (var letter in page.Letters)
+ {
+
+ unchecked { letters += 1; }
+ unchecked
+ {
+ location += letter.Location.X;
+ location += letter.Location.Y;
+ location += letter.Font.Name.Length;
+ }
+ }
+ }
+
+ return (letters, location);
+ }
+ }
+
+ private static void WriteFile(string name, byte[] bytes, string extension = "pdf")
+ {
+ try
+ {
+ if (!Directory.Exists("Builder"))
+ {
+ Directory.CreateDirectory("Builder");
+ }
+
+ var output = Path.Combine("Builder", $"{name}.{extension}");
+
+ File.WriteAllBytes(output, bytes);
+ }
+ catch
+ {
+ // ignored.
+ }
+ }
+ }
}
diff --git a/src/UglyToad.PdfPig.Tests/Writer/PdfMergerTests.cs b/src/UglyToad.PdfPig.Tests/Writer/PdfMergerTests.cs
index ec7cee85..74a906e4 100644
--- a/src/UglyToad.PdfPig.Tests/Writer/PdfMergerTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Writer/PdfMergerTests.cs
@@ -165,9 +165,8 @@
);
}
}
- }
-
-
+ }
+
[Fact]
public void CanMergeMultipleWithSelection()
{
diff --git a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs
index 138be36b..0682cceb 100644
--- a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs
+++ b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs
@@ -90,7 +90,7 @@ namespace UglyToad.PdfPig.Writer
/// If stream should be disposed when builder is.
/// Type of pdf stream writer to use
/// Pdf version to use in header.
- public PdfDocumentBuilder(Stream stream, bool disposeStream=false, PdfWriterType type=PdfWriterType.Default, decimal version=1.7m)
+ public PdfDocumentBuilder(Stream stream, bool disposeStream = false, PdfWriterType type = PdfWriterType.Default, decimal version = 1.7m)
{
switch (type)
{
@@ -286,10 +286,10 @@ namespace UglyToad.PdfPig.Writer
public DictionaryToken Page { get; set; }
public IReadOnlyList Parents { get; set; }
}
- private readonly ConditionalWeakTable> existingCopies =
+ private readonly ConditionalWeakTable> existingCopies =
new ConditionalWeakTable>();
- private readonly ConditionalWeakTable> existingTrees =
- new ConditionalWeakTable>();
+ private readonly ConditionalWeakTable> existingTrees =
+ new ConditionalWeakTable>();
///
/// Add a new page with the specified size, this page will be included in the output when is called.
///
@@ -312,7 +312,8 @@ namespace UglyToad.PdfPig.Writer
{
pagesInfos[i] = new PageInfo
{
- Page = pageDict, Parents = parents
+ Page = pageDict,
+ Parents = parents
};
i++;
}
@@ -350,7 +351,7 @@ namespace UglyToad.PdfPig.Writer
// manually copy page dict / resources as we need to modify some
var copiedPageDict = new Dictionary();
- Dictionary resources = new Dictionary();
+ Dictionary resources = new Dictionary();
// just put all parent resources into new page
foreach (var dict in pageInfo.Parents)
@@ -358,6 +359,18 @@ namespace UglyToad.PdfPig.Writer
if (dict.TryGet(NameToken.Resources, out var resourceToken))
{
CopyResourceDict(resourceToken, resources);
+ }
+ if (dict.TryGet(NameToken.MediaBox, out var mb))
+ {
+ copiedPageDict[NameToken.MediaBox] = WriterUtil.CopyToken(context, mb, document.Structure.TokenScanner, refs);
+ }
+ if (dict.TryGet(NameToken.CropBox, out var cb))
+ {
+ copiedPageDict[NameToken.CropBox] = WriterUtil.CopyToken(context, cb, document.Structure.TokenScanner, refs);
+ }
+ if (dict.TryGet(NameToken.Rotate, out var rt))
+ {
+ copiedPageDict[NameToken.Rotate] = WriterUtil.CopyToken(context, rt, document.Structure.TokenScanner, refs);
}
}
@@ -396,10 +409,19 @@ namespace UglyToad.PdfPig.Writer
{
if (!destinationDict.ContainsKey(NameToken.Create(item.Key)))
{
- if (item.Value is IndirectReferenceToken ir)
+ if (item.Value is IndirectReferenceToken ir)
{
- // convert indirect to direct as PdfPageBuilder needs to modify resource entries
- destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, document.Structure.TokenScanner.Get(ir.Data).Data, document.Structure.TokenScanner, refs);
+ // convert indirect to direct as PdfPageBuilder needs to modify resource entries
+ var obj = document.Structure.TokenScanner.Get(ir.Data);
+ if (obj.Data is StreamToken)
+ {
+ // rare case, have seen /SubType as stream token, can't make direct
+ destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, item.Value, document.Structure.TokenScanner, refs);
+ }
+ else
+ {
+ destinationDict[NameToken.Create(item.Key)] = WriterUtil.CopyToken(context, obj.Data, document.Structure.TokenScanner, refs);
+ }
}
else
{
@@ -458,7 +480,7 @@ namespace UglyToad.PdfPig.Writer
}
const int desiredLeafSize = 25; // allow customization at some point?
- var numLeafs = (int) Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize));
+ var numLeafs = (int)Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize));
var leafRefs = new List();
var leafChildren = new List>();
@@ -584,17 +606,17 @@ namespace UglyToad.PdfPig.Writer
{
// TODO shorten page tree when there is a single or small number of pages left in a branch
var count = 0;
- var thisObj = context.ReserveObjectNumber();
-
+ var thisObj = context.ReserveObjectNumber();
+
var children = new List();
if (pagesNodes.Count > desiredLeafSize)
{
- var currentTreeDepth = (int) Math.Ceiling(Math.Log(pagesNodes.Count, desiredLeafSize));
- var perBranch = (int) Math.Ceiling(Math.Pow(desiredLeafSize, currentTreeDepth - 1));
+ var currentTreeDepth = (int)Math.Ceiling(Math.Log(pagesNodes.Count, desiredLeafSize));
+ var perBranch = (int)Math.Ceiling(Math.Pow(desiredLeafSize, currentTreeDepth - 1));
var branches = (int)Math.Ceiling(decimal.Divide(pagesNodes.Count, (decimal)perBranch));
for (var i = 0; i < branches; i++)
{
- var part = pagesNodes.Skip(i*perBranch).Take(perBranch).ToList();
+ var part = pagesNodes.Skip(i * perBranch).Take(perBranch).ToList();
var result = CreatePageTree(part, thisObj);
count += result.Count;
children.Add(result.Ref);
@@ -787,8 +809,8 @@ namespace UglyToad.PdfPig.Writer
if (!completed)
{
CompleteDocument();
- }
-
+ }
+
context.Dispose();
}
}