drupal/image_scale_fill · version 1.1.0

Fixed-size image derivatives without cropping

Image Scale and Fill Background adds one effect to Drupal’s image style system. It scales a source image to fit a configured canvas without cropping or distorting it, then fills the remaining area with a background derived from the image itself.

Requirements. Drupal 10.3 or newer, and the GD image toolkit. Under ImageMagick the effect returns without modifying the image, while still reporting the configured dimensions to Drupal — so the rendered <img> carries dimensions the file does not have. Raster sources only: GD cannot read SVG, and Drupal image styles do not apply to SVG files.

What the effect does

The effect runs when a derivative is first generated. The result is written beside the source’s stream wrapper — a public source produces a public derivative, served as a static file thereafter; a private source produces a private one, served through Drupal. Either way the processing cost is incurred once per derivative rather than per request. Saving an image style discards its existing derivatives, which are regenerated on the next request for each one.

It reports the configured canvas back to Drupal as the output size, which means the rendered <img> carries width and height attributes that are identical for every image in a listing.

The effect never crops the image it places on the canvas. The Scaled background type does take a centre-cropped, cover-scaled copy of the source, but that copy sits behind the intact image. For art-directed cropping, where an editor selects the region to keep, use Focal Point or Image Widget Crop. Format conversion is a separate effect chained after this one in the same image style.

Where this is used

The effect applies wherever a layout requires images of one fixed size, the source images arrive at proportions the site does not control, and cropping is not acceptable.

Listing and teaser grids
Article indexes, related-content rails and category listings, where derivatives of uneven height break card alignment and push captions out of register.
Social and open-graph images
An og:image must be 1200×630 in the file itself; the consumer is a scraper that does not process the site’s stylesheets.
Logo, partner and sponsor listings
Marks span a wide range of proportions and are usually transparent PNGs. The effect produces a uniform tile and supplies the background the source does not contain.
Syndication surfaces
Newsletters, RSS enclosures and feeds consumed by third parties, where the dimensions declared in the file are the only dimensions available.
Wire, archive and user-supplied imagery
Content whose composition is not known in advance, where an automated centre crop may remove the subject.
Responsive image styles
Because the output size is exactly the configured canvas, a set of styles at 400×225, 800×450 and 1600×900 produces correct width descriptors and a constant aspect ratio across the whole srcset.

Where the stored dimensions do not matter — the image is only ever rendered inside the site’s own stylesheets — object-fit: contain on a fixed-size element achieves the same visual result with no derivative, no storage and no regeneration. Section 08 sets out the cases it does not cover.

Output dimensions compared with core image effects

Editorial image sources arrive at dimensions and aspect ratios the receiving site does not control. The five sources below range from 9.8:1 to 1:1.5, and one is smaller than the target canvas. Each grid applies a single image style at 800×450 and is laid out as a CSS grid with img { width: 100% }.

canvas 800×450 · this section concerns output dimensions; background treatments are shown at full size in section 05

Core: ScaleProportions and content are preserved. Output dimensions vary with the source: five sources produced five different sizes, so card heights and caption positions vary.
Lago di Alserio, 800×82
Lago di Alserio800×82
Pangong Tso, 800×259
Pangong Tso800×259
Hong Kong at night, 516×450
Hong Kong at night516×450
Scarlet macaw, 300×450
Scarlet macaw300×450
Community Site Guide, 150×212
Community Site Guide150×212
Core: Scale and CropOutput dimensions are uniform. Content outside the target ratio is discarded: the panorama loses most of its width, the portrait its upper and lower thirds, and the book cover the top of its title.
Lago di Alserio, 800×450
Lago di Alserio800×450
Pangong Tso, 800×450
Pangong Tso800×450
Hong Kong at night, 800×450
Hong Kong at night800×450
Scarlet macaw, 800×450
Scarlet macaw800×450
Community Site Guide, 800×450
Community Site Guide800×450
Scale and fill backgroundOutput dimensions are uniform and no content is discarded. The area the scaled image does not cover is filled from the image itself.
Lago di Alserio, 800×450
Lago di Alserio800×450
Pangong Tso, 800×450
Pangong Tso800×450
Hong Kong at night, 800×450
Hong Kong at night800×450
Scarlet macaw, 800×450
Scarlet macaw800×450
Community Site Guide, 800×450
Community Site Guide800×450
EffectOutput sizeAspect ratioContent
Scalevariespreservedpreserved
Resizeexactnot preservedpreserved
Scale and Cropexactpreservedcropped
Scale and fill backgroundexactpreservedpreserved

