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)
{
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:
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);
decoded = UnwrapIndexedColorSpaceBytes(indexed, decoded);
}
return decoded.ToArray();
}
private static byte[] UnpackIndices(IReadOnlyList<byte> input, int bitsPerComponent)
{
IEnumerable<byte> Unpack(byte b)
private static int GetBytesPerPixel(ColorSpaceDetails details)
{
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
for (int i = 8 - bitsPerComponent; i >= 0; i -= bitsPerComponent)
{
yield return (byte)((b >> i) & ((int)Math.Pow(2, bitsPerComponent) - 1));
}
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++)
{
int sourceIndex = y * strideWidth;

View File

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