/// <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; } }
private LzwString(byte value, byte firstChar, int length, LzwString previous) { this.value = value; this.FirstChar = firstChar; this.Length = length; this.previous = previous; }
/// <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; } } }