mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-11-24 16:53:20 +08:00
support looking up in reply to value for annotation #362
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
namespace UglyToad.PdfPig.Tests.Integration;
|
||||||
|
|
||||||
|
using Annotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
public class AnnotationReplyToTests
|
||||||
|
{
|
||||||
|
private static string GetFilename()
|
||||||
|
{
|
||||||
|
return IntegrationHelpers.GetDocumentPath("annotation-comments.pdf");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HasCorrectNumberOfAnnotations()
|
||||||
|
{
|
||||||
|
using var document = PdfDocument.Open(GetFilename());
|
||||||
|
|
||||||
|
var page = document.GetPage(1);
|
||||||
|
|
||||||
|
var annotations = page.ExperimentalAccess.GetAnnotations().ToList();
|
||||||
|
|
||||||
|
Assert.Equal(4, annotations.Count);
|
||||||
|
|
||||||
|
Assert.Equal(AnnotationType.Text, annotations[0].Type);
|
||||||
|
Assert.Equal(AnnotationType.Popup, annotations[1].Type);
|
||||||
|
Assert.Equal(AnnotationType.Text, annotations[2].Type);
|
||||||
|
Assert.Equal(AnnotationType.Popup, annotations[3].Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SecondTextReplyToFirst()
|
||||||
|
{
|
||||||
|
using var document = PdfDocument.Open(GetFilename());
|
||||||
|
|
||||||
|
var page = document.GetPage(1);
|
||||||
|
|
||||||
|
var annotations = page.ExperimentalAccess.GetAnnotations().ToList();
|
||||||
|
|
||||||
|
Assert.Equal(annotations[0], annotations[2].InReplyTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -290,6 +290,7 @@
|
|||||||
public static readonly NameToken Inklist = new NameToken("InkList");
|
public static readonly NameToken Inklist = new NameToken("InkList");
|
||||||
public static readonly NameToken Intent = new NameToken("Intent");
|
public static readonly NameToken Intent = new NameToken("Intent");
|
||||||
public static readonly NameToken Interpolate = new NameToken("Interpolate");
|
public static readonly NameToken Interpolate = new NameToken("Interpolate");
|
||||||
|
public static readonly NameToken Irt = new NameToken("IRT");
|
||||||
public static readonly NameToken It = new NameToken("IT");
|
public static readonly NameToken It = new NameToken("IT");
|
||||||
public static readonly NameToken ItalicAngle = new NameToken("ItalicAngle");
|
public static readonly NameToken ItalicAngle = new NameToken("ItalicAngle");
|
||||||
// J
|
// J
|
||||||
|
|||||||
@@ -88,15 +88,30 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasDownAppearance => downAppearanceStream != null;
|
public bool HasDownAppearance => downAppearanceStream != null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Annotation"/> this annotation was in reply to. Can be <see langword="null" />
|
||||||
|
/// </summary>
|
||||||
|
public Annotation InReplyTo { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="Annotation"/>.
|
/// Create a new <see cref="Annotation"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Annotation(DictionaryToken annotationDictionary, AnnotationType type, PdfRectangle rectangle,
|
public Annotation(
|
||||||
string content, string name, string modifiedDate,
|
DictionaryToken annotationDictionary,
|
||||||
AnnotationFlags flags, AnnotationBorder border, IReadOnlyList<QuadPointsQuadrilateral> quadPoints,
|
AnnotationType type,
|
||||||
|
PdfRectangle rectangle,
|
||||||
|
string content,
|
||||||
|
string name,
|
||||||
|
string modifiedDate,
|
||||||
|
AnnotationFlags flags,
|
||||||
|
AnnotationBorder border,
|
||||||
|
IReadOnlyList<QuadPointsQuadrilateral> quadPoints,
|
||||||
PdfAction action,
|
PdfAction action,
|
||||||
AppearanceStream normalAppearanceStream, AppearanceStream rollOverAppearanceStream,
|
AppearanceStream normalAppearanceStream,
|
||||||
AppearanceStream downAppearanceStream, string appearanceState)
|
AppearanceStream rollOverAppearanceStream,
|
||||||
|
AppearanceStream downAppearanceStream,
|
||||||
|
string appearanceState,
|
||||||
|
Annotation inReplyTo)
|
||||||
{
|
{
|
||||||
AnnotationDictionary = annotationDictionary ?? throw new ArgumentNullException(nameof(annotationDictionary));
|
AnnotationDictionary = annotationDictionary ?? throw new ArgumentNullException(nameof(annotationDictionary));
|
||||||
Type = type;
|
Type = type;
|
||||||
@@ -112,6 +127,7 @@
|
|||||||
this.rollOverAppearanceStream = rollOverAppearanceStream;
|
this.rollOverAppearanceStream = rollOverAppearanceStream;
|
||||||
this.downAppearanceStream = downAppearanceStream;
|
this.downAppearanceStream = downAppearanceStream;
|
||||||
this.appearanceState = appearanceState;
|
this.appearanceState = appearanceState;
|
||||||
|
InReplyTo = inReplyTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
public IEnumerable<Annotation> GetAnnotations()
|
public IEnumerable<Annotation> GetAnnotations()
|
||||||
{
|
{
|
||||||
|
var lookupAnnotations = new Dictionary<IndirectReference, Annotation>();
|
||||||
|
|
||||||
if (!pageDictionary.TryGet(NameToken.Annots, tokenScanner, out ArrayToken annotationsArray))
|
if (!pageDictionary.TryGet(NameToken.Annots, tokenScanner, out ArrayToken annotationsArray))
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
@@ -45,6 +47,13 @@
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Annotation replyTo = null;
|
||||||
|
if (annotationDictionary.TryGet(NameToken.Irt, out IndirectReferenceToken referencedAnnotation)
|
||||||
|
&& lookupAnnotations.TryGetValue(referencedAnnotation.Data, out var linkedAnnotation))
|
||||||
|
{
|
||||||
|
replyTo = linkedAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
var type = annotationDictionary.Get<NameToken>(NameToken.Subtype, tokenScanner);
|
var type = annotationDictionary.Get<NameToken>(NameToken.Subtype, tokenScanner);
|
||||||
var annotationType = type.ToAnnotationType();
|
var annotationType = type.ToAnnotationType();
|
||||||
var action = GetAction(annotationDictionary);
|
var action = GetAction(annotationDictionary);
|
||||||
@@ -136,9 +145,29 @@
|
|||||||
appearanceState = appearanceStateToken.Data;
|
appearanceState = appearanceStateToken.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new Annotation(annotationDictionary, annotationType, rectangle,
|
var annotation = new Annotation(
|
||||||
contents, name, modifiedDate, flags, border, quadPointRectangles, action,
|
annotationDictionary,
|
||||||
normalAppearanceStream, rollOverAppearanceStream, downAppearanceStream, appearanceState);
|
annotationType,
|
||||||
|
rectangle,
|
||||||
|
contents,
|
||||||
|
name,
|
||||||
|
modifiedDate,
|
||||||
|
flags,
|
||||||
|
border,
|
||||||
|
quadPointRectangles,
|
||||||
|
action,
|
||||||
|
normalAppearanceStream,
|
||||||
|
rollOverAppearanceStream,
|
||||||
|
downAppearanceStream,
|
||||||
|
appearanceState,
|
||||||
|
replyTo);
|
||||||
|
|
||||||
|
if (token is IndirectReferenceToken indirectReference)
|
||||||
|
{
|
||||||
|
lookupAnnotations[indirectReference.Data] = annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return annotation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user