Browse Source

Fix decoding tiled tiff's with planar configuration

pull/2290/head
Brian Popow 3 years ago
parent
commit
c850e2d41b
  1. 125
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

125
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -520,65 +520,96 @@ internal class TiffDecoderCore : IImageDecoderInternals
int width = pixels.Width;
int height = pixels.Height;
int bitsPerPixel = this.BitsPerPixel;
int channels = this.BitsPerSample.Channels;
int tilesPerChannel = tileOffsets.Length / channels;
int bytesPerRow = ((width * bitsPerPixel) + 7) / 8;
int bytesPerTileRow = ((tileWidth * bitsPerPixel) + 7) / 8;
int uncompressedTilesSize = bytesPerTileRow * tileLength;
using IMemoryOwner<byte> tileBuffer = this.memoryAllocator.Allocate<byte>(uncompressedTilesSize, AllocationOptions.Clean);
using IMemoryOwner<byte> uncompressedPixelBuffer = this.memoryAllocator.Allocate<byte>(tilesDown * tileLength * bytesPerRow, AllocationOptions.Clean);
Span<byte> tileBufferSpan = tileBuffer.GetSpan();
Span<byte> uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan();
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
IMemoryOwner<byte>[] tilesBuffers = new IMemoryOwner<byte>[channels];
TiffBaseColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.Create(
this.configuration,
this.memoryAllocator,
this.ColorType,
this.BitsPerSample,
this.ExtraSamplesType,
this.ColorMap,
this.ReferenceBlackAndWhite,
this.YcbcrCoefficients,
this.YcbcrSubSampling,
this.byteOrder);
int tileIndex = 0;
for (int tileY = 0; tileY < tilesDown; tileY++)
try
{
int uncompressedPixelBufferOffset = tileY * tileLength * bytesPerRow;
int remainingPixelsInRow = width;
for (int tileX = 0; tileX < tilesAcross; tileX++)
int bytesPerTileRow = ((tileWidth * bitsPerPixel) + 7) / 8;
int uncompressedTilesSize = bytesPerTileRow * tileLength;
for (int i = 0; i < tilesBuffers.Length; i++)
{
cancellationToken.ThrowIfCancellationRequested();
tilesBuffers[i] = this.memoryAllocator.Allocate<byte>(uncompressedTilesSize, AllocationOptions.Clean);
}
bool isLastHorizontalTile = tileX == tilesAcross - 1;
using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
decompressor.Decompress(
this.inputStream,
tileOffsets[tileIndex],
tileByteCounts[tileIndex],
tileLength,
tileBufferSpan,
cancellationToken);
TiffBasePlanarColorDecoder<TPixel> colorDecoder = TiffColorDecoderFactory<TPixel>.CreatePlanar(
this.ColorType,
this.BitsPerSample,
this.ExtraSamplesType,
this.ColorMap,
this.ReferenceBlackAndWhite,
this.YcbcrCoefficients,
this.YcbcrSubSampling,
this.byteOrder);
int tileBufferOffset = 0;
uncompressedPixelBufferOffset += bytesPerTileRow * tileX;
int bytesToCopy = isLastHorizontalTile ? ((bitsPerPixel * remainingPixelsInRow) + 7) / 8 : bytesPerTileRow;
for (int y = 0; y < tileLength; y++)
int tileIndex = 0;
int remainingPixelsInColumn = height;
for (int tileY = 0; tileY < tilesDown; tileY++)
{
int remainingPixelsInRow = width;
int pixelColumnOffset = tileY * tileLength;
bool isLastVerticalTile = tileY == tilesDown - 1;
for (int tileX = 0; tileX < tilesAcross; tileX++)
{
Span<byte> uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy);
tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow);
tileBufferOffset += bytesPerTileRow;
uncompressedPixelBufferOffset += bytesPerRow;
int pixelRowOffset = tileX * tileWidth;
bool isLastHorizontalTile = tileX == tilesAcross - 1;
int tileIndexForChannel = tileIndex;
for (int i = 0; i < channels; i++)
{
cancellationToken.ThrowIfCancellationRequested();
decompressor.Decompress(
this.inputStream,
tileOffsets[tileIndexForChannel],
tileByteCounts[tileIndexForChannel],
tileLength,
tilesBuffers[i].GetSpan(),
cancellationToken);
tileIndexForChannel += tilesPerChannel;
}
if (isLastHorizontalTile && remainingPixelsInRow < tileWidth)
{
// Adjust pixel data in the tile buffer to fit the smaller then usual tile width.
for (int i = 0; i < channels; i++)
{
Span<byte> tileBufferSpan = tilesBuffers[i].GetSpan();
for (int y = 0; y < tileLength; y++)
{
int currentRowOffset = y * tileWidth;
Span<byte> adjustedRow = tileBufferSpan.Slice(y * remainingPixelsInRow, remainingPixelsInRow);
tileBufferSpan.Slice(currentRowOffset, remainingPixelsInRow).CopyTo(adjustedRow);
}
}
}
colorDecoder.Decode(
tilesBuffers,
pixels,
pixelRowOffset,
pixelColumnOffset,
isLastHorizontalTile ? remainingPixelsInRow : tileWidth,
isLastVerticalTile ? remainingPixelsInColumn : tileLength);
remainingPixelsInRow -= tileWidth;
tileIndex++;
}
remainingPixelsInRow -= tileWidth;
tileIndex++;
remainingPixelsInColumn -= tileLength;
}
}
finally
{
foreach (IMemoryOwner<byte> buf in tilesBuffers)
{
buf?.Dispose();
}
}
colorDecoder.Decode(uncompressedPixelBufferSpan, pixels, 0, 0, width, height);
}
/// <summary>

Loading…
Cancel
Save