Pages as Images
Pdf::extractAsImages() rasterizes the pages of an existing PDF into standalone image files, one
per page, and returns the paths it wrote. Install the imagick extension with a PDF delegate
before you call it — that extension is what does the rasterizing.
Extracting Every Page#
Two arguments — the PDF to read and the directory to write into:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages');
Given a three-page invoice.pdf, that writes invoice-01.jpg, invoice-02.jpg and
invoice-03.jpg into pages/ and returns their full paths in an array keyed by 1-based page
number:
[
1 => '/path/to/pages/invoice-01.jpg',
2 => '/path/to/pages/invoice-02.jpg',
3 => '/path/to/pages/invoice-03.jpg',
]
The key is the page number in the source document:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages');
foreach ($images as $pageNumber => $image) {
echo $pageNumber . ': ' . basename($image) . "\n";
}
The name in front of the page number is the source file's name without its extension, so files from several PDFs extracted into one directory stay grouped by document. Create the destination directory before the call and make it writable — the method writes into it rather than creating it.
To know how many files are coming before any are written, Build\Image\Extractor::countPages()
counts a document's pages directly:
use Pop\Pdf\Build\Image\Extractor;
$extractor = new Extractor();
echo $extractor->countPages(__DIR__ . '/invoice.pdf');
That prints 3. Building an Extractor is also the cheapest way to check imagick is present,
since that's where the extension is looked for.
Formats and Resolution#
The third and fourth arguments are the output format and the resolution it's rasterized at,
defaulting to jpg at 300 DPI:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 150);
- six formats are supported —
jpg,jpeg,png,webp,tiffandtif— matched case-insensitively, and the format sets the extension on every file written - resolution decides the pixel dimensions: a US Letter page comes out 2550 by 3300 pixels at the default 300 DPI, 1275 by 1650 at 150
- JPEG and WebP write at quality 90 rather than the encoder's own default, because the usual destination for an extracted page is OCR, where compression artifacts along text edges cost more than the bytes they save; PNG and TIFF are lossless already and are written as they come
Reading a page's own size back is a matter of getimagesize() on the returned path:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300);
[$width, $height] = getimagesize($images[1]);
echo $width . 'x' . $height;
Naming the Output Files#
The fifth argument, $filenameFormat, is a sprintf() string that receives the source file's name
without its extension as argument 1 and the 1-based page number as argument 2; the extension is
appended afterward, so the format string covers the stem only. It defaults to '%1$s-%2$02d',
which is where invoice-01 comes from.
Dropping the stem gives files named for the page alone:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300, filenameFormat: 'page-%2$02d');
That writes page-01.png, page-02.png and page-03.png. Changing the padding and separator
gives the unpadded form:
use Pop\Pdf\Pdf;
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300, filenameFormat: 'page_%2$d');
That writes page_1.png, page_2.png and page_3.png. Both positional references stay available
in any order and with any padding, so '%1$s_page_%2$03d' writes invoice_page_001.png.
Selecting Pages#
$pages and $pageLimit are the last two arguments, and they sit behind $filenameFormat, so pass
them by name:
use Pop\Pdf\Pdf;
$firstTwo = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300, pageLimit: 2);
$oneAndThree = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300, pages: [1, 3]);
$pagestakes an array of 1-based page numbers, or a single number on its own —pages: 2andpages: [2]mean the same thing;$pageLimittakes the first n pages of the document- an explicit
$pageslist wins outright: passingpages: [3]alongsidepageLimit: 1writes page 3, not page 1 - filtering keeps the source document's numbering —
pages: [1, 3]returns the keys1and3and writesinvoice-01.pngandinvoice-03.png, so a result key is always the page it came from, whatever selection produced it; that's the opposite ofgetImageOnlyPages(), whose array is keyed from zero - a page number past the end of the document drops out of the selection, and a
$pageLimitlarger than the document extracts every page, so the count of the result tells you how much of a requested range the document actually held
use Pop\Pdf\Pdf;
$requested = [1, 9];
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'png', resolution: 300, pages: $requested);
echo count($images) . ' of ' . count($requested) . ' requested pages written';
Extracting for OCR#
Pdf::isImageOnlyDocument() reports whether a document is scanned images rather than real text,
and gates this call naturally: when it returns true, the pages have to go through OCR instead of
text extraction.
use Pop\Pdf\Pdf;
$file = __DIR__ . '/invoice.pdf';
if (Pdf::isImageOnlyDocument($file)) {
foreach (Pdf::extractAsImages($file, __DIR__ . '/pages', format: 'png', resolution: 300) as $pageNumber => $image) {
// hand $image to an OCR engine, attribute the result to $pageNumber
}
}
Because the result is keyed by source page number, whatever an OCR engine returns can be attributed straight back to the page it came from. See Image-Only Pages for the per-page classification behind that check.
Errors#
Four conditions raise Pop\Pdf\Build\Exception, each one a thing to have in place before the call:
- Install the
imagickextension, which is what does the rasterizing. - Pass a
$filethat exists on disk. - Pass a
$locationthat is an existing, writable directory. - Pass one of the six supported formats.
Each message names what it found:
use Pop\Pdf\Pdf;
use Pop\Pdf\Build\Exception;
try {
$images = Pdf::extractAsImages(__DIR__ . '/invoice.pdf', __DIR__ . '/pages', format: 'bmp');
} catch (Exception $e) {
echo $e->getMessage();
}
That prints Error: The format 'bmp' is not supported.
See Also#
- Image-Only Pages — deciding whether a document needs OCR at all
- Extracting Text — pulling the text layer out of a document that has one
- Importing — reading an existing PDF back in as pages you can edit