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.