Upscaling. In 1.1.0 the effect always scales to fit, including when the source is smaller than the canvas — the 150×212 book cover above is enlarged. Core’s Scale effect has an upscale setting for this; this effect does not. Use a separate style for sources that must not be enlarged, or open an issue.

Transparent sources and irregular proportions

The six logo files below span 4.23:1 to 1:1.38 — a narrower spread than the photographs in section 03, but concentrated at the extremes rather than distributed across them. All six are transparent PNGs, which contain no background content from which a fill can be derived. This listing uses a square 640×640 canvas: in a 16:9 canvas the 4.23:1 wordmark would fill 58% of the frame against 76% in a square, so the square shows more of what the effect does.

canvas 640×640 · sources rasterised from SVG, since image styles do not process SVG files

Core: ScaleSix sources produced six different output sizes.
LibreOffice, 640×151
LibreOffice640×151
Drupal, 640×171
Drupal640×171
Nextcloud, 640×451
Nextcloud640×451
Kdenlive, 640×481
Kdenlive640×481
Blender, 640×523
Blender640×523
Jenkins, 463×640
Jenkins463×640
Core: Scale and CropOutput dimensions are uniform. Cropping removes the parts of each mark outside the target ratio: the Drupal wordmark renders as “up” and LibreOffice as “ibreO Document”.
LibreOffice, 640×640
LibreOffice640×640
Drupal, 640×640
Drupal640×640
Nextcloud, 640×640
Nextcloud640×640
Kdenlive, 640×640
Kdenlive640×640
Blender, 640×640
Blender640×640
Jenkins, 640×640
Jenkins640×640
Scale and fill backgroundOutput dimensions are uniform with each mark intact. Transparent sources receive a filled background rather than being composited onto the black canvas.
LibreOffice, 640×640
LibreOffice640×640
Drupal, 640×640
Drupal640×640
Nextcloud, 640×640
Nextcloud640×640
Kdenlive, 640×640
Kdenlive640×640
Blender, 640×640
Blender640×640
Jenkins, 640×640
Jenkins640×640

SVG sources. Logo files are commonly SVG, which GD cannot read and Drupal image styles do not process. Rasterise on upload, restrict the field to raster formats, or handle SVG separately with SVG Image. The marks on this page were rasterised to PNG before processing.

Background treatments

The background is derived from the source image rather than configured as a colour. The available combinations are a repeated copy of the image, a cover-scaled copy that is blurred or darkened, and the image’s dominant colour as a flat field or a gradient.

canvas 800×450 · the control below changes the source behind all five results · the first three are derived from a copy of the image, the last two from a single measured colour

Scarlet macaw, Tiled backgroundTiled
Scarlet macaw, Blurred backgroundBlurred
Scarlet macaw, Darkened backgroundDarkened
Scarlet macaw, Dominant colour backgroundDominant colour
Scarlet macaw, Dominant gradient backgroundDominant gradient
Source

Scarlet macaw

Background type × background style, as the configuration form presents them. A sixth combination, tiled with the coloured overlay, is not shown: its mean per-channel difference from scaled-with-overlay measured 7.17 of 255, because the overlay obscures the repetition that distinguishes a tiled background.

Macaw parrot (Unsplash).jpg by Andrew Pons, CC0 · Zellige loose tile shapes.jpg by Jadcooper, CC BY-SA 4.0

Selecting a treatment. Blurred suits photographs. Dominant colour is the least expensive option and produces the most uniform grid. Tiled is appropriate for pattern and texture sources; repetition is apparent on other subjects. Darkened retains some structure from the source while keeping overlaid text legible.

Background choice moves file size by well under a factor of two: across the sources shown the per-option means ran 40–50 KB per WebP derivative at 800×450, with individual files between 25 and 63 KB.

Fill selection for transparent sources

