Custom Stream Filter Registry
HotPDF can decode application-defined PDF stream filters inside the same bounded pipeline used by its built-in Flate, LZW, ASCII85, ASCIIHex, and RunLength decoders
Register push or pull filters
Implement IHPDFCustomStreamFilter, choose csfmPush or csfmPull, and register the interface through THotPDF.RegisterCustomStreamFilter
Names are matched case-insensitively without a leading slash, duplicate registration is explicit, built-in names cannot be replaced, and each document accepts at most 64 custom names
Registry lookups retain an interface snapshot under a short critical section; filter callbacks and interface destruction run outside the registry lock
One budget across every stage
Custom output consumes DecodeBudgetBytes and DocumentDecodeBudgetBytes through the existing aggregate tracker, so a mixed custom and built-in chain cannot reset expansion accounting between stages
THPDFCustomStreamFilterRequest.MaxOutputBytes reports the remaining per-chain allowance, while zero means the configured per-chain budget is unlimited
The request also supplies the decoded PDF filter name, zero-based stage index, pipeline depth, input size when available, and the caller cancellation token
Cancellation and seek contracts
The cancellation-aware DecodeLoadedStreamToStream overload checks before and after custom execution and during pull-stream transfer
Custom implementations should check Request.CancellationToken inside long push loops or blocking external work
csscSeekable declares that the borrowed input, push destination, or returned pull stream must support seeking; contract violations produce dpsSeekContractViolation
Failure isolation
Every custom stage writes to a bounded THPDFAdaptiveTempStream before any bytes are published to the next stage or caller destination
A false result, exception, cancellation, seek violation, or budget failure discards that temporary output and returns a typed pipeline status without leaking a custom exception across the public decode boundary
A successful pull filter transfers ownership of its returned stream to HotPDF; returning the borrowed input or a nil stream is rejected
Telemetry
GetCustomStreamFilterStatistics reports registered names, push and pull attempts, success, failure, cancellation and seek-violation counts, aggregate input and produced bytes, plus the latest name and diagnostic
THPDFDecodePipelineInfo.CustomFilterCount and CustomFilterFailureCount describe the current chain
Example
Filter := TApplicationFilter.Create;
PDF.RegisterCustomStreamFilter(Filter);
try
if not PDF.DecodeLoadedStreamToStream(StreamObject, Output,
CancellationToken, Info) then
HandleDecodeFailure(Info.Status, Info.Diagnostic);
finally
PDF.UnregisterCustomStreamFilter(Filter.FilterName);
end;