Browse Source

Merge pull request #1662 from SixLabors/bp/tiffavoidsinglespan

TiffEncoder: Avoid buffer2D.GetSingleSpan() and use GetPixelRowSpan instead
pull/1664/head
Brian Popow 5 years ago
committed by GitHub
parent
commit
5966a2eddf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs
  2. 4
      src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs
  3. 38
      src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs
  4. 19
      src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs
  5. 40
      src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs

4
src/ImageSharp/Formats/Tiff/Compression/Compressors/T4BitCompressor.cs

@ -213,7 +213,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression.Compressors
this.compressedDataBuffer = this.Allocator.Allocate<byte>(maxNeededBytes);
}
/// <summary>Writes a image compressed with CCITT T4 to the stream.</summary>
/// <summary>
/// Writes a image compressed with CCITT T4 to the stream.
/// </summary>
/// <param name="pixelsAsGray">The pixels as 8-bit gray array.</param>
/// <param name="height">The strip height.</param>
public override void CompressStrip(Span<byte> pixelsAsGray, int height)

4
src/ImageSharp/Formats/Tiff/Writers/TiffBaseColorWriter{TPixel}.cs

@ -79,10 +79,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
this.Dispose(true);
}
protected static Span<T> GetStripPixels<T>(Buffer2D<T> buffer2D, int y, int height)
where T : struct
=> buffer2D.GetSingleSpan().Slice(y * buffer2D.Width, height * buffer2D.Width);
protected abstract void EncodeStrip(int y, int height, TiffBaseCompressor compressor);
/// <summary>

38
src/ImageSharp/Formats/Tiff/Writers/TiffBiColorWriter{TPixel}.cs

@ -36,38 +36,50 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
/// <inheritdoc/>
protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor)
{
this.pixelsAsGray ??= this.MemoryAllocator.Allocate<byte>(height * this.Image.Width);
Span<byte> pixelAsGraySpan = this.pixelsAsGray.Slice(0, height * this.Image.Width);
Span<TPixel> pixelsBlackWhite = GetStripPixels(this.imageBlackWhite.GetRootFramePixelBuffer(), y, height);
PixelOperations<TPixel>.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhite, pixelAsGraySpan, pixelsBlackWhite.Length);
int width = this.Image.Width;
if (compressor.Method == TiffCompression.CcittGroup3Fax || compressor.Method == TiffCompression.Ccitt1D)
{
// Special case for T4BitCompressor.
compressor.CompressStrip(pixelAsGraySpan, height);
int stripPixels = width * height;
this.pixelsAsGray ??= this.MemoryAllocator.Allocate<byte>(stripPixels);
Span<byte> pixelAsGraySpan = this.pixelsAsGray.GetSpan();
int lastRow = y + height;
int grayRowIdx = 0;
for (int row = y; row < lastRow; row++)
{
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
Span<byte> pixelAsGrayRow = pixelAsGraySpan.Slice(grayRowIdx * width, width);
PixelOperations<TPixel>.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGrayRow, width);
grayRowIdx++;
}
compressor.CompressStrip(pixelAsGraySpan.Slice(0, stripPixels), height);
}
else
{
// Write uncompressed image.
int bytesPerStrip = this.BytesPerRow * height;
this.bitStrip ??= this.MemoryAllocator.AllocateManagedByteBuffer(bytesPerStrip);
this.pixelsAsGray ??= this.MemoryAllocator.Allocate<byte>(width);
Span<byte> pixelAsGraySpan = this.pixelsAsGray.GetSpan();
Span<byte> rows = this.bitStrip.Slice(0, bytesPerStrip);
rows.Clear();
int grayPixelIndex = 0;
for (int s = 0; s < height; s++)
int outputRowIdx = 0;
int lastRow = y + height;
for (int row = y; row < lastRow; row++)
{
int bitIndex = 0;
int byteIndex = 0;
Span<byte> outputRow = rows.Slice(s * this.BytesPerRow);
Span<byte> outputRow = rows.Slice(outputRowIdx * this.BytesPerRow);
Span<TPixel> pixelsBlackWhiteRow = this.imageBlackWhite.GetPixelRowSpan(row);
PixelOperations<TPixel>.Instance.ToL8Bytes(this.Configuration, pixelsBlackWhiteRow, pixelAsGraySpan, width);
for (int x = 0; x < this.Image.Width; x++)
{
int shift = 7 - bitIndex;
if (pixelAsGraySpan[grayPixelIndex++] == 255)
if (pixelAsGraySpan[x] == 255)
{
outputRow[byteIndex] |= (byte)(1 << shift);
}
@ -79,6 +91,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
bitIndex = 0;
}
}
outputRowIdx++;
}
compressor.CompressStrip(rows, height);

