public static TiffBasePlanarColorDecoder <TPixel> CreatePlanar(
            TiffColorType colorType,
            TiffBitsPerSample bitsPerSample,
            ushort[] colorMap,
            Rational[] referenceBlackAndWhite,
            Rational[] ycbcrCoefficients,
            ushort[] ycbcrSubSampling,
            ByteOrder byteOrder)
        {
            switch (colorType)
            {
            case TiffColorType.Rgb888Planar:
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbPlanarTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.YCbCrPlanar:
                return(new YCbCrPlanarTiffColor <TPixel>(referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling));

            case TiffColorType.Rgb161616Planar:
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb16PlanarTiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.Rgb242424Planar:
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb24PlanarTiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.Rgb323232Planar:
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb32PlanarTiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            default:
                throw TiffThrowHelper.InvalidColorType(colorType.ToString());
            }
        }
예제 #2
0
        /// <summary>
        /// Writes decoded pixel to buffer at a given position.
        /// </summary>
        /// <param name="buffer">The buffer to write to.</param>
        /// <param name="offset">The position to write to.</param>
        /// <returns>The number of bytes written.</returns>
        public int WriteTo(Span <byte> buffer, int offset)
        {
            if (this.Length == 0)
            {
                return(0);
            }

            if (this.Length == 1)
            {
                buffer[offset] = this.value;
                return(1);
            }

            LzwString e      = this;
            int       endIdx = this.Length - 1;

            if (endIdx >= buffer.Length)
            {
                TiffThrowHelper.ThrowImageFormatException("Error reading lzw compressed stream. Either pixel buffer to write to is to small or code length is invalid!");
            }

            for (int i = endIdx; i >= 0; i--)
            {
                buffer[offset + i] = e.value;
                e = e.previous;
            }

            return(this.Length);
        }
예제 #3
0
        private void AddStringToTable(LzwString lzwString)
        {
            if (this.tableLength > this.table.Length)
            {
                TiffThrowHelper.ThrowImageFormatException($"TIFF LZW with more than {MaxBits} bits per code encountered (table overflow)");
            }

            this.table[this.tableLength++] = lzwString;

            if (this.tableLength > this.maxCode)
            {
                this.bitsPerCode++;

                if (this.bitsPerCode > MaxBits)
                {
                    // Continue reading MaxBits (12 bit) length codes.
                    this.bitsPerCode = MaxBits;
                }

                this.bitMask = BitmaskFor(this.bitsPerCode);
                this.maxCode = this.MaxCode();
            }

            if (lzwString.Length > this.maxString)
            {
                this.maxString = lzwString.Length;
            }
        }
예제 #4
0
        public static TiffBaseCompressor Create(
            TiffCompression method,
            Stream output,
            MemoryAllocator allocator,
            int width,
            int bitsPerPixel,
            DeflateCompressionLevel compressionLevel,
            TiffPredictor predictor)
        {
            switch (method)
            {
            // The following compression types are not implemented in the encoder and will default to no compression instead.
            case TiffCompression.ItuTRecT43:
            case TiffCompression.ItuTRecT82:
            case TiffCompression.OldJpeg:
            case TiffCompression.OldDeflate:
            case TiffCompression.None:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");

                return(new NoCompressor(output, allocator, width, bitsPerPixel));

            case TiffCompression.Jpeg:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new TiffJpegCompressor(output, allocator, width, bitsPerPixel));

            case TiffCompression.PackBits:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new PackBitsCompressor(output, allocator, width, bitsPerPixel));

            case TiffCompression.Deflate:
                return(new DeflateCompressor(output, allocator, width, bitsPerPixel, predictor, compressionLevel));

            case TiffCompression.Lzw:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                return(new LzwCompressor(output, allocator, width, bitsPerPixel, predictor));

            case TiffCompression.CcittGroup3Fax:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T4BitCompressor(output, allocator, width, bitsPerPixel, false));

            case TiffCompression.CcittGroup4Fax:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T6BitCompressor(output, allocator, width, bitsPerPixel));

            case TiffCompression.Ccitt1D:
                DebugGuard.IsTrue(compressionLevel == DeflateCompressionLevel.DefaultCompression, "No deflate compression level is expected to be set");
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T4BitCompressor(output, allocator, width, bitsPerPixel, true));

            default:
                throw TiffThrowHelper.NotSupportedCompressor(method.ToString());
            }
        }
