image-flow is a C++ image toolkit with raster codecs, a layered compositor, and a deterministic CLI ops engine for procedural image editing.
- BMP/PNG/JPG/GIF encode and decode
- WebP encode and decode via
cwebpanddwebptooling (optional) - Layer and group compositing with transforms, masks, and blend modes
- IFLOW project format for full layer-stack serialization
- CLI ops pipeline for reproducible edits from shell scripts
- Procedural drawing, filtering, color grading, texturing, and geometry ops
makeBinaries:
build/bin/image_flowbuild/bin/generate_samplesbuild/bin/tests
./build/bin/image_flow help
./build/bin/image_flow help opsimage_flow new --width <w> --height <h> --out <project.iflow>image_flow new --from-image <file> [--fit <w>x<h>] --out <project.iflow>image_flow info --in <project.iflow>image_flow render --in <project.iflow> --out <image.{png|bmp|jpg|gif|webp|svg}>image_flow ops --in <project.iflow> --out <project.iflow> --op "<action key=value ...>" [--op ...]image_flow ops --in <project.iflow> --out <project.iflow> --ops-file <ops.txt>cat ops.txt | image_flow ops --in <project.iflow> --out <project.iflow> --stdin
CLI behavior notes:
new: choose exactly one source mode:--width/--heightfor a blank project, or--from-image(optionally with--fit) to seed from an image.
ops: choose exactly one input mode:--in <project.iflow>, or--width/--heightto start from an empty in-memory document.
--optokenization supports quoted values:name="Layer One"orname='Layer One'- Escape quote or backslash inside values with
\.
normalmultiplyscreenoverlaydarkenlightenaddsubtractdifferencecolor-dodge
add-layeradd-groupadd-grid-layersset-layerset-groupimport-imageresize-layer
set-transformconcat-transformclear-transform
set-transform and concat-transform support:
matrix=a,b,c,d,tx,ty- or composed params:
translate=x,yscale=s|sx,syskew=degx,degyrotate=degpivot=x,y
draw-filldraw-linedraw-rectdraw-fill-rectdraw-round-rectdraw-fill-round-rectdraw-ellipsedraw-fill-ellipsedraw-polylinedraw-polygondraw-fill-polygondraw-flood-filldraw-circledraw-fill-circledraw-arcdraw-quadratic-bezierdraw-bezier
All draw ops support:
- required:
path=<layer_path> - optional:
target=image|mask(defaultimage) - required for drawing color:
rgba=r,g,b,a
Draw op parameter reference:
draw-fill:path rgba [target]draw-line:path x0 y0 x1 y1 rgba [target]draw-rect:path x y width height rgba [target]draw-fill-rect:path x y width height rgba [target]draw-round-rect:path x y width height radius rgba [target]draw-fill-round-rect:path x y width height radius rgba [target]draw-ellipse:path cx cy rx ry rgba [target]draw-fill-ellipse:path cx cy rx ry rgba [target]draw-polyline:path points=x0,y0;x1,y1;... rgba [target]draw-polygon:path points=x0,y0;x1,y1;... rgba [target]draw-fill-polygon:path points=x0,y0;x1,y1;... rgba [target]draw-flood-fill:path x y rgba [tolerance] [target]draw-circle:path cx cy radius rgba [target]draw-fill-circle:path cx cy radius rgba [target]draw-arc:path cx cy radius rgba (start_rad/end_rad | start_deg/end_deg) [counterclockwise] [target]draw-quadratic-bezier:path x0 y0 cx cy x1 y1 rgba [target]draw-bezier:path x0 y0 cx1 cy1 cx2 cy2 x1 y1 rgba [target]
Drawing examples:
./build/bin/image_flow ops --in in.iflow --out out.iflow \
--op "draw-round-rect path=/0 x=40 y=30 width=220 height=140 radius=18 rgba=255,200,40,255" \
--op "draw-fill-round-rect path=/0 x=48 y=38 width=204 height=124 radius=14 rgba=20,20,30,220"
./build/bin/image_flow ops --in in.iflow --out out.iflow \
--op "draw-polyline path=/0 points=20,20;120,40;200,25;260,90 rgba=0,255,255,255" \
--op "draw-flood-fill path=/0 x=80 y=80 rgba=30,80,200,255 tolerance=12"
./build/bin/image_flow ops --in in.iflow --out out.iflow \
--op "draw-arc path=/0 cx=160 cy=120 radius=70 start_deg=350 end_deg=20 counterclockwise=false rgba=255,0,0,255" \
--op "draw-quadratic-bezier path=/0 x0=20 y0=180 cx=140 cy=40 x1=280 y1=180 rgba=255,255,0,255" \
--op "draw-bezier path=/0 x0=20 y0=200 cx1=90 cy=80 cx2=210 cy=80 x1=280 y1=200 rgba=0,255,255,255"Drawable supports both immediate primitives and retained path drawing.
Path model:
beginPath()moveTo(x, y)lineTo(x, y)quadraticCurveTo(cx, cy, x, y)bezierCurveTo(cx1, cy1, cx2, cy2, x, y)closePath()stroke(color)fillPath(color)
Stroke style controls:
setLineWidth(width)setLineCap(Butt|Round|Square)setLineJoin(Miter|Round|Bevel)setMiterLimit(limit)
Shape and fill primitives:
fill,linerect,fillRectroundRect,fillRoundRectellipse,fillEllipsecircle,fillCirclepolyline,polygon,fillPolygonarc(..., counterclockwise)floodFill(x, y, color, tolerance)
mask-enablemask-clearmask-set-pixelfill-layerset-pixel
gradient-layer(linearorradial)checker-layernoise-layerfractal-noisehatchpencil-strokes
apply-effect effect=grayscale|sepia|invert|thresholdreplace-colorchannel-mix(3x3 RGB matrix)levelsgammacurves
gaussian-bluredge-detect method=sobel|cannymorphology op=erode|dilate
./build/bin/image_flow new --from-image samples/tahoe200-finish.webp --fit 1400x900 --out build/output/images/demo.iflow
./build/bin/image_flow ops \
--in build/output/images/demo.iflow \
--out build/output/images/demo.iflow \
--op "add-layer name=Sketch width=1400 height=900 fill=0,0,0,0" \
--op "import-image path=/1 file=samples/tahoe200-finish.webp" \
--op "apply-effect path=/1 effect=grayscale" \
--op "apply-effect path=/1 effect=invert" \
--op "gaussian-blur path=/1 radius=8 sigma=3.6" \
--op "set-layer path=/1 blend=color-dodge opacity=0.95" \
--render build/output/images/demo.pngRun one script:
./sample_scripts/iflow_pencil_sketch_example.shRun all scripts:
./sample_scripts/run_all.sh
# or
make run-scriptsCurrent sample scripts:
sample_scripts/iflow_ops_example.shsample_scripts/iflow_orbital_wireframe_example.shsample_scripts/iflow_mask_etch_example.shsample_scripts/iflow_chroma_tunnel_example.shsample_scripts/iflow_pencil_sketch_example.sh
./build/bin/generate_samplesmake test- App output images:
build/output/images - Test output artifacts:
build/output/test-images