/rust-image-worker

Dynamically crop, resize and cache images, all on the CDN

Primary LanguageRustApache License 2.0Apache-2.0

fill mode

rust-image-worker

Dynamically crop, resize and cache images, all on the CDN

Why

The scenario:

  • You need to display images optimized for the layout of your website.
  • Perhaps these images get uploaded by your users, or they come from an external image provider.
  • You don't want to send images larger than what is neccesary, because you are considerate of users who may be accessing your site from slower connections such as mobiles.
  • Maybe you don't know what the size of all the source images are, but you still want them to fit neatly into your design.
  • Or, maybe you want to allow your users to change how their profile images are cropped, to move and scale within fixed dimensions, without having to upload again.

I've used and built such services in the past. I thought it would be a straightforward yet useful thing to build with Rust and WASM) on Cloudflare workers.

Rust has great native crates that do not need to pull in shared libraries or call out to other processes.

With workers we are able to cache the source and resulting images directly on the CDN.

Caveat

This software is currently used only for demonstration purposes and you should be aware of the limitations before using it for real.

How to use

Deploying the worker

  1. Follow instructions to install 🤠wrangler.
  2. Add your account id and zone id to the wrangler.toml
  3. Run $ wrangler publish

You should see something like:

🥳 Successfully published your script.
🥳 Successfully made your script available at image-worker...workers.dev
✨ Success! Your worker was successfully published. ✨

Calling the worker

You will be able to call the worker at the domain provided,e.g. http://image-worker...workers.dev.

The URL path should be formatted as an image filename with a file extension signifying the target image format. Supported output formats are PNG (.png) and JPEG (.jpg or .jpeg).

The query parameters should include a combination of:

  • origin: the full URL to the source image (required)
  • mode: one of fill, fit and limit (required, see modes for examples)
  • width, height: the desired dimensions (both required when mode is fill or limit, either one or both for fit)
  • dx, dy: the relative position when the image is cropped, numbers between -1.0 (left/top) and 1.0 (right/bottom) (default: 0.0, center)
  • scale: a positive rational number to scale the source image by (default: 1.0)
  • bg: a color in hex triplet format (default: transparent)

Modes

Fill mode

The source image is cropped in order to ensure that the full width and height is filled. The source image can be positioned using relative center offset dx and dy.

fill mode

Examples:

URL Image
https://.../image.png?
mode=fill&
width=180&
height=200&
origin=https://.../test_pattern.png
fill example
https://.../image.jpg?
mode=fill&
width=180&
height=200&
origin=https://.../Apollo_17.jpeg
fill example

Fit mode

The output image is exactly sized according to the given width and height, with no cropping of the source image. The source image can be positioned using relative center offset dx and dy.

fit mode

Examples:

URL Image
https://.../image.png?
mode=fit&
width=180&
height=200&
bg=abc&
origin=https://.../test_pattern.png
fit example
https://.../image.jpg?
mode=fit&
width=180&
height=200&
bg=abc&
origin=https://.../Apollo_17.jpeg
fit example
Scaled up and cropped to bottom-left
https://.../image.jpg?
mode=fit&
width=180&
height=200&
scale=1.5&
dx=-1&dy=1&
origin=https://.../Apollo_17.jpeg
fit example

Limit mode

The source image is scaled to fit within the given width and height.

limit mode

Examples:

URL Image
https://.../image.png?
mode=limit&
width=180&
height=200&
origin=https://.../test_pattern.png
limit example
https://.../image.jpg?
mode=limit&
width=180&
height=200&
origin=https://.../Apollo_17.jpeg
limit example
Scaled up and cropped to bottom-left
https://.../image.jpg?
mode=limit&
width=180&
height=200&
scale=1.5&
dx=-1&dy=1&
origin=https://.../Apollo_17.jpeg
limit example

Limitations

  • Cloudflare workers are limited in the amount of CPU time they are allowed to take per request (between 5ms for free and 50ms for business/enterprise accounts). This means that large images (> 1000 pixels in width or height), sometimes run out of processing time.

Development

To run pure Rust tests:

$ cargo test

And for a headless browser smoke test using Chrome:

$ wasm-pack test --headless --chrome

License

Apache 2.0