Skip to content

Latest commit

 

History

History
138 lines (100 loc) · 7.74 KB

PDF_IMPORT.md

File metadata and controls

138 lines (100 loc) · 7.74 KB

PDF Import

Back to root overview: README.md

tc-lib-pdf can import pages from existing PDFs as Form XObjects and place them on destination pages.

Source Registration and Page Count

$sourceId = $pdf->setImportSourceFile('/path/to/source.pdf');
// or: $sourceId = $pdf->setImportSourceData($rawPdfBytes);

$count = $pdf->getSourcePageCount($sourceId);

setImportSourceFile() reads the file through the same local-path allowlist as other resources: the path must be inside one of the allowedPaths file options (see REMOTE_RESOURCES.md). A path outside the allowlist raises ImportSourceNotFoundException, as a missing file does. setImportSourceData() takes the bytes directly and performs no path check.

The page count is derived from the page tree actually reachable through /Kids; the declared /Count entry of the /Pages dictionary is ignored, so a forged or wrong /Count cannot influence how many pages are counted or imported. Structurally broken page trees (missing /Kids, unexpected node types, duplicate or cyclic references) raise ImportCorruptedSourceException.

The reachable-page walk runs once per registered source and produces a flattened page index (one effective page dictionary per page, with inherited attributes resolved) that is cached and reused by getSourcePageCount(), importPage(), and importPages().

Parser Limits and Diagnostics

setImportSourceFile() and setImportSourceData() accept an optional configuration array that is forwarded to the parser. Parsing happens once per source, at registration time, so these settings belong here rather than in the per-page importPage() options.

Key Type Default Meaning
ignore_filter_errors bool false Keep a stream that fails to decode as raw data instead of failing
decode_streams bool false Decode stream payloads while parsing indirect objects
max_stream_size int 33554432 Maximum size in bytes of a single decoded stream; 0 means unlimited
max_resolution_depth int 64 Maximum number of indirect object resolutions in flight at once; values below 1 are clamped to 1
max_nesting_depth int 256 Maximum nesting depth of array and dictionary objects; values below 1 are clamped to 1
strict_limits bool false Fail with ImportResourceLimitException as soon as a limit leaves an object unresolved

Exceeding max_nesting_depth always raises ImportResourceLimitException: a dictionary or array that cannot be tokenized has no usable value to fall back to. Reaching max_resolution_depth, or meeting a reference cycle, leaves that reference unresolved and lets the rest of the document import; the affected pages may lose content whose object could not be reached.

Those non-fatal cases are recorded as document warnings, one per kind of event, with the number of occurrences and the first object affected:

$sourceId = $pdf->setImportSourceFile('/path/to/source.pdf');
$pdf->importPages($sourceId);
$pdf->getOutPDFString();

foreach ($pdf->getWarnings() as $warning) {
    // "The source document 3fa8c1d2 was not fully resolved while parsing: the indirect
    //  object resolution depth limit (64) left a reference unresolved 7 times, first
    //  at object 128_0"
}

The warning list is complete only after getOutPDFString() has been called, like every other document warning.

To fail instead of degrading, set strict_limits:

try {
    $sourceId = $pdf->setImportSourceFile('/path/to/source.pdf', ['strict_limits' => true]);
} catch (\Com\Tecnick\Pdf\Import\ImportResourceLimitException $exc) {
    // the source needs higher limits, or cannot be imported faithfully
}

To import a document that legitimately nests deeper than the defaults, raise the limits:

$sourceId = $pdf->setImportSourceFile('/path/to/source.pdf', [
    'max_resolution_depth' => 512,
    'max_nesting_depth'    => 2048,
]);

ImportResourceLimitException extends ImportCorruptedSourceException, so a handler for the latter around source registration also catches limit failures.

Page Content Streams

A page /Contents entry is accepted in every form the specification allows: a stream, an array of streams, or an indirect reference to either. Several streams are decoded and concatenated into the single stream of the resulting Form XObject.

A page whose /Contents entry cannot be resolved to any stream is imported as an empty Form XObject and reported as a document warning, so a blank imported page is never silent:

$pdf->importPage($sourceId, 1);
$pdf->getOutPDFString();

foreach ($pdf->getWarnings() as $warning) {
    // "The imported page 1 has a /Contents entry but no content stream could be
    //  extracted: the page will be blank"
}

A /Contents stream that exists but is empty, and an empty /Contents array, are legal empty contents and are not reported.

Import One Page and Place It

$tpl = $pdf->importPage($sourceId, 1, [
    'box' => 'CropBox',          // MediaBox|CropBox|BleedBox|TrimBox|ArtBox
    'groupXObject' => true,
    'cache' => true,
    'respectRotation' => true,
]);

$pdf->addPage();
$placed = $pdf->useImportedPage($tpl, 20, 20, 120, 80, [
    'keepAspectRatio' => true,
    'align' => 'CC',             // TL|TC|TR|CL|CC|CR|BL|BC|BR
    'clip' => true,
]);

Append Pages from a Source Document

// Append all pages.
$templates = $pdf->appendDocument($sourceId);

// Append only selected pages.
$templates = $pdf->appendDocument($sourceId, [1, 3, 5]);

// Add one imported page sized to the source page.
$tpl = $pdf->addPageFromImport($sourceId, 2);

Import Examples

Import Limitations and Fidelity Notes

  • Form and annotation semantics are not merged into editable destination structures; pages are imported as Form XObjects.
  • Digital signatures in source files are not preserved as valid signatures in the destination output.
  • Encrypted source PDFs are not importable with the bundled parser backend. Password-like options are accepted by the import API, but encrypted inputs fail with an explicit exception.
  • Multi-stream page contents are normalized by decoding and concatenating the stream bytes; this changes the low-level byte representation while preserving the rendered appearance.
  • Transparency-group behavior is conformance-aware: when transparency is disallowed by the active PDF mode (PDF/A-1, PDF/X-1a or PDF/X-3), import suppresses transparency groups to remain compliant.
  • Stream filters are conformance-aware: a source stream compressed with LZWDecode, which ISO 19005 forbids, is decoded and re-encoded with FlateDecode. When the stream cannot be re-encoded (an undecodable filter chain), a PDF/A destination raises ImportUnsupportedFeatureException and any other mode keeps the source stream unchanged. Importing a JPXDecode stream into a PDF/A-1 document raises the same exception, since ISO 19005-1 does not allow that filter.
  • Tagged structure (StructTreeRoot, structure elements, StructParents and marked-content IDs) of the source is not imported. Conformance awareness covers only the filter and transparency rules above. Imported pages are untagged, so a PDF/UA destination that contains imported pages is not PDF/UA compliant for that content.
  • Setting groupXObject to false can reduce output size, but may change compositing on source pages that rely on transparency blending.