start adding retrieval of annotations

This commit is contained in:
Eliot Jones
2018-12-20 18:18:32 +00:00
parent 9abf6e226c
commit a5349dd77a
11 changed files with 535 additions and 28 deletions

View File

@@ -0,0 +1,38 @@
namespace UglyToad.PdfPig.Tests.Integration
{
using System.Linq;
using Xunit;
public class CatGeneticsTests
{
private static string GetFilename()
{
return IntegrationHelpers.GetDocumentPath("cat-genetics.pdf");
}
[Fact]
public void CanReadContent()
{
using (var document = PdfDocument.Open(GetFilename()))
{
var page = document.GetPage(1);
Assert.Contains("catus", page.Text);
}
}
[Fact]
public void CanGetAnnotations()
{
using (var document = PdfDocument.Open(GetFilename(), new ParsingOptions { UseLenientParsing = false }))
{
var page = document.GetPage(1);
var annotations = page.GetAnnotations().ToList();
Assert.NotEmpty(annotations);
}
}
}
}

View File

@@ -0,0 +1,52 @@
namespace UglyToad.PdfPig.Annotations
{
using System;
/// <summary>
/// Specifies characteristics of an annotation in a PDF or FDF document.
/// </summary>
[Flags]
internal enum AnnotationFlags
{
/// <summary>
/// Do not display the annotation if it is not one of the standard annotation types.
/// </summary>
Invisible = 1 << 0,
/// <summary>
/// Do not display or print the annotation irrespective of type. Do not allow interaction.
/// </summary>
Hidden = 1 << 1,
/// <summary>
/// The annotation should be included when the document is physically printed.
/// </summary>
Print = 1 << 2,
/// <summary>
/// Do not zoom/scale the annotation as the zoom of the document is changed.
/// </summary>
NoZoom = 1 << 3,
/// <summary>
/// Do not rotate the annotation as the page is rotated.
/// </summary>
NoRotate = 1 << 4,
/// <summary>
/// Do not display the annotation in viewer applications as with <see cref="Hidden"/>, however allow the annotation to be printed if <see cref="Print"/> is set.
/// </summary>
NoView = 1 << 5,
/// <summary>
/// Allow the annotation to be displayed/printed if applicable but do not respond to user interaction, e.g. mouse clicks.
/// </summary>
ReadOnly = 1 << 6,
/// <summary>
/// Do not allow deleting the annotation or changing size/position but allow the contents to be modified.
/// </summary>
Locked = 1 << 7,
/// <summary>
/// Invert the meaning of the <see cref="NoView"/> flag.
/// </summary>
ToggleNoView = 1 << 8,
/// <summary>
/// Allow the annotation to be deleted, resized, moved or restyled but disallow changes to the annotation contents. Opposite to <see cref="Locked"/>.
/// </summary>
LockedContents = 1 << 9
}
}

View File

