Image Transforms
This Lambda converts a jpeg image to grayscale, using Rust code that is compiled to WASI-compliant WASM. It demonstrates the type of image transforms you may want to do at the source of the signal; for example, if your application involves a camera, you might want to convert to grayscale and downscale at the source of the signal, before passing the image along to downstream logic that performs object detection, collision detection, or some other kind of inference.
The source code can be found in the On Prem CLI repository at examples/lambda_grayscale.
How it works
In the On Prem platform, lambda events are JSON objects with a special data field reserved for binary content.
Every layer of the platform transfers the data field separately from the rest of the event object's other
fields, ensuring efficient transfer encoding that does not involve JSON parsing of any large content. Additionally,
event objects are conveyed as gRPC structs, further ensuring binary transfer encoding.
When an On Prem edge lambda is written in WASI+WASM, the input event is pre-processed by the On Prem edge agent,
and the data field is extracted and passed into the WASM module via stdin, while the other input event fields are
passed in as program arguments. Then, the transformed grayscale image is emitted via stdout, and the
On Prem agent conveys it to downstream chained lambdas, or a remote desktop in the case where
the lambda was manually triggered via the On Prem CLI, which is how one-shot testing of high-frequency
lambdas is typically done.
Assets
deployment.yaml
Cargo.toml
Makefile
src/
main.rs
main.rs:
use image::ImageFormat;
use std::io::{self, Cursor, Read, Write};
fn main() -> anyhow::Result<()> {
// Read
let mut buf = Vec::new();
io::stdin().read_to_end(&mut buf)?;
// Convert
let img = image::load_from_memory(&buf)?;
let transformed = img.grayscale();
// Serialize to a buffer
let mut buf: Vec<u8> = Vec::new();
transformed.write_to(&mut Cursor::new(&mut buf), ImageFormat::Jpeg)?;
// Write
io::stdout().write_all(&buf)?;
io::stdout().flush()?;
Ok(())
}
Cargo.toml:
[package]
name = "on-prem-example-lambda-grayscale"
description = "An On Prem edge lambda that converts a jpeg to grayscale using a WASI-compliant WASM module"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "grayscale"
path = "src/main.rs"
[dependencies]
anyhow = "1.0"
image = { version = "0.25.9", default-features = false, features = ["jpeg"] }
Makefile:
.PHONY: build
build:
rustup target add wasm32-wasip1
cargo build --target wasm32-wasip1 --release
.PHONY: clean
clean:
cargo clean
deployment.yaml:
id: d6hl1qhkun569e9bu6v0
kind: Lambda
name: lambda_grayscale
description: Convert a jpeg image to grayscale with a WASI-compliant WASM module.
runAt:
device:
deviceId: d5vmhgk3ofhmc59g2870
fileIds:
- "@target/wasm32-wasip1/release/grayscale.wasm"
scriptContentType: None
Building and Testing
First build the WASM module:
$ make
Use a local jpeg file as a test input. Examine the input file:
$ open in.jpg

Now test the image transform locally, before moving it to your edge environment:
$ wasmer run target/wasm32-wasip1/release/grayscale.wasm < in.jpg > out.jpg
Examine the output file:
$ open out.jpg

Deploying
Customize the runAt field in your deployment to point to one of your device ids. These can be
taken from the URL when using the cloud console.
$ vi deployment.yaml
runAt:
device:
deviceId: d5vmhgk3ofhmc59g2870
Next, upload it, along with the lambda definition, to the control plane:
$ onprem apply deployment.yaml
Uploaded grayscale.wasm (465.7K bytes)
File assets found: 1
Uploading import request...
Import complete
Operations performed:
┌────────────────────────┬─────────┬──────┬─────────┬─────────┬────────┐
│ Object ┆ Records ┆ Adds ┆ Updates ┆ Deletes ┆ Errors │
│ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ u32 ┆ u32 ┆ u32 ┆ u32 ┆ u32 │
╞════════════════════════╪═════════╪══════╪═════════╪═════════╪════════╡
│ ApiKeys ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Controllers ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ ControllerTemplates ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Devices ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Facilities ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Lambdas ┆ 1 ┆ 1 ┆ 0 ┆ 0 ┆ 0 │
│ LambdaTemplates ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Roles ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Tags ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
│ Teams ┆ 0 ┆ 0 ┆ 0 ┆ 0 ┆ 0 │
└────────────────────────┴─────────┴──────┴─────────┴─────────┴────────┘
If the agent is connected to the control plane, it will have downloaded its new config bundle containing the new lambda and associated WASM module file within a few seconds.
Run the Lambda
Now ask the control plane to invoke the lambda on the remote edge device.
$ onprem run lambda d6hl1qhkun569e9bu6v0 --event-data-from-file in.jpg --event-data-to-file out.jpg
Wrote event[data] to out.jpg (28.5K)
{}