CLI reference

obraz edit

obraz edit --plan FILE|- --input PICTURE... --output FILE
           [--asset NAME=FILE]... [--format FORMAT] [--quality N]
           [--allow-provider-cost] [--json]

Runs one edit plan on pictures from disk and writes the edited picture. The plan is the same document POST /v1/edits takes under plan; it is read from the file, or from standard input with --plan -. Pictures are given in the order the plan numbers them, input 0 first; fonts and .cube tables are named assets. The edit runs in this process, through the same code the service runs, so no Obraz service is needed.

The format is the output's extension, or --format (png, jpeg, webp, tiff, bmp, gif); JPEG needs --quality, 1 to 100, and no other format takes one.

Model steps go to the image-model service: OBRAZ_IMAGE_MODEL_URL (Brama, or https://api.openai.com), asking OBRAZ_IMAGE_MODEL, with the bearer the vault role in OBRAZ_IMAGE_MODEL_ROLE holds (read with stado credentials get --role, or from OBRAZ_CREDENTIALS_FILE without Stado; see configuration). Each is a billed provider call, so a plan with one needs --allow-provider-cost.

$ obraz edit --plan avatar.json --input photo.jpg --output avatar.png
output: avatar.png
mime_type: image/png
width: 256
height: 256
bytes: <size>
step 1: crop_ratio <w>x<h>
step 2: resize 256x256
step 3: mask 256x256

A model step's line ends with via <model>, the model the service says answered. With --json the same answer is one document: output, mime_type, width, height, bytes and steps.

Examples

# the same 4:5 crop and grade on every photo of a shoot
for photo in shoot/*.jpg; do
  obraz edit --plan post.json --input "$photo" --output "posts/$(basename "$photo" .jpg).png"
done

# a watermark: the logo is input 1
obraz edit --plan watermark.json --input photo.jpg --input logo.png --output marked.jpg --quality 90

# a product photo on white, the background removed by a model
obraz edit --plan product.json --input bottle.jpg --output bottle.png --allow-provider-cost

Refusals

Exit 2, nothing written:

the plan <path> cannot be read: <cause>

the plan could not be read from standard input: <cause>

the plan is not an edit plan: <the JSON reader's sentence>

<output> has no extension to name its format: pass --format (png, jpeg, webp, tiff, bmp, gif)

"<name>" is not a format Obraz writes; it writes png, jpeg, webp, tiff, bmp, gif

a JPEG output needs a quality from 1 to 100

JPEG quality is 1 to 100 on the encoder's scale, not <quality>

quality applies to JPEG only; <mime type> is written without one

refusing a plan with model steps without explicit --allow-provider-cost: each model step is a billable provider call

input <path> cannot be read: <cause>

<path> is not a picture Obraz can read: <cause>

--asset takes NAME=FILE, not "<value>"

asset <name> at <path> cannot be read: <cause>

asset <name> is given twice

and every refusal of the plan check on Editing pictures, such as step 1 (border): a border needs a width of at least 1 pixel.

Exit 1: a step the picture cannot take while editing (step 1 (scale): scaling the <w>x<h> picture by <factor> leaves no pixel), a model step the image-model service refused, a picture the format cannot hold, <output> cannot be written: <cause>, and the image-model service's configuration:

OBRAZ_IMAGE_MODEL_URL is not set: name the image-model service that runs the model steps (Brama's address from stado service directory connect brama --consumer obraz, or https://api.openai.com)

OBRAZ_IMAGE_MODEL is not set: name the model the model steps ask (image-model on Brama, gpt-image-1 on OpenAI)

OBRAZ_IMAGE_MODEL_ROLE is not set: name the vault role holding the image-model service's bearer and its field as ROLE#FIELD

and the role-reading refusals on configuration, with OBRAZ_IMAGE_MODEL_ROLE in place of OBRAZ_SECRET_ROLE.