mirror of
https://github.com/UglyToad/PdfPig.git
synced 2026-01-18 19:51:24 +08:00
move annotations to experimental access, support changing color state for document creation and update readme
This commit is contained in:
26
README.md
26
README.md
@@ -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.
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{
|
||||
var page = document.GetPage(1);
|
||||
|
||||
var annotations = page.GetAnnotations().ToList();
|
||||
var annotations = page.ExperimentalAccess.GetAnnotations().ToList();
|
||||
|
||||
Assert.NotEmpty(annotations);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
{
|
||||
var page = document.GetPage(i + 1);
|
||||
|
||||
Assert.NotNull(page.GetAnnotations().ToList());
|
||||
Assert.NotNull(page.ExperimentalAccess.GetAnnotations().ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Cos;
|
||||
using CrossReference;
|
||||
using Exceptions;
|
||||
using IO;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cos;
|
||||
using CrossReference;
|
||||
using Exceptions;
|
||||
using Parts.CrossReference;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace UglyToad.PdfPig.Parser.Parts.CrossReference
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using Cos;
|
||||
using Exceptions;
|
||||
using Filters;
|
||||
using PdfPig.CrossReference;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user