Docs / Sizing & layout

Sizing & layout v0.2.0

Sizing works on the source image, or on the region you picked with crop if you used one. picturium resizes the content, applies the fit mode, and adds pad last. All of this happens on every frame of an animation or video clip and on every rendered document page.

Raster transform order
  1. Autorotate
    / rotate
  2. Crop
  3. Size × DPR
    × scale
  4. Fit
    / gravity
  5. Pad
  6. Filters
  7. Watermark

What comes after sizing is covered in Filters & effects and Watermarking.

None of this applies when picturium hands back the source itself, which happens with original=true, f=pdf and f=svg. Documents & vectors explains those cases.

Width, height, aspect ratio

w / width and h / height set the size in pixels. Leaving a parameter out, setting it to 0, or leaving it empty all mean “don’t constrain this side”. Set just one and picturium works out the other from the source’s proportions, or from ar if you gave one.

/photo.jpg?w=800
/photo.jpg?h=600
/photo.jpg?w=800&ar=16/9
/photo.jpg?w=800&h=600

ar / aspect_ratio accepts:

  • auto for the source’s own ratio (the default)
  • square for 1:1
  • video for 16:9
  • a fraction such as 4/3, 16/10 or 1/1

Custom ratios have to be fractions, so ar=1 is rejected. With ar but no w or h, you get the largest area of that ratio that fits in the source. With both w and h set, the box is already decided and ar is ignored.

Fit modes

fit decides how the image fills a box, whether that box comes from both dimensions or from an explicit aspect ratio. With a single dimension and no ar there’s no box to fill, so every mode just resizes proportionally.

cover

Keeps the proportions, fills the whole box and crops whatever sticks out.

contain

Keeps the proportions, fits the whole image inside and fills the leftover space.

force

Stretches the image to exactly the box, ignoring proportions.

cover is the default. Reach for contain when nothing may be cut off, and for force only when you really do want the image distorted.

/photo.jpg?w=800&h=600&fit=cover
/photo.jpg?w=800&h=600&fit=contain&bg=white
/photo.jpg?w=800&h=600&fit=force

Gravity

g / gravity decides which part of the image cover keeps, and where contain places it on the canvas:

top · right · bottom · left · top-left · top-right · bottom-left · bottom-right · center · attention · entropy

It defaults to center, which you can change with image.gravity. attention and entropy let libvips pick the most interesting area of a still image. Animations fall back to center, so the crop doesn’t jump around from frame to frame.

/portrait.jpg?w=600&h=600&fit=cover&g=top
/landscape.jpg?w=600&h=600&fit=cover&g=attention
/logo.png?w=800&h=600&fit=contain&g=bottom-right

The crop= parameter has a gravity of its own. It defaults to image.crop_gravity and doesn’t inherit this one.

Scaling: dpr, scale, upsize

dpr and scale both multiply the requested size, and they stack. For example, w=400&dpr=2&scale=0.5 ends up at the same 400 pixels as plain w=400.

dpr

Multiplies the size. Also scales watermark padding, image scale and text size given in the request.

scale

Multiplies the requested size.

upsize

Allows output larger than the source.

With upsize=false, a box bigger than the source is shrunk to fit it, so you never get more pixels than the original has. If the box came from an explicit ar, it shrinks evenly so the ratio stays intact. Turn on upsize=true when you really need a larger image, for example for high-density screens.

/icon.png?w=64&h=64&dpr=2&upsize=true

When a request doesn’t set upsize, image.upsize decides. The exception is SVG, PDF, Office and vector sources: they have no fixed pixel size to lose, so they upsize by default.

Resampling

resample picks the kernel used when pixels get resized:

nearest

Hard pixel edges. Good for pixel art and masks.

linear

Fast, slightly soft.

cubic

Cubic interpolation.

lanczos2

Lanczos with a smaller window.

lanczos3

The default. High quality for general use.

The default comes from image.resample, which is lanczos3 unless you change it.

Padding & extend

pad / padding adds space after fitting. It takes one to four comma-separated whole numbers, in the same order as CSS:

10
10,20
10,20,30
10,20,30,40

extend decides what goes into that space, and into the empty part of a contain canvas:

  • bg: the bg / background colour (the default)
  • copy: the nearest edge pixel, stretched outwards
  • repeat: the image, tiled
  • mirror: mirrored copies of the image, tiled
/photo.jpg?w=800&h=600&fit=contain&pad=24&extend=bg&bg=white
/tile.png?pad=40&extend=repeat

By default extend comes from image.extend (bg) and the background is transparent.

Rotation

autorot / auto_rotate applies the EXIF orientation from the source. It follows image.auto_rotate, which is true by default. After that, rot / rotate turns the image by a quarter-turn, before any cropping or sizing.

none
90° anticlockwise
180°
90° clockwise
/scan.jpg?autorot=false&rot=right&w=1000

Only these quarter-turns are supported. There’s no arbitrary-angle rotation or flipping for the image itself.

Background colour

bg / background is the colour used by extend=bg, the empty part of a contain canvas, padding, and formats that can’t store transparency. It defaults to transparent.

You can use CSS colour names, hex without the # (3, 4, 6 or 8 digits), or the rgb(), rgba(), hsl(), hsla(), hwb(), oklab() and oklch() functions. Don’t put a raw # in the query: the browser treats everything after it as a fragment and never sends it.

/logo.png?w=600&h=400&fit=contain&bg=transparent
/logo.png?w=600&h=400&fit=contain&bg=ff8a1f
/logo.png?pad=32&bg=rgb(16,18,24)

Encoding happens after all of this. Output format & quality covers formats, quality, metadata and size limits, and the URL parameter reference lists every alias and default.