changes for intital InusualZ review

This commit is contained in:
Plaisted 2021-02-10 20:18:03 -06:00
parent 509164447b
commit ef0bcd2055
5 changed files with 68 additions and 125 deletions

View File

@ -1,33 +1,19 @@
namespace UglyToad.PdfPig.Writer namespace UglyToad.PdfPig.Writer
{ {
using Core;
using Graphics.Operations;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Text;
using Tokens; 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<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
private readonly Dictionary<byte[], IndirectReferenceToken> hashes = new Dictionary<byte[], IndirectReferenceToken>(new FNVByteComparison()); private readonly Dictionary<byte[], IndirectReferenceToken> hashes = new Dictionary<byte[], IndirectReferenceToken>(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(); private readonly MemoryStream ms = new MemoryStream();
public IndirectReferenceToken WriteToken(IToken token) public override IndirectReferenceToken WriteToken(IToken token)
{ {
if (!Initialized) if (!Initialized)
{ {
@ -51,7 +37,7 @@ using Core;
return ir; return ir;
} }
public IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) public override IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference)
{ {
if (!Initialized) if (!Initialized)
{ {
@ -68,45 +54,10 @@ using Core;
return indirectReference; 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(); hashes.Clear();
base.Dispose();
} }
class FNVByteComparison : IEqualityComparer<byte[]> class FNVByteComparison : IEqualityComparer<byte[]>

View File

@ -284,7 +284,7 @@ namespace UglyToad.PdfPig.Writer
internal class PageInfo internal class PageInfo
{ {
public DictionaryToken Page { get; set; } public DictionaryToken Page { get; set; }
public List<DictionaryToken> Parents { get; set; } public IReadOnlyList<DictionaryToken> Parents { get; set; }
} }
private readonly ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>> existingCopies = private readonly ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>> existingCopies =
new ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>>(); new ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>>();
@ -320,18 +320,15 @@ namespace UglyToad.PdfPig.Writer
existingTrees.Add(document, pagesInfos); 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."); throw new KeyNotFoundException($"Page {pageNumber} was not found in the source document.");
} }
var pageInfo = pagesInfos[pageNumber];
// copy content streams // copy content streams
var streams = new List<PdfPageBuilder.CopiedContentStream>(); var streams = new List<PdfPageBuilder.CopiedContentStream>();
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) if (token is ArrayToken array)
{ {
foreach (var item in array.Data) foreach (var item in array.Data)
@ -358,9 +355,9 @@ namespace UglyToad.PdfPig.Writer
// just put all parent resources into new page // just put all parent resources into new page
foreach (var dict in pageInfo.Parents) 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); WriterUtil.CopyToken(context, kvp.Value, document.Structure.TokenScanner, refs);
} }
// LocalizeFontAndXObject(resources); TODO work in progress
copiedPageDict[NameToken.Resources] = new DictionaryToken(resources); copiedPageDict[NameToken.Resources] = new DictionaryToken(resources);
var builder = new PdfPageBuilder(pages.Count + 1, this, streams, copiedPageDict); var builder = new PdfPageBuilder(pages.Count + 1, this, streams, copiedPageDict);
@ -453,7 +452,7 @@ namespace UglyToad.PdfPig.Writer
font.Value.FontProgram.WriteFont(context, font.Value.FontKey.Reference); 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 numLeafs = (int) Math.Ceiling(Decimal.Divide(Pages.Count, desiredLeafSize));
var leafRefs = new List<IndirectReferenceToken>(); var leafRefs = new List<IndirectReferenceToken>();

View File

@ -747,15 +747,6 @@
return value; return value;
} }
internal interface IPageContentStream : IContentStream
{
bool ReadOnly { get; }
bool HasContent { get; }
void Add(IGraphicsStateOperation operation);
IndirectReferenceToken Write(IPdfStreamWriter writer);
}
/// <summary> /// <summary>
/// Provides access to the raw page data structures for advanced editing use cases. /// Provides access to the raw page data structures for advanced editing use cases.
/// </summary> /// </summary>
@ -767,6 +758,15 @@
List<IGraphicsStateOperation> Operations { get; } List<IGraphicsStateOperation> Operations { get; }
} }
internal interface IPageContentStream : IContentStream
{
bool ReadOnly { get; }
bool HasContent { get; }
void Add(IGraphicsStateOperation operation);
IndirectReferenceToken Write(IPdfStreamWriter writer);
}
internal class DefaultContentStream : IPageContentStream internal class DefaultContentStream : IPageContentStream
{ {
private readonly List<IGraphicsStateOperation> operations; private readonly List<IGraphicsStateOperation> operations;

View File

@ -13,16 +13,13 @@
/// </summary> /// </summary>
internal class PdfStreamWriter : IPdfStreamWriter internal class PdfStreamWriter : IPdfStreamWriter
{ {
private Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>(); protected const decimal DefaultVersion = 1.2m;
private const decimal DefaultVersion = 1.2m; protected Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
private bool Initialized { get; set; } protected bool DisposeStream { get; set; }
private int CurrentNumber { get; set; } = 1; protected bool Initialized { get; set; }
protected int CurrentNumber { get; set; } = 1;
public Stream Stream { get; set; } internal PdfStreamWriter(Stream baseStream, bool disposeStream = true)
private bool DisposeStream { get; set; }
public PdfStreamWriter(Stream baseStream, bool disposeStream = true)
{ {
Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); Stream = baseStream ?? throw new ArgumentNullException(nameof(baseStream));
if (!baseStream.CanWrite) if (!baseStream.CanWrite)
@ -33,40 +30,9 @@
DisposeStream = disposeStream; DisposeStream = disposeStream;
} }
public void InitializePdf(decimal version) public Stream Stream { get; protected set; }
{
WriteString($"%PDF-{version.ToString("0.0", CultureInfo.InvariantCulture)}", Stream);
Stream.WriteText("%"); public virtual IndirectReferenceToken WriteToken(IToken token)
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)
{ {
if (!Initialized) if (!Initialized)
{ {
@ -80,7 +46,7 @@
return ir; return ir;
} }
public IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference) public virtual IndirectReferenceToken WriteToken(IToken token, IndirectReferenceToken indirectReference)
{ {
if (!Initialized) if (!Initialized)
{ {
@ -98,10 +64,39 @@
return new IndirectReferenceToken(new IndirectReference(CurrentNumber++, 0)); 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) public void CompletePdf(IndirectReferenceToken catalogReference, IndirectReferenceToken documentInformationReference = null)
{ {
TokenWriter.WriteCrossReferenceTable(offsets, catalogReference.Data, Stream, documentInformationReference?.Data); 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;
}
} }
} }

View File

@ -14,9 +14,8 @@
{ {
public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<NameToken, IToken> dict, NameToken key) public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<NameToken, IToken> dict, NameToken key)
{ {
if (dict.ContainsKey(key)) if (dict.TryGetValue(key, out var item))
{ {
var item = dict[key];
if (!(item is DictionaryToken dt)) if (!(item is DictionaryToken dt))
{ {
throw new ApplicationException("Expected dictionary token, got " + item.GetType()); throw new ApplicationException("Expected dictionary token, got " + item.GetType());
@ -40,9 +39,8 @@
public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<string, IToken> dict, string key) public static Dictionary<string, IToken> GetOrCreateDict(this Dictionary<string, IToken> dict, string key)
{ {
if (dict.ContainsKey(key)) if (dict.TryGetValue(key, out var item))
{ {
var item = dict[key];
if (!(item is DictionaryToken dt)) if (!(item is DictionaryToken dt))
{ {
throw new ApplicationException("Expected dictionary token, got " + item.GetType()); throw new ApplicationException("Expected dictionary token, got " + item.GetType());
@ -161,7 +159,7 @@
return tokenToCopy; return tokenToCopy;
} }
internal static IEnumerable<(DictionaryToken, List<DictionaryToken>)> WalkTree(PageTreeNode node, List<DictionaryToken> parents=null) internal static IEnumerable<(DictionaryToken, IReadOnlyList<DictionaryToken>)> WalkTree(PageTreeNode node, List<DictionaryToken> parents=null)
{ {
if (parents == null) if (parents == null)
{ {