LZW Compression Support

Overview

HotPDF decodes legacy PDF streams that use the LZWDecode filter and can reverse the TIFF or PNG predictors commonly paired with that filter

Key Features

  • PDF EarlyChange=1 and EarlyChange=0 code-width transitions
  • Most-significant-bit and least-significant-bit fill order
  • Clear-code reset, end-of-information, and KwKwK expansion handling
  • Direct output to a TStream without constructing a second result string
  • Configurable output limits and optional strict initial-clear and end-of-information checks
  • TIFF Predictor 2 at 1, 2, 4, 8, or 16 bits per component
  • PNG None, Sub, Up, Average, and Paeth row filters
  • Per-decode statistics for code widths, dictionary growth, resets, expansions, and output bytes

Types

  • TPDFLZWDecompressor is the reusable decoder class
  • TPDFLZWCompressor is the matching encoder class
  • TPDFLZWParms carries PDF predictor geometry
  • TPDFLZWFillOrder selects foTop or foBottom bit order
  • EHPDFLZWError reports malformed input, unsupported geometry, and configured-limit failures

Configuration Properties

  • FillOrder selects the compressed bit order
  • EarlyChange selects the PDF dictionary-width transition rule and defaults to True
  • InitialCodeSize accepts values from 2 through 9 and defaults to 9 for PDF
  • For reduced alphabets, every uncompressed byte must be smaller than 1 shl (InitialCodeSize - 1); compression raises EHPDFLZWError before writing output if a byte is outside that range
  • MaxOutputBytes stops excessive expansion before the configured limit is crossed, with zero meaning unlimited
  • RequireInitialClear requires the first code to reset the dictionary
  • RequireEndOfInformation rejects a stream that ends without its terminator

Methods

function Decompress(const Input: AnsiString): AnsiString; overload;
function Decompress(const Input: AnsiString;
  Parms: TPDFLZWParms): AnsiString; overload;
function TryDecompress(const Input: AnsiString;
  out Output: AnsiString): Boolean; overload;
function TryDecompress(const Input: AnsiString; Parms: TPDFLZWParms;
  out Output: AnsiString): Boolean; overload;
function DecompressToStream(const Input: AnsiString;
  OutputStream: TStream): Int64;
function DecompressStream(InputStream, OutputStream: TStream;
  RestoreInputPosition: Boolean = True): Int64;
  • Decompress raises EHPDFLZWError on invalid input
  • TryDecompress returns False and exposes the reason through LastError
  • DecompressToStream and DecompressStream return the number of decoded bytes written
  • DecompressStream reads from the current input position and restores that position by default when the stream is seekable

Basic LZW Decompression

TPDFLZWCompressor.CompressToStream and CompressStream return the number of encoded bytes written, including the clear code and end-of-information code for empty input; the default PDF configuration writes 3 bytes for an empty input

uses
  HPDFLZW;

procedure DecompressLZWData;
var
  Decompressor: TPDFLZWDecompressor;
  CompressedData: AnsiString;
  DecompressedData: AnsiString;
begin
  Decompressor := TPDFLZWDecompressor.Create;
  try
    Decompressor.FillOrder := foTop;
    Decompressor.EarlyChange := True;
    Decompressor.MaxOutputBytes := 64 * 1024 * 1024;
    DecompressedData := Decompressor.Decompress(CompressedData);
    ProcessDecompressedData(DecompressedData);
  finally
    Decompressor.Free;
  end;
end;

Stream Output and Diagnostics

procedure DecodeLZWToStream(const CompressedData: AnsiString;
  Destination: TStream);
var
  Decompressor: TPDFLZWDecompressor;
begin
  Decompressor := TPDFLZWDecompressor.Create;
  try
    Decompressor.RequireInitialClear := True;
    Decompressor.RequireEndOfInformation := True;
    Decompressor.DecompressToStream(CompressedData, Destination);
    LogDecodeStatistics(
      Decompressor.CodesRead,
      Decompressor.PeakCodeSize,
      Decompressor.PeakDictionarySize,
      Decompressor.OutputBytes);
  finally
    Decompressor.Free;
  end;
end;

Predictor Parameters

  • Predictor=1 returns the decompressed bytes unchanged
  • Predictor=2 reverses TIFF horizontal differencing
  • Predictor=10..15 reverses the PNG filter tag stored at the start of each row
  • Colors, BitsPerComponent, and Columns define the exact row geometry
  • ExpandedTo8Bit and ColorSpace remain available for source compatibility

Decode Statistics

  • CodesRead, ClearCodesRead, and DictionaryAdds
  • KwKwKExpansions, PeakCodeSize, and PeakDictionarySize
  • OutputBytes and EndedWithEndOfInformation

Error Handling

  • Codes beyond the next dictionary entry are rejected
  • Broken prefix chains and an invalid first code are rejected
  • Truncated input is rejected when RequireEndOfInformation is enabled
  • Output expansion is checked before each phrase is emitted
  • Predictor rows must be complete and use a valid geometry and PNG row tag

See Also