19
src/ImageSharp/Formats/Tiff/Writers/TiffCompositeColorWriter{TPixel}.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -30,12 +31,22 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
this.rowBuffer.Clear();
Span<byte> rowSpan = this.rowBuffer.GetSpan().Slice(0, this.BytesPerRow * height);
Span<byte> outputRowSpan = this.rowBuffer.GetSpan().Slice(0, this.BytesPerRow * height);
Span<TPixel> pixels = GetStripPixels(this.Image.PixelBuffer, y, height);
int width = this.Image.Width;
using IMemoryOwner<TPixel> stripPixelBuffer = this.MemoryAllocator.Allocate<TPixel>(height * width);
Span<TPixel> stripPixels = stripPixelBuffer.GetSpan();
int lastRow = y + height;
int stripPixelsRowIdx = 0;
for (int row = y; row < lastRow; row++)
{
Span<TPixel> stripPixelsRow = this.Image.PixelBuffer.GetRowSpan(row);
stripPixelsRow.CopyTo(stripPixels.Slice(stripPixelsRowIdx * width, width));
stripPixelsRowIdx++;
}
this.EncodePixels(pixels, rowSpan);
compressor.CompressStrip(rowSpan, height);
this.EncodePixels(stripPixels, outputRowSpan);
compressor.CompressStrip(outputRowSpan, height);
}
protected abstract void EncodePixels(Span<TPixel> pixels, Span<byte> buffer);

40
src/ImageSharp/Formats/Tiff/Writers/TiffPaletteWriter{TPixel}.cs

@ -5,7 +5,6 @@ using System;
using System.Buffers;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Tiff.Compression;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -21,6 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
private readonly int colorPaletteSize;
private readonly int colorPaletteBytes;
private readonly IndexedImageFrame<TPixel> quantizedImage;
private IMemoryOwner<byte> indexedPixelsBuffer;
public TiffPaletteWriter(
ImageFrame<TPixel> image,
@ -55,22 +55,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
/// <inheritdoc />
protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor)
{
Span<byte> indexedPixels = GetStripPixels(((IPixelSource)this.quantizedImage).PixelBuffer, y, height);
int width = this.Image.Width;
if (this.BitsPerPixel == 4)
{
int width = this.Image.Width;
int halfWidth = width >> 1;
int excess = (width & 1) * height; // (width % 2) * height
int rows4BitBufferLength = (halfWidth * height) + excess;
using IMemoryOwner<byte> rows4bitBuffer = this.MemoryAllocator.Allocate<byte>(rows4BitBufferLength);
Span<byte> rows4bit = rows4bitBuffer.GetSpan();
int idxPixels = 0;
this.indexedPixelsBuffer ??= this.MemoryAllocator.Allocate<byte>(rows4BitBufferLength);
Span<byte> rows4bit = this.indexedPixelsBuffer.GetSpan();
int idx4bitRows = 0;
for (int row = 0; row < height; row++)
int lastRow = y + height;
for (int row = y; row < lastRow; row++)
{
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
int idxPixels = 0;
for (int x = 0; x < halfWidth; x++)
{
rows4bit[idx4bitRows] = (byte)((indexedPixels[idxPixels] << 4) | (indexedPixels[idxPixels + 1] & 0xF));
rows4bit[idx4bitRows] = (byte)((indexedPixelRow[idxPixels] << 4) | (indexedPixelRow[idxPixels + 1] & 0xF));
idxPixels += 2;
idx4bitRows++;
}
@ -78,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
// Make sure rows are byte-aligned.
if (width % 2 != 0)
{
rows4bit[idx4bitRows++] = (byte)(indexedPixels[idxPixels++] << 4);
rows4bit[idx4bitRows++] = (byte)(indexedPixelRow[idxPixels] << 4);
}
}
@ -86,12 +88,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Writers
}
else
{
compressor.CompressStrip(indexedPixels, height);
int stripPixels = width * height;
this.indexedPixelsBuffer ??= this.MemoryAllocator.AllocateManagedByteBuffer(stripPixels);
Span<byte> indexedPixels = this.indexedPixelsBuffer.GetSpan();
int lastRow = y + height;
int indexedPixelsRowIdx = 0;
for (int row = y; row < lastRow; row++)
{
ReadOnlySpan<byte> indexedPixelRow = this.quantizedImage.GetPixelRowSpan(row);
indexedPixelRow.CopyTo(indexedPixels.Slice(indexedPixelsRowIdx * width, width));
indexedPixelsRowIdx++;
}
compressor.CompressStrip(indexedPixels.Slice(0, stripPixels), height);
}
}
/// <inheritdoc />
protected override void Dispose(bool disposing) => this.quantizedImage?.Dispose();
protected override void Dispose(bool disposing)
{
this.quantizedImage?.Dispose();
this.indexedPixelsBuffer?.Dispose();
}
private void AddColorMapTag()
{

Loading…
Cancel
Save