# JustUtils PDF compression benchmark — September 7, 2026

This is a measured local development-build benchmark, published by JustUtils with automated browser checks and AI-assisted inspection/visual review. It has no named human specialist sign-off. Corrections: support@justutils.com.

## Evidence

- [Browser results](browser-results.json): timestamp, exact bytes and SHA-256 hashes, settings, library versions, source hashes, UI messages, screenshot filenames.
- [Independent inspection](inspection-results.json): pypdf text/link/form checks and OpenSSL CMS integrity checks.
- [Render results](render-results.json): Poppler settings, image filenames, pixel comparisons (not a quality score).
- [Completed scorecard](scorecard.csv).
- [Existing unsigned input](../pdf-feature-survival-fixture.pdf): version 1, generated September 1, 2026, 3,092 bytes; SHA-256 `70ad929cff0954fe6b3e00635c02a4ec306cd96db72e865415867eb8f3ddabe1`.
- [Synthetic signed input](signed-original.pdf): 10,414 bytes, signed September 7, 2026; SHA-256 `eca9821cb5e8d0778566c63df8d4c72cd76194bc3deece7b32edad2bd00a6d33`.
- [Public synthetic certificate](synthetic-certificate.crt): PEM-encoded, self-signed, not a verified identity. No private key is published or retained by the generator.

| Input | Preserve output | Balanced output | Smallest output |
| --- | --- | --- | --- |
| Unsigned | [3,092 bytes](feature-lossless.pdf) | [88,602 bytes](feature-balanced.pdf) | [51,486 bytes](feature-small.pdf) |
| Signed | [5,532 bytes](signed-lossless.pdf) | [100,293 bytes](signed-balanced.pdf) | [59,070 bytes](signed-small.pdf) |

All outputs have one 612 × 792 point page. Preserve keeps both known strings, the URI annotation, and the editable text field. The raster modes have no text, URI annotations, or editable fields. Original signature integrity passes; signed Preserve fails CMS verification and has an invalid ByteRange; both signed raster outputs have no cryptographic signature. The visible signature stamp remains in every output. Certificate trust fails separately because this is a synthetic self-signed certificate.

## Screenshots and renders

UI screenshots are named `{feature|signed}-{lossless|balanced|small}-ui.png`. These show the actual compressor results in a development build, including its development indicator. They are not screenshots of a deployed release.

PDF page renders are named `{feature|signed}-{original|lossless|balanced|small}-{96|192}dpi.png`. For example: [original screen view](feature-original-96dpi.png), [Balanced detail](feature-balanced-192dpi.png), [Smallest detail](feature-small-192dpi.png), [signed Preserve](signed-lossless-96dpi.png).

Visual inspection: page content, form value, and visible signature stamp remain; no clipping or missing pages was observed. The 8-point line and twelve colored rules remain distinguishable in the controlled 96 DPI view. Raster outputs show softer small text, lower-contrast thin rules, and JPEG artifacts at 192 DPI, especially Smallest. Heading weight also differs between the Poppler original and PDF.js raster output; standard-font substitution/rendering contributes to the comparison. Both Preserve outputs are pixel-identical to their respective original at 96 DPI. This is a limited visual observation, not a universal legibility pass.

## Environment and settings

One run per fixture/mode on September 7, 2026 at 02:08 UTC. Google Chrome headless 152.0.7977.77; macOS 26.6.2 build 25G83; Darwin 25.6.0 arm64; Node 24.19.0; Next 16.2.9 development build; pdf-lib 1.17.1; PDF.js 6.2.108; jsPDF 4.2.1. Verification: Python 3.12.14, pypdf 6.10.0, OpenSSL 3.6.3, Poppler 26.05.0. Synthetic signing only: pyHanko 0.35.0 (test dependency, absent from the app bundle).

Preserve uses `updateMetadata: false`, `useObjectStreams: true`, `addDefaultPage: false`, `objectsPerTick: 50`. Balanced uses 144 DPI/JPEG quality 0.76. Smallest uses 108 DPI/JPEG quality 0.58. The browser harness imports the same preset constants used by the actual UI.

## Reproduce in a checkout

Use the checked-in existing unsigned and signed inputs to rerun the compressor. Do not regenerate either input when comparing against these hashes. Install Playwright in a test environment and Chrome, and set `PLAYWRIGHT_MODULE` to the installed Playwright module when it is outside this project. Set `CHROME_PATH` only if Chrome needs an explicit executable path.

```sh
npm ci
npm run dev -- --hostname 127.0.0.1 --port 3019
```

In another terminal, from the repository root:

```sh
node --experimental-strip-types scripts/benchmark-pdf-compression.mjs
python3 scripts/inspect-pdf-benchmark.py
python3 scripts/render-pdf-benchmark.py
```

The first command requires a Node version supporting TypeScript stripping. Python inspection requires pypdf; rendering requires Pillow and Poppler's `pdftoppm`; signature verification requires OpenSSL with CMS support. The browser script uploads each input through the real file input, selects each radio option, clicks Reduce PDF size, waits for Compressed PDF ready, and downloads the result. It asserts visible signature warnings and zero uncaught page errors. The independent inspector asserts the observed feature and signature outcomes. Stop the development server afterward.

To generate a *new* synthetic signed fixture in a separate checkout, install the test-only `pyhanko==0.35.0` Python dependency and run `python3 scripts/generate-signed-pdf-benchmark.py`. This creates a fresh temporary 2048-bit RSA key, embeds a visible test stamp, and removes its temporary private key. A new random certificate and signing time necessarily change the fixture hash. Re-run all measurements and report new results; do not mix them with this snapshot.

These scripts write the dated evidence directory, so use a separate checkout or preserve this snapshot before rerunning. JPEG encoding, PDF metadata/IDs, font handling, browser/platform versions, and signature generation can change output hashes or byte counts. No timing or repeated-run distribution was measured.

## Limits and sources

The test covers a compact, digitally generated one-page PDF and one signed variant, not photo-heavy scans, a broad PDF corpus, large files, mobile memory limits, processing speed, accessibility, upload portals, other browsers, trusted signing identities, or timestamped signatures. Text extraction is not a clipboard UI test. URI presence is not a link navigation test. The form is edited/reopened with pypdf, not exercised in every PDF reader. OpenSSL `-noverify` skips certificate trust only; CMS content and signed-attribute verification remain enabled.

Implementation/test references: [PDF.js](https://mozilla.github.io/pdf.js/), [pdf-lib](https://pdf-lib.js.org/), [jsPDF](https://parallax.github.io/jsPDF/docs/), [pyHanko signing API](https://docs.pyhanko.eu/en/stable/lib-guide/signing.html), [OpenSSL CMS verification](https://docs.openssl.org/3.6/man1/openssl-cms/).