예제 #5
0
        /// <summary>
        /// Decodes and decompresses all pixel indices from the stream.
        /// </summary>
        /// <param name="pixels">The pixel array to decode to.</param>
        public void DecodePixels(Span <byte> pixels)
        {
            // Adapted from the pseudo-code example found in the TIFF 6.0 Specification, 1992.
            // See Section 13: "LZW Compression"/"LZW Decoding", page 61+
            int code;
            int offset = 0;

            while ((code = this.GetNextCode()) != EoiCode)
            {
                if (code == ClearCode)
                {
                    this.Init();
                    code = this.GetNextCode();

                    if (code == EoiCode)
                    {
                        break;
                    }

                    if (this.table[code] == null)
                    {
                        TiffThrowHelper.ThrowImageFormatException($"Corrupted TIFF LZW: code {code} (table size: {this.tableLength})");
                    }

                    offset += this.table[code].WriteTo(pixels, offset);
                }
                else
                {
                    if (this.table[this.oldCode] == null)
                    {
                        TiffThrowHelper.ThrowImageFormatException($"Corrupted TIFF LZW: code {this.oldCode} (table size: {this.tableLength})");
                    }

                    if (this.IsInTable(code))
                    {
                        offset += this.table[code].WriteTo(pixels, offset);

                        this.AddStringToTable(this.table[this.oldCode].Concatenate(this.table[code].FirstChar));
                    }
                    else
                    {
                        LzwString outString = this.table[this.oldCode].Concatenate(this.table[this.oldCode].FirstChar);

                        offset += outString.WriteTo(pixels, offset);
                        this.AddStringToTable(outString);
                    }
                }

                this.oldCode = code;

                if (offset >= pixels.Length)
                {
                    break;
                }
            }
        }
