mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-07-17 13:17:13 +08:00
Move GetOptionalContents into Experimental and get optional marked content recursively
This commit is contained in:
parent
78e6e582cd
commit
4cd1f60f5b
Binary file not shown.
@ -1,4 +1,6 @@
|
|||||||
using Xunit;
|
using System;
|
||||||
|
using UglyToad.PdfPig.Tokens;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace UglyToad.PdfPig.Tests.Integration
|
namespace UglyToad.PdfPig.Tests.Integration
|
||||||
{
|
{
|
||||||
@ -10,7 +12,7 @@ namespace UglyToad.PdfPig.Tests.Integration
|
|||||||
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("odwriteex.pdf")))
|
using (var document = PdfDocument.Open(IntegrationHelpers.GetDocumentPath("odwriteex.pdf")))
|
||||||
{
|
{
|
||||||
var page = document.GetPage(1);
|
var page = document.GetPage(1);
|
||||||
var oc = page.GetOptionalContents();
|
var oc = page.ExperimentalAccess.GetOptionalContents();
|
||||||
|
|
||||||
Assert.Equal(3, oc.Count);
|
Assert.Equal(3, oc.Count);
|
||||||
|
|
||||||
@ -23,5 +25,30 @@ namespace UglyToad.PdfPig.Tests.Integration
|
|||||||
Assert.Equal(1, oc["Text"].Count);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace UglyToad.PdfPig.Content
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A usage dictionary describing the nature of the content controlled by the group.
|
/// A usage dictionary describing the nature of the content controlled by the group.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDictionary<string, object> Usage { get; }
|
public IReadOnlyDictionary<string, IToken> Usage { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Underlying <see cref="MarkedContentElement"/>.
|
/// Underlying <see cref="MarkedContentElement"/>.
|
||||||
@ -110,7 +110,7 @@ namespace UglyToad.PdfPig.Content
|
|||||||
// Usage - Optional
|
// Usage - Optional
|
||||||
if (markedContentElement.Properties.TryGet(NameToken.Usage, out DictionaryToken usage))
|
if (markedContentElement.Properties.TryGet(NameToken.Usage, out DictionaryToken usage))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
this.Usage = usage.Data;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -119,29 +119,29 @@ namespace UglyToad.PdfPig.Content
|
|||||||
if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out DictionaryToken ocgsD))
|
if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out DictionaryToken ocgsD))
|
||||||
{
|
{
|
||||||
// dictionary or array
|
// dictionary or array
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException($"{NameToken.Ocgs}");
|
||||||
}
|
}
|
||||||
else if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out ArrayToken ocgsA))
|
else if (markedContentElement.Properties.TryGet(NameToken.Ocgs, out ArrayToken ocgsA))
|
||||||
{
|
{
|
||||||
// dictionary or array
|
// dictionary or array
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException($"{NameToken.Ocgs}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// P - Optional
|
// P - Optional
|
||||||
if (markedContentElement.Properties.TryGet(NameToken.P, out NameToken p))
|
if (markedContentElement.Properties.TryGet(NameToken.P, out NameToken p))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException($"{NameToken.P}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// VE - Optional
|
// VE - Optional
|
||||||
if (markedContentElement.Properties.TryGet(NameToken.VE, out ArrayToken ve))
|
if (markedContentElement.Properties.TryGet(NameToken.VE, out ArrayToken ve))
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException($"{NameToken.VE}");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
using Util.JetBrains.Annotations;
|
using Util.JetBrains.Annotations;
|
||||||
using Tokenization.Scanner;
|
using Tokenization.Scanner;
|
||||||
using Graphics;
|
using Graphics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
|
/// Contains the content and provides access to methods of a single page in the <see cref="PdfDocument"/>.
|
||||||
@ -166,11 +167,6 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<MarkedContentElement> GetMarkedContents() => Content.GetMarkedContents();
|
public IReadOnlyList<MarkedContentElement> GetMarkedContents() => Content.GetMarkedContents();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets any optional content on the page.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<string, IReadOnlyList<OptionalContentGroupElement>> GetOptionalContents() => Content.GetOptionalContents();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to useful members which will change in future releases.
|
/// Provides access to useful members which will change in future releases.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -198,6 +194,42 @@
|
|||||||
{
|
{
|
||||||
return annotationProvider.GetAnnotations();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,24 +67,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<MarkedContentElement> GetMarkedContents() => markedContents;
|
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>);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user