#21 enable document creation using standard 14 font to test output

This commit is contained in:
Eliot Jones
2018-12-02 16:14:55 +00:00
parent d4813ba3a9
commit d6a896dcb0
63 changed files with 646 additions and 62 deletions

View File

@@ -2,7 +2,9 @@
{
using System;
using System.IO;
using System.Linq;
using Content;
using PdfPig.Fonts;
using PdfPig.Geometry;
using PdfPig.Util;
using PdfPig.Writer;
@@ -59,6 +61,27 @@
return result;
}
[Fact]
public void CanWriteSinglePageStandard14FontHelloWorld()
{
var builder = new PdfDocumentBuilder();
var page = builder.AddPage(PageSize.A4);
var font = builder.AddStandard14Font(Standard14Font.Helvetica);
page.AddText("Hello World!", 12, new PdfPoint(25, 520), font);
var b = builder.Build();
using (var document = PdfDocument.Open(b))
{
var page1 = document.GetPage(1);
Assert.Equal(new[] {"Hello", "World!"}, page1.GetWords().Select(x => x.Text));
}
}
[Fact]
public void CanWriteSinglePageHelloWorld()
{

View File

@@ -36,23 +36,24 @@
private static readonly HashSet<string> Standard14Names = new HashSet<string>();
private static readonly Dictionary<string, string> Standard14Mapping = new Dictionary<string, string>(34);
private static readonly Dictionary<string, FontMetrics> Standard14AfmMap = new Dictionary<string, FontMetrics>(34);
private static readonly Dictionary<Standard14Font, FontMetrics> Standard14AfmTypeMap = new Dictionary<Standard14Font, FontMetrics>(14);
static Standard14()
{
AddAdobeFontMetrics("Courier-Bold");
AddAdobeFontMetrics("Courier-BoldOblique");
AddAdobeFontMetrics("Courier");
AddAdobeFontMetrics("Courier-Oblique");
AddAdobeFontMetrics("Helvetica");
AddAdobeFontMetrics("Helvetica-Bold");
AddAdobeFontMetrics("Helvetica-BoldOblique");
AddAdobeFontMetrics("Helvetica-Oblique");
AddAdobeFontMetrics("Symbol");
AddAdobeFontMetrics("Times-Bold");
AddAdobeFontMetrics("Times-BoldItalic");
AddAdobeFontMetrics("Times-Italic");
AddAdobeFontMetrics("Times-Roman");
AddAdobeFontMetrics("ZapfDingbats");
AddAdobeFontMetrics("Courier-Bold", Standard14Font.CourierBold);
AddAdobeFontMetrics("Courier-BoldOblique", Standard14Font.CourierBoldOblique);
AddAdobeFontMetrics("Courier", Standard14Font.Courier);
AddAdobeFontMetrics("Courier-Oblique", Standard14Font.CourierOblique);
AddAdobeFontMetrics("Helvetica", Standard14Font.Helvetica);
AddAdobeFontMetrics("Helvetica-Bold", Standard14Font.HelveticaBold);
AddAdobeFontMetrics("Helvetica-BoldOblique", Standard14Font.HelveticaBoldOblique);
AddAdobeFontMetrics("Helvetica-Oblique", Standard14Font.HelveticaOblique);
AddAdobeFontMetrics("Symbol", Standard14Font.Symbol);
AddAdobeFontMetrics("Times-Bold", Standard14Font.TimesBold);
AddAdobeFontMetrics("Times-BoldItalic", Standard14Font.TimesBoldItalic);
AddAdobeFontMetrics("Times-Italic", Standard14Font.TimesItalic);
AddAdobeFontMetrics("Times-Roman", Standard14Font.TimesRoman);
AddAdobeFontMetrics("ZapfDingbats", Standard14Font.ZapfDingbats);
// alternative names from Adobe Supplement to the ISO 32000
AddAdobeFontMetrics("CourierCourierNew", "Courier");
@@ -79,12 +80,12 @@
AddAdobeFontMetrics("Times,BoldItalic", "Times-BoldItalic");
}
private static void AddAdobeFontMetrics(string fontName)
private static void AddAdobeFontMetrics(string fontName, Standard14Font? type = null)
{
AddAdobeFontMetrics(fontName, fontName);
AddAdobeFontMetrics(fontName, fontName, type);
}
private static void AddAdobeFontMetrics(string fontName, string afmName)
private static void AddAdobeFontMetrics(string fontName, string afmName, Standard14Font? type = null)
{
Standard14Names.Add(fontName);
Standard14Mapping.Add(fontName, afmName);
@@ -109,6 +110,10 @@
}
Standard14AfmMap[fontName] = Parser.Parse(bytes, true);
if (type.HasValue)
{
Standard14AfmTypeMap[type.Value] = Standard14AfmMap[fontName];
}
}
catch (Exception ex)
{
@@ -128,6 +133,11 @@
return metrics;
}
public static FontMetrics GetAdobeFontMetrics(Standard14Font fontType)
{
return Standard14AfmTypeMap[fontType];
}
/// <summary>
/// Determines if a font with this name is a standard 14 font.
/// </summary>
@@ -157,4 +167,22 @@
return mappedName;
}
}
internal enum Standard14Font
{
TimesRoman = 0,
TimesBold = 1,
TimesItalic=2,
TimesBoldItalic = 3,
Helvetica = 4,
HelveticaBold = 5,
HelveticaOblique = 6,
HelveticaBoldOblique = 7,
Courier = 8,
CourierBold = 9,
CourierOblique = 10,
CourierBoldOblique = 11,
Symbol = 12,
ZapfDingbats = 13
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.ClippingPaths
{
using System.IO;
using Content;
internal class ModifyClippingByEvenOddIntersect : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.ClippingPaths
{
using System.IO;
using Content;
internal class ModifyClippingByNonZeroWindingIntersect : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class CloseAndStrokePath : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class CloseFillPathEvenOddRuleAndStroke : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class CloseFillPathNonZeroWindingAndStroke : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class EndPath : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class FillPathEvenOddRule : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class FillPathEvenOddRuleAndStroke : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class FillPathNonZeroWinding : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class FillPathNonZeroWindingAndStroke : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class FillPathNonZeroWindingCompatibility : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System.IO;
using Content;
internal class SetColorRenderingIntent : IGraphicsStateOperation
@@ -12,5 +13,10 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System.IO;
using Content;
internal class SetFlatnessTolerance : IGraphicsStateOperation
@@ -20,6 +21,11 @@
operationContext.GetCurrentState().Flatness = Tolerance;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Tolerance} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System;
using System.IO;
using Content;
using Core;
@@ -28,6 +29,11 @@
operationContext.GetCurrentState().CapStyle = Cap;
}
public void Write(Stream stream)
{
throw new NotImplementedException();
}
public override string ToString()
{
return $"{(int) Cap} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System.IO;
using Content;
using Core;
@@ -21,6 +22,11 @@
operationContext.GetCurrentState().LineDashPattern = Pattern;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Pattern.Array} {Pattern.Phase} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System;
using System.IO;
using Content;
using Core;
@@ -28,6 +29,11 @@
operationContext.GetCurrentState().JoinStyle = Join;
}
public void Write(Stream stream)
{
throw new NotImplementedException();
}
public override string ToString()
{
return $"{(int)Join} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System.IO;
using Content;
internal class SetLineWidth : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.LineWidth = Width;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Width} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.General
{
using System.IO;
using Content;
internal class SetMiterLimit : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.MiterLimit = Limit;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Limit} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal interface IGraphicsStateOperation
@@ -7,5 +8,7 @@
string Operator { get; }
void Run(IOperationContext operationContext, IResourceStore resourceStore);
void Write(Stream stream);
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
using Tokens;
@@ -23,6 +24,11 @@
operationContext.ApplyXObject(xobject);
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Name} {Symbol}";

