mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
changes for intital InusualZ review
This commit is contained in:
parent
509164447b
commit
ef0bcd2055
@ -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<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||
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();
|
||||
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<byte[]>
|
||||
|
@ -27,7 +27,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
private readonly Dictionary<int, PdfPageBuilder> pages = new Dictionary<int, PdfPageBuilder>();
|
||||
private readonly Dictionary<Guid, FontStored> fonts = new Dictionary<Guid, FontStored>();
|
||||
private bool completed = false;
|
||||
internal int fontId = 0;
|
||||
internal int fontId = 0;
|
||||
|
||||
private readonly static ArrayToken DefaultProcSet = new ArrayToken(new List<NameToken>
|
||||
{
|
||||
@ -284,7 +284,7 @@ namespace UglyToad.PdfPig.Writer
|
||||
internal class PageInfo
|
||||
{
|
||||
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 =
|
||||
new ConditionalWeakTable<IPdfTokenScanner, Dictionary<IndirectReference, IndirectReferenceToken>>();
|
||||
@ -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<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)
|
||||
{
|
||||
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<IndirectReferenceToken>();
|
||||
|
@ -747,15 +747,6 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
internal interface IPageContentStream : IContentStream
|
||||
{
|
||||
bool ReadOnly { get; }
|
||||
bool HasContent { get; }
|
||||
void Add(IGraphicsStateOperation operation);
|
||||
IndirectReferenceToken Write(IPdfStreamWriter writer);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the raw page data structures for advanced editing use cases.
|
||||
/// </summary>
|
||||
@ -767,6 +758,15 @@
|
||||
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
|
||||
{
|
||||
private readonly List<IGraphicsStateOperation> operations;
|
||||
|
@ -13,16 +13,13 @@
|
||||
/// </summary>
|
||||
internal class PdfStreamWriter : IPdfStreamWriter
|
||||
{
|
||||
private Dictionary<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||
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<IndirectReference, long> offsets = new Dictionary<IndirectReference, long>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,8 @@
|
||||
{
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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<DictionaryToken>)> WalkTree(PageTreeNode node, List<DictionaryToken> parents=null)
|
||||
internal static IEnumerable<(DictionaryToken, IReadOnlyList<DictionaryToken>)> WalkTree(PageTreeNode node, List<DictionaryToken> parents=null)
|
||||
{
|
||||
if (parents == null)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user