Pop PDF
Build

Images

addImage() places an image on a page at a point you choose, and takes either a plain file path or a Page\Image object.

Placing an Image#

addImage($path, $x, $y) reads the file and places its bottom left corner at $x, $y — see Pages & Coordinates. Both default to 0.

PHP
use Pop\Pdf\Document;
use Pop\Pdf\Document\Page;
use Pop\Pdf\Pdf;

$page = new Page(Page::LETTER);
$page->addImage(__DIR__ . '/photo.jpg', x: 72, y: 500);

Pdf::writeToFile(new Document($page), filename: __DIR__ . '/photo.pdf');

Unresized, an image places at one PDF point per source pixel — a 400 by 200 pixel JPEG covers exactly 400 by 200 points with no resize*() or scale() call.

Build an Image object with createImageFromFile() when a page needs to resize it, scale it, or read its dimensions back before placing it:

PHP
use Pop\Pdf\Document;
use Pop\Pdf\Document\Page;
use Pop\Pdf\Document\Page\Image;
use Pop\Pdf\Pdf;

$page  = new Page(Page::LETTER);
$image = Image::createImageFromFile(__DIR__ . '/photo.jpg');
$page->addImage($image, x: 72, y: 500);

Pdf::writeToFile(new Document($page), filename: __DIR__ . '/photo.pdf');

The two forms place identically — a bare string builds the same Image internally via createImageFromFile() — so reach for the object only when you need what it unlocks.

Supported Formats#

createImageFromFile() accepts JPEG, PNG and GIF in any color mode — RGB, grayscale, CMYK JPEGs, and indexed or true-grayscale PNGs all place without incident, and GIF frames convert to PNG internally before embedding.

  • A PNG with a full alpha channel throws Pop\Pdf\Build\Image\Exception at write time: PNG alpha channels are not supported. Only 8-bit transparent PNG images are supported. Indexed transparency — a single transparent color rather than a per-pixel alpha channel — places fine.
  • Any other file type, or a missing path, throws Pop\Pdf\Document\Page\Exception before the page is touched: That image file does not exist. or That image type is not supported. Only GIF, JPG and PNG image types are supported. (a TIFF included).

Images from a Stream#

createImageFromStream() takes the same bytes as a string instead of a path — for an image fetched, generated or uploaded rather than read from disk:

PHP
use Pop\Pdf\Document\Page\Image;

$bytes = file_get_contents('https://example.com/logo.png');
$image = Image::createImageFromStream($bytes);

Both createImageFromFile() and createImageFromStream() are static factories that build a new Image and call the instance method behind them, loadImageFromFile() or loadImageFromStream(). Call load* directly on an Image already in hand to swap its source without building a new one:

PHP
use Pop\Pdf\Document\Page\Image;

$image = new Image();
$image->loadImageFromStream($bytes);

isFile() and isStream() report which source built the Image — otherwise the two are identical: same resizing behavior, same embedded dimensions for the same bytes resized the same way. Resizing below uses a file-sourced Image; everything there applies equally to a stream-sourced one.

Resizing#

resizeToWidth() and resizeToHeight() set one dimension and scale the other to match the image's original aspect ratio:

PHP
use Pop\Pdf\Document\Page\Image;

// A 400 by 200 pixel source
$image = Image::createImageFromFile(__DIR__ . '/photo.jpg');
$image->resizeToWidth(200);
echo $image->getResizedWidth() . ' x ' . $image->getResizedHeight(); // 200 x 100

resizeToHeight(50) on the same source reports 100 x 50 — width follows height at the same 2-to-1 ratio. resize($pixel) targets whichever original dimension is larger: on the 400 by 200 source, resize(100) treats width as larger and reports 100 x 50, the same as resizeToWidth(100); on a taller-than-wide source, resize() targets height instead.

None of the three touch the source file — they record a target that getResizeDimensions() reports back, and resampling happens once, when the document compiles.

Every resizing method takes a second, optional argument, $preserveResolution — see Preserved Resolution for what it changes.

Scaling#

scale() multiplies both dimensions by a single factor instead of targeting a pixel count:

PHP
use Pop\Pdf\Document\Page\Image;

$image = Image::createImageFromFile(__DIR__ . '/photo.jpg');
$image->scale(0.25);
echo $image->getResizedWidth() . ' x ' . $image->getResizedHeight(); // 100 x 50

scale(0.25) reports 100 x 50, matching resize(100) above — the two agree whenever the factor matches the ratio a resize target implies; reach for scale() when you know the ratio rather than a target pixel count.

Reading Back Dimensions#

getWidth() and getHeight() report the source image's own pixel dimensions, unaffected by any resize or scale call. getResizedWidth(), getResizedHeight() and getResizeDimensions() report the target set by whichever of resizeToWidth(), resizeToHeight(), resize() or scale() ran last:

PHP
use Pop\Pdf\Document\Page\Image;

$image = Image::createImageFromFile(__DIR__ . '/photo.jpg');
var_dump($image->getResizedWidth());     // NULL
var_dump($image->getResizeDimensions()); // NULL

$image->resizeToWidth(150);
var_dump($image->getResizeDimensions()); // array('width' => 150, 'height' => 75)

Until one of those four methods runs, all three getters return null.

Preserved Resolution#

Every resizing and scaling method takes a trailing $preserveResolution argument, and isPreserveResolution() reports what was passed:

  • false (default) — re-samples the pixel data down to the resize target before embedding; placed and embedded sizes match, and the file is smaller.
  • true — keeps the full source pixel data embedded and only shrinks the placed size: a resize to 100 x 50 still shows a 100 by 50 point box on the page, but the pixels behind it stay at the original resolution.
PHP
use Pop\Pdf\Document\Page\Image;

$image = Image::createImageFromFile(__DIR__ . '/photo.jpg');
$image->resizeToWidth(100, preserveResolution: true);
var_dump($image->isPreserveResolution()); // true

The benefit of this is that it will keep high quality images looking sharp when they are scaled down. Performing a resize without preserving the resolution can lead to noticeable image degradation. However, the trade-off of preserving resolution is that the PDF file size will be larger.

A Page Built From an Image#

Page::createFromImage($file, $quality = 70) builds a page sized to match the image exactly, with the image placed to cover it edge to edge:

PHP
use Pop\Pdf\Document;
use Pop\Pdf\Document\Page;
use Pop\Pdf\Pdf;

$document = new Document();
$scans = ['scanned-1.jpg', 'scanned-2.jpg', 'scanned-3.jpg'];

foreach ($scans as $scan) {
    $document->addPage(Page::createFromImage(__DIR__ . '/' . $scan, quality: 50));
}

Pdf::writeToFile($document, filename: __DIR__ . '/scanned.pdf');

The page always matches the source's pixel dimensions exactly. Every source, JPEG, PNG or GIF, converts to JPEG before embedding, so $quality always applies, even to an already-JPEG source. The lower the quality, the smaller the PDF file size, but the more the page images will show degradation.

createFromImage() is the direct route from a scanned page image to a one-page PDF; reach for Placing an Image instead when the image is one element among others — text, a drawn path, other images — on a page you are composing yourself.

See Also#

  • Pages & Coordinates — the coordinate system every addImage() call places against
  • Drawing & Paths — combining drawn shapes with placed images on the same page
  • Saving & Output — writing the finished document to a file or a browser response