A transparent source contains no background content from which to derive a fill, and a blurred copy of a logo reproduces the logo rather than producing a background. One setting decides what happens, with four values: three of them detect a transparent source and give it a flat filled background, while the fourth skips the detection entirely and applies the configured background type as if the source were a photograph. Two marks are shown below, one drawn in dark ink and one in white. Each row begins with the transparent source displayed over a checkerboard.

canvas 640×640

The Blender mark over a transparency checkerboardSourcetransparent PNG
Blender mark on black with a blurred copy of itself behind itDo nothingbackground type is applied
Blender mark on a white groundAutomaticdark ink, light fill
Blender mark on a warm off-white groundFixed colour#F2EFE8
Blender mark on a pale orange groundFrom the imagetint of the mark

Dark ink. All four options produce a legible result, so the choice is stylistic rather than functional.

The white wordmark over a transparency checkerboardSourcetransparent PNG
White wordmark on black, not legibleDo nothingbackground type is applied
White wordmark legible on a dark groundAutomaticlight ink, dark fill
White wordmark on a warm off-white ground, not legibleFixed colour#F2EFE8
White wordmark on a dark grey groundFrom the imageshade of the mark

White ink. Only Automatic produces a legible result. The fixed colour is the same in both rows.

OptionBehaviourApplicable when
Do nothing noneThe configured background type is applied to the logo as it would be to a photograph, producing a black canvas with a blurred copy of the mark behind it, or under dominant colour the mark’s own colourSources are never transparent
Automatic autoA light or dark fill, selected per image from the proportion of ink that is lightSource artwork is not controlled by the site
Fixed colour fixedOne configured colour for every source Source artwork is known and consistent
From the image from_imageThe mark’s mean ink colour, mixed 85% toward white or blackA uniform white background is not acceptable

How Automatic decides. It measures the proportion of the artwork’s ink whose WCAG relative luminance exceeds 0.5, and selects the dark fill when that proportion exceeds 70%. The luminance threshold is a high bar: mid-grey #808080 sits at approximately 0.22 and counts as dark. Automatic and Fixed produce identical output on dark-ink sources only when the fixed colour equals the configured light colour; with the fixed colour set to a page background, as above, they differ. Added in issue #3618813.

Detection threshold. A source is treated as transparent when 5% or more of sampled pixels carry any transparency at all, antialiased edges included. Sampling is roughly 60 points per axis rather than every pixel. Across the thirteen sources shown on this page, the seven transparent logos measured 28.6% to 76.5% and the six photographs measured a flat 0.0%; nothing fell between. For source sets with that separation, one image style can process photographs and logos together.

Overlay transparency and tiling

Overlay transparency sets opacity. Higher values produce a darker result. The overlay colour is fixed at black; the “Colored overlay” label does not indicate a configurable colour.

Background darkened slightlyTransparency 15background at 85% brightness
Background darkened moderatelyTransparency 60background at 40%, the default
Background darkened almost to blackTransparency 90background at 10%

At 100 the overlay is opaque and the background type has no effect on the output.

A tiled background is always combined with a blur or an overlay. The configuration provides no unmodified option. An unmodified tile requires the coloured overlay with transparency set to 0, which paints a fully transparent rectangle.

Tiled zellige background, blurredTiled, blurredthe default pairing
Tiled zellige background, unmodifiedTiled, overlay at 0repetition visible
Tiled Hong Kong background, unmodifiedThe same on a photographrepetition apparent

Tiling produces visible repetition, which suits pattern sources.

When CSS object-fit is sufficient

object-fit: contain on a fixed-size element requires no derivatives, storage or regeneration, and is sufficient wherever the derivative’s stored dimensions do not matter. It does not cover the following four cases.

A fill derived from each image. CSS can place a flat colour behind a letterboxed image. It cannot blur that image or calculate its dominant colour.

Cropping. object-fit: cover discards the same content as Scale and Crop, at render time rather than at derivative generation.

Consumers that do not process CSS. An og:image must be 1200×630 in the file itself. The same applies to newsletters, RSS enclosures and any surface rendered outside the site’s own stylesheets.

Declared dimensions. Every derivative matches the configured canvas, so the effect reports one size to Drupal and every rendered <img> carries identical width and height attributes. Sources of varying proportion do not. The same property makes a responsive image style produce a constant aspect ratio across its srcset.

Installation and configuration

