General support for extraction of images with BitsPerComponent < 8

This commit is contained in:
Kasper Frank
2021-05-11 10:06:17 +02:00
parent 92a00782bf
commit a56be02cfd
2 changed files with 45 additions and 30 deletions

View File

@@ -28,48 +28,64 @@
if (details == null) if (details == null)
{ {
return decoded.ToArray(); return decoded.ToArray();
}
if (bitsPerComponent != 8)
{
// Unpack components such that they occupy one byte each
decoded = UnpackComponents(decoded, bitsPerComponent);
}
// Remove padding bytes when the stride width differs from the image width
var bytesPerPixel = details is IndexedColorSpaceDetails ? 1 : GetBytesPerPixel(details);
var strideWidth = decoded.Count / imageHeight / bytesPerPixel;
if (strideWidth != imageWidth)
{
decoded = RemoveStridePadding(decoded.ToArray(), strideWidth, imageWidth, imageHeight, bytesPerPixel);
} }
switch (details) // In case of indexed color space images, unwrap indices to actual pixel component values
if (details is IndexedColorSpaceDetails indexed)
{ {
case IndexedColorSpaceDetails indexed: decoded = UnwrapIndexedColorSpaceBytes(indexed, decoded);
if (bitsPerComponent != 8)
{
// To ease unwrapping further below the indices are unpacked to occupy a single byte each
decoded = UnpackIndices(decoded, bitsPerComponent);
// Remove padding bytes when the stride width differs from the image width
var stride = (imageWidth * bitsPerComponent + 7) / 8;
var strideWidth = stride * (8 / bitsPerComponent);
if (strideWidth != imageWidth)
{
decoded = RemoveStridePadding(decoded.ToArray(), strideWidth, imageWidth, imageHeight);
}
}
return UnwrapIndexedColorSpaceBytes(indexed, decoded);
} }
return decoded.ToArray(); return decoded.ToArray();
} }
private static byte[] UnpackIndices(IReadOnlyList<byte> input, int bitsPerComponent) private static int GetBytesPerPixel(ColorSpaceDetails details)
{ {
IEnumerable<byte> Unpack(byte b) var colorSpace = (details is IndexedColorSpaceDetails indexed) ? indexed.BaseColorSpaceDetails.Type : details.Type;
switch (colorSpace)
{
case ColorSpace.DeviceRGB:
return 3;
case ColorSpace.DeviceCMYK:
return 4;
default:
return 1;
}
}
private static byte[] UnpackComponents(IReadOnlyList<byte> input, int bitsPerComponent)
{
IEnumerable<byte> Unpack(byte b)
{
// Enumerate bits in bitsPerComponent-sized chunks from MSB to LSB, masking on the appropriate bits
for (int i = 8 - bitsPerComponent; i >= 0; i -= bitsPerComponent)
{ {
// Enumerate bits in bitsPerComponent-sized chunks from MSB to LSB, masking on the appropriate bits yield return (byte)((b >> i) & ((int)Math.Pow(2, bitsPerComponent) - 1));
for (int i = 8 - bitsPerComponent; i >= 0; i -= bitsPerComponent)
{
yield return (byte)((b >> i) & ((int)Math.Pow(2, bitsPerComponent) - 1));
}
} }
}
return input.SelectMany(b => Unpack(b)).ToArray();
return input.SelectMany(b => Unpack(b)).ToArray();
} }
private static byte[] RemoveStridePadding(byte[] input, int strideWidth, int imageWidth, int imageHeight) private static byte[] RemoveStridePadding(byte[] input, int strideWidth, int imageWidth, int imageHeight, int multiplier)
{ {
var result = new byte[imageWidth * imageHeight]; var result = new byte[imageWidth * imageHeight * multiplier];
for (int y = 0; y < imageHeight; y++) for (int y = 0; y < imageHeight; y++)
{ {
int sourceIndex = y * strideWidth; int sourceIndex = y * strideWidth;

View File

@@ -2,7 +2,6 @@
{ {
using Content; using Content;
using Graphics.Colors; using Graphics.Colors;
using System.Collections.Generic;
using UglyToad.PdfPig.Core; using UglyToad.PdfPig.Core;
internal static class PngFromPdfImageFactory internal static class PngFromPdfImageFactory