Move GetOptionalContents into Experimental and get optional marked content recursively

This commit is contained in:
BobLd 2021-02-13 15:01:06 +00:00
parent 78e6e582cd
commit 4cd1f60f5b
5 changed files with 73 additions and 33 deletions

View File

@ -1,4 +1,6 @@
using Xunit;
using System;
using UglyToad.PdfPig.Tokens;
using Xunit;
namespace UglyToad.PdfPig.Tests.Integration
{
@ -10,7 +12,7 @@ namespace UglyToad.PdfPig.Tests.Integration
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("odwriteex.pdf")))
{
var page = document.GetPage(1);
var oc = page.GetOptionalContents();
var oc = page.ExperimentalAccess.GetOptionalContents();
Assert.Equal(3, oc.Count);
@ -23,5 +25,30 @@ namespace UglyToad.PdfPig.Tests.Integration
Assert.Equal(1, oc["Text"].Count);
}
}
[Fact]
public void MarkedOptionalContentRecursion()
{
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("Layer pdf - 322_High_Holborn_building_Brochure.pdf")))
{
var page1 = document.GetPage(1);
var oc1 = page1.ExperimentalAccess.GetOptionalContents();
Assert.Equal(16, oc1.Count);
Assert.Contains("NEW ARRANGEMENT", oc1);
var page2 = document.GetPage(2);
var oc2 = page2.ExperimentalAccess.GetOptionalContents();
Assert.Equal(15, oc2.Count);
Assert.DoesNotContain("NEW ARRANGEMENT", oc2);
Assert.Contains("WDL Shell text", oc2);
Assert.Equal(2, oc2["WDL Shell text"].Count);
var page3 = document.GetPage(3);
var oc3 = page3.ExperimentalAccess.GetOptionalContents();
Assert.Equal(15, oc3.Count);
Assert.Contains("WDL Shell text", oc3);
Assert.Equal(2, oc3["WDL Shell text"].Count);
}
}
}
}

View File

@ -30,7 +30,7 @@ namespace UglyToad.PdfPig.Content
/// <summary>
/// A usage dictionary describing the nature of the content controlled by the group.
/// </summary>
public IDictionary<string, object> Usage { get; }
public IReadOnlyDictionary<string, IToken> Usage { get; }
/// <summary>
/// Underlying <see cref="MarkedContentElement"/>.
@ -110,7 +110,7 @@ namespace UglyToad.PdfPig.Content
// Usage - Optional
if (markedContentElement.Properties.TryGet(NameToken.Usage, out DictionaryToken usage))
{
throw new NotImplementedException();
this.Usage = usage.Data;
}
break;
@ -119,29 +119,29 @@ namespace UglyToad.PdfPig.Content
if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out DictionaryToken ocgsD))
{
// dictionary or array
throw new NotImplementedException();
throw new NotImplementedException($"{NameToken.Ocgs}");
}
else if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out ArrayToken ocgsA))
{
// dictionary or array
throw new NotImplementedException();
throw new NotImplementedException($"{NameToken.Ocgs}");
}
// P - Optional
if (markedContentElement.Properties.TryGet(NameToken.P, out NameToken p))
{
throw new NotImplementedException();
throw new NotImplementedException($"{NameToken.P}");
}
// VE - Optional
if (markedContentElement.Properties.TryGet(NameToken.VE, out ArrayToken ve))
{
throw new NotImplementedException();
throw new NotImplementedException($"{NameToken.VE}");
}
break;
default:
throw new ArgumentException($"Unknown Optional Content of type '{Type}'.", nameof(Type));
throw new ArgumentException($"Unknown Optional Content of type '{Type}' not known.", nameof(Type));
}
}

View File

@ -10,6 +10,7 @@
using Util.JetBrains.Annotations;
using Tokenization.Scanner;
using Graphics;
using System.Linq;
/// <summary>
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
@ -166,11 +167,6 @@
/// </summary>
public IReadOnlyList<MarkedContentElement> GetMarkedContents() => Content.GetMarkedContents();
/// <summary>
/// Gets any optional content on the page.
/// </summary>
public IDictionary<string, IReadOnlyList<OptionalContentGroupElement>> GetOptionalContents() => Content.GetOptionalContents();
/// <summary>
/// Provides access to useful members which will change in future releases.
/// </summary>
@ -198,6 +194,42 @@
{
return annotationProvider.GetAnnotations();
}
/// <summary>
/// Gets any optional content on the page.
/// <para>Does not handle XObjects and annotations for the time being.</para>
/// </summary>
public IDictionary<string, IReadOnlyList<OptionalContentGroupElement>> GetOptionalContents()
{
// 4.10.2
// Optional content in content stream
var mc = page.Content?.GetMarkedContents();
List<OptionalContentGroupElement> mcesOptional = new List<OptionalContentGroupElement>();
GetOptionalContentsRecursively(mc, ref mcesOptional);
// Optional content in XObjects and annotations
// TO DO
//var annots = GetAnnotations().ToList();
return mcesOptional.GroupBy(oc => oc.Name).ToDictionary(g => g.Key, g => g.ToList() as IReadOnlyList<OptionalContentGroupElement>);
}
private void GetOptionalContentsRecursively(IReadOnlyList<MarkedContentElement> markedContentElements, ref List<OptionalContentGroupElement> mcesOptional)
{
foreach (var mce in markedContentElements)
{
if (mce.Tag == "OC")
{
mcesOptional.Add(new OptionalContentGroupElement(mce));
// we don't recurse
}
else if (mce.Children?.Count > 0)
{
GetOptionalContentsRecursively(mce.Children, ref mcesOptional);
}
}
}
}
}
}

View File

@ -67,24 +67,5 @@
}
public IReadOnlyList<MarkedContentElement> GetMarkedContents() => markedContents;
public IDictionary<string, IReadOnlyList<OptionalContentGroupElement>> GetOptionalContents()
{
const string ocTag = "OC";
List<OptionalContentGroupElement> optionalContent = new List<OptionalContentGroupElement>();
// 4.10.2
// Optional content in content stream
foreach (var omc in GetMarkedContents().Where(mc => mc.Tag == ocTag))
{
optionalContent.Add(new OptionalContentGroupElement(omc));
}
// Optional content in XObjects and annotations
// TO DO
return optionalContent.GroupBy(oc => oc.Name).ToDictionary(g => g.Key, g => g.ToList() as IReadOnlyList<OptionalContentGroupElement>);
}
}
}