composer require drupal/image_scale_fill:^1.1
drush en image_scale_fill
drush updatedb

Add Scale and fill background to an image style at /admin/config/media/image-styles. Place it last in the style: anything after it operates on the canvas this effect has drawn. Three decisions determine the remaining settings.

Transparent sources

If any source is a transparent logo, set Images with a transparent background to Automatic and set its light colour to the page background colour. If no source is transparent, the setting has no effect.

Fill derivation

Derived from the image: Background type: Scaled, Background style: Blurred. Neutral: Background type: Dominant color. Pattern artwork: Tiled with the overlay at 0.

Generation volume

For bulk regeneration, prefer dominant colour, or retain the blur and reduce Resize ratio. See section 11.

Upgrading an existing site. The database update sets every image style that already uses this effect to Do nothing, so the images those styles produce do not change. The update re-saves each affected style, which discards its generated derivatives; each is rebuilt on the next request for it. The Automatic default applies only to effects added afterwards. Sites that deploy configuration from files should re-export after running the update; a style left un-exported is re-saved on every configuration import, which discards its derivatives each time.

SettingDefaultRangeEffect
Width, Height1–10000 each; the form additionally caps the product at 40 megapixelsThe output canvas. The form rejects both; the configuration schema constrains each side only, not the product. Configuration arriving through an unvalidated import is reduced at runtime and logged. A 40-megapixel canvas requires roughly 160 MB for the canvas alone, before the decoded source, so PHP’s memory limit binds well before the cap
Background typeScaledTiled · Scaled · Dominant colorThe content the fill is derived from
Background styleBlurredBlurred · Colored overlayApplies to Tiled and Scaled only, and is ignored for Dominant color. The overlay colour is fixed at black
Blur radius91–50Blur extent and cost. 3 to 50 measured 741 ms to 3095 ms at 1200×630
Blur sigma60.1–50The form rejects a sigma above the blur radius. An imported value above the radius is reduced silently at runtime, without a log entry
Resize ratio0.30.1–1Canvas reduction applied before blurring, and the largest single cost factor: 0.1 to 1.0 measured 555 ms to 5533 ms at 1200×630
Overlay transparency600–100Opacity. Higher values are darker; at 100 the background type has no effect
Dominant styleSingle colorSingle color · GradientThe gradient end colour is each channel of the dominant colour reduced by 50 and clamped at 0, so a near-black dominant colour produces little or no ramp
Gradient directionVerticalVertical · HorizontalGradient axis
Images with a transparent backgroundAutomatic for new effects; Do nothing for effects that predate the updateDo nothing · Automatic · Fixed color · From the imageSee section 06
Light / dark / fixed colour#FFFFFF / #000000 / #FFFFFF#RRGGBB onlyThe light colour is applied behind dark artwork and is the one to match to the page background. A malformed imported value falls back to white

Blur work is capped. The blur is bounded at twelve million pixel-coefficient operations, so a large canvas combined with a high radius is reduced to stay within the budget and the reduction is logged. Worst-case cost is therefore bounded whatever an editor configures, but resize ratio and blur radius do not always apply literally at large canvas sizes.

Exported image styles

Configuration read back from a site with these styles saved, validated against the image.style.* schema and its constraints. Save each block under the filename shown in the configuration sync directory. The UUIDs need only be unique within the destination site; keep them, or replace both the map key and the uuid value with one new value — they must match.

Article river and section fronts image.style.isf_teaser_card.yml

uuid: 1847cea3-391c-4a90-8c5c-92a2ad9811e3
langcode: en
status: true
dependencies:
  module:
    - image_scale_fill
name: isf_teaser_card
label: 'Teaser 800x450'
effects:
  0970fc3e-50eb-43f6-a3b2-d25a6271c1b7:
    uuid: 0970fc3e-50eb-43f6-a3b2-d25a6271c1b7
    id: scale_and_fill_background
    weight: 1
    data:
      width: 800
      height: 450
      background_type: scaled
      background_style: blurred
      background_style_dominant: single_color
      radius: 9
      sigma: 6.0
      resize_ratio: 0.3
      gradient_direction: vertical
      transparency: 60
      transparent_handling: auto
      transparent_light_color: '#FFFFFF'
      transparent_dark_color: '#1A1A1A'
      transparent_color: '#FFFFFF'

