protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor) { if (this.rowBuffer == null) { this.rowBuffer = this.MemoryAllocator.Allocate <byte>(this.BytesPerRow * height); } this.rowBuffer.Clear(); Span <byte> outputRowSpan = this.rowBuffer.GetSpan().Slice(0, this.BytesPerRow * 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(stripPixels, outputRowSpan); compressor.CompressStrip(outputRowSpan, height); }
public virtual void Write(TiffBaseCompressor compressor, int rowsPerStrip) { DebugGuard.IsTrue(this.BytesPerRow == compressor.BytesPerRow, "bytes per row of the compressor does not match tiff color writer"); int stripsCount = (this.Image.Height + rowsPerStrip - 1) / rowsPerStrip; uint[] stripOffsets = new uint[stripsCount]; uint[] stripByteCounts = new uint[stripsCount]; int stripIndex = 0; compressor.Initialize(rowsPerStrip); for (int y = 0; y < this.Image.Height; y += rowsPerStrip) { long offset = compressor.Output.Position; int height = Math.Min(rowsPerStrip, this.Image.Height - y); this.EncodeStrip(y, height, compressor); long endOffset = compressor.Output.Position; stripOffsets[stripIndex] = (uint)offset; stripByteCounts[stripIndex] = (uint)(endOffset - offset); stripIndex++; } DebugGuard.IsTrue(stripIndex == stripsCount, "stripIndex and stripsCount should match"); this.AddStripTags(rowsPerStrip, stripOffsets, stripByteCounts); }
/// <inheritdoc /> protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor) { int width = this.Image.Width; if (this.BitsPerPixel == 4) { int halfWidth = width >> 1; int excess = (width & 1) * height; // (width % 2) * height int rows4BitBufferLength = (halfWidth * height) + excess; this.indexedPixelsBuffer ??= this.MemoryAllocator.Allocate <byte>(rows4BitBufferLength); Span <byte> rows4bit = this.indexedPixelsBuffer.GetSpan(); int idx4bitRows = 0; int lastRow = y + height; for (int row = y; row < lastRow; row++) { ReadOnlySpan <byte> indexedPixelRow = this.quantizedImage.DangerousGetRowSpan(row); int idxPixels = 0; for (int x = 0; x < halfWidth; x++) { rows4bit[idx4bitRows] = (byte)((indexedPixelRow[idxPixels] << 4) | (indexedPixelRow[idxPixels + 1] & 0xF)); idxPixels += 2; idx4bitRows++; } // Make sure rows are byte-aligned. if (width % 2 != 0) { rows4bit[idx4bitRows++] = (byte)(indexedPixelRow[idxPixels] << 4); } } compressor.CompressStrip(rows4bit.Slice(0, idx4bitRows), height); } else { int stripPixels = width * height; this.indexedPixelsBuffer ??= this.MemoryAllocator.Allocate <byte>(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.DangerousGetRowSpan(row); indexedPixelRow.CopyTo(indexedPixels.Slice(indexedPixelsRowIdx * width, width)); indexedPixelsRowIdx++; } compressor.CompressStrip(indexedPixels.Slice(0, stripPixels), height); } }
/// <inheritdoc/> protected override void EncodeStrip(int y, int height, TiffBaseCompressor compressor) { int width = this.Image.Width; if (compressor.Method == TiffCompression.CcittGroup3Fax || compressor.Method == TiffCompression.Ccitt1D) { // Special case for T4BitCompressor. 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.Allocate <byte>(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 outputRowIdx = 0; int lastRow = y + height; for (int row = y; row < lastRow; row++) { int bitIndex = 0; int byteIndex = 0; 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[x] == 255) { outputRow[byteIndex] |= (byte)(1 << shift); } bitIndex++; if (bitIndex == 8) { byteIndex++; bitIndex = 0; } } outputRowIdx++; } compressor.CompressStrip(rows, height); } }
protected abstract void EncodeStrip(int y, int height, TiffBaseCompressor compressor);