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()); } }
/// <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); }
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; } }
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()); } }
/// <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; } } }
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; } } }
/// <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."); } }
/// <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(); } }
/// <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."); } }
/// <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); } }
/// <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"); } } }
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]); }
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()); } }
/// <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; }