Introduction
- Imageflow can be used as a library (libimageflow or imageflow-dotnet)
- Imageflow can be used as a command-line tool for scripting (imageflow_tool)
- Imageflow can be used as an HTTP server (Imageflow.Server)
All share support for the querystring API (RIAPI). libimageflow, imageflow-dotnet, and imageflow_tool currently support the JSON API.
The querystring API is much simpler, but the JSON API can compose multiple images or generate multiple image versions in a single job. You can also use the querystring API from within the JSON API.
Querystring API
Also called RIAPI (RESTful Image API)
This API doesn't care about the order in which you specify commands; they're executed in a standard order regardless.
trim whitespace
-> srotate
-> sflip
-> crop
-> scale
-> filter
-> pad
-> rotate
-> flip
Executing with imageflow_tool
imageflow_tool v1/querystring --in a.jpg --out b.jpg --command "w=100&h=100&mode=max" --quiet
URLs with demo server
http://localhost:39876/demo_images/tulip-leaf.jpg?w=300&h=300&mode=max
Common examples
width=100&height=100&mode=max&scale=down
ensures the image is downscaled to 100x100 or less, but does not upscale the image if it is already smaller than that. Aspect ratio is maintained.width=200&height=200&mode=max&scale=both
ensures the image is downscaled or upscaled to fit within 200x200, maintaining aspect ratio.width=200&height=200&mode=pad&scale=both
ensures the image is downscaled or upscaled to fit within 200x200, maintaining aspect ratio, then is padded to make the result always 200x200.width=300&height=300&mode=crop&scale=both
ensures the image is downscaled or upscaled to fit around 300x300, then minimally cropped to meet the aspect ratio.scale=both
ensures the image is upscaled if smaller so the result is always 300x300.
Querystring API
Also called RIAPI (RESTful Image API)
This API doesn't care about the order in which you specify commands; they're executed in a standard order regardless.
trim whitespace
-> srotate
-> sflip
-> crop
-> scale
-> filter
-> pad
-> rotate
-> flip
Executing with imageflow_tool
imageflow_tool v1/querystring --in a.jpg --out b.jpg --command "w=100&h=100&mode=max" --quiet
URLs with demo server
http://localhost:39876/demo_images/tulip-leaf.jpg?w=300&h=300&mode=max
Common examples
width=100&height=100&mode=max&scale=down
ensures the image is downscaled to 100x100 or less, but does not upscale the image if it is already smaller than that. Aspect ratio is maintained.width=200&height=200&mode=max&scale=both
ensures the image is downscaled or upscaled to fit within 200x200, maintaining aspect ratio.width=200&height=200&mode=pad&scale=both
ensures the image is downscaled or upscaled to fit within 200x200, maintaining aspect ratio, then is padded to make the result always 200x200.width=300&height=300&mode=crop&scale=both
ensures the image is downscaled or upscaled to fit around 300x300, then minimally cropped to meet the aspect ratio.scale=both
ensures the image is upscaled if smaller so the result is always 300x300.
Image Transform Commands
width
constrains the image width.w
is an alias forwidth
height
constrains the image height.h
is an alias forheight
dpr
is a multiplier forwidth
/height
to make responsive image usage easier.mode
determines how to handle aspect ratio differences.stretch
distorts the image to be exactly the given dimensions, ifscale=both
. Ifscale=down
(the default), the image is only scaled ifwidth
andheight
are smaller than the image.pad
scales the image to fit withinwidth
andheight
, then pads 2 edges (bgcolor
) to make it.crop
scales the image to fit abovewidth
andheight
, then minimally crops to meet aspect ratio.max
scales the image to fit withinwidth
andheight
scale
controls whether images are upsampled or not.down
- Never upscale an image - return at original size insteadboth
- Downscale or upscale to meet size requirements. Image enlargement causes blurriness and should be avoided.canvas
- Add padding instead of upscaling to meet size requirements.up
- Never downscale, only upscale to meet requirements. Rarely used.
anchor
determines how the image is aligned when you usemode=crop
,mode=pad
orscale=canvas
. The default ismiddlecenter
- values are
topleft
,topcenter
,topright
,middleleft
,middlecenter
,middleright
,bottomleft
,bottomcenter
, andbottomright
.
- values are
sflip
flips the source image in thex
,y
, orxy
dimensions.flip
flips the result image in thex
,y
, orxy
dimensions.srotate
rotates the source image90
,180
, or270
degrees.rotate
rotates the result image90
,180
, or270
degrees.crop=x1,y1,x2,y2
crops the source image to the given coordinates. If x2 or y2 are negative, they are relative to the bottom-right corner of the image.crop=10,10,-10,-10
removes 10 pixels from the edge of the image.cropxunits=100&cropyunits=100
makes thecrop
coordinates percentages of the image instead of pixels.trim.threshold=80
specifies a threshold to use for trimming whitespace.trim.percentpadding=0.5
specifies percentage of padding to restore after trimming.bgcolor
must be in the form RGB, RGBA, RRGGBBAA, RRGGBB, or be a named color.bgcolor
determines the color of padding added withmode=pad
orscale=canvas
.ignoreicc=true
causes the source image's color profile to be ignored and treated as sRGB.ignore_icc_errors=true
causes color profile errors to be ignored rather than causing the operation to fail.
Image Filter Commands
f.sharpen=0..99
determines how much sharpening to apply when scaling the image.f.sharpenwhen=always|downscaling|sizediffers
determines when to sharpen.down.filter
determines the down-sampling filter to use. Must be one ofrobidoux
,robidoux_sharp
,robidoux_fast
,ginseng
,ginseng_sharp
,lanczos
,lanczos_sharp
,lanczos_2
,lanczos_2_sharp
,cubic
,cubic_sharp
,catmull_rom
,mitchell
,cubic_b_spline
,hermite
,jinc
,triangle
,linear
,box
,fastest
,n_cubic
,n_cubic_sharp
up.filter
determines the up-sampling filter to use. Seedown.filter
down.colorspace=srgb
downscales in the srgb color space instead of linear RGB. Mimics widespread but bad behavior; destroys image highlights.up.colorspace=srgb
up-scales in the srgb color space instead of linear RGB.s.grayscale
=true|y|ry|ntsc|bt709|flat
transforms the image into grayscale using various methods.s.sepia=true
turns the image into sepia tones.invert=true
inverts the image colors in the srgb spaces.alpha=0..1
makes the image partially transparents.contrast=-1..1
adjusts the contrast in the srgb spaces.brightness=-1..1
adjusts brightness in the srgb spaces.saturation=-1..1
adjusts saturation in the srgb space
Image Encoding Commands
format=png|gif|jpeg|webp
determines the format to encode the image as. Defaults to the original format.jpeg.quality=0..100
determines the jpeg encoding quality. Default is90
jpeg.progressive=true
enables progressive jpeg encoding.jpeg.turbo=true
encodes files faster at the expense of file size.webp.quality=0..100
determines the webp encoding quality.webp.lossless=true
enables lossless webp encoding. Defaultfalse
png.lossless=false
disables lossless PNG encoding. Defaulttrue
unlesspng.quality
is specified.png.quality=0..100
determines lossy png quality. Default100
.png.min_quality=0..100
determines the minimum png quality that must be realized before lossless is used. Default0
Querystring Examples
TODO
4 ways to grayscale
s.grayscale
=true|y|ry|ntsc|bt709|flat
(true, ntsc, and y produce identical results)
The following examples use NTSC/Y/True, RY, BT709, and Flat respectively
1 way to sepia
Inversion
Adjust opacity/alpha
s.alpha
= 0..1
For true transparency, combine with format=png
. Otherwise, the image will be blended against bgcolor
.
Adjust contrast
s.contrast
= -1..1
Adjust brightness
s.brightness
= -1..1
Adjust saturation
s.saturation
= -1..1
JSON API
JSON is primarily used by libimageflow and imageflow_tool.
You can specify a series of steps
to take (the easiest), or you can specify a graph with
nodes and edges (which allows for multiple inputs and outputs). Note that you can watermark with a series of steps.
JSON jobs have the keys io
and framewise
, which refer to your inputs/outputs and steps/graph to apply to each image frame.
JSON jobs also have a security
key that you can read more about here.
If you're using imageflow_tool v1/build
, you'll need to specify your inputs and outputs. This isn't needed if you're using libimageflow
and v1/execute
, as you'll have already registered the inputs and outputs.
The following example uses steps
to constrain an image to 1400px or less and encodes it in 8-bit png.
{
"io": [
{
"io_id": 0,
"direction": "in",
"io": "placeholder"
},
{
"io_id": 1,
"direction": "out",
"io": "placeholder"
}
],
"security": {
"max_decode_size": {
"w": 10000,
"h": 10000,
"megapixels": 100
},
"max_frame_size": null,
"max_encode_size": null
},
"framewise": {
"steps": [
{
"decode": {
"io_id": 0
}
},
{
"constrain": {
"mode": "within",
"w": 1400
}
},
{
"encode": {
"io_id": 1,
"preset": {
"pngquant": {
"quality": 80
}
}
}
}
]
}
}
JSON API
JSON is primarily used by libimageflow and imageflow_tool.
You can specify a series of steps
to take (the easiest), or you can specify a graph with
nodes and edges (which allows for multiple inputs and outputs). Note that you can watermark with a series of steps.
JSON jobs have the keys io
and framewise
, which refer to your inputs/outputs and steps/graph to apply to each image frame.
JSON jobs also have a security
key that you can read more about here.
If you're using imageflow_tool v1/build
, you'll need to specify your inputs and outputs. This isn't needed if you're using libimageflow
and v1/execute
, as you'll have already registered the inputs and outputs.
The following example uses steps
to constrain an image to 1400px or less and encodes it in 8-bit png.
{
"io": [
{
"io_id": 0,
"direction": "in",
"io": "placeholder"
},
{
"io_id": 1,
"direction": "out",
"io": "placeholder"
}
],
"security": {
"max_decode_size": {
"w": 10000,
"h": 10000,
"megapixels": 100
},
"max_frame_size": null,
"max_encode_size": null
},
"framewise": {
"steps": [
{
"decode": {
"io_id": 0
}
},
{
"constrain": {
"mode": "within",
"w": 1400
}
},
{
"encode": {
"io_id": 1,
"preset": {
"pngquant": {
"quality": 80
}
}
}
}
]
}
}
Security
If you're getting things like source images, command strings or width/height values from untrusted sources, it's important to place limits on image sizes to prevent denial-of-service attacks.
JSON jobs have a security
key that can be filled out like this:
Note that max_frame_size
also limits the maximum decode and encode size,
so you don't have to specify max_decode_size
and max_encode_size
unless they are smaller.
If you don't specify a default, a max_frame_size
of 10,000x10,000 and 100 megapixels will be set for you.
{
"security": {
"max_decode_size": {
"w": 10000,
"h": 10000,
"megapixels": 50
},
"max_frame_size": {
"w": 10000,
"h": 10000,
"megapixels": 100
},
"max_encode_size": {
"w": 8000,
"h": 8000,
"megapixels": 20
}
}
}
Decode Command
Typically, you only need to specify the io_id
of the file you're decoding.
{
"decode": {
"io_id": 0
}
}
However, some decoders accept commands that can be used to speed up the process.
The following causes the JPEG decoder to spatially downscale - in linear light - while decoding.
The image may not be scaled to the exact size requested, but it will be closer.
{
"decode": {
"io_id": 0,
"commands": [
{
"jpeg_downscale_hints": {
"width": 1600,
"height": 1600,
"scale_luma_spatially": true,
"gamma_correct_for_srgb_during_spatial_luma_scaling": true
}
}
]
}
}
You can also do this for WebP images, although there is no support for linear light scaling:
{
"decode": {
"io_id": 0,
"commands": [
{
"webp_decoder_hints": {
"width": 1600,
"height": 1600
}
}
]
}
}
You can force the color profile to be ignored.
{
"decode": {
"io_id": 0,
"commands": [
"discard_color_profile"
]
}
}
Or just ignore color profile errors.
{
"decode": {
"io_id": 0,
"commands": [
"ignore_color_profile_errors"
]
}
}
Encode Command
When encoding, you'll need the io_id
of the file you're encoding to, and a encoding preset.
{
"encode": {
"io_id": 1,
"preset": "gif"
}
}
Jpeg (MozJpeg encoder)
quality: 0..100
controls the image quality. Consider 80 as a good starting point.progressive: true
enables progressive jpeg encoding, which takes more CPU time.
{
"mozjpeg": {
"quality": 90,
"progressive": false
}
}
Gif
"gif"
Lossless PNG
{
"lodepng": {
"maximum_deflate": false
}
}
Lossy PNG
quality: 0..100
specifies the target quality to aim for.minimum_quality: 0.100
specifies the actual quality below which to switch to lossless PNG.speed: 1..10
controls the speed/quality tradeoff for encoding.maximum_deflate: true
gains 1-2% in file size reduction at the expense of a tenfold increase in CPU time.
{
"pngquant": {
"quality": 90,
"minimum_quality": 20,
"speed": null,
"maximum_deflate": null
}
}
WebP (Lossy)
quality: 0..100
determines the encoding quality. 80 is a good starting point.
{
"webplossy": {
"quality": 80
}
}
WebP (Lossless)
"webplossless"
Deprecated Presets
{
"libjpegturbo": {
"quality": 90,
"progressive": false,
"optimize_huffman_coding": true
}
}
{
"libpng": {
"depth": "png_24",
"matte": {
"srgb": {
"hex": "9922FF"
}
},
"zlib_compression": 7
}
}
Constrain
w
The width constraint in pixelsh
The height constraint in pixelsmode
A constraint modegravity
determines how the image is anchored when cropped or padded.{x: 0, y: 0}
represents top-left,{x: 50, y: 50}
represents center,{x:100, y:100}
represents bottom-right. Default:center
hints
See resampling hintscanvas_color
See Color. The color of padding added to the image.
{
"constrain": {
"mode": "within",
"w": 800,
"h": 600,
"hints": {
"sharpen_percent": 7
},
"gravity": { "percentage": { "x": 50, "y": 50}},
"canvas_color": "transparent"
}
}
Constraint Modes
distort
Distort the image to exactly the given dimensions. If only one dimension is specified, behaves likefit
.within
Ensure the result fits within the provided dimensions. No upscaling.fit
Fit the image within the dimensions, upscaling if neededlarger_than
Ensure the image is larger than the given dimensionswithin_crop
Crop to desired aspect ratio if image is larger than requested, then downscale. Ignores smaller images. If only one dimension is specified, behaves likewithin
.fit_crop
Crop to desired aspect ratio, then downscale or upscale to fit. If only one dimension is specified, behaves likefit
.aspect_crop
Crop to desired aspect ratio, no upscaling or downscaling. If only one dimension is specified, behaves like Fit.within_pad
Pad to desired aspect ratio if image is larger than requested, then downscale. Ignores smaller images. If only one dimension is specified, behaves likewithin
fit_pad
Pad to desired aspect ratio, then downscale or upscale to fit If only one dimension is specified, behaves likefit
.
Region Command
Region is like a crop command, but you can specify coordinates outside of the image and thereby add padding. It's like a window.
You can specify a region as a percentage of the image's width and height:
{
"region_percent": {
"x1": -1.0,
"y1": -1.0,
"x2": 101.0,
"y2": 101.0,
"background_color": "transparent"
}
}
Or you can specify a pixel region
{
"region": {
"x1": -1,
"y1": -1,
"x2": 800,
"y2": 800,
"background_color": "transparent"
}
}
Crop Whitespace Command
threshold: 1..255
determines how much noise/edges to tolerate before cropping is finalized.80
is a good starting point.percent_padding
determines how much of the image to restore after cropping to provide some padding.0.5
(half a percent) is a good starting point.
{
"crop_whitespace": {
"threshold": 80,
"percent_padding" : 2
}
}
Rotation and flipping
The following nodes are simply strings rather than objects
[
"flip_h",
"flip_v",
"transpose",
"rotate_90",
"rotate_180",
"rotate_270"
]
Fill Rectangle Command
This draws a black 8x8 square at the top-left of the image.
{
"fill_rect": {
"x1": 0,
"y1": 0,
"x2": 8,
"y2": 8,
"color": "black"
}
}
Expand Canvas Command
The following adds a 10px pink border around the image.
{
"expand_canvas": {
"left": 10,
"top": 10,
"right": 10,
"bottom": 10,
"color": {
"srgb": {
"hex": "FFEECCFF"
}
}
}
}
Watermark
io_id
(required) specifies which input image to use as a watermark.gravity
determines how the image is placed within thefit_box
.{x: 0, y: 0}
represents top-left,{x: 50, y: 50}
represents center,{x:100, y:100}
represents bottom-right. Default:center
fit_mode
is one ofdistort
,within
,fit
,within_crop
, orfit_crop
. Meanings are the same as for constraint modes. Default:within
fit_box
can be eitherimage_percentage
(a box represented by percentages of target image width/height) orimage_margins
(a box represented by pixels from the edge of the image). Defaultimage_margins
0min_canvas_width
sets a minimum canvas width below which the watermark will be hidden.min_canvas_height
sets a minimum canvas height below which the watermark will be hidden.opacity
(0..1) How opaque to draw the image. Default 1.0hints
See resampling hints
Example with fit_box: image_percentage
This will align the watermark to 10% from the bottom and right edges of the image, scaling the watermark down if it takes more than 80% of the image space, drawing it at 80% opacity and applying 15% sharpening. It will not display on images smaller than 50x50px in either dimension.
{
"watermark": {
"io_id": 1,
"gravity": {
"percentage" : {
"x": 100,
"y": 100
}
},
"fit_mode": "within",
"fit_box": {
"image_percentage": {
"x1": 10,
"y1": 10,
"x2": 90,
"y2": 90
}
},
"min_canvas_width": 50,
"min_canvas_height": 50,
"opacity": 0.8,
"hints": {
"sharpen_percent": 15
}
}
}
Example with fit_box: image_margins
This will stretch/distort the watermark to fill the image except for a 5px margin.
{
"watermark": {
"io_id": 1,
"gravity": { "center": null },
"fit_mode": "distort",
"fit_box": {
"image_margins": {
"left": 5,
"top": 5,
"right": 5,
"bottom": 5
}
}
}
}
Command String Command
It's possible to execute a querystring command within a JSON file.
This is commonly used by libimageflow
bindings to execute querystring commands.
When specifying a decode
io_id
, no decode
node is needed.
When specifying an encode
io_id
, no encode
node is needed.
When specifying both, no other nodes are needed in the job. This is the preferred method of use, as decode hints will be optimized and encoder commands will be honored.
{
"command_string": {
"kind": "ir4",
"value": "width=100&height=100&mode=max",
"decode": 0,
"encode": 1
}
}
White Balance sRGB Command
This command is not recommended as it operates in the sRGB space and does not produce perfect results.
{
"white_balance_histogram_area_threshold_srgb": {
"threshold": 30
}
}
Color Filter sRGB
This command is not ideal as it operates in the sRGB space. For alpha operations it doesn't matter, and for grayscale conversion it matches various international standards.
{
"color_filter_srgb": "grayscale_ntsc"
}
{
"color_filter_srgb": "grayscale_flat"
}
{
"color_filter_srgb": "grayscale_bt709"
}
{
"color_filter_srgb": "grayscale_ry"
}
{
"color_filter_srgb": "sepia"
}
{
"color_filter_srgb": "invert"
}
alpha: 0..1
{
"color_filter_srgb": {"alpha": 0.5}
}
contrast: -1..1
{
"color_filter_srgb": {"contrast": 0.5}
}
brightness: -1..1
{
"color_filter_srgb": {"brightness": 0.5}
}
saturation: -1...1
{
"color_filter_srgb": {"saturation": 0.5}
}
Resampling Hints
Resampling hints can be specified in constraint commands, scale commands, watermarking, and for compositing. They offer control over image sharpness, resampling color space, background color, and more.
sharpen_percent
(0..100) The amount of sharpening to apply during resamplingup_filter
The resampling filter to use if upscaling in one or more directionsdown_filter
The resampling filter to use if downscaling in both directions.scaling_colorspace
Uselinear
for the best results, orsrgb
to mimick poorly-written software.srgb
can destroy image highlights.background_color
The background color to apply.resample_when
One ofsize_differs
,size_differs_or_sharpening_requested
, oralways
.sharpen_when
One ofdownscaling
,upscaling
,size_differs
, oralways
{
"sharpen_percent": 15,
"down_filter": "robidoux",
"up_filter": "ginseng",
"scaling_colorspace": "linear",
"background_color": "transparent",
"resample_when": "size_differs_or_sharpening_requested",
"sharpen_when": "downscaling"
}
Resampling Filters
robidoux
- The default and recommended downsampling filterrobidoux_sharp
- A sharper version of the aboverobidoux_fast
- A faster, less accurate version of robidouxginseng
- The default and suggested upsampling filterginseng_sharp
lanczos
lanczos_sharp
lanczos_2
lanczos_2_sharp
cubic
cubic_sharp
catmull_rom
mitchell
cubic_b_spline
hermite
jinc
triangle
linear
box
fastest
n_cubic
n_cubic_sharp
Colors
Colors can be named, or be RRGGBBAA hexadecimals.
transparent
black
{ "srgb": { "hex" : "ffffff" } }
Using a JSON Graph
The following generates 4 sizes of images in a single job. Much execution time is saved because the image is not re-decoded for each output.
Still, it is best to use a fluent API to help build JSON graphs, as it can be error prone.
{
"io": [
{
"io_id": 0,
"direction": "in",
"io": "placeholder"
},
{
"io_id": 1,
"direction": "out",
"io": "placeholder"
},
{
"io_id": 2,
"direction": "out",
"io": "placeholder"
},
{
"io_id": 3,
"direction": "out",
"io": "placeholder"
},
{
"io_id": 4,
"direction": "out",
"io": "placeholder"
}
],
"framewise": {
"graph": {
"nodes": {
"0": {
"decode": {
"io_id": 0
}
},
"1": {
"constrain": {
"mode": "within",
"w": 1600
}
},
"2": {
"constrain": {
"mode": "within",
"w": 1200
}
},
"3": {
"constrain": {
"mode": "within",
"w": 800
}
},
"4": {
"constrain": {
"mode": "within",
"w": 400
}
},
"5": {
"encode": {
"io_id": 1,
"preset": {
"mozjpeg": {
"quality": 90
}
}
}
},
"6": {
"encode": {
"io_id": 2,
"preset": {
"mozjpeg": {
"quality": 90
}
}
}
},
"7": {
"encode": {
"io_id": 3,
"preset": {
"mozjpeg": {
"quality": 90
}
}
}
}
"8": {
"encode": {
"io_id": 4,
"preset": {
"mozjpeg": {
"quality": 90
}
}
}
},
},
"edges": [
{
"from": 4,
"to": 8,
"kind": "input"
},
{
"from": 2,
"to": 4,
"kind": "input"
},
{
"from": 1,
"to": 2,
"kind": "input"
},
{
"from": 0,
"to": 1,
"kind": "input"
},
{
"from": 3,
"to": 7,
"kind": "input"
},
{
"from": 1,
"to": 3,
"kind": "input"
},
{
"from": 2,
"to": 6,
"kind": "input"
},
{
"from": 1,
"to": 5,
"kind": "input"
}
]
}
}
}
Create Canvas Command.
The following node creates a 200x200 transparent canvas.
{
"create_canvas": {
"format": "bgra_32",
"w": 200,
"h": 200,
"color": "transparent"
}
}
The following node creates a 200x200 black canvas. Transparency operations will not work as the canvas doesn't support an alpha channel.
{
"create_canvas": {
"format": "bgr_32",
"w": 200,
"h": 200,
"color": "black"
}
}
Copy Rectangle Command
This node can only be used with graph
, as it requires both a canvas
and an input
node.
The following node copies (but does not blend/composite) a 100x100 square from the input
node to x:100, y:100
on the canvas
node.
{
"copy_rect_to_canvas": {
"from_x": 0,
"from_y": 0,
"w": 100,
"h": 100,
"x": 100,
"y": 100
}
}
Draw Image Exact Command
The following node will compose the input
image with the top-left 100x100 square on the
canvas
, distorting it if the aspect ratio is different. 15% sharpening will be applied.
This node can only be used with graph
.
{
"draw_image_exact": {
"x": 0,
"y": 0,
"w": 100,
"h": 100,
"blend": "compose",
"hints": {
"sharpen_percent": 15
}
}
}