Search by

tenma / image

Lento Leisenfeld

Image size and scaled WebP copies on Tenma, decoded off the event loop by a native plugin, with limits against decompression bombs.

v0.1.0 2026-10-31 14:59 UTC

This package is not auto-updated.

Last update: 2026-10-31 21:41:05 UTC


README

Image size and scaled WebP copies on Tenma. A native plugin decodes, scales and encodes on threads of its own, so a request that converts an image waits in its fiber while the server goes on. Meant for untrusted bytes, such as pictures downloaded from elsewhere: hard limits apply before anything is decoded.

use Tenma\Image\Picture;

[$width, $height, $extension] = Picture::measure($bytes);   // [1200, 1800, 'jpg']
$webp = Picture::webp($bytes, 640);                         // 640 px wide, aspect ratio kept
  • Picture::measure($bytes) reads the header alone and returns width, height and the file extension: jpg, png, webp or gif. It runs on the worker thread and takes no fiber.
  • Picture::webp($bytes, $width) scales down to $width (never up), keeps the aspect ratio and writes lossy WebP of quality 82; an image with alpha keeps it, a GIF gives its first frame. It runs on the plugin's thread pool, one thread per core, and must be called in a fiber (a request, or Threading\Task).
  • Both throw RuntimeException with a message starting image: for bytes that are no supported image or that exceed a limit.

Limits

Limit Value Checked
Input 32 MB before the bytes are read
Pixels 40 megapixels from the header, before decoding
Decoder heap 512 MB by the decoder while it decodes
WebP side 16383 px by the encoder (a limit of the format)

A file of a few bytes whose header claims 50000 by 50000 pixels fails at the second limit. EXIF orientation is not applied: the pixels come out as stored.

Install

composer require tenma/image
vendor/bin/tenma-image install

The install downloads the plugin of this version for the machine, checks it against its SHA-256 and adds it to tenma.json.

Platforms: macOS arm64, Linux x64 and arm64.

Develop

cd plugin && cargo test && cargo build --release && mkdir -p ../lib
cp target/release/libtenma_image.dylib ../lib/tenma_image.plugin   # .so on Linux
cd .. && composer test && composer stan

The PHP tests run the plugin under a real tenma and skip when tenma or the plugin is missing.

License

The package: MIT or Apache-2.0, at your option. The plugin links libwebp (BSD-3-Clause with a patent grant), built from source; its license is in licenses/libwebp.txt. The Rust crates it is built from are MIT or Apache-2.0.