@@ -0,0 +1,360 @@
namespace UglyToad.PdfPig.Annotations
{
using System;
using System.Collections.Generic;
using Exceptions;
using Geometry;
using Parser.Parts;
using Tokenization.Scanner;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
internal class AnnotationProvider
{
private readonly IPdfTokenScanner tokenScanner;
private readonly DictionaryToken pageDictionary;
private readonly bool isLenientParsing;
public AnnotationProvider(IPdfTokenScanner tokenScanner, DictionaryToken pageDictionary, bool isLenientParsing)
{
this.tokenScanner = tokenScanner ?? throw new ArgumentNullException(nameof(tokenScanner));
this.pageDictionary = pageDictionary ?? throw new ArgumentNullException(nameof(pageDictionary));
this.isLenientParsing = isLenientParsing;
}
public IEnumerable<Annotation> GetAnnotations()
{
if (!pageDictionary.TryGet(NameToken.Annots, out IToken annotationsToken)
|| !DirectObjectFinder.TryGet(annotationsToken, tokenScanner, out ArrayToken annotationsArray))
{
yield break;
}
foreach (var token in annotationsArray.Data)
{
if (!DirectObjectFinder.TryGet(token, tokenScanner, out DictionaryToken annotationDictionary))
{
if (isLenientParsing)
{
continue;
}
throw new PdfDocumentFormatException($"The annotations dictionary contained an annotation which wasn't a dictionary: {token}.");
}
if (!isLenientParsing && annotationDictionary.TryGet(NameToken.Type, out NameToken dictionaryType))
{
if (dictionaryType != NameToken.Annot)
{
throw new PdfDocumentFormatException($"The annotations dictionary contained a non-annotation type dictionary: {annotationDictionary}.");
}
}
var type = annotationDictionary.Get<NameToken>(NameToken.Subtype, tokenScanner);
var annotationType = type.ToAnnotationType();
var rectangle = annotationDictionary.Get<ArrayToken>(NameToken.Rect, tokenScanner).ToRectangle();
string content = null;
if (annotationDictionary.TryGet(NameToken.Contents, out var contentToken) && DirectObjectFinder.TryGet(contentToken, tokenScanner, out StringToken contentString))
{
content = contentString.Data;
}
yield return new Annotation(annotationDictionary, rectangle, content, null, null);
}
}
}
internal class Annotation
{
/// <summary>
/// The underlying PDF dictionary which this annotation was created from.
/// </summary>
[NotNull]
public DictionaryToken AnnotationDictionary { get; }
/// <summary>
/// The rectangle in user space units specifying the location to place this annotation on the page.
/// </summary>
public PdfRectangle Rectangle { get; }
/// <summary>
/// The annotation text, or if the annotation does not display text, a description of the annotation's contents. Optional.
/// </summary>
[CanBeNull]
public string Content { get; }
/// <summary>
/// The name of this annotation which should be unique per page. Optional.
/// </summary>
[CanBeNull]
public string Name { get; }
/// <summary>
/// The date and time the annotation was last modified, can be in any format. Optional.
/// </summary>
[CanBeNull]
public string ModifiedDate { get; }
public AnnotationFlags Flags { get; } = (AnnotationFlags)0;
/// <summary>
/// Create a new <see cref="Annotation"/>.
/// </summary>
public Annotation(DictionaryToken annotationDictionary, PdfRectangle rectangle, string content, string name, string modifiedDate)
{
AnnotationDictionary = annotationDictionary ?? throw new ArgumentNullException(nameof(annotationDictionary));
Rectangle = rectangle;
Content = content;
Name = name;
ModifiedDate = modifiedDate;
}
}
/// <summary>
/// The standard annotation types in PDF documents.
/// </summary>
internal enum AnnotationType
{
/// <summary>
/// A 'sticky note' style annotation displaying some text with open/closed pop-up state.
/// </summary>
Text = 0,
/// <summary>
/// A link to elsewhere in the document or an external application/web link.
/// </summary>
Link = 1,
/// <summary>
/// Displays text on the page. Unlike <see cref="Text"/> there is no associated pop-up.
/// </summary>
FreeText = 2,
/// <summary>
/// Display a single straight line on the page with optional line ending styles.
/// </summary>
Line = 3,
/// <summary>
/// Display a rectangle on the page.
/// </summary>
Square = 4,
/// <summary>
/// Display an ellipse on the page.
/// </summary>
Circle = 5,
/// <summary>
/// Display a closed polygon on the page.
/// </summary>
Polygon = 6,
/// <summary>
/// Display a set of connected lines on the page which is not a closed polygon.
/// </summary>
PolyLine = 7,
/// <summary>
/// A highlight for text or content with associated annotation texyt.
/// </summary>
Highlight = 8,
/// <summary>
/// An underline under text with associated annotation text.
/// </summary>
Underline = 9,
/// <summary>
/// A jagged squiggly line under text with associated annotation text.
/// </summary>
Squiggly = 10,
/// <summary>
/// A strikeout through some text with associated annotation text.
/// </summary>
StrikeOut = 11,
/// <summary>
/// Text or graphics intended to display as if inserted by a rubber stamp.
/// </summary>
Stamp = 12,
/// <summary>
/// A visual symbol indicating the presence of text edits.
/// </summary>
Caret = 13,
/// <summary>
/// A freehand 'scribble' formed by one or more paths.
/// </summary>
Ink = 14,
/// <summary>
/// Displays text in a pop-up window for entry or editing.
/// </summary>
Popup = 15,
/// <summary>
/// A file.
/// </summary>
FileAttachment = 16,
/// <summary>
/// A sound to be played through speakers.
/// </summary>
Sound = 17,
/// <summary>
/// Embeds a movie from a file in a PDF document.
/// </summary>
Movie = 18,
/// <summary>
/// Used by interactive forms to represent field appearance and manage user interactions.
/// </summary>
Widget = 19,
/// <summary>
/// Specifies a page region for media clips to be played and actions to be triggered from.
/// </summary>
Screen = 20,
/// <summary>
/// Represents a symbol used during the physical printing process to maintain output quality, e.g. color bars or cut marks.
/// </summary>
PrinterMark = 21,
/// <summary>
/// Used during the physical printing process to prevent colors mixing.
/// </summary>
TrapNet = 22,
/// <summary>
/// Adds a watermark at a fixed size and position irrespective of page size.
/// </summary>
Watermark = 23,
/// <summary>
/// Represents a 3D model/artwork, for example from CAD, in a PDF document.
/// </summary>
Artwork3D = 24,
/// <summary>
/// A custom annotation type.
/// </summary>
Other = 25
}
internal static class AnnotationExtensions
{
public static AnnotationType ToAnnotationType(this NameToken name)
{
if (name.Data == NameToken.Text.Data)
{
return AnnotationType.Text;
}
if (name.Data == NameToken.Link.Data)
{
return AnnotationType.Link;
}
if (name.Data == NameToken.FreeText.Data)
{
return AnnotationType.FreeText;
}
if (name.Data == NameToken.Line.Data)
{
return AnnotationType.Line;
}
if (name.Data == NameToken.Square.Data)
{
return AnnotationType.Square;
}
if (name.Data == NameToken.Circle.Data)
{
return AnnotationType.Circle;
}
if (name.Data == NameToken.Polygon.Data)
{
return AnnotationType.Polygon;
}
if (name.Data == NameToken.PolyLine.Data)
{
return AnnotationType.PolyLine;
}
if (name.Data == NameToken.Highlight.Data)
{
return AnnotationType.Highlight;
}
if (name.Data == NameToken.Underline.Data)
{
return AnnotationType.Underline;
}
if (name.Data == NameToken.Squiggly.Data)
{
return AnnotationType.Squiggly;
}
if (name.Data == NameToken.StrikeOut.Data)
{
return AnnotationType.StrikeOut;
}
if (name.Data == NameToken.Stamp.Data)
{
return AnnotationType.Stamp;
}
if (name.Data == NameToken.Caret.Data)
{
return AnnotationType.Caret;
}
if (name.Data == NameToken.Ink.Data)
{
return AnnotationType.Ink;
}
if (name.Data == NameToken.Popup.Data)
{
return AnnotationType.Popup;
}
if (name.Data == NameToken.FileAttachment.Data)
{
return AnnotationType.FileAttachment;
}
if (name.Data == NameToken.Sound.Data)
{
return AnnotationType.Sound;
}
if (name.Data == NameToken.Movie.Data)
{
return AnnotationType.Movie;
}
if (name.Data == NameToken.Widget.Data)
{
return AnnotationType.Widget;
}
if (name.Data == NameToken.Screen.Data)
{
return AnnotationType.Screen;
}
if (name.Data == NameToken.PrinterMark.Data)
{
return AnnotationType.PrinterMark;
}
if (name.Data == NameToken.TrapNet.Data)
{
return AnnotationType.TrapNet;
}
if (name.Data == NameToken.Watermark.Data)
{
return AnnotationType.Watermark;
}
if (name.Data == NameToken.Annotation3D.Data)
{
return AnnotationType.Artwork3D;
}
return AnnotationType.Other;
}
}
}

