mirror of
https://github.com/UglyToad/PdfPig.git
synced 2025-04-05 20:55:01 +08:00
Improve Jpeg2000Helper to support J2K codec and add test
This commit is contained in:
parent
a4a0fe220a
commit
204f488ebf
@ -2,12 +2,13 @@
|
||||
{
|
||||
using PdfPig.Images;
|
||||
using System;
|
||||
using UglyToad.PdfPig.Tests.Integration;
|
||||
|
||||
public class Jpeg2000HelperTests
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -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]
|
||||
public void GetJp2BitsPerComponent_ThrowsException_WhenInputIsTooShort()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetJp2BitsPerComponent(new byte[11]));
|
||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetBitsPerComponent(new byte[11]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetJp2BitsPerComponent_ThrowsException_WhenSignatureBoxIsInvalid()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetJp2BitsPerComponent(new byte[12]));
|
||||
Assert.Throws<InvalidOperationException>(() => Jpeg2000Helper.GetBitsPerComponent(new byte[12]));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GetAllDocuments))]
|
||||
public void GetJp2BitsPerComponent_ReturnsCorrectBitsPerComponent_WhenValidInput(string path)
|
||||
[Fact]
|
||||
public void GetJp2BitsPerComponentJ2K()
|
||||
{
|
||||
byte[] image = File.ReadAllBytes(Path.Combine(DocumentFolder.Value, path));
|
||||
Assert.Equal(8, Jpeg2000Helper.GetJp2BitsPerComponent(image));
|
||||
string path = IntegrationHelpers.GetSpecificTestDocumentPath("GHOSTSCRIPT-688999-2.pdf");
|
||||
|
||||
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.
@ -8,7 +8,7 @@
|
||||
/// <summary>
|
||||
/// Get bits per component values for Jp2 (Jpx) encoded images (first component).
|
||||
/// </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
|
||||
if (jp2Bytes.Length < 12)
|
||||
@ -18,16 +18,21 @@
|
||||
|
||||
// Verify the JP2 signature box
|
||||
uint length = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(0, 4));
|
||||
uint type = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(4, 4));
|
||||
uint magic = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(8, 4));
|
||||
|
||||
if (length != 0x0000000C || type != 0x6A502020 || magic != 0x0D0A870A)
|
||||
if (length == 0xFF4FFF51)
|
||||
{
|
||||
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
|
||||
return ParseBoxes(jp2Bytes.Slice(12));
|
||||
uint type = BinaryPrimitives.ReadUInt32BigEndian(jp2Bytes.Slice(4, 4));
|
||||
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)
|
||||
@ -37,7 +42,7 @@
|
||||
{
|
||||
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
|
||||
@ -55,7 +60,7 @@
|
||||
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)
|
||||
|
@ -60,11 +60,11 @@
|
||||
if (dictionary.TryGet(NameToken.BitsPerComponent, out NumericToken? bitsPerComponentToken))
|
||||
{
|
||||
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
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user