View File

@@ -0,0 +1,32 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Util;
internal static class OperationWriteHelper
{
private static readonly byte WhiteSpace = OtherEncodings.StringAsLatin1Bytes(" ")[0];
private static readonly byte NewLine = OtherEncodings.StringAsLatin1Bytes("\n")[0];
public static void WriteText(this Stream stream, string text)
{
var bytes = OtherEncodings.StringAsLatin1Bytes(text);
stream.Write(bytes, 0, bytes.Length);
}
public static void WriteWhiteSpace(this Stream stream)
{
stream.WriteByte(WhiteSpace);
}
public static void WriteNewLine(this Stream stream)
{
stream.WriteByte(NewLine);
}
public static void WriteDecimal(this Stream stream, decimal value)
{
stream.WriteText(value.ToString("G"));
}
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -26,6 +27,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{ControlPoint1.X} {ControlPoint1.Y} {ControlPoint2.X} {ControlPoint2.Y} {End.X} {End.Y} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -23,6 +24,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{ControlPoint1.X} {ControlPoint1.Y} {End.X} {End.Y} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -27,6 +28,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{LowerLeft.X} {LowerLeft.Y} {Width} {Height} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -23,6 +24,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{ControlPoint2.X} {ControlPoint2.Y} {End.X} {End.Y} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -20,6 +21,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{End.X} {End.Y} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
using Geometry;
@@ -20,6 +21,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Point.X} {Point.Y} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.PathConstruction
{
using System.IO;
using Content;
internal class CloseSubpath : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetNonStrokeColorDeviceCmyk : IGraphicsStateOperation
@@ -28,6 +29,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{C} {M} {Y} {K} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetNonStrokeColorDeviceGray : IGraphicsStateOperation
@@ -19,6 +20,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Gray} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetNonStrokeColorDeviceRgb : IGraphicsStateOperation
@@ -25,6 +26,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{R} {G} {B} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetStrokeColorDeviceCmyk : IGraphicsStateOperation
@@ -28,6 +29,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{C} {M} {Y} {K} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetStrokeColorDeviceGray : IGraphicsStateOperation
@@ -19,6 +20,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Gray} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class SetStrokeColorDeviceRgb : IGraphicsStateOperation
@@ -25,6 +26,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{R} {G} {B} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState
{
using System;
using System.IO;
using Content;
using PdfPig.Core;
@@ -37,6 +38,24 @@
operationContext.GetCurrentState().CurrentTransformationMatrix = newCtm;
}
public void Write(Stream stream)
{
stream.WriteDecimal(Value[0]);
stream.WriteWhiteSpace();
stream.WriteDecimal(Value[1]);
stream.WriteWhiteSpace();
stream.WriteDecimal(Value[2]);
stream.WriteWhiteSpace();
stream.WriteDecimal(Value[3]);
stream.WriteWhiteSpace();
stream.WriteDecimal(Value[4]);
stream.WriteWhiteSpace();
stream.WriteDecimal(Value[5]);
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return $"{Value[0]} {Value[1]} {Value[2]} {Value[3]} {Value[4]} {Value[5]} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState
{
using System;
using System.IO;
using Content;
internal class Pop : IGraphicsStateOperation
@@ -27,6 +28,11 @@
}
}
public void Write(Stream stream)
{
throw new NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState
{
using System.IO;
using Content;
internal class Push : IGraphicsStateOperation
@@ -22,5 +23,10 @@
{
context.PushState();
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations
{
using System.IO;
using Content;
internal class StrokePath : IGraphicsStateOperation
@@ -18,6 +19,11 @@
{
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextObjects
{
using System.IO;
using Content;
using PdfPig.Core;
@@ -20,6 +21,12 @@
operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Identity;
}
public void Write(Stream stream)
{
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextObjects
{
using System.IO;
using Content;
using PdfPig.Core;
@@ -20,6 +21,12 @@
operationContext.TextMatrices.TextLineMatrix = TransformationMatrix.Identity;
}
public void Write(Stream stream)
{
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning
{
using System.IO;
using Content;
/// <summary>
@@ -27,6 +28,11 @@
tdOperation.Run(operationContext, resourceStore);
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return Symbol;

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning
{
using System.IO;
using Content;
using PdfPig.Core;
@@ -40,6 +41,16 @@
operationContext.TextMatrices.TextMatrix = transformed;
}
public void Write(Stream stream)
{
stream.WriteDecimal(Tx);
stream.WriteWhiteSpace();
stream.WriteDecimal(Ty);
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return $"{Tx} {Ty} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning
{
using System.IO;
using Content;
using TextState;
@@ -30,6 +31,11 @@
tdOperation.Run(operationContext, resourceStore);
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Tx} {Ty} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextPositioning
{
using System;
using System.IO;
using Content;
using PdfPig.Core;
@@ -30,6 +31,11 @@
operationContext.TextMatrices.TextLineMatrix = newMatrix;
}
public void Write(Stream stream)
{
throw new NotImplementedException();
}
public override string ToString()
{
return $"{Value[0]} {Value[1]} {Value[2]} {Value[3]} {Value[4]} {Value[5]} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextShowing
{
using System.IO;
using Content;
using TextPositioning;
using Util.JetBrains.Annotations;
@@ -36,6 +37,11 @@
showText.Run(operationContext, resourceStore);
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Text} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextShowing
{
using System.IO;
using Content;
using TextPositioning;
using TextState;
@@ -48,6 +49,11 @@
showText.Run(operationContext, resourceStore);
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{WordSpacing} {CharacterSpacing} {Text} {Symbol}";

View File

@@ -1,5 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextShowing
{
using System;
using System.IO;
using Content;
using IO;
using Util;
@@ -50,6 +52,19 @@
operationContext.ShowText(input);
}
public void Write(Stream stream)
{
if (Text == null && Bytes != null)
{
throw new NotImplementedException("Support for writing hex not done yet.");
}
stream.WriteText($"({Text})");
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return $"{Text} {Symbol}";

View File

@@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.IO;
using Content;
using Tokens;
@@ -36,5 +37,10 @@
{
operationContext.ShowPositionedText(Array);
}
public void Write(Stream stream)
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
internal class SetCharacterSpacing : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.FontState.CharacterSpacing = Spacing;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Spacing} {Symbol}";

View File

@@ -1,6 +1,7 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System;
using System.IO;
using Content;
using Tokens;
using Util.JetBrains.Annotations;
@@ -37,6 +38,16 @@
currentState.FontState.FontName = Font;
}
public void Write(Stream stream)
{
stream.WriteText(Font.ToString());
stream.WriteWhiteSpace();
stream.WriteDecimal(Size);
stream.WriteWhiteSpace();
stream.WriteText(Symbol);
stream.WriteNewLine();
}
public override string ToString()
{
return $"{Font} {Size} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
internal class SetHorizontalScaling : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.FontState.HorizontalScaling = Scale;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Scale} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
internal class SetTextLeading : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.FontState.Leading = Leading;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Leading} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
using Core;
@@ -23,6 +24,11 @@
currentState.FontState.RenderingMode = Mode;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Mode} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
internal class SetTextRise : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.FontState.Rise = Rise;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Rise} {Symbol}";

View File

@@ -1,5 +1,6 @@
namespace UglyToad.PdfPig.Graphics.Operations.TextState
{
using System.IO;
using Content;
internal class SetWordSpacing : IGraphicsStateOperation
@@ -22,6 +23,11 @@
currentState.FontState.WordSpacing = Spacing;
}
public void Write(Stream stream)
{
throw new System.NotImplementedException();
}
public override string ToString()
{
return $"{Spacing} {Symbol}";

View File

@@ -0,0 +1,15 @@
namespace UglyToad.PdfPig.Writer
{
using System.Collections.Generic;
using Geometry;
using Tokens;
internal interface IWritingFont
{
bool HasWidths { get; }
bool TryGetBoundingBox(char character, out PdfRectangle boundingBox);
IReadOnlyDictionary<IToken, IToken> GetDictionary(NameToken fontKeyName);
}
}

View File

@@ -5,12 +5,15 @@
using System.IO;
using System.Linq;
using Content;
using Fonts;
using Fonts.TrueType;
using Fonts.TrueType.Parser;
using Geometry;
using Graphics.Operations;
using IO;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
internal class PdfDocumentBuilder
{
@@ -21,7 +24,7 @@
private readonly Dictionary<Guid, FontStored> fonts = new Dictionary<Guid, FontStored>();
public IReadOnlyDictionary<int, PdfPageBuilder> Pages => pages;
public IReadOnlyDictionary<Guid, TrueTypeFontProgram> Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram);
public IReadOnlyDictionary<Guid, IWritingFont> Fonts => fonts.ToDictionary(x => x.Key, x => x.Value.FontProgram);
public AddedFont AddTrueTypeFont(IReadOnlyList<byte> fontFileBytes)
{
@@ -31,7 +34,7 @@
var id = Guid.NewGuid();
var i = fonts.Count;
var added = new AddedFont(id, NameToken.Create($"F{i}"));
fonts[id] = new FontStored(added, font);
fonts[id] = new FontStored(added, new TrueTypeWritingFont(font));
return added;
}
@@ -41,6 +44,16 @@
}
}
public AddedFont AddStandard14Font(Standard14Font type)
{
var id = Guid.NewGuid();
var name = NameToken.Create($"F{fonts.Count}");
var added = new AddedFont(id, name);
fonts[id] = new FontStored(added, new Standard14WritingFont(Standard14.GetAdobeFontMetrics(type)));
return added;
}
public PdfPageBuilder AddPage(PageSize size, bool isPortrait = true)
{
if (!size.TryGetPdfRectangle(out var rectangle))
@@ -97,22 +110,12 @@
// Body
foreach (var font in fonts)
{
var widths = new ArrayToken(new[] { new NumericToken(0), new NumericToken(255) });
var widthsObj = WriteObject(widths, memory, objectLocations, ref number);
var fontDictionary = font.Value.FontProgram.GetDictionary(font.Value.FontKey.Name);
// TODO
// var descriptorRef = new IndirectReference(number++, 0);
var dictionary = new DictionaryToken(new Dictionary<IToken, IToken>
{
{ NameToken.Type, NameToken.Font },
{ NameToken.Subtype, NameToken.TrueType },
{ NameToken.FirstChar, new NumericToken(0) },
{ NameToken.LastChar, new NumericToken(255) },
{ NameToken.Encoding, NameToken.WinAnsiEncoding },
{ NameToken.Widths, widthsObj },
//{ NameToken.FontDesc, new IndirectReferenceToken(descriptorRef) }
});
var dictionary = new DictionaryToken(fontDictionary);
var fontObj = WriteObject(dictionary, memory, objectLocations, ref number);
fontsWritten.Add(font.Key, fontObj);
@@ -133,22 +136,37 @@
resources.Add(NameToken.Font, new IndirectReferenceToken(fontsDictionaryRef.Number));
}
var page = new DictionaryToken(new Dictionary<IToken, IToken>
var pageReferences = new List<IndirectReferenceToken>();
foreach (var page in pages)
{
{ NameToken.Type, NameToken.Page },
var pageDictionary = new Dictionary<IToken, IToken>
{
NameToken.Resources,
new DictionaryToken(resources)
},
{ NameToken.MediaBox, RectangleToArray(pages[1].PageSize) }
});
{NameToken.Type, NameToken.Page},
{
NameToken.Resources,
new DictionaryToken(resources)
},
{NameToken.MediaBox, RectangleToArray(page.Value.PageSize)}
};
var pageRef = WriteObject(page, memory, objectLocations, ref number);
if (page.Value.Operations.Count > 0)
{
var contentStream = WriteContentStream(page.Value.Operations);
var contentStreamObj = WriteObject(contentStream, memory, objectLocations, ref number);
pageDictionary[NameToken.Contents] = new IndirectReferenceToken(contentStreamObj.Number);
}
var pageRef = WriteObject(new DictionaryToken(pageDictionary), memory, objectLocations, ref number);
pageReferences.Add(new IndirectReferenceToken(pageRef.Number));
}
var pagesDictionary = new DictionaryToken(new Dictionary<IToken, IToken>
{
{ NameToken.Type, NameToken.Pages },
{ NameToken.Kids, new ArrayToken(new [] { new IndirectReferenceToken(pageRef.Number) }) },
{ NameToken.Kids, new ArrayToken(pageReferences) },
{ NameToken.Count, new NumericToken(1) }
});
@@ -168,6 +186,28 @@
}
}
private static StreamToken WriteContentStream(IReadOnlyList<IGraphicsStateOperation> content)
{
using (var memoryStream = new MemoryStream())
{
foreach (var operation in content)
{
operation.Write(memoryStream);
}
var bytes = memoryStream.ToArray();
var streamDictionary = new Dictionary<IToken, IToken>
{
{ NameToken.Length, new NumericToken(bytes.Length) }
};
var stream = new StreamToken(new DictionaryToken(streamDictionary), bytes);
return stream;
}
}
private static ArrayToken RectangleToArray(PdfRectangle rectangle)
{
return new ArrayToken(new[]
@@ -201,14 +241,16 @@
internal class FontStored
{
[NotNull]
public AddedFont FontKey { get; }
public TrueTypeFontProgram FontProgram { get; }
[NotNull]
public IWritingFont FontProgram { get; }
public FontStored(AddedFont fontKey, TrueTypeFontProgram fontProgram)
public FontStored(AddedFont fontKey, IWritingFont fontProgram)
{
FontKey = fontKey;
FontProgram = fontProgram;
FontKey = fontKey ?? throw new ArgumentNullException(nameof(fontKey));
FontProgram = fontProgram ?? throw new ArgumentNullException(nameof(fontProgram));
}
}
@@ -225,5 +267,4 @@
}
}
}
}

View File

@@ -8,6 +8,7 @@
using Graphics.Operations;
using Graphics.Operations.SpecialGraphicsState;
using Graphics.Operations.TextObjects;
using Graphics.Operations.TextPositioning;
using Graphics.Operations.TextShowing;
using Graphics.Operations.TextState;
@@ -59,24 +60,18 @@
try
{
var ctm = TransformationMatrix.FromValues(position.X, 0, position.Y, 0, 0, 0);
var realWidth = ctm.Transform(widthRect).Width;
var realWidth = widthRect.Width;
if (realWidth + position.X > PageSize.Width)
{
throw new InvalidOperationException("Text would exceed the bounds.");
}
operations.Add(new ModifyCurrentTransformationMatrix(new[]
{
position.X, 0, position.Y, 0, 0, 0
}));
var beginText = BeginText.Value;
operations.Add(beginText);
operations.Add(new SetFontAndSize(font.Name, fontSize));
operations.Add(new MoveToNextLineWithOffset(position.X, position.Y));
operations.Add(new ShowText(text));
operations.Add(EndText.Value);
@@ -90,7 +85,7 @@
return this;
}
private static decimal CalculateGlyphSpaceTextWidth(string text, TrueTypeFontProgram font)
private static decimal CalculateGlyphSpaceTextWidth(string text, IWritingFont font)
{
var width = 0m;
for (var i = 0; i < text.Length; i++)

View File

@@ -0,0 +1,47 @@
namespace UglyToad.PdfPig.Writer
{
using System.Collections.Generic;
using Fonts;
using Fonts.Encodings;
using Geometry;
using Tokens;
internal class Standard14WritingFont : IWritingFont
{
private readonly FontMetrics metrics;
public bool HasWidths { get; } = false;
public Standard14WritingFont(FontMetrics metrics)
{
this.metrics = metrics;
}
public bool TryGetBoundingBox(char character, out PdfRectangle boundingBox)
{
var encoding = StandardEncoding.Instance;
boundingBox = default(PdfRectangle);
if (!metrics.CharacterMetrics.TryGetValue(encoding.GetName(character), out var characterMetric))
{
return false;
}
boundingBox = new PdfRectangle(characterMetric.BoundingBox.Left, characterMetric.BoundingBox.Bottom,
characterMetric.BoundingBox.Left + characterMetric.WidthX, characterMetric.BoundingBox.Top);
return true;
}
public IReadOnlyDictionary<IToken, IToken> GetDictionary(NameToken fontKeyName)
{
return new Dictionary<IToken, IToken>
{
{ NameToken.Type, NameToken.Font },
{ NameToken.Subtype, NameToken.Type1 },
{ NameToken.BaseFont, NameToken.Create(metrics.FontName) },
{ NameToken.Encoding, NameToken.MacRomanEncoding },
{ NameToken.Name, fontKeyName }
};
}
}
}

View File

@@ -36,6 +36,9 @@
private static readonly byte[] StartXref = OtherEncodings.StringAsLatin1Bytes("startxref");
private static readonly byte[] StreamStart = OtherEncodings.StringAsLatin1Bytes("stream");
private static readonly byte[] StreamEnd = OtherEncodings.StringAsLatin1Bytes("endstream");
private static readonly byte StringStart = GetByte("(");
private static readonly byte StringEnd = GetByte(")");
@@ -81,8 +84,9 @@
case ObjectToken objectToken:
WriteObject(objectToken, outputStream);
break;
case StreamToken _:
throw new NotImplementedException();
case StreamToken streamToken:
WriteStream(streamToken, outputStream);
break;
case StringToken stringToken:
WriteString(stringToken, outputStream);
break;
@@ -268,6 +272,17 @@
WriteLineBreak(outputStream);
}
private static void WriteStream(StreamToken streamToken, Stream outputStream)
{
WriteDictionary(streamToken.StreamDictionary, outputStream);
WriteLineBreak(outputStream);
outputStream.Write(StreamStart, 0, StreamStart.Length);
WriteLineBreak(outputStream);
outputStream.Write(streamToken.Data.ToArray(), 0, streamToken.Data.Count);
WriteLineBreak(outputStream);
outputStream.Write(StreamEnd, 0, StreamEnd.Length);
}
private static void WriteString(StringToken stringToken, Stream outputStream)
{
outputStream.WriteByte(StringStart);

View File

@@ -0,0 +1,33 @@
namespace UglyToad.PdfPig.Writer
{
using System.Collections.Generic;
using Fonts.TrueType;
using Geometry;
using Tokens;
internal class TrueTypeWritingFont : IWritingFont
{
private readonly TrueTypeFontProgram font;
public TrueTypeWritingFont(TrueTypeFontProgram font)
{
this.font = font;
}
public bool HasWidths { get; } = true;
public bool TryGetBoundingBox(char character, out PdfRectangle boundingBox)
{
return font.TryGetBoundingBox(character, out boundingBox);
}
public IReadOnlyDictionary<IToken, IToken> GetDictionary(NameToken fontKeyName)
{
return new Dictionary<IToken, IToken>
{
{ NameToken.Type, NameToken.Font },
{ NameToken.Subtype, NameToken.TrueType }
};
}
}
}