diff --git a/src/UglyToad.PdfPig/Writer/PdfDedupStreamWriter.cs b/src/UglyToad.PdfPig/Writer/PdfDedupStreamWriter.cs index 4556f470..38c77cbc 100644 --- a/src/UglyToad.PdfPig/Writer/PdfDedupStreamWriter.cs +++ b/src/UglyToad.PdfPig/Writer/PdfDedupStreamWriter.cs @@ -1,33 +1,19 @@ namespace UglyToad.PdfPig.Writer { -using Core; - using Graphics.Operations; - using System; using System.Collections.Generic; - using System.Globalization; using System.IO; - using System.Text; using Tokens; - internal class PdfDedupStreamWriter : IPdfStreamWriter + internal class PdfDedupStreamWriter : PdfStreamWriter { - - public Stream Stream { get; } - private int CurrentNumber { get; set; } = 1; - private bool DisposeStream { get; set; } - private const decimal DefaultVersion = 1.2m; - private bool Initialized { get; set; } - private readonly Dictionary offsets = new Dictionary(); private readonly Dictionary hashes = new Dictionary(new FNVByteComparison()); - public PdfDedupStreamWriter(Stream stream, bool dispose) + public PdfDedupStreamWriter(Stream stream, bool dispose) : base(stream, dispose) { - Stream = stream; - DisposeStream = dispose; } - private MemoryStream ms = new MemoryStream(); - public IndirectReferenceToken WriteToken(IToken token) + private readonly MemoryStream ms = new MemoryStream(); + public override IndirectReferenceToken WriteToken(IToken token) { if (!Initialized) { @@ -51,7 +37,7 @@ using Core; return ir; } - public IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) + public override IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) { if (!Initialized) { @@ -68,45 +54,10 @@ using Core; return indirectReference; } - public IndirectReferenceToken ReserveObjectNumber() + public new void Dispose() { - return new IndirectReferenceToken(new IndirectReference(CurrentNumber++, 0)); - } - - public void InitializePdf(decimal version) - { - WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream); - - Stream.WriteText("%"); - Stream.WriteByte(169); - Stream.WriteByte(205); - Stream.WriteByte(196); - Stream.WriteByte(210); - Stream.WriteNewLine(); - - Initialized = true; - } - - public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference=null) - { - TokenWriter.WriteCrossReferenceTable(offsets, catalogReference.Data, Stream, documentInformationReference?.Data); - } - - private static void WriteString(string text, Stream stream) - { - var bytes = OtherEncodings.StringAsLatin1Bytes(text); - stream.Write(bytes, 0, bytes.Length); - stream.WriteNewLine(); - } - - public void Dispose() - { - if (DisposeStream) - { - Stream.Dispose(); - } - hashes.Clear(); + base.Dispose(); } class FNVByteComparison : IEqualityComparer diff --git a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs index 39dcf826..cf50df52 100644 --- a/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfDocumentBuilder.cs @@ -27,7 +27,7 @@ namespace UglyToad.PdfPig.Writer private readonly Dictionary pages = new Dictionary(); private readonly Dictionary fonts = new Dictionary(); private bool completed = false; - internal int fontId = 0; + internal int fontId = 0; private readonly static ArrayToken DefaultProcSet = new ArrayToken(new List { @@ -284,7 +284,7 @@ namespace UglyToad.PdfPig.Writer internal class PageInfo { public DictionaryToken Page { get; set; } - public List Parents { get; set; } + public IReadOnlyList Parents { get; set; } } private readonly ConditionalWeakTable> existingCopies = new ConditionalWeakTable>(); @@ -320,18 +320,15 @@ namespace UglyToad.PdfPig.Writer existingTrees.Add(document, pagesInfos); } - if (!pagesInfos.ContainsKey(pageNumber)) + if (!pagesInfos.TryGetValue(pageNumber, out PageInfo pageInfo)) { throw new KeyNotFoundException($"Page {pageNumber} was not found in the source document."); } - var pageInfo = pagesInfos[pageNumber]; - // copy content streams var streams = new List(); - if (pageInfo.Page.ContainsKey(NameToken.Contents)) + if (pageInfo.Page.TryGet(NameToken.Contents, out IToken token)) { - var token = pageInfo.Page.Data[NameToken.Contents]; if (token is ArrayToken array) { foreach (var item in array.Data) @@ -358,9 +355,9 @@ namespace UglyToad.PdfPig.Writer // just put all parent resources into new page foreach (var dict in pageInfo.Parents) { - if (dict.TryGet(NameToken.Resources, out var token)) + if (dict.TryGet(NameToken.Resources, out var resourceToken)) { - CopyResourceDict(token, resources); + CopyResourceDict(resourceToken, resources); } } @@ -382,6 +379,8 @@ namespace UglyToad.PdfPig.Writer WriterUtil.CopyToken(context, kvp.Value, document.Structure.TokenScanner, refs); } + // LocalizeFontAndXObject(resources); TODO work in progress + copiedPageDict[NameToken.Resources] = new DictionaryToken(resources); var builder = new PdfPageBuilder(pages.Count + 1, this, streams, copiedPageDict); @@ -444,7 +443,7 @@ namespace UglyToad.PdfPig.Writer return dict; } } - + private void CompleteDocument() { // write fonts to reserved object numbers @@ -453,7 +452,7 @@ namespace UglyToad.PdfPig.Writer font.Value.FontProgram.WriteFont(context, font.Value.FontKey.Reference); } - int desiredLeafSize = 25; + const int desiredLeafSize = 25; // allow customization at some point? var numLeafs = (int) Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize)); var leafRefs = new List(); diff --git a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs index 408c38fa..9a754d16 100644 --- a/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs +++ b/src/UglyToad.PdfPig/Writer/PdfPageBuilder.cs @@ -747,15 +747,6 @@ return value; } - internal interface IPageContentStream : IContentStream - { - bool ReadOnly { get; } - bool HasContent { get; } - void Add(IGraphicsStateOperation operation); - IndirectReferenceToken Write(IPdfStreamWriter writer); - - } - /// /// Provides access to the raw page data structures for advanced editing use cases. /// @@ -767,6 +758,15 @@ List Operations { get; } } + internal interface IPageContentStream : IContentStream + { + bool ReadOnly { get; } + bool HasContent { get; } + void Add(IGraphicsStateOperation operation); + IndirectReferenceToken Write(IPdfStreamWriter writer); + + } + internal class DefaultContentStream : IPageContentStream { private readonly List operations; diff --git a/src/UglyToad.PdfPig/Writer/PdfStreamWriter.cs b/src/UglyToad.PdfPig/Writer/PdfStreamWriter.cs index ab9ef78c..f444e3dc 100644 --- a/src/UglyToad.PdfPig/Writer/PdfStreamWriter.cs +++ b/src/UglyToad.PdfPig/Writer/PdfStreamWriter.cs @@ -13,16 +13,13 @@ /// internal class PdfStreamWriter : IPdfStreamWriter { - private Dictionary offsets = new Dictionary(); - private const decimal DefaultVersion = 1.2m; - private bool Initialized { get; set; } - private int CurrentNumber { get; set; } = 1; + protected const decimal DefaultVersion = 1.2m; + protected Dictionary offsets = new Dictionary(); + protected bool DisposeStream { get; set; } + protected bool Initialized { get; set; } + protected int CurrentNumber { get; set; } = 1; - public Stream Stream { get; set; } - - private bool DisposeStream { get; set; } - - public PdfStreamWriter(Stream baseStream, bool disposeStream = true) + internal PdfStreamWriter(Stream baseStream, bool disposeStream = true) { Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); if (!baseStream.CanWrite) @@ -33,40 +30,9 @@ DisposeStream = disposeStream; } - public void InitializePdf(decimal version) - { - WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream); + public Stream Stream { get; protected set; } - Stream.WriteText("%"); - Stream.WriteByte(169); - Stream.WriteByte(205); - Stream.WriteByte(196); - Stream.WriteByte(210); - Stream.WriteNewLine(); - Initialized = true; - } - - public void Dispose() - { - if (!DisposeStream) - { - Stream = null; - return; - } - - Stream?.Dispose(); - Stream = null; - } - - - private static void WriteString(string text, Stream stream) - { - var bytes = OtherEncodings.StringAsLatin1Bytes(text); - stream.Write(bytes, 0, bytes.Length); - stream.WriteNewLine(); - } - - public IndirectReferenceToken WriteToken(IToken token) + public virtual IndirectReferenceToken WriteToken(IToken token) { if (!Initialized) { @@ -80,7 +46,7 @@ return ir; } - public IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) + public virtual IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) { if (!Initialized) { @@ -98,10 +64,39 @@ return new IndirectReferenceToken(new IndirectReference(CurrentNumber++, 0)); } + public void InitializePdf(decimal version) + { + WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream); - public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference=null) + Stream.WriteText("%"); + Stream.WriteByte(169); + Stream.WriteByte(205); + Stream.WriteByte(196); + Stream.WriteByte(210); + Stream.WriteNewLine(); + Initialized = true; + } + + public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference = null) { TokenWriter.WriteCrossReferenceTable(offsets, catalogReference.Data, Stream, documentInformationReference?.Data); } + + private static void WriteString(string text, Stream stream) + { + var bytes = OtherEncodings.StringAsLatin1Bytes(text); + stream.Write(bytes, 0, bytes.Length); + stream.WriteNewLine(); + } + + public void Dispose() + { + if (DisposeStream) + { + Stream?.Dispose(); + } + + Stream = null; + } } } diff --git a/src/UglyToad.PdfPig/Writer/WriterUtil.cs b/src/UglyToad.PdfPig/Writer/WriterUtil.cs index 357c1cc0..1320cc23 100644 --- a/src/UglyToad.PdfPig/Writer/WriterUtil.cs +++ b/src/UglyToad.PdfPig/Writer/WriterUtil.cs @@ -14,9 +14,8 @@ { public static Dictionary GetOrCreateDict(this Dictionary dict, NameToken key) { - if (dict.ContainsKey(key)) + if (dict.TryGetValue(key, out var item)) { - var item = dict[key]; if (!(item is DictionaryToken dt)) { throw new ApplicationException("Expected dictionary token, got " + item.GetType()); @@ -40,9 +39,8 @@ public static Dictionary GetOrCreateDict(this Dictionary dict, string key) { - if (dict.ContainsKey(key)) + if (dict.TryGetValue(key, out var item)) { - var item = dict[key]; if (!(item is DictionaryToken dt)) { throw new ApplicationException("Expected dictionary token, got " + item.GetType()); @@ -161,7 +159,7 @@ return tokenToCopy; } - internal static IEnumerable<(DictionaryToken, List)> WalkTree(PageTreeNode node, List parents=null) + internal static IEnumerable<(DictionaryToken, IReadOnlyList)> WalkTree(PageTreeNode node, List parents=null) { if (parents == null) {