mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0754e7f003 | ||
![]() |
306642a234 | ||
![]() |
204f488ebf | ||
![]() |
a4a0fe220a |
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
{
|
{
|
||||||
using PdfPig.Images;
|
using PdfPig.Images;
|
||||||
using System;
|
using System;
|
||||||
|
using UglyToad.PdfPig.Tests.Integration;
|
||||||
|
|
||||||
public class Jpeg2000HelperTests
|
public class Jpeg2000HelperTests
|
||||||
{
|
{
|
||||||
private static readonly Lazy<string> DocumentFolder = new Lazy<string>(() => Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "Images", "Files", "Jpx")));
|
private static readonly Lazy<string> DocumentFolder = new Lazy<string>(() => Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "Images", "Files", "Jpx")));
|
||||||
|
|
||||||
public static IEnumerable<object[]> GetAllDocuments
|
public static IEnumerable<object[]> GetAllJp2Files
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -15,24 +16,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(GetAllJp2Files))]
|
||||||
|
public void GetJp2BitsPerComponent_ReturnsCorrectBitsPerComponent_WhenValidInput(string path)
|
||||||
|
{
|
||||||
|
byte[] image = File.ReadAllBytes(Path.Combine(DocumentFolder.Value, path));
|
||||||
|
Assert.Equal(8, Jpeg2000Helper.GetBitsPerComponent(image));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetJp2BitsPerComponent_ThrowsException_WhenInputIsTooShort()
|
public void GetJp2BitsPerComponent_ThrowsException_WhenInputIsTooShort()
|
||||||
{
|
{
|
||||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetJp2BitsPerComponent(new byte[11]));
|
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetBitsPerComponent(new byte[11]));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetJp2BitsPerComponent_ThrowsException_WhenSignatureBoxIsInvalid()
|
public void GetJp2BitsPerComponent_ThrowsException_WhenSignatureBoxIsInvalid()
|
||||||
{
|
{
|
||||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetJp2BitsPerComponent(new byte[12]));
|
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetBitsPerComponent(new byte[12]));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[MemberData(nameof(GetAllDocuments))]
|
public void GetJp2BitsPerComponentJ2K()
|
||||||
public void GetJp2BitsPerComponent_ReturnsCorrectBitsPerComponent_WhenValidInput(string path)
|
|
||||||
{
|
{
|
||||||
byte[] image = File.ReadAllBytes(Path.Combine(DocumentFolder.Value, path));
|
string path = IntegrationHelpers.GetSpecificTestDocumentPath("GHOSTSCRIPT-688999-2.pdf");
|
||||||
Assert.Equal(8, Jpeg2000Helper.GetJp2BitsPerComponent(image));
|
|
||||||
|
using (var document = PdfDocument.Open(path))
|
||||||
|
{
|
||||||
|
var page1 = document.GetPage(1);
|
||||||
|
var jpxImage = page1.GetImages().Single();
|
||||||
|
|
||||||
|
var bpc = Jpeg2000Helper.GetBitsPerComponent(jpxImage.RawBytes);
|
||||||
|
|
||||||
|
Assert.Equal(8, bpc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -231,6 +231,11 @@
|
|||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
|
||||||
|
{
|
||||||
|
// No op
|
||||||
|
}
|
||||||
|
|
||||||
public override void PaintShading(NameToken shadingName)
|
public override void PaintShading(NameToken shadingName)
|
||||||
{
|
{
|
||||||
// No op
|
// No op
|
||||||
|
@ -206,6 +206,11 @@
|
|||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
|
||||||
|
{
|
||||||
|
// No op
|
||||||
|
}
|
||||||
|
|
||||||
public override void PaintShading(NameToken shadingName)
|
public override void PaintShading(NameToken shadingName)
|
||||||
{
|
{
|
||||||
// No op
|
// No op
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -381,6 +381,19 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PdfRectangle
|
#region PdfRectangle
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a <see cref="PdfRectangle"/> into its <see cref="PdfPath"/> representation.
|
||||||
|
/// </summary>
|
||||||
|
public static PdfPath ToPdfPath(this PdfRectangle rectangle)
|
||||||
|
{
|
||||||
|
var clippingSubpath = new PdfSubpath();
|
||||||
|
clippingSubpath.Rectangle(rectangle.BottomLeft.X,
|
||||||
|
rectangle.BottomLeft.Y,
|
||||||
|
rectangle.Width,
|
||||||
|
rectangle.Height);
|
||||||
|
return new PdfPath() { clippingSubpath };
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the point is located inside the rectangle.
|
/// Whether the point is located inside the rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -145,15 +145,8 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected static PdfPath GetInitialClipping(CropBox cropBox)
|
protected static PdfPath GetInitialClipping(CropBox cropBox)
|
||||||
{
|
{
|
||||||
var cropBoxBounds = cropBox.Bounds;
|
// Initiate CurrentClippingPath to cropBox
|
||||||
|
var clippingPath = cropBox.Bounds.ToPdfPath();
|
||||||
// initiate CurrentClippingPath to cropBox
|
|
||||||
var clippingSubpath = new PdfSubpath();
|
|
||||||
clippingSubpath.Rectangle(cropBoxBounds.BottomLeft.X,
|
|
||||||
cropBoxBounds.BottomLeft.Y,
|
|
||||||
cropBoxBounds.Width,
|
|
||||||
cropBoxBounds.Height);
|
|
||||||
var clippingPath = new PdfPath() { clippingSubpath };
|
|
||||||
clippingPath.SetClipping(FillingRule.EvenOdd);
|
clippingPath.SetClipping(FillingRule.EvenOdd);
|
||||||
return clippingPath;
|
return clippingPath;
|
||||||
}
|
}
|
||||||
@ -581,7 +574,14 @@
|
|||||||
new MemoryInputBytes(contentStream),
|
new MemoryInputBytes(contentStream),
|
||||||
ParsingOptions.Logger);
|
ParsingOptions.Logger);
|
||||||
|
|
||||||
// 3. We don't respect clipping currently.
|
// 3. Clip according to the form dictionary's BBox entry.
|
||||||
|
if (formStream.StreamDictionary.TryGet<ArrayToken>(NameToken.Bbox, PdfScanner, out var bboxToken))
|
||||||
|
{
|
||||||
|
var points = bboxToken.Data.OfType<NumericToken>().Select(x => x.Double).ToArray();
|
||||||
|
PdfRectangle bbox = new PdfRectangle(points[0], points[1], points[2], points[3]);
|
||||||
|
PdfRectangle transformedBox = startState.CurrentTransformationMatrix.Transform(bbox);
|
||||||
|
ClipToRectangle(transformedBox, FillingRule.EvenOdd); // TODO - Check that Even Odd is valid
|
||||||
|
}
|
||||||
|
|
||||||
// 4. Paint the objects.
|
// 4. Paint the objects.
|
||||||
bool hasCircularReference = HasFormXObjectCircularReference(formStream, xObjectName, operations);
|
bool hasCircularReference = HasFormXObjectCircularReference(formStream, xObjectName, operations);
|
||||||
@ -668,6 +668,9 @@
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract void ModifyClippingIntersect(FillingRule clippingRule);
|
public abstract void ModifyClippingIntersect(FillingRule clippingRule);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
protected abstract void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public virtual void SetNamedGraphicsState(NameToken stateName)
|
public virtual void SetNamedGraphicsState(NameToken stateName)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,6 @@ namespace UglyToad.PdfPig.Graphics
|
|||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Colors;
|
|
||||||
using Content;
|
using Content;
|
||||||
using Filters;
|
using Filters;
|
||||||
using Geometry;
|
using Geometry;
|
||||||
@ -212,7 +211,7 @@ namespace UglyToad.PdfPig.Graphics
|
|||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddCurrentSubpath() // Not an override
|
private void AddCurrentSubpath()
|
||||||
{
|
{
|
||||||
if (CurrentSubpath is null)
|
if (CurrentSubpath is null)
|
||||||
{
|
{
|
||||||
@ -385,16 +384,12 @@ namespace UglyToad.PdfPig.Graphics
|
|||||||
var currentState = GetCurrentState();
|
var currentState = GetCurrentState();
|
||||||
if (CurrentPath.IsStroked)
|
if (CurrentPath.IsStroked)
|
||||||
{
|
{
|
||||||
CurrentPath.LineDashPattern = currentState.LineDashPattern;
|
CurrentPath.SetStrokeDetails(currentState);
|
||||||
CurrentPath.StrokeColor = currentState.CurrentStrokingColor;
|
|
||||||
CurrentPath.LineWidth = currentState.LineWidth;
|
|
||||||
CurrentPath.LineCapStyle = currentState.CapStyle;
|
|
||||||
CurrentPath.LineJoinStyle = currentState.JoinStyle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentPath.IsFilled)
|
if (CurrentPath.IsFilled)
|
||||||
{
|
{
|
||||||
CurrentPath.FillColor = currentState.CurrentNonStrokingColor;
|
CurrentPath.SetFillDetails(currentState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ParsingOptions.ClipPaths)
|
if (ParsingOptions.ClipPaths)
|
||||||
@ -427,7 +422,8 @@ namespace UglyToad.PdfPig.Graphics
|
|||||||
|
|
||||||
if (ParsingOptions.ClipPaths)
|
if (ParsingOptions.ClipPaths)
|
||||||
{
|
{
|
||||||
var currentClipping = GetCurrentState().CurrentClippingPath!;
|
var graphicsState = GetCurrentState();
|
||||||
|
var currentClipping = graphicsState.CurrentClippingPath!;
|
||||||
currentClipping.SetClipping(clippingRule);
|
currentClipping.SetClipping(clippingRule);
|
||||||
|
|
||||||
var newClippings = CurrentPath.Clip(currentClipping, ParsingOptions.Logger);
|
var newClippings = CurrentPath.Clip(currentClipping, ParsingOptions.Logger);
|
||||||
@ -437,11 +433,32 @@ namespace UglyToad.PdfPig.Graphics
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GetCurrentState().CurrentClippingPath = newClippings;
|
graphicsState.CurrentClippingPath = newClippings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void ClipToRectangle(PdfRectangle rectangle, FillingRule clippingRule)
|
||||||
|
{
|
||||||
|
// https://github.com/apache/pdfbox/blob/f4bfe47de37f6fe69e8f98b164c3546facfd5e91/pdfbox/src/main/java/org/apache/pdfbox/contentstream/PDFStreamEngine.java#L611
|
||||||
|
var graphicsState = GetCurrentState();
|
||||||
|
var clip = rectangle.ToPdfPath();
|
||||||
|
clip.SetClipping(clippingRule);
|
||||||
|
|
||||||
|
var currentClipping = graphicsState.CurrentClippingPath!;
|
||||||
|
currentClipping.SetClipping(clippingRule);
|
||||||
|
var newClippings = clip.Clip(currentClipping, ParsingOptions.Logger);
|
||||||
|
|
||||||
|
if (newClippings is null)
|
||||||
|
{
|
||||||
|
ParsingOptions.Logger.Warn("Empty clipping path found. Clipping path not updated.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
graphicsState.CurrentClippingPath = newClippings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void RenderInlineImage(InlineImage inlineImage)
|
protected override void RenderInlineImage(InlineImage inlineImage)
|
||||||
{
|
{
|
||||||
images.Add(Union<XObjectContentRecord, InlineImage>.Two(inlineImage));
|
images.Add(Union<XObjectContentRecord, InlineImage>.Two(inlineImage));
|
||||||
|
@ -6,7 +6,9 @@
|
|||||||
using UglyToad.PdfPig.Graphics.Core;
|
using UglyToad.PdfPig.Graphics.Core;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A path is made up of one or more disconnected subpaths, each comprising a sequence of connected segments. The topology of the path is unrestricted: it may be concave or convex, may contain multiple subpaths representing disjoint areas, and may intersect itself in arbitrary ways.
|
/// A path is made up of one or more disconnected subpaths, each comprising a sequence of connected segments.
|
||||||
|
/// The topology of the path is unrestricted: it may be concave or convex, may contain multiple subpaths representing
|
||||||
|
/// disjoint areas, and may intersect itself in arbitrary ways.
|
||||||
/// <para>A path shall be composed of straight and curved line segments, which may connect to one another or may be disconnected.</para>
|
/// <para>A path shall be composed of straight and curved line segments, which may connect to one another or may be disconnected.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PdfPath : List<PdfSubpath>
|
public class PdfPath : List<PdfSubpath>
|
||||||
@ -29,7 +31,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The fill color.
|
/// The fill color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IColor? FillColor { get; internal set; }
|
public IColor? FillColor { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the path is stroked.
|
/// Returns true if the path is stroked.
|
||||||
@ -39,31 +41,31 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The stroke color.
|
/// The stroke color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IColor? StrokeColor { get; internal set; }
|
public IColor? StrokeColor { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thickness in user space units of path to be stroked.
|
/// Thickness in user space units of path to be stroked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double LineWidth { get; internal set; }
|
public double LineWidth { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pattern to be used for stroked lines.
|
/// The pattern to be used for stroked lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LineDashPattern? LineDashPattern { get; internal set; }
|
public LineDashPattern? LineDashPattern { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cap style to be used for stroked lines.
|
/// The cap style to be used for stroked lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LineCapStyle LineCapStyle { get; internal set; }
|
public LineCapStyle LineCapStyle { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The join style to be used for stroked lines.
|
/// The join style to be used for stroked lines.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public LineJoinStyle LineJoinStyle { get; internal set; }
|
public LineJoinStyle LineJoinStyle { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the clipping mode for this path and IsClipping to true.
|
/// Set the clipping mode for this path and <c>IsClipping</c> to <c>true</c>.
|
||||||
/// <para>IsFilled and IsStroked flags will be set to false.</para>
|
/// <para><c>IsFilled</c> and <c>IsStroked</c> flags will be set to <c>false</c>.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetClipping(FillingRule fillingRule)
|
public void SetClipping(FillingRule fillingRule)
|
||||||
{
|
{
|
||||||
@ -74,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set the filling rule for this path and IsFilled to true.
|
/// Set the filling rule for this path and <c>IsFilled</c> to <c>true</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetFilled(FillingRule fillingRule)
|
public void SetFilled(FillingRule fillingRule)
|
||||||
{
|
{
|
||||||
@ -83,13 +85,35 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set IsStroked to true.
|
/// Set <c>IsStroked</c> to <c>true</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetStroked()
|
public void SetStroked()
|
||||||
{
|
{
|
||||||
IsStroked = true;
|
IsStroked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the path stroke details, i.e. <c>LineDashPattern</c>, <c>StrokeColor</c>, <c>LineWidth</c>, <c>LineCapStyle</c> and <c>LineJoinStyle</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="graphicsState">The current graphics state.</param>
|
||||||
|
public void SetStrokeDetails(CurrentGraphicsState graphicsState)
|
||||||
|
{
|
||||||
|
LineDashPattern = graphicsState.LineDashPattern;
|
||||||
|
StrokeColor = graphicsState.CurrentStrokingColor;
|
||||||
|
LineWidth = graphicsState.LineWidth;
|
||||||
|
LineCapStyle = graphicsState.CapStyle;
|
||||||
|
LineJoinStyle = graphicsState.JoinStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the path fill details, i.e. <c>FillColor</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="graphicsState">The current graphics state.</param>
|
||||||
|
public void SetFillDetails(CurrentGraphicsState graphicsState)
|
||||||
|
{
|
||||||
|
FillColor = graphicsState.CurrentNonStrokingColor;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a clone with no Subpaths.
|
/// Create a clone with no Subpaths.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get bits per component values for Jp2 (Jpx) encoded images (first component).
|
/// Get bits per component values for Jp2 (Jpx) encoded images (first component).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte GetJp2BitsPerComponent(ReadOnlySpan<byte> jp2Bytes)
|
public static byte GetBitsPerComponent(ReadOnlySpan<byte> jp2Bytes)
|
||||||
{
|
{
|
||||||
// Ensure the input has at least 12 bytes for the signature box
|
// Ensure the input has at least 12 bytes for the signature box
|
||||||
if (jp2Bytes.Length < 12)
|
if (jp2Bytes.Length < 12)
|
||||||
@ -18,16 +18,21 @@
|
|||||||
|
|
||||||
// Verify the JP2 signature box
|
// Verify the JP2 signature box
|
||||||
uint length = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(0, 4));
|
uint length = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(0, 4));
|
||||||
uint type = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(4, 4));
|
if (length == 0xFF4FFF51)
|
||||||
uint magic = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(8, 4));
|
|
||||||
|
|
||||||
if (length != 0x0000000C || type != 0x6A502020 || magic != 0x0D0A870A)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid JP2 signature box.");
|
// J2K format detected (SOC marker) (See GHOSTSCRIPT-688999-2.pdf)
|
||||||
|
return ParseCodestream(jp2Bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proceed to parse JP2 boxes
|
uint type = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(4, 4));
|
||||||
return ParseBoxes(jp2Bytes.Slice(12));
|
uint magic = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(8, 4));
|
||||||
|
if (length == 0x0000000C && type == 0x6A502020 && magic == 0x0D0A870A)
|
||||||
|
{
|
||||||
|
// JP2 format detected
|
||||||
|
return ParseBoxes(jp2Bytes.Slice(12));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Invalid JP2 or J2K signature.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte ParseBoxes(ReadOnlySpan<byte> jp2Bytes)
|
private static byte ParseBoxes(ReadOnlySpan<byte> jp2Bytes)
|
||||||
@ -37,7 +42,7 @@
|
|||||||
{
|
{
|
||||||
if (offset + 8 > jp2Bytes.Length)
|
if (offset + 8 > jp2Bytes.Length)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Invalid JP2 box structure.");
|
throw new InvalidOperationException("Invalid JP2 or J2K box structure.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read box length and type
|
// Read box length and type
|
||||||
@ -55,7 +60,7 @@
|
|||||||
offset += (int)(boxLength > 0 ? boxLength : 8); // Box length of 0 means the rest of the file
|
offset += (int)(boxLength > 0 ? boxLength : 8); // Box length of 0 means the rest of the file
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidOperationException("Codestream box not found in JP2 file.");
|
throw new InvalidOperationException("Codestream box not found in JP2 or J2K file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte ParseCodestream(ReadOnlySpan<byte> codestream)
|
private static byte ParseCodestream(ReadOnlySpan<byte> codestream)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
<TargetFrameworks>netstandard2.0;net462;net471;net6.0;net8.0</TargetFrameworks>
|
||||||
<LangVersion>12</LangVersion>
|
<LangVersion>12</LangVersion>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<IsTestProject>False</IsTestProject>
|
<IsTestProject>False</IsTestProject>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<SignAssembly>true</SignAssembly>
|
<SignAssembly>true</SignAssembly>
|
||||||
|
@ -60,11 +60,11 @@
|
|||||||
if (dictionary.TryGet(NameToken.BitsPerComponent, out NumericToken? bitsPerComponentToken))
|
if (dictionary.TryGet(NameToken.BitsPerComponent, out NumericToken? bitsPerComponentToken))
|
||||||
{
|
{
|
||||||
bitsPerComponent = bitsPerComponentToken.Int;
|
bitsPerComponent = bitsPerComponentToken.Int;
|
||||||
System.Diagnostics.Debug.Assert(bitsPerComponent == Jpeg2000Helper.GetJp2BitsPerComponent(xObject.Stream.Data.Span));
|
System.Diagnostics.Debug.Assert(bitsPerComponent == Jpeg2000Helper.GetBitsPerComponent(xObject.Stream.Data.Span));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bitsPerComponent = Jpeg2000Helper.GetJp2BitsPerComponent(xObject.Stream.Data.Span);
|
bitsPerComponent = Jpeg2000Helper.GetBitsPerComponent(xObject.Stream.Data.Span);
|
||||||
System.Diagnostics.Debug.Assert(new int[] { 1, 2, 4, 8, 16 }.Contains(bitsPerComponent));
|
System.Diagnostics.Debug.Assert(new int[] { 1, 2, 4, 8, 16 }.Contains(bitsPerComponent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<PackageTags>PDF;Reader;Document;Adobe;PDFBox;PdfPig;pdf-extract;pdf-to-text;pdf;file;text;C#;dotnet;.NET</PackageTags>
|
<PackageTags>PDF;Reader;Document;Adobe;PDFBox;PdfPig;pdf-extract;pdf-to-text;pdf;file;text;C#;dotnet;.NET</PackageTags>
|
||||||
<RepositoryUrl>https://github.com/UglyToad/PdfPig</RepositoryUrl>
|
<RepositoryUrl>https://github.com/UglyToad/PdfPig</RepositoryUrl>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<Version>0.1.10</Version>
|
<Version>0.1.11-alpha001</Version>
|
||||||
<AssemblyVersion>0.1.10.0</AssemblyVersion>
|
<AssemblyVersion>0.1.10.0</AssemblyVersion>
|
||||||
<FileVersion>0.1.10.0</FileVersion>
|
<FileVersion>0.1.10.0</FileVersion>
|
||||||
<PackageIconUrl>https://raw.githubusercontent.com/UglyToad/PdfPig/master/documentation/pdfpig.png</PackageIconUrl>
|
<PackageIconUrl>https://raw.githubusercontent.com/UglyToad/PdfPig/master/documentation/pdfpig.png</PackageIconUrl>
|
||||||
|
Loading…
Reference in New Issue
Block a user