예제 #6
0
        private void LoadNewByte()
        {
            this.Position++;
            this.ResetBitsRead();

            if (this.Position >= (ulong)this.DataLength)
            {
                TiffThrowHelper.ThrowImageFormatException("tiff image has invalid ccitt compressed data");
            }
        }
        public static TiffBaseDecompressor Create(
            Configuration configuration,
            TiffDecoderCompressionType method,
            MemoryAllocator allocator,
            TiffPhotometricInterpretation photometricInterpretation,
            int width,
            int bitsPerPixel,
            TiffColorType colorType,
            TiffPredictor predictor,
            FaxCompressionOptions faxOptions,
            byte[] jpegTables,
            TiffFillOrder fillOrder,
            ByteOrder byteOrder)
        {
            switch (method)
            {
            case TiffDecoderCompressionType.None:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new NoneTiffCompression(allocator, width, bitsPerPixel));

            case TiffDecoderCompressionType.PackBits:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new PackBitsTiffCompression(allocator, width, bitsPerPixel));

            case TiffDecoderCompressionType.Deflate:
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new DeflateTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian));

            case TiffDecoderCompressionType.Lzw:
                DebugGuard.IsTrue(faxOptions == FaxCompressionOptions.None, "No fax compression options are expected");
                return(new LzwTiffCompression(allocator, width, bitsPerPixel, colorType, predictor, byteOrder == ByteOrder.BigEndian));

            case TiffDecoderCompressionType.T4:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T4TiffCompression(allocator, fillOrder, width, bitsPerPixel, faxOptions, photometricInterpretation));

            case TiffDecoderCompressionType.T6:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new T6TiffCompression(allocator, fillOrder, width, bitsPerPixel, photometricInterpretation));

            case TiffDecoderCompressionType.HuffmanRle:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new ModifiedHuffmanTiffCompression(allocator, fillOrder, width, bitsPerPixel, photometricInterpretation));

            case TiffDecoderCompressionType.Jpeg:
                DebugGuard.IsTrue(predictor == TiffPredictor.None, "Predictor should only be used with lzw or deflate compression");
                return(new JpegTiffCompression(configuration, allocator, width, bitsPerPixel, jpegTables, photometricInterpretation));

            default:
                throw TiffThrowHelper.NotSupportedDecompressor(nameof(method));
            }
        }
        /// <inheritdoc/>
        protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span <byte> buffer)
        {
            if (this.compressedDataMemory == null)
            {
                this.compressedDataMemory = this.Allocator.Allocate <byte>(byteCount);
            }
            else if (this.compressedDataMemory.Length() < byteCount)
            {
                this.compressedDataMemory.Dispose();
                this.compressedDataMemory = this.Allocator.Allocate <byte>(byteCount);
            }

            Span <byte> compressedData = this.compressedDataMemory.GetSpan();

            stream.Read(compressedData, 0, byteCount);
            int compressedOffset   = 0;
            int decompressedOffset = 0;

            while (compressedOffset < byteCount)
            {
                byte headerByte = compressedData[compressedOffset];

                if (headerByte <= 127)
                {
                    int literalOffset = compressedOffset + 1;
                    int literalLength = compressedData[compressedOffset] + 1;

                    if ((literalOffset + literalLength) > compressedData.Length)
                    {
                        TiffThrowHelper.ThrowImageFormatException("Tiff packbits compression error: not enough data.");
                    }

                    compressedData.Slice(literalOffset, literalLength).CopyTo(buffer.Slice(decompressedOffset));

                    compressedOffset   += literalLength + 1;
                    decompressedOffset += literalLength;
                }
                else if (headerByte == 0x80)
                {
                    compressedOffset += 1;
                }
                else
                {
                    byte repeatData   = compressedData[compressedOffset + 1];
                    int  repeatLength = 257 - headerByte;

                    ArrayCopyRepeat(repeatData, buffer, decompressedOffset, repeatLength);

                    compressedOffset   += 2;
                    decompressedOffset += repeatLength;
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Decompresses image data into the supplied buffer.
        /// </summary>
        /// <param name="stream">The <see cref="Stream" /> to read image data from.</param>
        /// <param name="stripOffset">The strip offset of stream.</param>
        /// <param name="stripByteCount">The number of bytes to read from the input stream.</param>
        /// <param name="stripHeight">The height of the strip.</param>
        /// <param name="buffer">The output buffer for uncompressed data.</param>
        public void Decompress(BufferedReadStream stream, ulong stripOffset, ulong stripByteCount, int stripHeight, Span <byte> buffer)
        {
            DebugGuard.MustBeLessThanOrEqualTo(stripOffset, (ulong)long.MaxValue, nameof(stripOffset));
            DebugGuard.MustBeLessThanOrEqualTo(stripByteCount, (ulong)long.MaxValue, nameof(stripByteCount));

            stream.Seek((long)stripOffset, SeekOrigin.Begin);
            this.Decompress(stream, (int)stripByteCount, stripHeight, buffer);

            if ((long)stripOffset + (long)stripByteCount < stream.Position)
            {
                TiffThrowHelper.ThrowImageFormatException("Out of range when reading a strip.");
            }
        }
예제 #10
0
        /// <summary>
        /// An EOL is expected before the first data.
        /// </summary>
        protected virtual void ReadEolBeforeFirstData()
        {
            if (this.isFirstScanLine)
            {
                this.Value = this.ReadValue(this.eolPadding ? 16 : 12);

                if (!this.IsEndOfScanLine)
                {
                    TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error: expected start of data marker not found");
                }

                this.Reset();
            }
        }
예제 #11
0
        /// <summary>
        /// Decompresses image data into the supplied buffer.
        /// </summary>
        /// <param name="stream">The <see cref="Stream" /> to read image data from.</param>
        /// <param name="stripOffset">The strip offset of stream.</param>
        /// <param name="stripByteCount">The number of bytes to read from the input stream.</param>
        /// <param name="stripHeight">The height of the strip.</param>
        /// <param name="buffer">The output buffer for uncompressed data.</param>
        public void Decompress(BufferedReadStream stream, uint stripOffset, uint stripByteCount, int stripHeight, Span <byte> buffer)
        {
            if (stripByteCount > int.MaxValue)
            {
                TiffThrowHelper.ThrowImageFormatException("The StripByteCount value is too big.");
            }

            stream.Seek(stripOffset, SeekOrigin.Begin);
            this.Decompress(stream, (int)stripByteCount, stripHeight, buffer);

            if (stripOffset + stripByteCount < stream.Position)
            {
                TiffThrowHelper.ThrowImageFormatException("Out of range when reading a strip.");
            }
        }
예제 #12
0
        /// <inheritdoc/>
        protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span <byte> buffer)
        {
            if (this.faxCompressionOptions.HasFlag(FaxCompressionOptions.TwoDimensionalCoding))
            {
                TiffThrowHelper.ThrowNotSupported("TIFF CCITT 2D compression is not yet supported");
            }

            bool eolPadding = this.faxCompressionOptions.HasFlag(FaxCompressionOptions.EolPadding);

            using var bitReader = new T4BitReader(stream, this.FillOrder, byteCount, this.Allocator, eolPadding);

            buffer.Clear();
            uint bitsWritten  = 0;
            uint pixelWritten = 0;

            while (bitReader.HasMoreData)
            {
                bitReader.ReadNextRun();

                if (bitReader.RunLength > 0)
                {
                    this.WritePixelRun(buffer, bitReader, bitsWritten);

                    bitsWritten  += bitReader.RunLength;
                    pixelWritten += bitReader.RunLength;
                }

                if (bitReader.IsEndOfScanLine)
                {
                    // Write padding bytes, if necessary.
                    uint pad = 8 - (bitsWritten % 8);
                    if (pad != 8)
                    {
                        BitWriterUtils.WriteBits(buffer, (int)bitsWritten, pad, 0);
                        bitsWritten += pad;
                    }

                    pixelWritten = 0;
                }
            }

            // Edge case for when we are at the last byte, but there are still some unwritten pixels left.
            if (pixelWritten > 0 && pixelWritten < this.width)
            {
                bitReader.ReadNextRun();
                this.WritePixelRun(buffer, bitReader, bitsWritten);
            }
        }
예제 #13
0
        /// <inheritdoc/>
        protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span <byte> buffer)
        {
            using var bitReader = new ModifiedHuffmanBitReader(stream, this.FillOrder, byteCount, this.Allocator);

            buffer.Clear();
            uint bitsWritten   = 0;
            uint pixelsWritten = 0;

            while (bitReader.HasMoreData)
            {
                bitReader.ReadNextRun();

                if (bitReader.RunLength > 0)
                {
                    if (bitReader.IsWhiteRun)
                    {
                        BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.whiteValue);
                    }
                    else
                    {
                        BitWriterUtils.WriteBits(buffer, (int)bitsWritten, bitReader.RunLength, this.blackValue);
                    }

                    bitsWritten   += bitReader.RunLength;
                    pixelsWritten += bitReader.RunLength;
                }

                if (pixelsWritten == this.Width)
                {
                    bitReader.StartNewRow();
                    pixelsWritten = 0;

                    // Write padding bits, if necessary.
                    uint pad = 8 - (bitsWritten % 8);
                    if (pad != 8)
                    {
                        BitWriterUtils.WriteBits(buffer, (int)bitsWritten, pad, 0);
                        bitsWritten += pad;
                    }
                }

                if (pixelsWritten > this.Width)
                {
                    TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, decoded more pixels then image width");
                }
            }
        }
