move annotations to experimental access, support changing color state for document creation and update readme

This commit is contained in:
Eliot Jones
2018-12-30 14:12:04 +00:00
parent 55a0e6b646
commit 4d5518a599
14 changed files with 125 additions and 184 deletions

View File

@@ -112,23 +112,34 @@ The ```AddedFont``` class represents a key to the font stored on the document bu
This creates a new ```PdfPageBuilder``` with the specified size. The first added page is page number 1, then 2, then 3, etc. The page builder supports adding text, drawing lines and rectangles and measuring the size of text prior to drawing.
To draw lines and rectangles in black (different colors are not currently supported) use the methods:
To draw lines and rectangles use the methods:
void DrawLine(PdfPoint from, PdfPoint to, decimal lineWidth = 1)
void DrawRectangle(PdfPoint position, decimal width, decimal height, decimal lineWidth = 1)
The line width can be varied and defaults to 1.
The line width can be varied and defaults to 1. Rectangles are unfilled and the fill color cannot be changed at present.
To write text to the page you must have a reference to an ```AddedFont``` from the methods on ```PdfDocumentBuilder``` as described above. You can then draw the text to the page using:
IReadOnlyList<Letter> AddText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font)
Where ```position``` is the baseline of the text to draw. Currently **only ASCII text is supported** and the text will be drawn in black and the color cannot be varied. You can also measure the resulting size of text prior to drawing using the method:
Where ```position``` is the baseline of the text to draw. Currently **only ASCII text is supported**. You can also measure the resulting size of text prior to drawing using the method:
IReadOnlyList<Letter> MeasureText(string text, decimal fontSize, PdfPoint position, PdfDocumentBuilder.AddedFont font)
Which does not change the state of the page, unlike ```AddText```.
Changing the RGB color of text, lines and rectangles is supported using:
void SetStrokeColor(byte r, byte g, byte b)
void SetTextAndFillColor(byte r, byte g, byte b)
Which take RGB values between 0 and 255. The color will remain active for all operations called after these methods until reset is called using:
void ResetColor()
Which resets the color for stroke, fill and text drawing to black.
### Document Information ###
The ```PdfDocument``` provides access to the document metadata as ```DocumentInformation``` defined in the PDF file. These tend not to be provided therefore most of these entries will be ```null```:
@@ -183,7 +194,6 @@ Due to the way a PDF is structured internally the page text may not be a readabl
To help users resolve actual text order on the page, the ```Page``` file provides access to a list of the letters:
IReadOnlyList<Letter> letters = page.Letters;
These letters contain:
@@ -199,6 +209,14 @@ Letter position is measured in PDF coordinates where the origin is the lower lef
At this stage letter position is experimental and **will change in future versions**! Do not rely on letter positions remaining constant between different versions of this package.
### Annotations ###
New in v0.0.5 - Early support for retrieving annotations on each page is provided using the method:
page.ExperimentalAccess.GetAnnotations()
This call is not cached and the document must not have been disposed prior to use. The annotations API may change in future.
## Issues ##
At this stage the software is in Alpha. In order to proceed to Beta and production we need to see a wide variety of document types.

View File

@@ -29,7 +29,7 @@
{
var page = document.GetPage(1);
var annotations = page.GetAnnotations().ToList();
var annotations = page.ExperimentalAccess.GetAnnotations().ToList();
Assert.NotEmpty(annotations);
}

View File

@@ -23,7 +23,7 @@
{
var page = document.GetPage(i + 1);
Assert.NotNull(page.GetAnnotations().ToList());
Assert.NotNull(page.ExperimentalAccess.GetAnnotations().ToList());
}
}
}

View File

@@ -3,7 +3,6 @@
using System;
using System.Linq;
using Exceptions;
using PdfPig.Cos;
using PdfPig.CrossReference;
using PdfPig.Parser.FileStructure;
using PdfPig.Tokenization.Scanner;

View File

