/// <inheritdoc/> public override void Decode(IMemoryOwner <byte>[] data, Buffer2D <TPixel> pixels, int left, int top, int width, int height) { Span <byte> yData = data[0].GetSpan(); Span <byte> cbData = data[1].GetSpan(); Span <byte> crData = data[2].GetSpan(); if (this.ycbcrSubSampling != null && !(this.ycbcrSubSampling[0] == 1 && this.ycbcrSubSampling[1] == 1)) { ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], cbData, crData); } var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) { Span <TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(yData[offset], cbData[offset], crData[offset]); color.FromRgba32(rgba); pixelRow[x] = color; offset++; } offset += widthPadding; } }
public List <Bitmap> ReadBitmaps(string filePath) { bool isTff = FileUtils.IsTiff(filePath); return(isTff ? TiffUtils.GetBitmapsFromTiff(filePath) : new List <Bitmap>() { (Bitmap)Bitmap.FromFile(filePath) }); }
private static void ReverseChromaSubSampling(int width, int height, int horizontalSubSampling, int verticalSubSampling, Span <byte> planarCb, Span <byte> planarCr) { // If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively, // then the source data will be padded. width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); for (int row = height - 1; row >= 0; row--) { for (int col = width - 1; col >= 0; col--) { int offset = (row * width) + col; int subSampleOffset = (row / verticalSubSampling * (width / horizontalSubSampling)) + (col / horizontalSubSampling); planarCb[offset] = planarCb[subSampleOffset]; planarCr[offset] = planarCr[subSampleOffset]; } } }
/// <inheritdoc/> public override void Decode(ReadOnlySpan <byte> data, Buffer2D <TPixel> pixels, int left, int top, int width, int height) { var color = default(TPixel); int offset = 0; var l8 = default(L8); for (int y = top; y < top + height; y++) { Span <TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { byte intensity = (byte)(byte.MaxValue - data[offset++]); pixelRow[x] = TiffUtils.ColorFromL8(l8, intensity, color); } } }
private static void UndoGray32Bit(Span <byte> pixelBytes, int width, bool isBigEndian) { int rowBytesCount = width * 4; int height = pixelBytes.Length / rowBytesCount; if (isBigEndian) { for (int y = 0; y < height; y++) { int offset = 0; Span <byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); uint pixelValue = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span <byte> rowSpan = rowBytes.Slice(offset, 4); uint diff = TiffUtils.ConvertToUIntBigEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue); offset += 4; } } } else { for (int y = 0; y < height; y++) { int offset = 0; Span <byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); uint pixelValue = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span <byte> rowSpan = rowBytes.Slice(offset, 4); uint diff = TiffUtils.ConvertToUIntLittleEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue); offset += 4; } } } }
/// <inheritdoc/> public override void Decode(ReadOnlySpan <byte> data, Buffer2D <TPixel> pixels, int left, int top, int width, int height) { // Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those, // we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623 Rgba64 rgba = TiffUtils.Rgba64Default; var color = default(TPixel); color.FromVector4(TiffUtils.Vector4Default); int offset = 0; for (int y = top; y < top + height; y++) { Span <TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); if (this.isBigEndian) { for (int x = 0; x < pixelRow.Length; x++) { ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; pixelRow[x] = TiffUtils.ColorFromRgba64(rgba, r, g, b, color); } } else { int byteCount = pixelRow.Length * 6; PixelOperations <TPixel> .Instance.FromRgb48Bytes( this.configuration, data.Slice(offset, byteCount), pixelRow, pixelRow.Length); offset += byteCount; } } }
/// <inheritdoc/> public override void Decode(ReadOnlySpan <byte> data, Buffer2D <TPixel> pixels, int left, int top, int width, int height) { ReadOnlySpan <byte> ycbcrData = data; if (this.ycbcrSubSampling != null && !(this.ycbcrSubSampling[0] == 1 && this.ycbcrSubSampling[1] == 1)) { // 4 extra rows and columns for possible padding. int paddedWidth = width + 4; int paddedHeight = height + 4; int requiredBytes = paddedWidth * paddedHeight * 3; using IMemoryOwner <byte> tmpBuffer = this.memoryAllocator.Allocate <byte>(requiredBytes); Span <byte> tmpBufferSpan = tmpBuffer.GetSpan(); ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], data, tmpBufferSpan); ycbcrData = tmpBufferSpan; } var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) { Span <TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(ycbcrData[offset], ycbcrData[offset + 1], ycbcrData[offset + 2]); color.FromRgba32(rgba); pixelRow[x] = color; offset += 3; } offset += widthPadding * 3; } }
/// <summary> /// Returns a list with <see cref="DocumentInspectorPageOrientation">DocumentInspectorPageOrientations</see> /// according to the amount of "pages" in the <paramref name="inputFile"/> /// </summary> /// <param name="inputFile">The input file</param> /// <returns></returns> public List <DocumentInspectorPageOrientation> DetectPageOrientation(string inputFile) { return(DetectPageOrientation(TiffUtils.SplitTiffImage(inputFile))); }