예제 #14
0
        public YCbCrConverter(Rational[] referenceBlackAndWhite, Rational[] coefficients)
        {
            referenceBlackAndWhite ??= DefaultReferenceBlackWhite;
            coefficients ??= DefaultLuma;

            if (referenceBlackAndWhite.Length != 6)
            {
                TiffThrowHelper.ThrowImageFormatException("reference black and white array should have 6 entry's");
            }

            if (coefficients.Length != 3)
            {
                TiffThrowHelper.ThrowImageFormatException("luma coefficients array should have 6 entry's");
            }

            this.yExpander  = new CodingRangeExpander(referenceBlackAndWhite[0], referenceBlackAndWhite[1], 255);
            this.cbExpander = new CodingRangeExpander(referenceBlackAndWhite[2], referenceBlackAndWhite[3], 127);
            this.crExpander = new CodingRangeExpander(referenceBlackAndWhite[4], referenceBlackAndWhite[5], 127);
            this.converter  = new YCbCrToRgbConverter(coefficients[0], coefficients[1], coefficients[2]);
        }
예제 #15
0
        private static void Decode2DScanline(T6BitReader bitReader, bool whiteIsZero, CcittReferenceScanline referenceScanline, Span <byte> scanline)
        {
            int width = scanline.Length;

            bitReader.StartNewRow();

            // 2D Encoding variables.
            int  a0       = -1;
            byte fillByte = whiteIsZero ? (byte)0 : (byte)255;

            // Process every code word in this scanline.
            int unpacked = 0;

            while (true)
            {
                // Read next code word and advance pass it.
                bool isEol = bitReader.ReadNextCodeWord();

                // Special case handling for EOL.
                if (isEol)
                {
                    // If a TIFF reader encounters EOFB before the expected number of lines has been extracted,
                    // it is appropriate to assume that the missing rows consist entirely of white pixels.
                    scanline.Fill(whiteIsZero ? (byte)0 : (byte)255);
                    break;
                }

                // Update 2D Encoding variables.
                int b1 = referenceScanline.FindB1(a0, fillByte);

                // Switch on the code word.
                int a1;
                switch (bitReader.Code.Type)
                {
                case CcittTwoDimensionalCodeType.None:
                    TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, could not read a valid code word.");
                    break;

                case CcittTwoDimensionalCodeType.Pass:
                    int b2 = referenceScanline.FindB2(b1);
                    scanline.Slice(unpacked, b2 - unpacked).Fill(fillByte);
                    unpacked = b2;
                    a0       = b2;
                    break;

                case CcittTwoDimensionalCodeType.Horizontal:
                    // Decode M(a0a1)
                    bitReader.ReadNextRun();
                    int runLength = (int)bitReader.RunLength;
                    if (runLength > (uint)(scanline.Length - unpacked))
                    {
                        TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error");
                    }

                    scanline.Slice(unpacked, runLength).Fill(fillByte);
                    unpacked += runLength;
                    fillByte  = (byte)~fillByte;

                    // Decode M(a1a2)
                    bitReader.ReadNextRun();
                    runLength = (int)bitReader.RunLength;
                    if (runLength > (uint)(scanline.Length - unpacked))
                    {
                        TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error");
                    }

                    scanline.Slice(unpacked, runLength).Fill(fillByte);
                    unpacked += runLength;
                    fillByte  = (byte)~fillByte;

                    // Prepare next a0
                    a0 = unpacked;
                    break;

                case CcittTwoDimensionalCodeType.Vertical0:
                    a1 = b1;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalR1:
                    a1 = b1 + 1;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalR2:
                    a1 = b1 + 2;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalR3:
                    a1 = b1 + 3;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalL1:
                    a1 = b1 - 1;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalL2:
                    a1 = b1 - 2;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                case CcittTwoDimensionalCodeType.VerticalL3:
                    a1 = b1 - 3;
                    scanline.Slice(unpacked, a1 - unpacked).Fill(fillByte);
                    unpacked = a1;
                    a0       = a1;
                    fillByte = (byte)~fillByte;
                    bitReader.SwapColor();
                    break;

                default:
                    throw new NotSupportedException("ccitt extensions are not supported.");
                }

                // This line is fully unpacked. Should exit and process next line.
                if (unpacked == width)
                {
                    break;
                }

                if (unpacked > width)
                {
                    TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error, unpacked data > width");
                }
            }
        }
        public static TiffBaseColorDecoder <TPixel> Create(
            Configuration configuration,
            MemoryAllocator memoryAllocator,
            TiffColorType colorType,
            TiffBitsPerSample bitsPerSample,
            ushort[] colorMap,
            Rational[] referenceBlackAndWhite,
            Rational[] ycbcrCoefficients,
            ushort[] ycbcrSubSampling,
            ByteOrder byteOrder)
        {
            switch (colorType)
            {
            case TiffColorType.WhiteIsZero:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZeroTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.WhiteIsZero1:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero1TiffColor <TPixel>());

            case TiffColorType.WhiteIsZero4:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero4TiffColor <TPixel>());

            case TiffColorType.WhiteIsZero8:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero8TiffColor <TPixel>());

            case TiffColorType.WhiteIsZero16:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 16, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero16TiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.WhiteIsZero24:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 24, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero24TiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.WhiteIsZero32:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 32, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero32TiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.WhiteIsZero32Float:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 32, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new WhiteIsZero32FloatTiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.BlackIsZero:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZeroTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.BlackIsZero1:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 1, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero1TiffColor <TPixel>());

            case TiffColorType.BlackIsZero4:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 4, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero4TiffColor <TPixel>());

            case TiffColorType.BlackIsZero8:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 8, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero8TiffColor <TPixel>(configuration));

            case TiffColorType.BlackIsZero16:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 16, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero16TiffColor <TPixel>(configuration, byteOrder == ByteOrder.BigEndian));

            case TiffColorType.BlackIsZero24:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 24, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero24TiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.BlackIsZero32:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 32, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero32TiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.BlackIsZero32Float:
                DebugGuard.IsTrue(bitsPerSample.Channels == 1 && bitsPerSample.Channel0 == 32, "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new BlackIsZero32FloatTiffColor <TPixel>(byteOrder == ByteOrder.BigEndian));

            case TiffColorType.Rgb:
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.Rgb222:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 2 &&
                    bitsPerSample.Channel1 == 2 &&
                    bitsPerSample.Channel0 == 2,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.Rgb444:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 4 &&
                    bitsPerSample.Channel1 == 4 &&
                    bitsPerSample.Channel0 == 4,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb444TiffColor <TPixel>());

            case TiffColorType.Rgb888:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 8 &&
                    bitsPerSample.Channel1 == 8 &&
                    bitsPerSample.Channel0 == 8,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb888TiffColor <TPixel>(configuration));

            case TiffColorType.Rgb101010:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 10 &&
                    bitsPerSample.Channel1 == 10 &&
                    bitsPerSample.Channel0 == 10,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.Rgb121212:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 12 &&
                    bitsPerSample.Channel1 == 12 &&
                    bitsPerSample.Channel0 == 12,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.Rgb141414:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 14 &&
                    bitsPerSample.Channel1 == 14 &&
                    bitsPerSample.Channel0 == 14,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbTiffColor <TPixel>(bitsPerSample));

            case TiffColorType.Rgb161616:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 16 &&
                    bitsPerSample.Channel1 == 16 &&
                    bitsPerSample.Channel0 == 16,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb161616TiffColor <TPixel>(configuration, isBigEndian: byteOrder == ByteOrder.BigEndian));

            case TiffColorType.Rgb242424:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 24 &&
                    bitsPerSample.Channel1 == 24 &&
                    bitsPerSample.Channel0 == 24,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb242424TiffColor <TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian));

            case TiffColorType.Rgb323232:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 32 &&
                    bitsPerSample.Channel1 == 32 &&
                    bitsPerSample.Channel0 == 32,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new Rgb323232TiffColor <TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian));

            case TiffColorType.RgbFloat323232:
                DebugGuard.IsTrue(
                    bitsPerSample.Channels == 3 &&
                    bitsPerSample.Channel2 == 32 &&
                    bitsPerSample.Channel1 == 32 &&
                    bitsPerSample.Channel0 == 32,
                    "bitsPerSample");
                DebugGuard.IsTrue(colorMap == null, "colorMap");
                return(new RgbFloat323232TiffColor <TPixel>(isBigEndian: byteOrder == ByteOrder.BigEndian));

            case TiffColorType.PaletteColor:
                DebugGuard.NotNull(colorMap, "colorMap");
                return(new PaletteTiffColor <TPixel>(bitsPerSample, colorMap));

            case TiffColorType.YCbCr:
                return(new YCbCrTiffColor <TPixel>(memoryAllocator, referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling));

            default:
                throw TiffThrowHelper.InvalidColorType(colorType.ToString());
            }
        }
