mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
add support for quadpoints to annotations
highlight, link, strikeout, squiggly and underline annotation types may define a set of quadrilaterals using the quadpoints entry. this defines the regions to show/activate the annotation. the order of points in the quadpoints array does not match the specification so we provide a convenience class to access the point data rather than interpreting it as a rectangle: https://stackoverflow.com/questions/9855814/pdf-spec-vs-acrobat-creation-quadpoints.
This commit is contained in:
parent
e064d39671
commit
00bd285262
@ -1,6 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Tests.Integration
|
||||
{
|
||||
using System.Linq;
|
||||
using Annotations;
|
||||
using Xunit;
|
||||
|
||||
public class CatGeneticsTests
|
||||
@ -31,6 +32,13 @@
|
||||
var annotations = page.ExperimentalAccess.GetAnnotations().ToList();
|
||||
|
||||
Assert.NotEmpty(annotations);
|
||||
|
||||
var highlights = annotations.Where(x => x.Type == AnnotationType.Highlight);
|
||||
|
||||
foreach (var highlight in highlights)
|
||||
{
|
||||
Assert.NotEmpty(highlight.QuadPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
"UglyToad.PdfPig.Annotations.AnnotationBorder",
|
||||
"UglyToad.PdfPig.Annotations.AnnotationFlags",
|
||||
"UglyToad.PdfPig.Annotations.AnnotationType",
|
||||
"UglyToad.PdfPig.Annotations.QuadPointsQuadrilateral",
|
||||
"UglyToad.PdfPig.Content.Catalog",
|
||||
"UglyToad.PdfPig.Content.CropBox",
|
||||
"UglyToad.PdfPig.Content.DocumentInformation",
|
||||
|
@ -1,6 +1,7 @@
|
||||
namespace UglyToad.PdfPig.Annotations
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
using Tokens;
|
||||
using Util.JetBrains.Annotations;
|
||||
@ -54,11 +55,18 @@
|
||||
/// </summary>
|
||||
public AnnotationBorder Border { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Rectangles defined using QuadPoints, for <see cref="AnnotationType.Link"/> these are the regions used to activate the link,
|
||||
/// for text markup annotations these are the text regions to apply the markup to.
|
||||
/// See <see cref="QuadPointsQuadrilateral.Points"/> for more information regarding the order of the points.
|
||||
/// </summary>
|
||||
public IReadOnlyList<QuadPointsQuadrilateral> QuadPoints { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Annotation"/>.
|
||||
/// </summary>
|
||||
public Annotation(DictionaryToken annotationDictionary, AnnotationType type, PdfRectangle rectangle, string content, string name, string modifiedDate,
|
||||
AnnotationFlags flags, AnnotationBorder border)
|
||||
AnnotationFlags flags, AnnotationBorder border, IReadOnlyList<QuadPointsQuadrilateral> quadPoints)
|
||||
{
|
||||
AnnotationDictionary = annotationDictionary ?? throw new ArgumentNullException(nameof(annotationDictionary));
|
||||
Type = type;
|
||||
@ -68,6 +76,7 @@
|
||||
ModifiedDate = modifiedDate;
|
||||
Flags = flags;
|
||||
Border = border;
|
||||
QuadPoints = quadPoints ?? EmptyArray<QuadPointsQuadrilateral>.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -59,10 +59,10 @@
|
||||
var name = GetNamedString(NameToken.Nm, annotationDictionary);
|
||||
var modifiedDate = GetNamedString(NameToken.M, annotationDictionary);
|
||||
|
||||
var flags = (AnnotationFlags) 0;
|
||||
var flags = (AnnotationFlags)0;
|
||||
if (annotationDictionary.TryGet(NameToken.F, out var flagsToken) && DirectObjectFinder.TryGet(flagsToken, tokenScanner, out NumericToken flagsNumericToken))
|
||||
{
|
||||
flags = (AnnotationFlags) flagsNumericToken.Int;
|
||||
flags = (AnnotationFlags)flagsNumericToken.Int;
|
||||
}
|
||||
|
||||
var border = AnnotationBorder.Default;
|
||||
@ -82,7 +82,36 @@
|
||||
border = new AnnotationBorder(horizontal, vertical, width, dashes);
|
||||
}
|
||||
|
||||
yield return new Annotation(annotationDictionary, annotationType, rectangle, contents, name, modifiedDate, flags, border);
|
||||
var quadPointRectangles = new List<QuadPointsQuadrilateral>();
|
||||
if (annotationDictionary.TryGet(NameToken.Quadpoints, tokenScanner, out ArrayToken quadPointsArray))
|
||||
{
|
||||
var values = new List<decimal>();
|
||||
for (var i = 0; i < quadPointsArray.Length; i++)
|
||||
{
|
||||
if (!(quadPointsArray[i] is NumericToken value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
values.Add(value.Data);
|
||||
|
||||
if (values.Count == 8)
|
||||
{
|
||||
quadPointRectangles.Add(new QuadPointsQuadrilateral(new[]
|
||||
{
|
||||
new PdfPoint(values[0], values[1]),
|
||||
new PdfPoint(values[2], values[3]),
|
||||
new PdfPoint(values[4], values[5]),
|
||||
new PdfPoint(values[6], values[7])
|
||||
}));
|
||||
|
||||
values.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return new Annotation(annotationDictionary, annotationType, rectangle, contents, name, modifiedDate, flags, border,
|
||||
quadPointRectangles);
|
||||
}
|
||||
}
|
||||
|
||||
|
45
src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs
Normal file
45
src/UglyToad.PdfPig/Annotations/QuadPointsQuadrilateral.cs
Normal file
@ -0,0 +1,45 @@
|
||||
namespace UglyToad.PdfPig.Annotations
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Core;
|
||||
|
||||
/// <summary>
|
||||
/// A QuadPoints quadrilateral is four points defining the region for an annotation to use.
|
||||
/// An annotation may cover multiple quadrilaterals.
|
||||
/// </summary>
|
||||
public class QuadPointsQuadrilateral
|
||||
{
|
||||
/// <summary>
|
||||
/// The 4 points defining this quadrilateral.
|
||||
/// The PDF specification defines these as being in anti-clockwise order starting from the lower-left corner, however
|
||||
/// Adobe's implementation doesn't obey the specification and points seem to go in the order: top-left, top-right,
|
||||
/// bottom-left, bottom-right. See: https://stackoverflow.com/questions/9855814/pdf-spec-vs-acrobat-creation-quadpoints.
|
||||
/// </summary>
|
||||
public IReadOnlyList<PdfPoint> Points { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="QuadPointsQuadrilateral"/>.
|
||||
/// </summary>
|
||||
public QuadPointsQuadrilateral(IReadOnlyList<PdfPoint> points)
|
||||
{
|
||||
if (points == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(points));
|
||||
}
|
||||
|
||||
if (points.Count != 4)
|
||||
{
|
||||
throw new ArgumentException($"Quadpoints quadrilateral should only contain 4 points, instead got {points.Count} points.");
|
||||
}
|
||||
|
||||
Points = points;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"[ {Points[0]}, {Points[1]}, {Points[2]}, {Points[3]} ]";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user