/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero) { throw new NotSupportedException("Modified Huffman compression does not support this photometric interpretation."); } if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 8) { throw new NotSupportedException("Unsupported bits per sample."); } context.BitsPerSample = TiffValueCollection.Single <ushort>(1); ReadOnlySpan <byte> inputSpan = input.Span; int width = context.ImageSize.Width; int height = context.ImageSize.Height; var bitWriter = new BitWriter2(outputWriter, 4096); // Process every scanline for (int row = 0; row < height; row++) { ReadOnlySpan <byte> rowSpan = inputSpan.Slice(0, width); inputSpan = inputSpan.Slice(width); CcittEncodingTable currentTable = CcittEncodingTable.WhiteInstance; CcittEncodingTable otherTable = CcittEncodingTable.BlackInstance; // ModifiedHuffman compression assumes WhiteIsZero photometric interpretation is used. // Since the first run is white run, we look for black pixel in the first iteration. byte nextRunPixel = 255; while (!rowSpan.IsEmpty) { // Get the length of the current run int runLength = rowSpan.IndexOf(nextRunPixel); if (runLength < 0) { runLength = rowSpan.Length; } currentTable.EncodeRun(ref bitWriter, runLength); rowSpan = rowSpan.Slice(runLength); // Switch to the other color CcittHelper.SwapTable(ref currentTable, ref otherTable); nextRunPixel = (byte)~nextRunPixel; } bitWriter.AdvanceAlignByte(); } bitWriter.Flush(); }
static public MemoryStream CompressToLZXStreamRAW(String FileToCompress) { using (Stream StreamToCompress = File.OpenRead(FileToCompress)) { var OutputStream = new MemoryStream(); var OutputBinaryWriter = new BinaryWriter(OutputStream); while (!StreamToCompress.Eof()) { byte[] CompressedBytes; long Position = StreamToCompress.Position; var UncompressedBytes = StreamToCompress.ReadBytesUpTo(0x8000); { var MS = new MemoryStream(); var BW = new BitWriter2(MS, 2, false); if (Position == 0) { BW.WriteBits(1, 0); // Header //BW.WriteBits(1, 1); // Header //BW.WriteBits(16, 183); //BW.WriteBits(16, 6912); } BW.WriteBits(3, 3); // Bits BW.WriteBits(24, UncompressedBytes.Length); BW.Align(); MS.WriteStruct((uint)0); MS.WriteStruct((uint)0); MS.WriteStruct((uint)0); MS.WriteBytes(UncompressedBytes); CompressedBytes = MS.ToArray(); } if ((UncompressedBytes.Length != 0x8000)) { OutputBinaryWriter.Write((byte)0xFF); OutputBinaryWriter.WriteEndian((ushort)UncompressedBytes.Length, Endianness.BigEndian); OutputBinaryWriter.WriteEndian((ushort)CompressedBytes.Length, Endianness.BigEndian); } else { OutputBinaryWriter.WriteEndian((ushort)CompressedBytes.Length, Endianness.BigEndian); } OutputStream.WriteBytes(CompressedBytes); } OutputStream.Position = 0; return(OutputStream); } }
/// <inheritdoc /> public void Compress(TiffCompressionContext context, ReadOnlyMemory <byte> input, IBufferWriter <byte> outputWriter) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (context.PhotometricInterpretation != TiffPhotometricInterpretation.WhiteIsZero && context.PhotometricInterpretation != TiffPhotometricInterpretation.BlackIsZero) { throw new NotSupportedException("Modified Huffman compression does not support this photometric interpretation."); } if (context.BitsPerSample.Count != 1 || context.BitsPerSample[0] != 8) { throw new NotSupportedException("Unsupported bits per sample."); } context.BitsPerSample = TiffValueCollection.Single <ushort>(1); ReadOnlySpan <byte> inputSpan = input.Span; int width = context.ImageSize.Width; int height = context.ImageSize.Height; var bitWriter = new BitWriter2(outputWriter, 4096); ReferenceScanline referenceScanline = new ReferenceScanline(whiteIsZero: true, width); // Process every scanline for (int row = 0; row < height; row++) { ReadOnlySpan <byte> scanline = inputSpan.Slice(0, width); inputSpan = inputSpan.Slice(width); Encode2DScanline(ref bitWriter, referenceScanline, scanline); referenceScanline = new ReferenceScanline(whiteIsZero: true, scanline); } bitWriter.Flush(); }
private static void Encode2DScanline(ref BitWriter2 bitWriter, ReferenceScanline referenceScanline, ReadOnlySpan <byte> scanline) { int width = scanline.Length; CcittEncodingTable currentTable = CcittEncodingTable.WhiteInstance; CcittEncodingTable otherTable = CcittEncodingTable.BlackInstance; CodingScanline codingScanline = new CodingScanline(whiteIsZero: true, scanline); byte a0Byte = 0; int a0 = -1; while (true) { int a1 = codingScanline.FindA1(a0, a0Byte); int b1 = referenceScanline.FindB1(a0, a0Byte); int b2 = referenceScanline.FindB2(b1); if (b2 < a1) { EncodePassCode(ref bitWriter); a0 = b2; } else { int a1b1 = b1 - a1; if (a1b1 >= -3 && a1b1 <= 3) { // Vertical mode coding switch (a1b1) { case 3: EncodeVerticalL3Code(ref bitWriter); break; case 2: EncodeVerticalL2Code(ref bitWriter); break; case 1: EncodeVerticalL1Code(ref bitWriter); break; case 0: EncodeVertical0Code(ref bitWriter); break; case -1: EncodeVerticalR1Code(ref bitWriter); break; case -2: EncodeVerticalR2Code(ref bitWriter); break; case -3: EncodeVerticalR3Code(ref bitWriter); break; default: break; } CcittHelper.SwapTable(ref currentTable, ref otherTable); a0 = a1; } else { int a2 = codingScanline.FindA2(a1); EncodeHorizontalCode(ref bitWriter); currentTable.EncodeRun(ref bitWriter, a1 - a0); otherTable.EncodeRun(ref bitWriter, a2 - a1); a0 = a2; } } if (a0 >= width) { break; } a0Byte = scanline[a0]; } }
private static void EncodeVerticalL3Code(ref BitWriter2 writer) { writer.Write(0b0000010, 7); }
private static void EncodeVerticalL1Code(ref BitWriter2 writer) { writer.Write(0b010, 3); }
private static void EncodeVerticalR2Code(ref BitWriter2 writer) { writer.Write(0b000011, 6); }
private static void EncodeVertical0Code(ref BitWriter2 writer) { writer.Write(0b1, 1); }
private static void EncodeHorizontalCode(ref BitWriter2 writer) { writer.Write(0b001, 3); }
private static void EncodePassCode(ref BitWriter2 writer) { writer.Write(0b0001, 4); }