Skip to content
getnextpdf.com

Pro edition

Filter

NextPDF\Pro\Filter provides two focused helpers: a parser for the PDF /DecodeParms dictionary and a reverse-filter for the PNG predictor applied to FlateDecoded streams. It is the predictor support used by the Pro Diff and Classifier extractors; it is not a general filter framework.

This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.

The Filter classes are available whenever nextpdf/pro is installed; no runtime capability flag gates this module.

Terminal window
composer require nextpdf/pro:^3

PDF streams may be FlateDecode-compressed and additionally pre-processed with a predictor to improve compression. ISO 32000-2:2020 §7.4.4.4 defines the predictor parameters (/Predictor, /Columns, /Colors, /BitsPerComponent) and the PNG predictor family (tags 10–15).

  • DecodeParms parses a /DecodeParms dictionary fragment into an immutable value object with sane defaults (predictor 1, columns 1, colors 1, bits-per-component 8). isPngPredictor() is true for tags 10–15.
  • PngPredictor applies the inverse of the five PNG filter types — None, Sub, Up, Average, Paeth — plus Optimum (predictor 15, per-row tag). It validates parameters and raises InvalidArgumentException on out-of-range values or a truncated row.

This module reverses an existing predictor when reading a stream. It does not implement the full set of PDF stream filters and it does not provide filter-tuning hooks.

The module reverses an existing predictor rather than offering a general filter framework. The Pro Diff and Classifier extractors only read what a producer already wrote, so a narrow scope is enough. That scope lets every input be bounded before any byte is processed. DecodeParms::fromDictionary() is the parse-time chokepoint: it rejects negative or oversized geometry and applies the DecodeParms::__construct() defaults where a key is absent. PngPredictor re-checks those bounds at apply time, so a hostile /DecodeParms raises a typed error rather than a large allocation. Callers branch on DecodeParms::isPngPredictor(), keeping the TIFF predictor out of a reverse filter that handles only tags 10–15.

Design background: Streams and filters.

  • DecodeParms::fromDictionary(string $raw): self — whitespace-tolerant integer matching; absent keys keep their defaults.
  • PngPredictor::inverse(string $raw, int $columns, int $colors, int $bitsPerComponent, int $predictor): string — predictor must be 10–15; columns and colors must be ≥ 1; bits-per-component must be 1, 2, 4, 8, or 16; a row shorter than the computed stride raises InvalidArgumentException.
  • Determinism. Output is a pure function of the inputs.
TypeKindKey members
NextPDF\Pro\Filter\DecodeParmsfinal readonly class__construct(int $predictor = 1, int $columns = 1, int $colors = 1, int $bitsPerComponent = 8), static fromDictionary(string $raw): self, isPngPredictor(): bool
NextPDF\Pro\Filter\PngPredictorfinal classstatic inverse(string $raw, int $columns, int $colors, int $bitsPerComponent, int $predictor): string
<?php
declare(strict_types=1);
use NextPDF\Pro\Filter\DecodeParms;
use NextPDF\Pro\Filter\PngPredictor;
$parms = DecodeParms::fromDictionary('<< /Predictor 15 /Columns 640 /Colors 3 >>');
if ($parms->isPngPredictor()) {
$raw = PngPredictor::inverse(
$flateDecodedBytes,
$parms->columns,
$parms->colors,
$parms->bitsPerComponent,
$parms->predictor,
);
}
<?php
declare(strict_types=1);
use InvalidArgumentException;
use NextPDF\Pro\Filter\DecodeParms;
use NextPDF\Pro\Filter\PngPredictor;
function undoPredictor(string $decoded, string $dictFragment): string
{
$parms = DecodeParms::fromDictionary($dictFragment);
if (! $parms->isPngPredictor()) {
return $decoded; // no predictor, or TIFF predictor — return as-is
}
try {
return PngPredictor::inverse(
$decoded,
$parms->columns,
$parms->colors,
$parms->bitsPerComponent,
$parms->predictor,
);
} catch (InvalidArgumentException) {
return $decoded; // malformed predictor metadata — fail safe
}
}
  • TIFF predictor (tag 2) is recognized by DecodeParms but is not reverse-filtered by PngPredictor (which accepts only 10–15). Callers should branch on isPngPredictor().
  • A predictor row shorter than the computed stride is rejected; it is not silently truncated.
  • The row stride is computed from columns * colors * bitsPerComponent; mismatched /DecodeParms versus actual stream layout produces a parameter or truncation error rather than corrupt output.

PngPredictor::inverse() is linear in stream length with a small per-byte constant. DecodeParms parsing is a few bounded regular-expression matches. See performance_budget.

Parameter ranges are validated before any byte processing, and a truncated row raises rather than reads out of bounds. Callers reversing predictors on untrusted streams should also bound the decompressed size upstream, as the Pro Diff and Classifier extractors do.

ClaimSpec clauseStatus
/DecodeParms parameters and defaultsISO 32000-2:2020 §7.4.4.4Verified (unit suite)
PNG predictor reverse-filter, tags 10–15ISO 32000-2:2020 §7.4.4.4Verified (unit suite)
Full PDF stream-filter frameworkNot supported (out of scope)

No Core equivalent is exposed for PNG-predictor reversal. Core’s own stream handling is internal to the engine and not part of this public surface.

This is a narrow predictor helper. It is not a cryptographic filter, a content sanitizer, or a data-reconstruction/disarm component; those concerns are out of scope.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.