mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-07-15 18:09:22 +08:00
changes for intital InusualZ review
This commit is contained in:
parent
509164447b
commit
ef0bcd2055
@ -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[]>
|
||||||
|
@ -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>();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user