/// <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;
            }
        }
Пример #2
0
        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];
                }
            }
        }
Пример #4
0
        /// <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);
                }
            }
        }
Пример #5
0
        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;
                    }
                }
            }
        }
Пример #6
0
        /// <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;
                }
            }
        }
Пример #7
0
        /// <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;
            }
        }
Пример #8
0
 /// <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)));
 }