@@ -96,10 +96,11 @@
page.DrawLine(new PdfPoint(30, 520), new PdfPoint(360, 520));
page.DrawLine(new PdfPoint(360, 520), new PdfPoint(360, 250));
page.SetStrokeColor(250, 132, 131);
page.DrawLine(new PdfPoint(25, 70), new PdfPoint(100, 70), 3);
page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
page.ResetColor();
page.DrawRectangle(new PdfPoint(30, 200), 250, 100, 0.5m);
page.DrawRectangle(new PdfPoint(30, 100), 250, 100, 0.5m);
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts", "TrueType");
var file = Path.Combine(path, "Andada-Regular.ttf");

View File

@@ -15,7 +15,6 @@
public class Page
{
private readonly DictionaryToken dictionary;
private readonly AnnotationProvider annotationProvider;
/// <summary>
/// The page number (starting at 1).
@@ -68,7 +67,6 @@
}
this.dictionary = dictionary ?? throw new ArgumentNullException(nameof(dictionary));
this.annotationProvider = annotationProvider ?? throw new ArgumentNullException(nameof(annotationProvider));
Number = number;
MediaBox = mediaBox;
@@ -80,7 +78,7 @@
Height = mediaBox.Bounds.Height;
Size = mediaBox.Bounds.GetPageSize();
ExperimentalAccess = new Experimental(this);
ExperimentalAccess = new Experimental(this, annotationProvider);
}
private static string GetText(PageContent content)
@@ -109,21 +107,18 @@
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>
public class Experimental
{
private readonly Page page;
private readonly AnnotationProvider annotationProvider;
internal Experimental(Page page)
internal Experimental(Page page, AnnotationProvider annotationProvider)
{
this.page = page;
this.annotationProvider = annotationProvider;
}
/// <summary>
@@ -135,6 +130,15 @@
{
return page.Content.GetImages();
}
/// <summary>
/// Get the annotation objects from the page.
/// </summary>
/// <returns>The lazily evaluated set of annotations on this page.</returns>
public IEnumerable<Annotation> GetAnnotations()
{
return annotationProvider.GetAnnotations();
}
}
}
}

View File