og:image and Twitter cards image.style.isf_social_card.yml

uuid: 2839306e-be49-4951-8414-43a26f729f97
langcode: en
status: true
dependencies:
  module:
    - image_scale_fill
name: isf_social_card
label: 'Social card 1200x630'
effects:
  496ddd09-75b6-4ac7-b13b-61fe03a9ebf4:
    uuid: 496ddd09-75b6-4ac7-b13b-61fe03a9ebf4
    id: scale_and_fill_background
    weight: 1
    data:
      width: 1200
      height: 630
      background_type: scaled
      background_style: blurred
      background_style_dominant: single_color
      radius: 9
      sigma: 6.0
      resize_ratio: 0.3
      gradient_direction: vertical
      transparency: 60
      transparent_handling: auto
      transparent_light_color: '#FFFFFF'
      transparent_dark_color: '#1A1A1A'
      transparent_color: '#FFFFFF'

High-volume archive listings and newsletters image.style.isf_archive_thumb.yml

uuid: fa14868f-027f-4ee5-8a15-e3bb8ad1cc40
langcode: en
status: true
dependencies:
  module:
    - image_scale_fill
name: isf_archive_thumb
label: 'Archive thumbnail 400x400'
effects:
  b0c16190-277b-4ef8-9ee5-afe16e084a2d:
    uuid: b0c16190-277b-4ef8-9ee5-afe16e084a2d
    id: scale_and_fill_background
    weight: 1
    data:
      width: 400
      height: 400
      background_type: dominant_color
      background_style: blurred
      background_style_dominant: single_color
      radius: 9
      sigma: 6.0
      resize_ratio: 0.3
      gradient_direction: vertical
      transparency: 60
      transparent_handling: auto
      transparent_light_color: '#FFFFFF'
      transparent_dark_color: '#1A1A1A'
      transparent_color: '#FFFFFF'

Sponsor, partner and event logo walls image.style.isf_partner_tile.yml

uuid: 2ca7bf53-71d3-4af3-9622-e4c0c872af12
langcode: en
status: true
dependencies:
  module:
    - image_scale_fill
name: isf_partner_tile
label: 'Partner tile 640x640'
effects:
  e541f0be-5439-441c-bc9a-a10e80134b13:
    uuid: e541f0be-5439-441c-bc9a-a10e80134b13
    id: scale_and_fill_background
    weight: 1
    data:
      width: 640
      height: 640
      background_type: dominant_color
      background_style: blurred
      background_style_dominant: single_color
      radius: 9
      sigma: 6.0
      resize_ratio: 0.3
      gradient_direction: vertical
      transparency: 60
      transparent_handling: auto
      transparent_light_color: '#FFFFFF'
      transparent_dark_color: '#1A1A1A'
      transparent_color: '#FFFFFF'

Derivative generation cost

Absolute timings in this environment — a DDEV container on a development workstation — varied by a factor of two to three between runs of the same measurement. Only the relationships below held steady across three runs, so those are what is quoted. Measure absolute figures against representative sources on the target hardware.

Cost is incurred when derivatives are generated, not per request. Saving an image style discards its derivatives, and each is regenerated on the next request that needs it, so the cost lands on front-end traffic rather than at deployment.

Resize ratio is the largest single factor, and it is consistent. At 1200×630, moving it from 0.1 to 1.0 multiplied the time by 10.0, 10.3 and 10.8 across three runs. It reduces the canvas before blurring, and the blurred result is scaled back up, so a low value is much cheaper and the difference is difficult to see.

Blur radius is the next. Raising it from 3 to 50 multiplied the time by roughly four.

Dominant colour is consistently cheaper than the blur, but the margin depends almost entirely on how expensive the source is to decode: across five sources at a fixed 800×450 canvas the gap ran from under 200 ms to over 600 ms in a single run. If the choice matters at your volume, measure it against your own sources.

Canvas size raises cost sub-linearly. The blur is applied to the canvas rather than the source, but per-derivative decoding and encoding dominate at small canvases: sixteen times the pixels produced between two and four times the time, depending on the run.

The effect writes warnings to the log when it reduces a canvas, clamps a setting or reduces the blur working area. These are worth checking after a bulk import.