mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-09-19 19:07:56 +08:00
Merge branch 'master' of https://github.com/UglyToad/PdfPig
This commit is contained in:
@@ -6,7 +6,5 @@
|
|||||||
{
|
{
|
||||||
Page Create(int number, DictionaryToken dictionary, PageTreeMembers pageTreeMembers,
|
Page Create(int number, DictionaryToken dictionary, PageTreeMembers pageTreeMembers,
|
||||||
bool isLenientParsing);
|
bool isLenientParsing);
|
||||||
|
|
||||||
void LoadResources(DictionaryToken dictionary, bool isLenientParsing);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,6 +7,12 @@
|
|||||||
{
|
{
|
||||||
void LoadResourceDictionary(DictionaryToken resourceDictionary, bool isLenientParsing);
|
void LoadResourceDictionary(DictionaryToken resourceDictionary, bool isLenientParsing);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove any named resources and associated state for the last resource dictionary loaded.
|
||||||
|
/// Does not affect the cached resources, just the labels associated with them.
|
||||||
|
/// </summary>
|
||||||
|
void UnloadResourceDictionary();
|
||||||
|
|
||||||
IFont GetFont(NameToken name);
|
IFont GetFont(NameToken name);
|
||||||
|
|
||||||
StreamToken GetXObject(NameToken name);
|
StreamToken GetXObject(NameToken name);
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
namespace UglyToad.PdfPig.Content
|
namespace UglyToad.PdfPig.Content
|
||||||
{
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Tokens;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the values inherited from the Page Tree for this page.
|
/// Contains the values inherited from the Page Tree for this page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -13,5 +16,7 @@
|
|||||||
public MediaBox MediaBox { get; set; }
|
public MediaBox MediaBox { get; set; }
|
||||||
|
|
||||||
public int Rotation { get; set; }
|
public int Rotation { get; set; }
|
||||||
|
|
||||||
|
public Queue<DictionaryToken> ParentResources { get; } = new Queue<DictionaryToken>();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -50,7 +50,10 @@
|
|||||||
{
|
{
|
||||||
currentNode = pageStack.Pop();
|
currentNode = pageStack.Pop();
|
||||||
|
|
||||||
pageFactory.LoadResources(currentNode.NodeDictionary, isLenientParsing);
|
if (currentNode.NodeDictionary.TryGet(NameToken.Resources, pdfScanner, out DictionaryToken resourcesDictionary))
|
||||||
|
{
|
||||||
|
pageTreeMembers.ParentResources.Enqueue(resourcesDictionary);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentNode.NodeDictionary.TryGet(NameToken.MediaBox, pdfScanner, out ArrayToken mediaBox))
|
if (currentNode.NodeDictionary.TryGet(NameToken.MediaBox, pdfScanner, out ArrayToken mediaBox))
|
||||||
{
|
{
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
using Parser.Parts;
|
using Parser.Parts;
|
||||||
using Tokenization.Scanner;
|
using Tokenization.Scanner;
|
||||||
using Tokens;
|
using Tokens;
|
||||||
|
using Util;
|
||||||
|
|
||||||
internal class ResourceStore : IResourceStore
|
internal class ResourceStore : IResourceStore
|
||||||
{
|
{
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
private readonly IFontFactory fontFactory;
|
private readonly IFontFactory fontFactory;
|
||||||
|
|
||||||
private readonly Dictionary<IndirectReference, IFont> loadedFonts = new Dictionary<IndirectReference, IFont>();
|
private readonly Dictionary<IndirectReference, IFont> loadedFonts = new Dictionary<IndirectReference, IFont>();
|
||||||
private readonly Dictionary<NameToken, IndirectReference> currentResourceState = new Dictionary<NameToken, IndirectReference>();
|
private readonly StackDictionary<NameToken, IndirectReference> currentResourceState = new StackDictionary<NameToken, IndirectReference>();
|
||||||
|
|
||||||
private readonly Dictionary<NameToken, DictionaryToken> extendedGraphicsStates = new Dictionary<NameToken, DictionaryToken>();
|
private readonly Dictionary<NameToken, DictionaryToken> extendedGraphicsStates = new Dictionary<NameToken, DictionaryToken>();
|
||||||
|
|
||||||
@@ -28,6 +29,8 @@
|
|||||||
|
|
||||||
public void LoadResourceDictionary(DictionaryToken resourceDictionary, bool isLenientParsing)
|
public void LoadResourceDictionary(DictionaryToken resourceDictionary, bool isLenientParsing)
|
||||||
{
|
{
|
||||||
|
currentResourceState.Push();
|
||||||
|
|
||||||
if (resourceDictionary.TryGet(NameToken.Font, out var fontBase))
|
if (resourceDictionary.TryGet(NameToken.Font, out var fontBase))
|
||||||
{
|
{
|
||||||
var fontDictionary = DirectObjectFinder.Get<DictionaryToken>(fontBase, scanner);
|
var fontDictionary = DirectObjectFinder.Get<DictionaryToken>(fontBase, scanner);
|
||||||
@@ -95,6 +98,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UnloadResourceDictionary()
|
||||||
|
{
|
||||||
|
currentResourceState.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadFontDictionary(DictionaryToken fontDictionary, bool isLenientParsing)
|
private void LoadFontDictionary(DictionaryToken fontDictionary, bool isLenientParsing)
|
||||||
{
|
{
|
||||||
foreach (var pair in fontDictionary.Data)
|
foreach (var pair in fontDictionary.Data)
|
||||||
|
@@ -392,7 +392,9 @@
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyValuePair.Value is StringToken || keyValuePair.Value is ArrayToken || keyValuePair.Value is DictionaryToken)
|
if (keyValuePair.Value is StringToken || keyValuePair.Value is ArrayToken
|
||||||
|
|| keyValuePair.Value is DictionaryToken
|
||||||
|
|| keyValuePair.Value is HexToken)
|
||||||
{
|
{
|
||||||
var inner = DecryptInternal(reference, keyValuePair.Value);
|
var inner = DecryptInternal(reference, keyValuePair.Value);
|
||||||
dictionary = dictionary.With(keyValuePair.Key, inner);
|
dictionary = dictionary.With(keyValuePair.Key, inner);
|
||||||
|
@@ -336,7 +336,8 @@
|
|||||||
* 5. Restore the saved graphics state, as if by invoking the Q operator.
|
* 5. Restore the saved graphics state, as if by invoking the Q operator.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (formStream.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources, pdfScanner, out var formResources))
|
var hasResources = formStream.StreamDictionary.TryGet<DictionaryToken>(NameToken.Resources, pdfScanner, out var formResources);
|
||||||
|
if (hasResources)
|
||||||
{
|
{
|
||||||
resourceStore.LoadResourceDictionary(formResources, isLenientParsing);
|
resourceStore.LoadResourceDictionary(formResources, isLenientParsing);
|
||||||
}
|
}
|
||||||
@@ -368,6 +369,11 @@
|
|||||||
|
|
||||||
// 5. Restore saved state.
|
// 5. Restore saved state.
|
||||||
PopState();
|
PopState();
|
||||||
|
|
||||||
|
if (hasResources)
|
||||||
|
{
|
||||||
|
resourceStore.UnloadResourceDictionary();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginSubpath()
|
public void BeginSubpath()
|
||||||
|
@@ -58,9 +58,23 @@
|
|||||||
MediaBox mediaBox = GetMediaBox(number, dictionary, pageTreeMembers, isLenientParsing);
|
MediaBox mediaBox = GetMediaBox(number, dictionary, pageTreeMembers, isLenientParsing);
|
||||||
CropBox cropBox = GetCropBox(dictionary, pageTreeMembers, mediaBox, isLenientParsing);
|
CropBox cropBox = GetCropBox(dictionary, pageTreeMembers, mediaBox, isLenientParsing);
|
||||||
|
|
||||||
UserSpaceUnit userSpaceUnit = GetUserSpaceUnits(dictionary);
|
var stackDepth = 0;
|
||||||
|
|
||||||
LoadResources(dictionary, isLenientParsing);
|
while (pageTreeMembers.ParentResources.Count > 0)
|
||||||
|
{
|
||||||
|
var resource = pageTreeMembers.ParentResources.Dequeue();
|
||||||
|
|
||||||
|
resourceStore.LoadResourceDictionary(resource, isLenientParsing);
|
||||||
|
stackDepth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dictionary.TryGet(NameToken.Resources, pdfScanner, out DictionaryToken resources))
|
||||||
|
{
|
||||||
|
resourceStore.LoadResourceDictionary(resources, isLenientParsing);
|
||||||
|
stackDepth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSpaceUnit userSpaceUnit = GetUserSpaceUnits(dictionary);
|
||||||
|
|
||||||
PageContent content = default(PageContent);
|
PageContent content = default(PageContent);
|
||||||
|
|
||||||
@@ -114,6 +128,11 @@
|
|||||||
|
|
||||||
var page = new Page(number, dictionary, mediaBox, cropBox, rotation, content, new AnnotationProvider(pdfScanner, dictionary, isLenientParsing));
|
var page = new Page(number, dictionary, mediaBox, cropBox, rotation, content, new AnnotationProvider(pdfScanner, dictionary, isLenientParsing));
|
||||||
|
|
||||||
|
for (var i = 0; i < stackDepth; i++)
|
||||||
|
{
|
||||||
|
resourceStore.UnloadResourceDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,17 +220,5 @@
|
|||||||
|
|
||||||
return mediaBox;
|
return mediaBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadResources(DictionaryToken dictionary, bool isLenientParsing)
|
|
||||||
{
|
|
||||||
if (!dictionary.TryGet(NameToken.Resources, out var token))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resources = DirectObjectFinder.Get<DictionaryToken>(token, pdfScanner);
|
|
||||||
|
|
||||||
resourceStore.LoadResourceDictionary(resources, isLenientParsing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
68
src/UglyToad.PdfPig/Util/StackDictionary.cs
Normal file
68
src/UglyToad.PdfPig/Util/StackDictionary.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
namespace UglyToad.PdfPig.Util
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
internal class StackDictionary<K, V>
|
||||||
|
{
|
||||||
|
private readonly List<Dictionary<K, V>> values = new List<Dictionary<K, V>>();
|
||||||
|
|
||||||
|
public V this[K key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (TryGetValue(key, out var result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new KeyNotFoundException($"No item with key {key} in stack.");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (values.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Cannot set item in empty stack, call {nameof(Push)} before use.");
|
||||||
|
}
|
||||||
|
|
||||||
|
values[values.Count - 1][key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(K key, out V result)
|
||||||
|
{
|
||||||
|
if (values.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Cannot get item from empty stack, call {nameof(Push)} before use.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = values.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (values[i].TryGetValue(key, out result))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = default(V);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Push()
|
||||||
|
{
|
||||||
|
values.Add(new Dictionary<K, V>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pop()
|
||||||
|
{
|
||||||
|
if (values.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cannot pop empty stacked dictionary.");
|
||||||
|
}
|
||||||
|
|
||||||
|
values.RemoveAt(values.Count - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user