diff --git a/src/UglyToad.PdfPig.Tests/Parser/PageContentParserTests.cs b/src/UglyToad.PdfPig.Tests/Parser/PageContentParserTests.cs
index 5cd05ebb..f6cef877 100644
--- a/src/UglyToad.PdfPig.Tests/Parser/PageContentParserTests.cs
+++ b/src/UglyToad.PdfPig.Tests/Parser/PageContentParserTests.cs
@@ -2,6 +2,7 @@
{
using System;
using System.IO;
+ using System.Text.RegularExpressions;
using PdfPig.Graphics;
using PdfPig.Graphics.Core;
using PdfPig.Graphics.Operations.General;
@@ -11,6 +12,7 @@
using PdfPig.Graphics.Operations.TextState;
using PdfPig.Parser;
using PdfPig.Tokens;
+ using PdfPig.Util;
using Xunit;
public class PageContentParserTests
@@ -29,6 +31,64 @@
Assert.NotEmpty(result);
}
+ [Fact]
+ public void CorrectlyWritesOperations()
+ {
+ var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Parser", "SimpleGoogleDocPageContent.txt");
+ var content = File.ReadAllText(path);
+ var input = StringBytesTestConverter.Convert(content, false);
+
+ var result = parser.Parse(input.Bytes);
+
+ var replacementRegex = new Regex(@"\s(\.\d+)\b");
+
+ using (var stream = new MemoryStream())
+ {
+ foreach (var operation in result)
+ {
+ operation.Write(stream);
+ }
+
+ var text = OtherEncodings.BytesAsLatin1String(stream.ToArray());
+
+ text = text.Replace("\n", " ");
+ content = content.Replace("\r\n", " ");
+ content = replacementRegex.Replace(content, " 0$1");
+
+ Assert.Equal(content, text);
+ }
+ }
+
+ [Fact]
+ public void CorrectlyWritesSmallTextContent()
+ {
+ const string s = @"BT
+/F13 48 Tf
+20 38 Td
+1 Tr
+2 w
+(ABC) Tj
+ET";
+ var input = StringBytesTestConverter.Convert(s, false);
+
+ var result = parser.Parse(input.Bytes);
+
+ using (var stream = new MemoryStream())
+ {
+ foreach (var operation in result)
+ {
+ operation.Write(stream);
+ }
+
+ var text = OtherEncodings.BytesAsLatin1String(stream.ToArray());
+
+ text = text.Replace("\n", " ").Trim();
+ var expected = s.Replace("\r\n", " ");
+
+ Assert.Equal(expected, text);
+ }
+ }
+
[Fact]
public void CorrectlyExtractsOptionsInTextContext()
{
diff --git a/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs b/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs
index 3b0e1884..8b3f2167 100644
--- a/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs
+++ b/src/UglyToad.PdfPig.Tests/PublicApiScannerTests.cs
@@ -92,6 +92,7 @@
"UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState.ModifyCurrentTransformationMatrix",
"UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState.Pop",
"UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState.Push",
+ "UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState.SetGraphicsStateParametersFromDictionary",
"UglyToad.PdfPig.Graphics.Operations.StrokePath",
"UglyToad.PdfPig.Graphics.Operations.TextObjects.BeginText",
"UglyToad.PdfPig.Graphics.Operations.TextObjects.EndText",
diff --git a/src/UglyToad.PdfPig/Content/Page.cs b/src/UglyToad.PdfPig/Content/Page.cs
index 3fdbddaa..c668bf7e 100644
--- a/src/UglyToad.PdfPig/Content/Page.cs
+++ b/src/UglyToad.PdfPig/Content/Page.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using Annotations;
+ using Graphics.Operations;
using Tokens;
using Util;
using Util.JetBrains.Annotations;
@@ -52,6 +53,11 @@
///
public PageSize Size { get; }
+ ///
+ /// The parsed graphics state operations in the content stream for this page.
+ ///
+ public IReadOnlyList Operations => Content.GraphicsStateOperations;
+
///
/// Access to members whose future locations within the API will change without warning.
///
diff --git a/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/SetGraphicsStateOperatorsFromDictionary.cs b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/SetGraphicsStateOperatorsFromDictionary.cs
new file mode 100644
index 00000000..40aaf41c
--- /dev/null
+++ b/src/UglyToad.PdfPig/Graphics/Operations/SpecialGraphicsState/SetGraphicsStateOperatorsFromDictionary.cs
@@ -0,0 +1,54 @@
+namespace UglyToad.PdfPig.Graphics.Operations.SpecialGraphicsState
+{
+ using System.IO;
+ using Tokens;
+
+ ///
+ ///
+ /// Set the specified parameters in the graphics state using the ExtGState subdictionary with the given name.
+ ///
+ public class SetGraphicsStateParametersFromDictionary : IGraphicsStateOperation
+ {
+ ///
+ /// The symbol for this operation in a stream.
+ ///
+ public const string Symbol = "gs";
+
+ ///
+ public string Operator => Symbol;
+
+ ///
+ /// The name of a graphics state parameter dictionary in the ExtGState subdictionary of the current resource dictionary.
+ ///
+ public NameToken Name { get; }
+
+ ///
+ /// Create a new .
+ ///
+ /// The name of the ExtGState dictionary.
+ public SetGraphicsStateParametersFromDictionary(NameToken name)
+ {
+ Name = name;
+ }
+
+ ///
+ public void Run(IOperationContext operationContext)
+ {
+ }
+
+ ///
+ public void Write(Stream stream)
+ {
+ stream.WriteText($"/{Name.Data}");
+ stream.WriteWhiteSpace();
+ stream.WriteText(Symbol);
+ stream.WriteNewLine();
+ }
+
+ ///
+ public override string ToString()
+ {
+ return $"{Name} {Symbol}";
+ }
+ }
+}