PHPackages                             machinateur/the-printer - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. machinateur/the-printer

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

machinateur/the-printer
=======================

The printer, a prototype. Create PDF documents and images from HTML content using puppeteer and headless-chrome.

1.1.0(1y ago)225MITPHPPHP &gt;=8.1

Since Oct 22Pushed 1y ago1 watchersCompare

[ Source](https://github.com/machinateur/the-printer)[ Packagist](https://packagist.org/packages/machinateur/the-printer)[ RSS](/packages/machinateur-the-printer/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (7)Versions (3)Used By (0)

machinateur/the-printer
=======================

[](#machinateurthe-printer)

The printer, a prototype. Create PDF documents and images from HTML content using puppeteer and headless-chrome.

This repository contains the express app (node) and a PHP client implementation with stream support.

The PHP SDK has zero package dependencies, to keep it as simple as possible.

Requirements
------------

[](#requirements)

- At least PHP `>=8.1` is required
    - Extensions `ext-json` and `ext-curl` are required
- Node LTS `18` is recommended
- Use NPM or Yarn
- Chrome (headless)

Installation
------------

[](#installation)

```
composer require machinateur/the-printer
npm i --save @machinateur/the-printer

```

Note that the express app is also bundled with the composer package.

Advantages
----------

[](#advantages)

- Support, not only for `pdf` documents, but also images (`png`, `jpeg`, `webp`)
- Design advanced PDF layouts using modern web technologies (HTML + CSS)
    - All the latest features, like `flex` etc., are available
- Preview design directly in chrome-based browsers `document.print()` dialog
    - No need for lengthy feedback and testing loops
- Large number of options available ([see "Supported endoints"](#supported-endpoints))
    - Full control over the printing process result
- JavaScript support (images only)
    - *You've been warned* :)
- Integrate fonts in various formats without the hardships (i.e. font-caches, loading delay, etc.)
    - The printing process will wait for fonts to load by default
    - All the well-known formats supported by chrome are available
- Full test coverage
    - The test-suite included with this library is well-procured
- Documentation
    - Many documentation resources are available
    - The code self-contains documentation (can be used to [generate an API reference](#generating-phpdoc))

Usage
-----

[](#usage)

### Running the express app

[](#running-the-express-app)

Run

```
npm start
```

or

```
node the-printer.js
```

to launch the express app. Make sure to install the dependencies first.

#### Supported CLI args and environment variables

[](#supported-cli-args-and-environment-variables)

The following arguments are supported, with respective fallback to the env-var.

- Option `--debug`: Control debug output and `dumpio` from chrome `STDOUT`/`STDERR`.
    - Fallback: `APP_DEBUG`
    - Default: `false`
- Option `--connect-to`: Use an existing browser instance at that address, supports `ws` and `http`.
    - Fallback: `APP_REMOTE`
    - Default: Launch headless chrome instance locally.
- Option `--script`: Control JavaScript execution.
    - Fallback: `APP_ENABLE_JAVASCRIPT`
    - Default: `false` (JavaScript is not executed)
- Option `--port`: Set the app port, format `\d+`.
    - Fallback: `APP_PORT`
    - Default: `3000`

### Calling from PHP

[](#calling-from-php)

From PHP the bundled client provided in this composer package may be used to interact with the express app. It has to be running for this to work.

#### Create and return a document from php

[](#create-and-return-a-document-from-php)

The following example will render a document (in `A5` format without header/footer) and return it directly to the output buffer.

```
$configuration = new \Machinateur\ThePrinter\Configuration\DocumentConfiguration();
$configuration->setPageFormat('A5');

$content = '';

$outputBuffer = \fopen('php://output', 'w', false, null);

$client = new \Machinateur\ThePrinter\Client('http://127.0.0.1:3000/', 10);

\header(\sprintf('%s: %s', 'Content-Type', 'application/pdf'), true, 200);

$client->document($configuration, $content, $outputBuffer);
```

You can use the `\Machinateur\ThePrinter\Client::documentBinary()` method instead, to get the output as a binary string. It's always possible to write to a stream resource and process/read it later, to save memory. If no buffer is provided, it is created as temporary stream and has to be closed by the implementor. The PDF documents do not support JavaScript execution before rendering. This is a engine limitation.

#### Create and return an image from php

[](#create-and-return-an-image-from-php)

The following example does about the same thing, but with a (full-page) screenshot.

```
$configuration = new \Machinateur\ThePrinter\Configuration\ImageConfiguration();
$configuration->setCapturePage(true);

$content = '';

$outputBuffer = \fopen('php://output', 'w', false, null);

$client = new \Machinateur\ThePrinter\Client('http://127.0.0.1:3000/', 10);

\header(\sprintf('%s: %s', 'Content-Type', 'image/png'), true, 200);

$client->image($configuration, $content, $outputBuffer);
```

As with the `\Machinateur\ThePrinter\Client::document()` method, there is a `\Machinateur\ThePrinter\Client::imageBinary()` method to retrieve the buffer as string blob. The provided HTML content is set as the page content directly. Keep in mind that JavaScript is disabled in case you rely on it for rendering. That setting can be controlled from the `--no-script` option or using the `APP_ENABLE_JAVASCRIPT` env-var.

### Calling from other languages

[](#calling-from-other-languages)

It's totally possible to interact with the express app from other programming languages as well. Just use the [supported endpoints](#supported-endpoints) directly via your favourite HTTP client. The response content will be a binary stream of the mime-type from the response header. In case of an error (request format or something else) the response will be a json object of type `{Error&{statusCode?:number}}` where `trace` is removed when not in debug mode.

### Using HTTP files

[](#using--http-files)

Find details on the available endpoints and their options in the HTTP files contained in this repository.

> TODO

Supported endpoints
-------------------

[](#supported-endpoints)

> **`POST` `/document`**
>
> Create a PDF document from the provided content string.
>
> ```
> {
>   "configuration": {
>     ...
>   },
>   "content": "",
>   "time": 1696091198
> }
> ```
>
>
>
> Configuration:
>
> ```
> /**
>  * @typedef {object} DocumentConfiguration
>  * @property {number|null} scale
>  * @property {boolean} displayContentOnly
>  * @property {boolean} displayBackgroundGraphic
>  * @property {boolean} displayTransparent
>  * @property {object|null} template
>  * @property {string|null} template.header
>  * @property {string|null} template.footer
>  * @property {string} pageOrientation
>  * @property {string|null} pageFormat
>  * @property {string|number|undefined} pageWidth
>  * @property {string|number|undefined} pageHeight
>  * @property {string} pageRange
>  * @property {boolean} pageOverride
>  * @property {object|null} margin
>  * @property {string|number|undefined} margin.top
>  * @property {string|number|undefined} margin.right
>  * @property {string|number|undefined} margin.bottom
>  * @property {string|number|undefined} margin.left
>  */
> ```
>
>
>
> Further reference:
>
> -
> -
> -

> **`POST` `/image`**
>
> Create an image from the provided content string.
>
> ```
> {
>   "configuration": {
>     ...
>   },
>   "content": "",
>   "time": 1696091198
> }
> ```
>
>
>
> Configuration:
>
> ```
> /**
>  * @typedef {object} ImageConfiguration
>  * @property {string|null} type
>  * @property {number|null} quality
>  * @property {number|null} scale
>  * @property {object|null} area
>  * @property {number} area.x
>  * @property {number} area.y
>  * @property {number} area.width
>  * @property {number} area.height
>  * @property {boolean} optimize
>  * @property {boolean} captureViewportOnly
>  * @property {boolean} captureSurface
>  * @property {boolean} capturePage
>  * @property {boolean} displayTransparent
>  */
> ```
>
>
>
> Further reference:
>
> -
> -

Development
-----------

[](#development)

### Setup

[](#setup)

To set this project up from scratch for development, run the following commands:

```
git clone git@github.com:machinateur/the-printer.git
cd the-printer
composer install
```

### Running tests

[](#running-tests)

Execute the PHPUnit test-suite using the following command:

```
composer run-script --timeout=0 tests
```

All tests are stored at `./tests` under the `\Machinateur\ThePrinter\Tests\...` namespace.

The configuration is stored in [`phpunit.xml.dist`](phpunit.xml.dist).

#### Running tests in multiple PHP versions

[](#running-tests-in-multiple-php-versions)

It's possible to run the tests in different versions of PHP without the need to install all those versions locally. Thanks to docker, this can be done using a single command:

```
PHP_VERSION=8.1

docker run --rm -v "$(pwd):/app" -w /app 'composer'           install
docker run --rm -v "$(pwd):/app" -w /app "php:${PHP_VERSION}" vendor/bin/phpunit
```

See [this guide](https://www.shiphp.com/blog/testing-multiple-versions-of-php) for some more details.

#### Generate coverage

[](#generate-coverage)

Execute the PHPUnit test-suite and gain coverage insights using the following command:

```
composer run-script --timeout=0 coverage
```

This command uses the text UI of PHPUnit exclusively.

#### About `ProcessTestCase`

[](#about-processtestcase)

The class `\Machinateur\ThePrinter\Tests\ProcessTestCase` is a custom `\PHPUnit\Framework\TestCase` that supports managing a background process that is started and stopped with the *test class* itself.

While this can impact the test-suite performance quite heavily, if used excessively and depending on the type of background process.

This is utilized to enable a functional test using `node` as background process running the `the-printer.js` server. The test is located at `` and holds some other interesting details, discussed [below](#embedded-phpt-test-suite).

#### About `ServerTestCase`

[](#about-servertestcase)

The class `\Machinateur\ThePrinter\Tests\Server\ServerTestCase` is a variant of the `ProcessTestCase` that specifically uses the PHP built-in webserver. This can be useful, if a test requires a *mocked webserver*.

This is utilized to mock server responses for actual testing of the `curl` calls within the `\Machinateur\ThePrinter\Stream\Connection`.

#### Embedded PHPT test-suite

[](#embedded-phpt-test-suite)

The project-level test-suite embeds a separate test-suite as part of the `\Machinateur\ThePrinter\Tests\Result\ResultTest`, where some separate [PHPT tests](https://qa.php.net/phpt_details.php) are loaded.

You can find other examples of such tests being used, for example in the [PHP `curl` extension](https://github.com/racklin/curl_ext_52x/blob/master/tests/curl_CURLOPT_READDATA.phpt)itself.

Thanks to [PHPUnit's built-in support](https://github.com/sebastianbergmann/phpunit/blob/10.5/src/Runner/PhptTestCase.php)for the ancient PHPT format, although somewhat thinly documented, they were really easy to integrate.

The PHPT tests are used to test the accuracy of actual printing results (image and document) using imagick. This comes with some drawbacks and was an experimental approach in the beginning. It can serve as an example for real world use-cases of this "digital print server".

Feel free to [browse the code](tests/Result) and have a look yourself. Improvements and creative additions are always welcomed.

#### Managing control files

[](#managing-control-files)

The comparison (aka. control) files for PHPT tests are stored under `tests/Result/res/`.

### Running static analysis

[](#running-static-analysis)

To execute PhpStan for static analysis, call the following composer script:

```
composer run-script lint
```

This command maps to `./vendor/bin/phpstan analyze` using the [`phpstan.neon`](phpstan.neon) file from the project root.

### Generating `phpdoc`

[](#generating-phpdoc)

It's possible to generate `phpdoc` with [phpDocumentor](https://docs.phpdoc.org/guide/getting-started/installing.html#installation):

```
rm -r docs/ var/phpdoc/
docker run --rm -v "$(pwd):/data" 'phpdoc/phpdoc:3'
```

The resulting documentation will be placed in `docs/`, the case is located at `var/phpdoc/`, both are ignored from git.

License
-------

[](#license)

It's MIT.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance38

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

2

Last Release

569d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2ac6a840f958d6940c5e2486c0ccc116f280f0f2ef3790b15f986b565a48459c?d=identicon)[machinateur](/maintainers/machinateur)

---

Top Contributors

[![machinateur](https://avatars.githubusercontent.com/u/81334941?v=4)](https://github.com/machinateur "machinateur (12 commits)")

---

Tags

pdfimagepuppeteerprintheadless-chrome

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/machinateur-the-printer/health.svg)

```
[![Health](https://phpackages.com/badges/machinateur-the-printer/health.svg)](https://phpackages.com/packages/machinateur-the-printer)
```

###  Alternatives

[spatie/browsershot

Convert a webpage to an image or pdf using headless Chrome

5.2k32.1M102](/packages/spatie-browsershot)[barryvdh/laravel-snappy

Snappy PDF/Image for Laravel

2.8k24.8M48](/packages/barryvdh-laravel-snappy)[spatie/pdf-to-image

Convert a pdf to an image

1.4k15.2M64](/packages/spatie-pdf-to-image)[chrome-php/chrome

Instrument headless chrome/chromium instances from PHP

2.6k4.5M64](/packages/chrome-php-chrome)[gotenberg/gotenberg-php

A PHP client for interacting with Gotenberg, a developer-friendly API for converting numerous document formats into PDF files, and more!

3685.2M19](/packages/gotenberg-gotenberg-php)[spiritix/php-chrome-html2pdf

A PHP library for converting HTML to PDF using Google Chrome

153472.0k3](/packages/spiritix-php-chrome-html2pdf)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
