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
  • 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
  • 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

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