Image output
output() produces one transformed image: keep or change the format, and
set quality, target size, resize and the other route-honored controls along the
way.
It is the single image-transform verb. You do not pick an operation — the SDK resolves the route from your input format and requested output format:
- Same format (or no format given) → the optimiser route.
- Format change → the transcoder route.
How much the SDK checks for you depends on the kind of mistake:
- An option key no image route recognises is rejected as soon as you call
output(), before any upload. - A real key that the resolved route does not honor (for example
progressiveon a format change) is caught when the recipe lowers, which both SDKs run before the upload — a route-invalid option never costs you bytes. It is aGislConfigErrorwithreason: 'option_not_on_route'; a planned option or value (for examplemetadataon a format change) is the same class withreason: 'feature_not_available'. - A value outside the option's enum (for example
metadata: 'keep'on AVIF or SVG) is caught before upload on the same-format route — the SDK checks the requested value against the format's accepted enum, not just the contract'splannedmarkers.
- TypeScript
- PHP
// Omit the format to keep the input format.
const result = await client
.file('photo.jpg')
.output(undefined, { quality: 80 })
.run({ maxWait: '2m' });
// Or change format.
const webp = await client
.file('photo.jpg')
.output('webp', { quality: 80 })
.run({ maxWait: '2m' });
// Omit the format to keep the input format.
$client->file('photo.jpg')
->output(options: ['quality' => 80])
->run(maxWait: '2m');
// Or change format.
$client->file('photo.jpg')
->output('webp', ['quality' => 80])
->run(maxWait: '2m');
Hitting a target size
Set encoding_mode: 'target_size' and give target_size_bytes (minimum 1024).
The encoder aims for that size instead of a quality slider. Honored on
same-format avif, jpeg and webp.
- TypeScript
- PHP
const result = await client
.file('photo.jpg')
.output(undefined, {
encoding_mode: 'target_size',
target_size_bytes: 200 * 1024,
})
.run({ maxWait: '2m' });
$client->file('photo.jpg')
->output(options: [
'encoding_mode' => 'target_size',
'target_size_bytes' => 200 * 1024,
])
->run(maxWait: '2m');
target_size_bytes is in bytes. For "200 KB", write 200 * 1024.
The target is best-effort, and the outcome rides the result, so you do not have
to infer it from sizeBytes:
| Field | On | Meaning |
|---|---|---|
targetSizeMet | each output | true if it landed at or under the target. false means the target was unreachable even at the lowest quality — the closest file is still produced and the run still succeeds. |
chosenQuality | each output | The quality the encoder settled on. |
targetSizeMissed | the run result | true if any output missed its target, false if all met it. |
targetSizeMet and targetSizeMissed are absent — undefined in TypeScript,
null in PHP — on a run that did not use target_size. chosenQuality is also
set by auto_quality, so it is absent only when neither mode was used.
- TypeScript
- PHP
const out = result.artifacts[0];
if (out.targetSizeMet === false) {
console.log(`over budget: ${out.sizeBytes} bytes at quality ${out.chosenQuality}`);
}
if (result.targetSizeMissed) {
console.warn('at least one output missed its target size');
}
$out = $result->artifacts[0];
if ($out->targetSizeMet === false) {
echo "over budget: {$out->sizeBytes} bytes at quality {$out->chosenQuality}\n";
}
if ($result->targetSizeMissed) {
error_log('at least one output missed its target size');
}
Hitting a perceptual quality
encoding_mode: 'auto_quality' targets a named perceptual quality instead of a
byte count: set quality_preset to best, good (the default), fair or
low, and the encoder picks the quality setting that meets it. Honored on
same-format avif, jpeg and webp. The achieved score comes back on each output
as measuredQuality (0–1) and qualityMetric (the metric it was measured
with, such as ssimulacra2); both are absent when no measurement was reported.
Resizing
resize() is part of the output transform, not a separate artifact — it merges
into the preceding output() step, so you get one image out. If nothing
precedes it, it adds a same-format output step carrying the resize. It never
emits a thumbnail.
Height is optional; width-only preserves the aspect ratio. fit takes max,
crop or scale.
- TypeScript
- PHP
// Width-only — aspect ratio preserved.
await client.file('photo.jpg').resize(1200).run({ maxWait: '2m' });
// Merged into the output() step — still one artifact.
await client
.file('photo.jpg')
.output('webp', { quality: 80 })
.resize(1200, 800, 'crop')
.run({ maxWait: '2m' });
// Width-only — aspect ratio preserved.
$client->file('photo.jpg')->resize(1200)->run(maxWait: '2m');
// Merged into the output() step — still one artifact.
$client->file('photo.jpg')
->output('webp', ['quality' => 80])
->resize(1200, 800, 'crop')
->run(maxWait: '2m');
You can equally pass width / height / fit straight to output() — same
result, same single operation.
Resize is raster-only. A vector input such as SVG has no resize on its route and throws when the recipe lowers.
Stripping metadata
metadata defaults to strip. Pass keep to preserve EXIF and friends on
same-format jpeg, png, webp, gif and tiff. On a format change it is planned,
so asking for it there is rejected rather than silently keeping metadata.
keep is not offered for AVIF or SVG — AVIF is re-encoded from pixels and
SVG is optimised as markup, so neither can carry the original metadata through.
Those routes accept strip only, and the SDK rejects metadata: 'keep' on an
AVIF or SVG base before upload rather than letting the server reject it.
auto_orient rotates per the EXIF orientation flag — worth pairing with
metadata: 'strip', since stripping EXIF otherwise discards the orientation
that some viewers rely on. Honored on the raster routes; SVG honors only
metadata. auto_orient on an SVG format change is rejected before upload
(SVG is vector — it cannot be auto-oriented).
- TypeScript
- PHP
await client
.file('photo.jpg')
.output(undefined, { metadata: 'keep', auto_orient: true })
.run({ maxWait: '2m' });
$client->file('photo.jpg')
->output(options: ['metadata' => 'keep', 'auto_orient' => true])
->run(maxWait: '2m');
Colour profile and chroma
color_profile handles the embedded ICC profile: keep, srgb (convert), or
strip. Availability depends on the route and value.
chroma_subsampling takes 420 (smallest), 422 or 444 (highest fidelity),
and is honored on same-format JPEG only.
- TypeScript
- PHP
await client
.file('photo.jpg')
.output(undefined, { color_profile: 'srgb', chroma_subsampling: '444' })
.run({ maxWait: '2m' });
$client->file('photo.jpg')
->output(options: ['color_profile' => 'srgb', 'chroma_subsampling' => '444'])
->run(maxWait: '2m');
Commonly used options
⚠️ Not exhaustive. This is a selected set — the ones most callers reach for, so an option missing from this table is not necessarily one the API rejects.
Two different things check your options, and they are worth telling apart:
- The file-first chain validates locally, before any upload, against the contract metadata bundled into the package — no network call.
getSchema()is the runtime inspection API. It returns the authoritative per-operation, per-media-type answer from the server, and is what to ask if you are deciding programmatically. Its result wraps the schema in a hit / not-modified envelope, so see reading the schema at runtime before you read it — and if you only need availability,capabilities()answers that without the envelope.
| Option | Type | Honored on |
|---|---|---|
quality | 1–100 | Same-format avif/jpeg/png/webp/gif/tiff, and lossy format changes. |
encoding_mode | quality | target_size | auto_quality | Same-format avif/jpeg/webp. |
quality_preset | best | good | fair | low | With encoding_mode: 'auto_quality'. Default good. |
target_size_bytes | number (≥ 1024) | With encoding_mode: 'target_size'. |
chroma_subsampling | 420 | 422 | 444 | Same-format jpeg. |
width / height | number | Raster routes. 1–16384; width × height ≤ 16MP. |
fit | max | crop | scale | When width or height is set. |
background | hex string | Format change to jpeg — fills transparency. |
progressive | boolean | Same-format jpeg. |
avif_speed | number | Same-format avif (encode speed). |
metadata | strip | keep | Same-format. keep not offered on avif/svg. Planned on format change. |
color_profile | keep | srgb | strip | Route- and value-dependent. |
auto_orient | boolean | Raster routes. Not honored on svg. |
lossless | boolean | Same-format jpeg/webp. |
Passing a format in the options bag is rejected — the first argument owns it.