PHPackages                             visuellverstehen/statamic-picturesque - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. visuellverstehen/statamic-picturesque

ActiveStatamic-addon[Image &amp; Media](/categories/media)

visuellverstehen/statamic-picturesque
=====================================

A Statamic tag for building HTML-only responsive images.

v2.1.0(2mo ago)1016.9k↑36.5%1[1 PRs](https://github.com/visuellverstehen/statamic-picturesque/pulls)MITPHPPHP ^8.3CI passing

Since Mar 10Pushed 2mo ago4 watchersCompare

[ Source](https://github.com/visuellverstehen/statamic-picturesque)[ Packagist](https://packagist.org/packages/visuellverstehen/statamic-picturesque)[ RSS](/packages/visuellverstehen-statamic-picturesque/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (5)Versions (30)Used By (0)

Picturesque
===========

[](#picturesque)

A Statamic addon that provides a custom tag for building HTML-only responsive images. It utilizes Glide to resize and crop images and create sources within a `` element for different DPRs and screen sizes.

To learn more about responsive images and how to use them, [this article](https://ericportis.com/posts/2014/srcset-sizes/) by Eric Portis is highly recommended. Although it was published in 2014 the key takeaways are now at least as relevant as they were back then.

How to Install
--------------

[](#how-to-install)

Run the following command from your project root:

```
composer require visuellverstehen/statamic-picturesque
```

How to Use
----------

[](#how-to-use)

The tag is available as `{{ picture }}` or `{{ picturesque }}` and supports different ways of using it:

### Non-breakpoint based image with `size` attribute

[](#non-breakpoint-based-image-with-size-attribute)

Creates a picture element using a single source with a resized/cropped image for all defined DPRs.

e. g. `{{ picture:img size="300x200" }}` or `{{ picture:img size="300|1.5:1" }}`

Takes width and (optionally) ratio through the `size` attribute, with values separated by a pipe. Results in:

```

```

### Breakpoint-based image without sizes

[](#breakpoint-based-image-without-sizes)

Creates a picture element using sources for each supplied breakpoint, each with a resized/cropped image for all defined DPRs.

e. g. `{{ picture:img default="300|1.5:1" md="1024|1.6:1" lg="1280|2:1" }}`

Takes width and ratio through breakpoint-specific attributes, with values separated by a pipe. Results in:

```

```

### Breakpoint-based image with sizes

[](#breakpoint-based-image-with-sizes)

Creates a picture element using sources for each supplied breakpoint, each with a resized/cropped image according to the supplied sizes.

e. g. `{{ picture:img default="300|1.5:1|100vw" md="1024|1.6:1|80vw" lg="1280|2:1|960px" }}`

Takes width, ratio and sizes through breakpoint-specific attributes, with values separated by a pipe. Results in:

```

```

### Additional information for all ways

[](#additional-information-for-all-ways)

#### Spaces in attributes

[](#spaces-in-attributes)

Feel free to use spaces within the attributes, if preferred. This might make the amount of parameters more readable, especially in multiline use:

```
{{ picture:img
    default="300 | 1.5:1 | 100vw"
    md="1024 | 1.6:1 | 80vw"
    lg="1280 | 2:1 | 960px"
}}

```

#### Image source

[](#image-source)

The image source can be supplied in different ways:
`{{ picture:img size="300|1.5:1" }}`
or
`{{ picture :src="img" size="300|1.5:1" }}`
with `img` being the field handle of your asset field.

If you're using the first option, be careful with the JSON mode ([see below](#json-mode)).

You can also supply an asset path: `{{ picture src="/assets/my-image.jpg" size="300|1.5:1" }}`

#### Cropping, ratio and size

[](#cropping-ratio-and-size)

If you want to keep the original image ratio (and don't crop at all), use `auto` instead of a ratio:
`{{ picture:img size="300 | auto | 100vw" […] }}`

When not cropping *and* not using the `sizes` attribute you can simply omit everything but the image width:
`{{ picture:img size="300" }}`

Instead of using a ratio to crop an image you can also supply a width and height:
`{{ picture:img size="300x100" md="600x400" }}`

If you want to use `width x height` as well as the `sizes` attribute, simply use `auto` as the second parameter:
`{{ picture:img size="300x100 | auto | 100vw" md="600x400 | auto | 80vw" }}`

The tag supports ratios as `1.5:1` or `1.5/1`, so use whichever way you prefer.

#### Format/filetypes

[](#formatfiletypes)

You can optionally add one or more filetypes for image conversion:
`{{ picture:img size="300x100" format="jpg, webp" }}`

If no `format` (or `filetype`) parameter is found, the default settings will be used (webp), which can be adjusted in the config. Please note that only supported filetypes can be used for conversion and all other supplied formats will be ignored.

#### Image orientation

[](#image-orientation)

By default Picturesque assumes you're working with landscape images. If you have a portrait image, you can change this behaviour by adding the `orientation` (or short `ori`, for all you impatient folks) parameter:
`{{ picture:img size="300 | 2:1" orientation="portrait" }}`

All calculations for ratio etc. then use the first number as the height and calculate the width from it. If you pass two sizes (`300x100`) while using portrait orientation, the first size is considered as height and the second one as width.

#### Breakpoints

[](#breakpoints)

The breakpoints for the media attributes can be configured ([see below](#configuration)) and use the [tailwindcss breakpoints](https://tailwindcss.com/docs/responsive-design) as default.

The default (so essentially the `0` breakpoint) can be defined through either the `size` or `default` parameter.

#### Glide Parameters

[](#glide-parameters)

You can pass any Glide image manipulation parameters to the tag using the `glide:` prefix:

```
{{ picture:img size="300x200" glide:blur="20" }}
{{ picture:img size="300x200" glide:quality="85" glide:brightness="75" }}
{{ picture:img size="300x200" glide:fit="contain" glide:bg="ffffff" }}
{{ picture:img size="300x200" glide:filt="greyscale" }}
```

All standard Glide parameters are supported, including:

- **Effects**: `blur`, `brightness`, `contrast`, `gamma`, `sharpen`
- **Filters**: `filt` (greyscale, sepia, etc.)
- **Quality**: `quality` or `q`
- **Fit modes**: `fit` (contain, max, fill, stretch, crop)
- **Background**: `bg` for background color when using fill modes

Please refer to the [Glide documentation](https://glide.thephpleague.com/2.0/api/quick-reference/) for all available parameters.

##### Important notes

[](#important-notes)

- Glide parameters for width (`w`, `width`) and height (`h`, `height`) are ignored as they are managed by Picturesque's responsive sizing.
- The `fit` parameter defaults to `crop_focal` when not specified.
- Glide parameters are applied to all generated image variants (different sizes, breakpoints and formats).

#### JSON mode

[](#json-mode)

If you don't want to get a precompiled HTML string but rather have all the data as JSON for passing it on (e. g. to a Vue component), you can tell the tag to do just that:
`{{ picture:json :src="img" size="300|1.5:1" }}`
or
`{{ picture:img output="json" size="300|1.5:1" }}`

Results in:

```
{
    "sources": {
        "default": {
            "type": "image\/webp",
            "srcset": "[img-url]?fm=webp&fit=crop&w=300&h=200&s=[…] 1x,[img-url]?fm=webp&fit=crop&w=600&h=400&s=[…] 2x"
            "width": "300",
            "height": "200"
        }
    },
    "img": {
        "alt": "Alt text provided by img asset.",
        "src": "[img-url]?w=300&fit=crop&s=[…]",
        "loading": "lazy",
        "width": "300",
        "height": "200"
    }
}
```

### Additional `img` element attributes

[](#additional-img-element-attributes)

To pass on some additional data to the generated `img` element, the following attributes are available:

#### Alt text

[](#alt-text)

The tag by default checks the source asset for an alt text. You can overwrite the alt text like this:
`{{ picture:img size="300x200" alt="I wish everyone would care about alt texts." }}`

#### CSS classes

[](#css-classes)

To attach css classes to the img element, use this:
`{{ picture:img size="300x200" class="w-full object-cover" }}`

If you want to attach classes to the picture element, use the `wrapperClass` attribute:
`{{ picture:img size="300x200" wrapperClass="foo bar" }}`

#### Lazy-loading

[](#lazy-loading)

You can disable lazy loading (which is activated by default) like this: `{{ picture:img size="300x200" lazy="false" }}`

A setting in the config ([see below](#configuration)) allows you to adjust the default behaviour.

### Using the base class

[](#using-the-base-class)

If you want to use the logic of the tag outside of an Antlers template you can simply use the `Picturesque` base class:

```
use VV\Picturesque\Picturesque;

// ...

public function makePicture(string $imageUrl)
{
    return (new Picturesque($imageUrl))
        ->default('300 | 1.5:1')
        ->breakpoint('md', '1024 | 1.6:1')
        ->breakpoint('lg', '1280 | 2:1 | 960px')
        ->format(['webp', 'jpg'])
        ->glideParams([
            'blur' => 10,
            'quality' => 85,
            'fit' => 'contain',
            'bg' => 'ffffff'
        ])
        ->alt('A huge billboard that says ›I wish everyone would care about alt texts.‹')
        ->class('w-full object-cover')
        ->lazy(true)
        ->generate() // you always have to call this!
        ->html(); // or ->json()
}
```

Please be aware that the image currently has to be a Statamic asset and must be findable through the Asset facade (`Statamic\Facades\Asset::find($url)`).

Configuration
-------------

[](#configuration)

The addon provides several configuration options through it's `config/picturesque.php` file. Check out the descriptions in there. All settings have sensible default options, so in the best-cast-scenario you don't have to configure anything.

More about us
-------------

[](#more-about-us)

- [www.visuellverstehen.de](https://visuellverstehen.de)

License
-------

[](#license)

The MIT license (MIT). Please take a look at the [license file](LICENSE.md) for more information.

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance86

Actively maintained with recent releases

Popularity33

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity71

Established project with proven stability

 Bus Factor1

Top contributor holds 77.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~54 days

Recently: every ~128 days

Total

21

Last Release

74d ago

Major Versions

v0.3.0-beta → v1.0.02023-04-13

v1.5.0 → v2.0.02025-08-28

PHP version history (2 changes)v0.1.0-betaPHP ^8.0

v2.1.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/57dcd9370600b66b5ad7d99dd2b633e36d3a9458e656d650045f5f5eaf540e2d?d=identicon)[visuellverstehen](/maintainers/visuellverstehen)

![](https://www.gravatar.com/avatar/16b77aabdc6e9a51c63341aa7ad7b295b05bb05b1814b1218963a806f2341f68?d=identicon)[simonerd](/maintainers/simonerd)

---

Top Contributors

[![simonerd](https://avatars.githubusercontent.com/u/7941370?v=4)](https://github.com/simonerd "simonerd (54 commits)")[![el-schneider](https://avatars.githubusercontent.com/u/26460248?v=4)](https://github.com/el-schneider "el-schneider (7 commits)")[![juliawarnke](https://avatars.githubusercontent.com/u/44929138?v=4)](https://github.com/juliawarnke "juliawarnke (6 commits)")[![florianbrinkmann](https://avatars.githubusercontent.com/u/2310924?v=4)](https://github.com/florianbrinkmann "florianbrinkmann (3 commits)")

---

Tags

imageresponsiveglidepictureaddonstatamicv5v6

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/visuellverstehen-statamic-picturesque/health.svg)

```
[![Health](https://phpackages.com/badges/visuellverstehen-statamic-picturesque/health.svg)](https://phpackages.com/packages/visuellverstehen-statamic-picturesque)
```

###  Alternatives

[multiavatar/multiavatar-php

Multicultural Avatar Generator

653150.0k4](/packages/multiavatar-multiavatar-php)[visuellverstehen/statamic-classify

A useful helper to add CSS classes to all HTML tags generated by the bard editor.

20116.8k](/packages/visuellverstehen-statamic-classify)[spacecatninja/imager-x

Ninja powered image transforms.

29390.0k23](/packages/spacecatninja-imager-x)[sitegeist/sms-responsive-images

Provides ViewHelpers and configuration to render valid responsive images based on TYPO3's image cropping tool.

34493.1k2](/packages/sitegeist-sms-responsive-images)[heyday/silverstripe-responsive-images

Configure and send a series of image size options to the client without loading any resources until a media query can be executed.

5387.7k6](/packages/heyday-silverstripe-responsive-images)[admad/cakephp-glide

CakePHP plugin for using Glide image manipulation library.

34160.7k1](/packages/admad-cakephp-glide)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