예제 #17
0
        /// <summary>
        /// Read the next run of pixels.
        /// </summary>
        public void ReadNextRun()
        {
            if (this.terminationCodeFound)
            {
                this.IsWhiteRun           = !this.IsWhiteRun;
                this.terminationCodeFound = false;
            }

            // Initialize for next run.
            this.Reset();

            // We expect an EOL before the first data.
            this.ReadEolBeforeFirstData();

            // A code word must have at least 2 bits.
            this.Value = this.ReadValue(MinCodeLength);

            do
            {
                if (this.CurValueBitsRead > this.maxCodeLength)
                {
                    TiffThrowHelper.ThrowImageFormatException("ccitt compression parsing error: invalid code length read");
                }

                bool isMakeupCode = this.IsMakeupCode();
                if (isMakeupCode)
                {
                    if (this.IsWhiteRun)
                    {
                        this.RunLength += this.WhiteMakeupCodeRunLength();
                    }
                    else
                    {
                        this.RunLength += this.BlackMakeupCodeRunLength();
                    }

                    this.isStartOfRow = false;
                    this.Reset(resetRunLength: false);
                    continue;
                }

                bool isTerminatingCode = this.IsTerminatingCode();
                if (isTerminatingCode)
                {
                    // Each line starts with a white run. If the image starts with black, a white run with length zero is written.
                    if (this.isStartOfRow && this.IsWhiteRun && this.WhiteTerminatingCodeRunLength() == 0)
                    {
                        this.Reset();
                        this.isStartOfRow         = false;
                        this.terminationCodeFound = true;
                        this.RunLength            = 0;
                        break;
                    }

                    if (this.IsWhiteRun)
                    {
                        this.RunLength += this.WhiteTerminatingCodeRunLength();
                    }
                    else
                    {
                        this.RunLength += this.BlackTerminatingCodeRunLength();
                    }

                    this.terminationCodeFound = true;
                    this.isStartOfRow         = false;
                    break;
                }

                uint currBit = this.ReadValue(1);
                this.Value = (this.Value << 1) | currBit;

                if (this.IsEndOfScanLine)
                {
                    this.StartNewRow();
                }
            }while (!this.IsEndOfScanLine);

            this.isFirstScanLine = false;
        }