@@ -1,160 +0,0 @@
namespace UglyToad.PdfPig.Cos
{
using System.Collections.Generic;
using System.IO;
using System.Text;
/// <summary>
/// The "PDFDocEncoding" encoding. Note that this is *not* a Type 1 font encoding, it is used only within PDF "text strings".
/// </summary>
internal static class PdfDocEncoding
{
private const char ReplacementCharacter = '\uFFFD';
private static readonly int[] CodeToUni;
private static readonly IReadOnlyDictionary<char, int> UnicodeToCode;
static PdfDocEncoding()
{
var temporaryMap = new Dictionary<char, int>(256);
CodeToUni = new int[256];
// initialize with basically ISO-8859-1
for (int i = 0; i < 256; i++)
{
// skip entries not in Unicode column
if (i > 0x17 && i < 0x20)
{
continue;
}
if (i > 0x7E && i < 0xA1)
{
continue;
}
if (i == 0xAD)
{
continue;
}
Set(i, (char)i, temporaryMap);
}
// then do all deviations (based on the table in ISO 32000-1:2008)
// block 1
Set(0x18, '\u02D8', temporaryMap); // BREVE
Set(0x19, '\u02C7', temporaryMap); // CARON
Set(0x1A, '\u02C6', temporaryMap); // MODIFIER LETTER CIRCUMFLEX ACCENT
Set(0x1B, '\u02D9', temporaryMap); // DOT ABOVE
Set(0x1C, '\u02DD', temporaryMap); // DOUBLE ACUTE ACCENT
Set(0x1D, '\u02DB', temporaryMap); // OGONEK
Set(0x1E, '\u02DA', temporaryMap); // RING ABOVE
Set(0x1F, '\u02DC', temporaryMap); // SMALL TILDE
// block 2
Set(0x7F, ReplacementCharacter, temporaryMap); // undefined
Set(0x80, '\u2022', temporaryMap); // BULLET
Set(0x81, '\u2020', temporaryMap); // DAGGER
Set(0x82, '\u2021', temporaryMap); // DOUBLE DAGGER
Set(0x83, '\u2026', temporaryMap); // HORIZONTAL ELLIPSIS
Set(0x84, '\u2014', temporaryMap); // EM DASH
Set(0x85, '\u2013', temporaryMap); // EN DASH
Set(0x86, '\u0192', temporaryMap); // LATIN SMALL LETTER SCRIPT F
Set(0x87, '\u2044', temporaryMap); // FRACTION SLASH (solidus)
Set(0x88, '\u2039', temporaryMap); // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
Set(0x89, '\u203A', temporaryMap); // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
Set(0x8A, '\u2212', temporaryMap); // MINUS SIGN
Set(0x8B, '\u2030', temporaryMap); // PER MILLE SIGN
Set(0x8C, '\u201E', temporaryMap); // DOUBLE LOW-9 QUOTATION MARK (quotedblbase)
Set(0x8D, '\u201C', temporaryMap); // LEFT DOUBLE QUOTATION MARK (quotedblleft)
Set(0x8E, '\u201D', temporaryMap); // RIGHT DOUBLE QUOTATION MARK (quotedblright)
Set(0x8F, '\u2018', temporaryMap); // LEFT SINGLE QUOTATION MARK (quoteleft)
Set(0x90, '\u2019', temporaryMap); // RIGHT SINGLE QUOTATION MARK (quoteright)
Set(0x91, '\u201A', temporaryMap); // SINGLE LOW-9 QUOTATION MARK (quotesinglbase)
Set(0x92, '\u2122', temporaryMap); // TRADE MARK SIGN
Set(0x93, '\uFB01', temporaryMap); // LATIN SMALL LIGATURE FI
Set(0x94, '\uFB02', temporaryMap); // LATIN SMALL LIGATURE FL
Set(0x95, '\u0141', temporaryMap); // LATIN CAPITAL LETTER L WITH STROKE
Set(0x96, '\u0152', temporaryMap); // LATIN CAPITAL LIGATURE OE
Set(0x97, '\u0160', temporaryMap); // LATIN CAPITAL LETTER S WITH CARON
Set(0x98, '\u0178', temporaryMap); // LATIN CAPITAL LETTER Y WITH DIAERESIS
Set(0x99, '\u017D', temporaryMap); // LATIN CAPITAL LETTER Z WITH CARON
Set(0x9A, '\u0131', temporaryMap); // LATIN SMALL LETTER DOTLESS I
Set(0x9B, '\u0142', temporaryMap); // LATIN SMALL LETTER L WITH STROKE
Set(0x9C, '\u0153', temporaryMap); // LATIN SMALL LIGATURE OE
Set(0x9D, '\u0161', temporaryMap); // LATIN SMALL LETTER S WITH CARON
Set(0x9E, '\u017E', temporaryMap); // LATIN SMALL LETTER Z WITH CARON
Set(0x9F, ReplacementCharacter, temporaryMap); // undefined
Set(0xA0, '\u20AC', temporaryMap); // EURO SIGN
// end of deviations
UnicodeToCode = temporaryMap;
}
private static void Set(int code, char unicode, Dictionary<char, int> unicodeToCode)
{
CodeToUni[code] = unicode;
unicodeToCode[unicode] = code;
}
/**
* Returns the string representation of the given PDFDocEncoded bytes.
*/
public static string ToString(byte[] bytes)
{
if (bytes == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
foreach (var b in bytes)
{
if ((b & 0xff) >= CodeToUni.Length)
{
sb.Append('?');
}
else
{
sb.Append((char)CodeToUni[b & 0xff]);
}
}
return sb.ToString();
}
/// <summary>
/// Returns the given string encoded with PDFDocEncoding.
/// </summary>
public static byte[] GetBytes(string text)
{
using (var memoryStream = new MemoryStream())
using (var write = new StreamWriter(memoryStream))
{
foreach (var c in text)
{
if (!UnicodeToCode.TryGetValue(c, out int value))
{
write.Write(0);
}
else
{
write.Write(value);
}
}
return memoryStream.ToArray();
}
}
/// <summary>
/// Returns true if the given character is available in PDFDocEncoding.
/// </summary>
/// <param name="character">UTF-16 character</param>
public static bool ContainsChar(char character)
{
return UnicodeToCode.ContainsKey(character);
}
}
}

View File

@@ -28,7 +28,14 @@
public void Write(Stream stream)
{
throw new System.NotImplementedException();
stream.WriteDecimal(R);
stream.WriteWhiteSpace();
stream.WriteDecimal(G);
stream.WriteWhiteSpace();
stream.WriteDecimal(B);
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()

View File

@@ -28,7 +28,14 @@
public void Write(Stream stream)
{
throw new System.NotImplementedException();
stream.WriteDecimal(R);
stream.WriteWhiteSpace();
stream.WriteDecimal(G);
stream.WriteWhiteSpace();
stream.WriteDecimal(B);
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()

View File

@@ -4,7 +4,6 @@ namespace UglyToad.PdfPig.Graphics
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Cos;
using Exceptions;
using Operations;
using Operations.TextShowing;

View File

@@ -2,7 +2,6 @@
{
using System;
using System.Collections.Generic;
using Cos;
using CrossReference;
using Exceptions;
using IO;

View File

@@ -2,7 +2,6 @@
{
using System.Collections.Generic;
using System.Linq;
using Cos;
using CrossReference;
using Exceptions;
using Parts.CrossReference;

View File

@@ -1,7 +1,6 @@
namespace UglyToad.PdfPig.Parser.Parts.CrossReference
{
using System.Collections.Generic;
using Cos;
using Exceptions;
using Filters;
using PdfPig.CrossReference;

View File

@@ -8,6 +8,7 @@
using Graphics.Operations;
using Graphics.Operations.General;
using Graphics.Operations.PathConstruction;
using Graphics.Operations.SpecialGraphicsState;
using Graphics.Operations.TextObjects;
using Graphics.Operations.TextPositioning;
using Graphics.Operations.TextShowing;
@@ -84,6 +85,51 @@
}
}
/// <summary>
/// Sets the stroke color for any following operations to the RGB value. Use <see cref="ResetColor"/> to reset.
/// </summary>
/// <param name="r">Red - 0 to 255</param>
/// <param name="g">Green - 0 to 255</param>
/// <param name="b">Blue - 0 to 255</param>
public void SetStrokeColor(byte r, byte g, byte b)
{
operations.Add(Push.Value);
operations.Add(new SetStrokeColorDeviceRgb(RgbToDecimal(r), RgbToDecimal(g), RgbToDecimal(b)));
}
/// <summary>
/// Sets the stroke color with the exact decimal value between 0 and 1 for any following operations to the RGB value. Use <see cref="ResetColor"/> to reset.
/// </summary>
/// <param name="r">Red - 0 to 1</param>
/// <param name="g">Green - 0 to 1</param>
/// <param name="b">Blue - 0 to 1</param>
internal void SetStrokeColorExact(decimal r, decimal g, decimal b)
{
operations.Add(Push.Value);
operations.Add(new SetStrokeColorDeviceRgb(CheckRgbDecimal(r, nameof(r)),
CheckRgbDecimal(g, nameof(g)), CheckRgbDecimal(b, nameof(b))));
}
/// <summary>
/// Sets the fill and text color for any following operations to the RGB value. Use <see cref="ResetColor"/> to reset.
/// </summary>
/// <param name="r">Red - 0 to 255</param>
/// <param name="g">Green - 0 to 255</param>
/// <param name="b">Blue - 0 to 255</param>
public void SetTextAndFillColor(byte r, byte g, byte b)
{
operations.Add(Push.Value);
operations.Add(new SetNonStrokeColorDeviceRgb(RgbToDecimal(r), RgbToDecimal(g), RgbToDecimal(b)));
}
/// <summary>
/// Restores the stroke, text and fill color to default (black).
/// </summary>
public void ResetColor()
{
operations.Add(Pop.Value);
}
/// <summary>
/// Calculates the size and position of each letter in a given string in the provided font without changing the state of the page.
/// </summary>
@@ -221,5 +267,28 @@
return letters;
}
private static decimal RgbToDecimal(byte value)
{
var res = Math.Max(0, value / (decimal)byte.MaxValue);
res = Math.Min(1, res);
return res;
}
private static decimal CheckRgbDecimal(decimal value, string argument)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(argument, $"Provided decimal for RGB color was less than zero: {value}.");
}
if (value > 1)
{
throw new ArgumentOutOfRangeException(argument, $"Provided decimal for RGB color was greater than one: {value}.");
}
return value;
}
}
}