Overview
tc-lib-pdf-image handles image import, conversion, and embedding structures used by PDF generators.
Decoding, re-encoding, alpha extraction, and ICC handling all happen here, so document-level code deals in image identifiers and placement rather than in pixels.
Repository and API Docs
- GitHub: https://github.com/tecnickcom/tc-lib-pdf-image
- API docs: https://tcpdf.org/docs/srcdoc/tc-lib-pdf-image
- Packagist: https://packagist.org/packages/tecnickcom/tc-lib-pdf-image
Project Metadata
| Item | Value |
|---|---|
| Namespace | \Com\Tecnick\Pdf\Image |
| License | GNU LGPL v3 |
Installation
composer require tecnickcom/tc-lib-pdf-image
Where It Fits
When a document pulls in artwork the application did not produce: uploads, assets from a CDN, or files a customer supplied.
Features
Import Support
- Native PNG and JPEG parsing
- Other formats re-encoded to PNG or JPEG through GD
- Transparency, palette and ICC profile handling
- PNG chunks are validated on import: bit depth against colour type, palette size,
tRNSpayload andiCCPchunk, withIDATandIENDrequired and the ICC decompression bounded - The ICC profile of a JPEG is extracted by walking the marker chain, and the full
APP2chunk sequence is required - An image above the pixel budget (64 megapixels) is rejected before it reaches GD
- An indexed image carrying partial alpha is split into an image and its soft mask
PDF Integration
- Image caching keys for repeated assets, keyed on the mask flag and on the alternate image list
- Alternate image support for print/display contexts
- Output helpers for embedding image objects
- An ICC profile is used as the base of an
/Indexedcolour space getImageDimensionsByKey()returns the stored dimensions of an already imported image, optionally scaled to a target box- Missing width or height is derived automatically from the source image, preserving its aspect ratio
Transparency-Free Output
The notransparency constructor flag of Output serves the conformance modes that forbid transparency (PDF/A-1, PDF/X-1a, PDF/X-3). It suppresses the /SMask entry and drops the mask sub-image of an alpha-split image, so only the flattened image is emitted and the alpha channel is lost.
Two accessors let the caller report that loss and the colour-space one next to it:
hasDroppedAlpha()is true once a soft mask has been dropped for that reason.hasDeviceCmykImage()is true when any added image is emitted inDeviceCMYK, which ISO 19005 allows only when the output intent defines the same space.
tc-lib-pdf reads both and turns them into document warnings; see /docs/standards/.
File Access
The importer takes a configured \Com\Tecnick\File\File helper instead of a plain options array, so host and path allowlists are owned by the calling application:
$fileHelper = new \Com\Tecnick\File\File(
allowedHosts: ['example.com', 'cdn.example.com'],
allowedPaths: ['/srv/app/images', __DIR__ . '/images'],
);
$img = new \Com\Tecnick\Pdf\Image\Import(
kunit: 1.0,
encrypt: $encrypt,
fileHelper: $fileHelper,
);
An existing importer can be rebound to a different helper with withFileHelper().
Persistent Image Cache
Processing an image (decode, resize, re-encode, alpha-mask extraction) is the expensive part of importing. By default the result is cached in memory for the lifetime of the Import instance, so reusing the same image within one document is cheap.
To reuse processed images across documents and processes, inject an optional external cache. The library ships only the contract, \Com\Tecnick\Pdf\Image\ImageCacheInterface, and you provide the backend (filesystem, APCu, Redis, a PSR-16 cache, and so on):
interface ImageCacheInterface
{
/** @return array|null Stored image data, or null on a miss. */
public function get(string $key): ?array;
public function set(string $key, array $data): void;
}
Pass an implementation as the imageCache constructor argument; the default null keeps the in-memory-only behavior:
$img = new \Com\Tecnick\Pdf\Image\Import(
kunit: 1.0,
encrypt: $encrypt,
fileHelper: $fileHelper,
imageCache: $myCache, // any ImageCacheInterface implementation
);
On a miss the processed data is written through to the cache; on a later run a hit short-circuits all processing. For local files the persistent key folds in the file modification time and size, so editing an image in place invalidates its stale entry automatically. An entry loaded from the cache is validated before use, and a backend failure is treated as a miss.
A minimal filesystem-backed implementation:
use Com\Tecnick\Pdf\Image\ImageCacheInterface;
final class FilesystemImageCache implements ImageCacheInterface
{
public function __construct(private readonly string $dir) {}
public function get(string $key): ?array
{
$file = $this->dir . '/' . hash('xxh128', $key) . '.cache';
if (!is_file($file)) {
return null;
}
$data = unserialize((string) file_get_contents($file), ['allowed_classes' => false]);
return is_array($data) ? $data : null;
}
public function set(string $key, array $data): void
{
$file = $this->dir . '/' . hash('xxh128', $key) . '.cache';
file_put_contents($file, serialize($data), LOCK_EX);
}
}
The cache store is a trust boundary: stored bytes are embedded verbatim into generated PDFs, so use a store only your application can write to, and deserialize with object restoration disabled (['allowed_classes' => false]).
Integration Notes
The importer rejects anything above 64 megapixels before it reaches GD, which covers the obvious decompression bombs. Check dimensions and type at your own boundary too, where you can return a useful error instead of an exception.
Decide on one DPI assumption for incoming artwork and apply it at upload. Images that arrive tagged at 72, 150, and 300 DPI otherwise lay out at three different physical sizes from the same pixel count.
SVG is not handled here: it is markup, tc-lib-pdf renders it, and it can reference remote and local resources. Untrusted SVG needs the allowlists in /docs/remote-resources/, not an image-format check.
Requirements
- PHP 8.2 or later
- Extensions:
gd,zlib - Package dependencies:
tecnickcom/tc-lib-file,tecnickcom/tc-lib-pdf-encrypt - Composer
Example
<?php
require_once __DIR__ . '/vendor/autoload.php';
$encrypt = new \Com\Tecnick\Pdf\Encrypt\Encrypt();
$fileHelper = new \Com\Tecnick\File\File(
allowedPaths: [__DIR__],
);
$img = new \Com\Tecnick\Pdf\Image\Import(
kunit: 1.0,
encrypt: $encrypt,
fileHelper: $fileHelper,
);
$imageId = $img->add(__DIR__ . '/image.png');
// The cache key of an imported image gives access to its stored data and dimensions.
$key = $img->getKey(__DIR__ . '/image.png');
var_dump($imageId, $img->getImageDimensionsByKey($key));
Development and Packaging
- QA and local checks:
make deps,make help,make qa - Coverage report:
make qa-coverage - Packaging:
make rpm,make deb
Support and Contribution
- Sponsor: https://github.com/sponsors/tecnickcom
- Contribution guide: https://github.com/tecnickcom/tc-lib-pdf-image/blob/main/CONTRIBUTING.md
- Security policy: https://github.com/tecnickcom/tc-lib-pdf-image/blob/main/SECURITY.md