Skip to content
Merged
14 changes: 4 additions & 10 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:

steps:
- name: Install libgdi+, which is required for tests running on ubuntu
if: ${{ matrix.options.os == 'buildjet-4vcpu-ubuntu-2204-arm' }}
if: ${{ contains(matrix.options.os, 'ubuntu') }}
run: sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev

- name: Git Config
Expand Down Expand Up @@ -108,18 +108,12 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-

- name: DotNet Setup
if: ${{ matrix.options.sdk-preview != true }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
6.0.x

- name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x

- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
runs-on: ${{matrix.options.os}}

steps:
- name: Install libgdi+, which is required for tests running on ubuntu
run: sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev

- name: Git Config
shell: bash
run: |
Expand Down Expand Up @@ -55,9 +58,11 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-

- name: DotNet Setup
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x

- name: DotNet Build
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Png/PngThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static void ThrowInvalidParameter(object value, string message, [CallerAr
=> throw new NotSupportedException($"Invalid {name}. {message}. Was '{value}'.");

[DoesNotReturn]
public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value1))] string name2 = "")
public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value2))] string name2 = "")
=> throw new NotSupportedException($"Invalid {name1} or {name2}. {message}. Was '{value1}' and '{value2}'.");

[DoesNotReturn]
Expand Down
31 changes: 14 additions & 17 deletions src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ private void DecodeTilesPlanar<TPixel>(
}

/// <summary>
/// Decodes the image data for Tiff's which arrange the pixel data in tiles and the chunky configuration.
/// Decodes the image data for TIFFs which arrange the pixel data in tiles and the chunky configuration.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="frame">The image frame to decode into.</param>
Expand All @@ -634,28 +634,26 @@ private void DecodeTilesChunky<TPixel>(
int width = pixels.Width;
int height = pixels.Height;
int bitsPerPixel = this.BitsPerPixel;

int bytesPerRow = RoundUpToMultipleOfEight(width * bitsPerPixel);
int bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth * bitsPerPixel);
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);

using IMemoryOwner<byte> tileBuffer = this.memoryAllocator.Allocate<byte>(bytesPerTileRow * tileLength, AllocationOptions.Clean);
Span<byte> tileBufferSpan = tileBuffer.GetSpan();
Span<byte> uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan();

using TiffBaseDecompressor decompressor = this.CreateDecompressor<TPixel>(frame.Width, bitsPerPixel);
TiffBaseColorDecoder<TPixel> colorDecoder = this.CreateChunkyColorDecoder<TPixel>();

int tileIndex = 0;
for (int tileY = 0; tileY < tilesDown; tileY++)
{
int remainingPixelsInRow = width;
int rowStartY = tileY * tileLength;
int rowEndY = Math.Min(rowStartY + tileLength, height);

for (int tileX = 0; tileX < tilesAcross; tileX++)
{
cancellationToken.ThrowIfCancellationRequested();

int uncompressedPixelBufferOffset = tileY * tileLength * bytesPerRow;
bool isLastHorizontalTile = tileX == tilesAcross - 1;
int remainingPixelsInRow = width - (tileX * tileWidth);

decompressor.Decompress(
this.inputStream,
Expand All @@ -666,22 +664,21 @@ private void DecodeTilesChunky<TPixel>(
cancellationToken);

int tileBufferOffset = 0;
uncompressedPixelBufferOffset += bytesPerTileRow * tileX;
int bytesToCopy = isLastHorizontalTile ? RoundUpToMultipleOfEight(bitsPerPixel * remainingPixelsInRow) : bytesPerTileRow;
for (int y = 0; y < tileLength; y++)
int rowWidth = Math.Min(tileWidth, remainingPixelsInRow);
int left = tileX * tileWidth;

for (int y = rowStartY; y < rowEndY; y++)
{
Span<byte> uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy);
tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow);
// Decode the tile row directly into the pixel buffer.
ReadOnlySpan<byte> tileRowSpan = tileBufferSpan.Slice(tileBufferOffset, bytesToCopy);
colorDecoder.Decode(tileRowSpan, pixels, left, y, rowWidth, 1);
tileBufferOffset += bytesPerTileRow;
uncompressedPixelBufferOffset += bytesPerRow;
}

remainingPixelsInRow -= tileWidth;
tileIndex++;
}
}

colorDecoder.Decode(uncompressedPixelBufferSpan, pixels, 0, 0, width, height);
}

private TiffBaseColorDecoder<TPixel> CreateChunkyColorDecoder<TPixel>()
Expand Down
Loading