This commit is contained in:
BobLd
2019-11-26 12:16:43 +00:00
9 changed files with 124 additions and 21 deletions

View File

@@ -6,7 +6,5 @@
{
Page Create(int number, DictionaryToken dictionary, PageTreeMembers pageTreeMembers,
bool isLenientParsing);
void LoadResources(DictionaryToken dictionary, bool isLenientParsing);
}
}

View File

@@ -7,6 +7,12 @@
{
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);
StreamToken GetXObject(NameToken name);

View File

@@ -1,5 +1,8 @@
namespace UglyToad.PdfPig.Content
{
using System.Collections.Generic;
using Tokens;
/// <summary>
/// Contains the values inherited from the Page Tree for this page.
/// </summary>
@@ -13,5 +16,7 @@
public MediaBox MediaBox { get; set; }
public int Rotation { get; set; }
public Queue<DictionaryToken> ParentResources { get; } = new Queue<DictionaryToken>();
}
}

View File

@@ -45,12 +45,15 @@
}
var pageTreeMembers = new PageTreeMembers();
while (pageStack.Count > 0)
{
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))
{

View File

@@ -7,6 +7,7 @@
using Parser.Parts;
using Tokenization.Scanner;
using Tokens;
using Util;
internal class ResourceStore : IResourceStore
{
@@ -14,7 +15,7 @@
private readonly IFontFactory fontFactory;
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>();
@@ -28,6 +29,8 @@
public void LoadResourceDictionary(DictionaryToken resourceDictionary, bool isLenientParsing)
{
currentResourceState.Push();
if (resourceDictionary.TryGet(NameToken.Font, out var fontBase))
{
var fontDictionary = DirectObjectFinder.Get<DictionaryToken>(fontBase, scanner);
@@ -95,6 +98,11 @@
}
}
public void UnloadResourceDictionary()
{
currentResourceState.Pop();
}
private void LoadFontDictionary(DictionaryToken fontDictionary, bool isLenientParsing)
{
foreach (var pair in fontDictionary.Data)

View File

@@ -392,7 +392,9 @@
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);
dictionary = dictionary.With(keyValuePair.Key, inner);

View File

@@ -336,7 +336,8 @@
* 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);
}
@@ -368,6 +369,11 @@
// 5. Restore saved state.
PopState();
if (hasResources)
{
resourceStore.UnloadResourceDictionary();
}
}
public void BeginSubpath()

View File

@@ -57,11 +57,25 @@
MediaBox mediaBox = GetMediaBox(number, dictionary, pageTreeMembers, isLenientParsing);
CropBox cropBox = GetCropBox(dictionary, pageTreeMembers, mediaBox, isLenientParsing);
var stackDepth = 0;
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);
LoadResources(dictionary, isLenientParsing);
PageContent content = default(PageContent);
if (!dictionary.TryGet(NameToken.Contents, out var contents))
@@ -114,6 +128,11 @@
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;
}
@@ -201,17 +220,5 @@
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);
}
}
}

View 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);
}
}
}