View File

@@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Annotations;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
using XObjects;
@@ -12,6 +14,9 @@
/// </summary>
public class Page
{
private readonly DictionaryToken dictionary;
private readonly AnnotationProvider annotationProvider;
/// <summary>
/// The page number (starting at 1).
/// </summary>
@@ -54,13 +59,17 @@
[NotNull]
public Experimental ExperimentalAccess { get; }
internal Page(int number, MediaBox mediaBox, CropBox cropBox, PageContent content)
internal Page(int number, DictionaryToken dictionary, MediaBox mediaBox, CropBox cropBox, PageContent content,
AnnotationProvider annotationProvider)
{
if (number <= 0)
{
throw new ArgumentOutOfRangeException(nameof(number), "Page number cannot be 0 or negative.");
}
this.dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
this.annotationProvider = annotationProvider ?? throw new ArgumentNullException(nameof(annotationProvider));
Number = number;
MediaBox = mediaBox;
CropBox = cropBox;
@@ -100,6 +109,11 @@
return (wordExtractor ?? DefaultWordExtractor.Instance).GetWords(Letters);
}
internal IEnumerable<Annotation> GetAnnotations()
{
return annotationProvider.GetAnnotations();
}
/// <summary>
/// Provides access to useful members which will change in future releases.
/// </summary>

View File

@@ -104,10 +104,7 @@
{
var mediaBox = DirectObjectFinder.Get<ArrayToken>(token, pdfScanner);
pageTreeMembers.MediaBox = new MediaBox(new PdfRectangle(mediaBox.GetNumeric(0).Data,
mediaBox.GetNumeric(1).Data,
mediaBox.GetNumeric(2).Data,
mediaBox.GetNumeric(3).Data));
pageTreeMembers.MediaBox = new MediaBox(mediaBox.ToRectangle());
}
if (!currentPageDictionary.TryGet(NameToken.Kids, out var kids)

View File

@@ -33,7 +33,7 @@
var privateDictionary = CompactFontFormatPrivateDictionary.GetDefault();
if (topDictionary.PrivateDictionaryLocation.HasValue)
if (topDictionary.PrivateDictionaryLocation.HasValue && topDictionary.PrivateDictionaryLocation.Value.Size > 0)
{
var privateDictionaryBytes = data.SnapshotPortion(topDictionary.PrivateDictionaryLocation.Value.Offset,
topDictionary.PrivateDictionaryLocation.Value.Size);

View File

@@ -130,12 +130,8 @@
{
return new PdfRectangle(0, 0, 0, 0);
}
var x1 = boxArray.GetNumeric(0).Data;
var y1 = boxArray.GetNumeric(1).Data;
var x2 = boxArray.GetNumeric(2).Data;
var y2 = boxArray.GetNumeric(3).Data;
return new PdfRectangle(x1, y1, x2, y2);
return boxArray.ToRectangle();
}
private static string GetCharSet(DictionaryToken dictionary)

View File

@@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using Annotations;
using Content;
using Exceptions;
using Filters;
@@ -45,7 +46,7 @@
if (type != null && !type.Equals(NameToken.Page) && !isLenientParsing)
{
throw new InvalidOperationException($"Page {number} had its type was specified as {type} rather than 'Page'.");
throw new InvalidOperationException($"Page {number} had its type specified as {type} rather than 'Page'.");
}
MediaBox mediaBox = GetMediaBox(number, dictionary, pageTreeMembers, isLenientParsing);
@@ -98,7 +99,7 @@
content = GetContent(bytes, cropBox, userSpaceUnit, isLenientParsing);
}
var page = new Page(number, mediaBox, cropBox, content);
var page = new Page(number, dictionary, mediaBox, cropBox, content, new AnnotationProvider(pdfScanner, dictionary, isLenientParsing));
return page;
}
@@ -128,12 +129,7 @@
CropBox cropBox;
if (dictionary.TryGet(NameToken.CropBox, out var cropBoxObject) && cropBoxObject is ArrayToken cropBoxArray)
{
var x1 = cropBoxArray.GetNumeric(0).Int;
var y1 = cropBoxArray.GetNumeric(1).Int;
var x2 = cropBoxArray.GetNumeric(2).Int;
var y2 = cropBoxArray.GetNumeric(3).Int;
cropBox = new CropBox(new PdfRectangle(x1, y1, x2, y2));
cropBox = new CropBox(cropBoxArray.ToIntRectangle());
}
else
{
@@ -148,12 +144,7 @@
MediaBox mediaBox;
if (dictionary.TryGet(NameToken.MediaBox, out var mediaboxObject) && mediaboxObject is ArrayToken mediaboxArray)
{
var x1 = mediaboxArray.GetNumeric(0).Int;
var y1 = mediaboxArray.GetNumeric(1).Int;
var x2 = mediaboxArray.GetNumeric(2).Int;
var y2 = mediaboxArray.GetNumeric(3).Int;
mediaBox = new MediaBox(new PdfRectangle(x1, y1, x2, y2));
mediaBox = new MediaBox(mediaboxArray.ToIntRectangle());
}
else
{

View File

@@ -23,6 +23,7 @@
public static readonly NameToken Alt = new NameToken("Alt");
public static readonly NameToken Alpha = new NameToken("Alpha");
public static readonly NameToken Alternate = new NameToken("Alternate");
public static readonly NameToken Annotation3D = new NameToken("3D");
public static readonly NameToken Annot = new NameToken("Annot");
public static readonly NameToken Annots = new NameToken("Annots");
public static readonly NameToken AntiAlias = new NameToken("AntiAlias");
@@ -82,6 +83,7 @@
public static readonly NameToken Calrgb = new NameToken("CalRGB");
public static readonly NameToken Cap = new NameToken("Cap");
public static readonly NameToken CapHeight = new NameToken("CapHeight");
public static readonly NameToken Caret = new NameToken("Caret");
public static readonly NameToken Catalog = new NameToken("Catalog");
public static readonly NameToken CcittfaxDecode = new NameToken("CCITTFaxDecode");
public static readonly NameToken CcittfaxDecodeAbbreviation = new NameToken("CCF");
@@ -98,6 +100,7 @@
public static readonly NameToken CidToGidMap = new NameToken("CIDToGIDMap");
public static readonly NameToken CidSet = new NameToken("CIDSet");
public static readonly NameToken CidSystemInfo = new NameToken("CIDSystemInfo");
public static readonly NameToken Circle = new NameToken("Circle");
public static readonly NameToken Cl = new NameToken("CL");
public static readonly NameToken ClrF = new NameToken("ClrF");
public static readonly NameToken ClrFf = new NameToken("ClrFf");
@@ -203,6 +206,7 @@
public static readonly NameToken Fdf = new NameToken("FDF");
public static readonly NameToken Ff = new NameToken("Ff");
public static readonly NameToken Fields = new NameToken("Fields");
public static readonly NameToken FileAttachment = new NameToken("FileAttachment");
public static readonly NameToken Filespec = new NameToken("Filespec");
public static readonly NameToken Filter = new NameToken("Filter");
public static readonly NameToken First = new NameToken("First");
@@ -226,6 +230,7 @@
public static readonly NameToken Form = new NameToken("Form");
public static readonly NameToken Formtype = new NameToken("FormType");
public static readonly NameToken Frm = new NameToken("FRM");
public static readonly NameToken FreeText = new NameToken("FreeText");
public static readonly NameToken Ft = new NameToken("FT");
public static readonly NameToken Function = new NameToken("Function");
public static readonly NameToken FunctionType = new NameToken("FunctionType");
@@ -242,6 +247,7 @@
public static readonly NameToken HideMenubar = new NameToken("HideMenubar");
public static readonly NameToken HideToolbar = new NameToken("HideToolbar");
public static readonly NameToken HideWindowui = new NameToken("HideWindowUI");
public static readonly NameToken Highlight = new NameToken("Highlight");
// I
public static readonly NameToken I = new NameToken("I");
public static readonly NameToken Ic = new NameToken("IC");
@@ -258,6 +264,7 @@
public static readonly NameToken Index = new NameToken("Index");
public static readonly NameToken Indexed = new NameToken("Indexed");
public static readonly NameToken Info = new NameToken("Info");
public static readonly NameToken Ink = new NameToken("Ink");
public static readonly NameToken Inklist = new NameToken("InkList");
public static readonly NameToken Interpolate = new NameToken("Interpolate");
public static readonly NameToken It = new NameToken("IT");
@@ -288,6 +295,8 @@
public static readonly NameToken Length2 = new NameToken("Length2");
public static readonly NameToken Lighten = new NameToken("Lighten");
public static readonly NameToken Limits = new NameToken("Limits");
public static readonly NameToken Line = new NameToken("Line");
public static readonly NameToken Link = new NameToken("Link");
public static readonly NameToken Lj = new NameToken("LJ");
public static readonly NameToken Ll = new NameToken("LL");
public static readonly NameToken Lle = new NameToken("LLE");
@@ -317,6 +326,7 @@
public static readonly NameToken Ml = new NameToken("ML");
public static readonly NameToken MmType1 = new NameToken("MMType1");
public static readonly NameToken ModDate = new NameToken("ModDate");
public static readonly NameToken Movie = new NameToken("Movie");
public static readonly NameToken Multiply = new NameToken("Multiply");
// N
public static readonly NameToken N = new NameToken("N");
@@ -384,12 +394,16 @@
public static readonly NameToken PdfDocEncoding = new NameToken("PDFDocEncoding");
public static readonly NameToken Perms = new NameToken("Perms");
public static readonly NameToken Pg = new NameToken("Pg");
public static readonly NameToken Polygon = new NameToken("Polygon");
public static readonly NameToken PolyLine = new NameToken("PolyLine");
public static readonly NameToken Popup = new NameToken("Popup");
public static readonly NameToken PreRelease = new NameToken("PreRelease");
public static readonly NameToken Predictor = new NameToken("Predictor");
public static readonly NameToken Prev = new NameToken("Prev");
public static readonly NameToken PrintArea = new NameToken("PrintArea");
public static readonly NameToken PrintClip = new NameToken("PrintClip");
public static readonly NameToken PrintScaling = new NameToken("PrintScaling");
public static readonly NameToken PrinterMark = new NameToken("PrinterMark");
public static readonly NameToken ProcSet = new NameToken("ProcSet");
public static readonly NameToken Process = new NameToken("Process");
public static readonly NameToken Producer = new NameToken("Producer");
@@ -440,8 +454,11 @@
public static readonly NameToken Smask = new NameToken("SMask");
public static readonly NameToken SoftLight = new NameToken("SoftLight");
public static readonly NameToken Sound = new NameToken("Sound");
public static readonly NameToken Square = new NameToken("Square");
public static readonly NameToken Squiggly = new NameToken("Squiggly");
public static readonly NameToken Ss = new NameToken("SS");
public static readonly NameToken St = new NameToken("St");
public static readonly NameToken Stamp = new NameToken("Stamp");
public static readonly NameToken StandardEncoding = new NameToken("StandardEncoding");
public static readonly NameToken State = new NameToken("State");
public static readonly NameToken StateModel = new NameToken("StateModel");
@@ -451,6 +468,7 @@
public static readonly NameToken StemV = new NameToken("StemV");
public static readonly NameToken StmF = new NameToken("StmF");
public static readonly NameToken StrF = new NameToken("StrF");
public static readonly NameToken StrikeOut = new NameToken("StrikeOut");
public static readonly NameToken StructParent = new NameToken("StructParent");
public static readonly NameToken StructParents = new NameToken("StructParents");
public static readonly NameToken StructTreeRoot = new NameToken("StructTreeRoot");
@@ -468,6 +486,7 @@
public static readonly NameToken T = new NameToken("T");
public static readonly NameToken Target = new NameToken("Target");
public static readonly NameToken Templates = new NameToken("Templates");
public static readonly NameToken Text = new NameToken("Text");
public static readonly NameToken Threads = new NameToken("Threads");
public static readonly NameToken Thumb = new NameToken("Thumb");
public static readonly NameToken Ti = new NameToken("TI");
@@ -482,6 +501,7 @@
public static readonly NameToken Trapped = new NameToken("Trapped");
public static readonly NameToken Trans = new NameToken("Trans");
public static readonly NameToken Transparency = new NameToken("Transparency");
public static readonly NameToken TrapNet = new NameToken("TrapNet");
public static readonly NameToken Tref = new NameToken("TRef");
public static readonly NameToken TrimBox = new NameToken("TrimBox");
public static readonly NameToken TrueType = new NameToken("TrueType");
@@ -498,6 +518,7 @@
public static readonly NameToken U = new NameToken("U");
public static readonly NameToken Ue = new NameToken("UE");
public static readonly NameToken Uf = new NameToken("UF");
public static readonly NameToken Underline = new NameToken("Underline");
public static readonly NameToken Unchanged = new NameToken("Unchanged");
public static readonly NameToken Unix = new NameToken("Unix");
public static readonly NameToken Uri = new NameToken("URI");
@@ -516,6 +537,7 @@
// W
public static readonly NameToken W = new NameToken("W");
public static readonly NameToken W2 = new NameToken("W2");
public static readonly NameToken Watermark = new NameToken("Watermark");
public static readonly NameToken WhitePoint = new NameToken("WhitePoint");
public static readonly NameToken Widget = new NameToken("Widget");
public static readonly NameToken Width = new NameToken("Width");

View File

@@ -2,6 +2,7 @@
{
using System;
using Exceptions;
using Geometry;
using JetBrains.Annotations;
using Tokens;
@@ -80,7 +81,7 @@
if (index < 0 || index >= array.Data.Count)
{
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException($"Cannot index into array at index {index}. Array was: {array}.");
}
if (array.Data[index] is NumericToken numeric)
@@ -88,7 +89,43 @@
return numeric;
}
throw new PdfDocumentFormatException();
throw new PdfDocumentFormatException($"The array did not contain a number at index {index}. Array was: {array}.");
}
public static PdfRectangle ToRectangle(this ArrayToken array)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
if (array.Data.Count != 4)
{
throw new PdfDocumentFormatException($"Cannot convert array to rectangle, expected 4 values instead got: {array}.");
}
return new PdfRectangle(array.GetNumeric(0).Data,
array.GetNumeric(1).Data,
array.GetNumeric(2).Data,
array.GetNumeric(3).Data);
}
public static PdfRectangle ToIntRectangle(this ArrayToken array)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
if (array.Data.Count != 4)
{
throw new PdfDocumentFormatException($"Cannot convert array to rectangle, expected 4 values instead got: {array}.");
}
return new PdfRectangle(array.GetNumeric(0).Int,
array.GetNumeric(1).Int,
array.GetNumeric(2).Int,
array.GetNumeric(3).Int);
}
}
}