PdfPig/src/UglyToad.PdfPig/Annotations/AnnotationProvider.cs

149 lines
6.8 KiB
C#
Raw Normal View History

2018-12-21 02:18:32 +08:00
namespace UglyToad.PdfPig.Annotations
{
using System;
using System.Collections.Generic;
2018-12-22 23:54:32 +08:00
using System.Linq;
using Core;
2018-12-21 02:18:32 +08:00
using Parser.Parts;
using Tokenization.Scanner;
using Tokens;
using Util;
internal class AnnotationProvider
{
private readonly IPdfTokenScanner tokenScanner;
private readonly DictionaryToken pageDictionary;
private readonly TransformationMatrix matrix;
2018-12-21 02:18:32 +08:00
public AnnotationProvider(IPdfTokenScanner tokenScanner, DictionaryToken pageDictionary,
TransformationMatrix matrix)
2018-12-21 02:18:32 +08:00
{
this.matrix = matrix;
2018-12-21 02:18:32 +08:00
this.tokenScanner = tokenScanner ?? throw new ArgumentNullException(nameof(tokenScanner));
this.pageDictionary = pageDictionary ?? throw new ArgumentNullException(nameof(pageDictionary));
}
public IEnumerable<Annotation> GetAnnotations()
{
if (!pageDictionary.TryGet(NameToken.Annots, tokenScanner, out ArrayToken annotationsArray))
2018-12-21 02:18:32 +08:00
{
yield break;
}
foreach (var token in annotationsArray.Data)
{
if (!DirectObjectFinder.TryGet(token, tokenScanner, out DictionaryToken annotationDictionary))
{
continue;
}
var type = annotationDictionary.Get<NameToken>(NameToken.Subtype, tokenScanner);
var annotationType = type.ToAnnotationType();
var rectangle = matrix.Transform(annotationDictionary.Get<ArrayToken>(NameToken.Rect, tokenScanner).ToRectangle(tokenScanner));
2018-12-21 02:18:32 +08:00
2018-12-22 23:54:32 +08:00
var contents = GetNamedString(NameToken.Contents, annotationDictionary);
var name = GetNamedString(NameToken.Nm, annotationDictionary);
var modifiedDateAsString = GetNamedString(NameToken.M, annotationDictionary);
if (!DateFormatHelper.TryParseDateTimeOffset(modifiedDateAsString, out var modifiedDate)) modifiedDate = default(DateTimeOffset);
2018-12-22 23:54:32 +08:00
var flags = (AnnotationFlags)0;
2018-12-22 23:54:32 +08:00
if (annotationDictionary.TryGet(NameToken.F, out var flagsToken) && DirectObjectFinder.TryGet(flagsToken, tokenScanner, out NumericToken flagsNumericToken))
2018-12-21 02:18:32 +08:00
{
flags = (AnnotationFlags)flagsNumericToken.Int;
2018-12-21 02:18:32 +08:00
}
2018-12-22 23:54:32 +08:00
var border = AnnotationBorder.Default;
if (annotationDictionary.TryGet(NameToken.Border, out var borderToken) && DirectObjectFinder.TryGet(borderToken, tokenScanner, out ArrayToken borderArray)
&& borderArray.Length >= 3)
{
var horizontal = borderArray.GetNumeric(0).Data;
var vertical = borderArray.GetNumeric(1).Data;
var width = borderArray.GetNumeric(2).Data;
var dashes = default(IReadOnlyList<decimal>);
2018-12-21 02:18:32 +08:00
2018-12-22 23:54:32 +08:00
if (borderArray.Length == 4 && borderArray.Data[4] is ArrayToken dashArray)
{
dashes = dashArray.Data.OfType<NumericToken>().Select(x => x.Data).ToList();
}
2018-12-21 02:18:32 +08:00
2018-12-22 23:54:32 +08:00
border = new AnnotationBorder(horizontal, vertical, width, dashes);
}
2018-12-21 02:18:32 +08:00
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[]
{
matrix.Transform(new PdfPoint(values[0], values[1])),
matrix.Transform(new PdfPoint(values[2], values[3])),
matrix.Transform(new PdfPoint(values[4], values[5])),
matrix.Transform(new PdfPoint(values[6], values[7]))
}));
values.Clear();
}
}
}
StreamToken normalAppearanceStream = null, downAppearanceStream = null, rollOverAppearanceStream = null;
if (annotationDictionary.TryGet(NameToken.Ap, out DictionaryToken appearanceDictionary))
{
// The normal appearance of this annotation
if (appearanceDictionary.TryGet(NameToken.N, out IndirectReferenceToken normalAppearanceRef))
{
normalAppearanceStream = tokenScanner.Get(normalAppearanceRef.Data)?.Data as StreamToken;
}
// If present, the 'roll over' appearance of this annotation (when hovering the mouse pointer over this annotation)
if (appearanceDictionary.TryGet(NameToken.R, out IndirectReferenceToken rollOverAppearanceRef))
{
rollOverAppearanceStream = tokenScanner.Get(rollOverAppearanceRef.Data)?.Data as StreamToken;
}
// If present, the 'down' appearance of this annotation (when you click on it)
if (appearanceDictionary.TryGet(NameToken.D, out IndirectReferenceToken downAppearanceRef))
{
downAppearanceStream = tokenScanner.Get(downAppearanceRef.Data)?.Data as StreamToken;
}
}
yield return new Annotation(annotationDictionary, annotationType, rectangle,
contents, name, modifiedDate, flags, border, quadPointRectangles,
normalAppearanceStream, rollOverAppearanceStream, downAppearanceStream);
2018-12-22 23:54:32 +08:00
}
2018-12-21 02:18:32 +08:00
}
2018-12-22 23:54:32 +08:00
private string GetNamedString(NameToken name, DictionaryToken dictionary)
2018-12-21 02:18:32 +08:00
{
2018-12-22 23:54:32 +08:00
string content = null;
if (dictionary.TryGet(name, out var contentToken))
2018-12-21 02:18:32 +08:00
{
2018-12-22 23:54:32 +08:00
if (contentToken is StringToken contentString)
{
content = contentString.Data;
}
else if (contentToken is HexToken contentHex)
{
content = contentHex.Data;
}
else if (DirectObjectFinder.TryGet(contentToken, tokenScanner, out StringToken indirectContentString))
{
content = indirectContentString.Data;
}
2018-12-21 02:18:32 +08:00
}
2018-12-22 23:54:32 +08:00
return content;
2018-12-21 02:18:32 +08:00
}
}
2018-12-22 23:54:32 +08:00
}