Skip to content

About

Responsive images for Symfony: one Twig component for AVIF/WebP srcset, blur placeholders, Glide/Imgix, inspired by next/image

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Latest commit

 

History

186 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Latest Stable Version Total Downloads License PHP Version CI Status Coverage

PicassoBundle

The missing image component for Symfony.
Inspired by Next.js Image — built for the Symfony ecosystem.

Write one line of Twig. Get AVIF, WebP, responsive srcset, blur placeholders, and lazy loading — automatically.

📖 Documentation


Before PicassoBundle

<!-- You write all of this manually... and maintain it forever -->
<picture>
    <source
        type="image/avif"
        srcset="/images/hero-640.avif 640w, /images/hero-1080.avif 1080w, /images/hero-1920.avif 1920w"
        sizes="100vw"
    />
    <source
        type="image/webp"
        srcset="/images/hero-640.webp 640w, /images/hero-1080.webp 1080w, /images/hero-1920.webp 1920w"
        sizes="100vw"
    />
    <img
        src="/images/hero-1080.jpg"
        srcset="/images/hero-640.jpg 640w, /images/hero-1080.jpg 1080w, /images/hero-1920.jpg 1920w"
        sizes="100vw"
        width="1920"
        height="1080"
        loading="lazy"
        alt="Hero"
    />
</picture>

After PicassoBundle

<twig:Picasso:Image src="hero.jpg" width="1920" height="1080" sizes="100vw" alt="Hero" />

Same output. Zero boilerplate. All formats, srcsets, and placeholders generated automatically.


Why PicassoBundle?

Images account for the largest share of page weight on most websites. Serving them correctly — with modern formats, responsive srcsets, proper lazy loading, and blur placeholders — is critical for both Core Web Vitals and user experience, but the implementation is tedious and error-prone.

PicassoBundle solves this the same way Next.js Image did for React: a single component that handles everything.

Without PicassoBundle With PicassoBundle
Format negotiation Manual AVIF/WebP/JPEG <source> tags Automatic from config
Responsive srcset Hand-crafted per breakpoint Generated from sizes prop
Blur placeholders DIY or skip it Built-in (LQIP, BlurHash, or custom)
Dimension detection Hardcoded or forgotten Auto-detected from image stream
LCP optimization Manually set loading/fetchpriority One priority prop
Image sources Filesystem only Filesystem, S3, Flysystem, Vich, URL
CDN support Build your own integration Imgix out of the box, or plug in any CDN

Features

  • One component, full optimization — <twig:Picasso:Image> renders a complete <picture> with AVIF, WebP, and JPEG sources
  • Automatic responsive srcset — generates width descriptors for all configured breakpoints, no manual work
  • Blur placeholders — built-in LQIP and BlurHash support for instant perceived loading
  • Smart dimension detection — reads image dimensions from the stream automatically, preserves aspect ratio
  • Priority images — one prop for loading="eager" + fetchpriority="high" (LCP optimization)
  • Multiple image sources — Local filesystem, Flysystem (S3, GCS, Azure), VichUploaderBundle, remote URLs
  • Local or CDN transforms — Glide for self-hosted, Imgix for CDN, or bring your own
  • Signed URLs — HMAC-signed transformation URLs prevent abuse
  • Private images — serve thumbnails from your own routes, behind your security voters, with the same srcset and formats
  • PSR-6 metadata caching — dimension detection and BlurHash results cached
  • Fully extensible — add custom loaders, transformers, or placeholders with PHP attributes (#[AsImageLoader], #[AsImageTransformer], #[AsPlaceholder])

Requirements

Glide, BlurHash, Flysystem, VichUploaderBundle and remote URLs each need an optional package: see Installation.

Installation

composer require silarhi/picasso-bundle

# and a transformer: Glide renders the images locally (Imgix needs no extra package)
composer require league/glide

Upgrading from 1.x? Follow UPGRADE-2.0.md, or the upgrade guide.

Quick Start

1. Configure a loader, a transformer and a placeholder:

# config/packages/picasso.yaml
picasso:
    loaders:
        filesystem:
            path: '%kernel.project_dir%/public/uploads'
    transformers:
        glide:
            sign_key: '%env(PICASSO_SIGN_KEY)%'
    placeholders:
        blur: { type: transformer } # optional: blurred preview while the image loads

2. Import the routes (required for Glide local serving):

# config/routes/picasso.yaml
picasso:
    resource: '@PicassoBundle/config/routes.php'

3. Use the Twig component in your templates:

<twig:Picasso:Image
    src="photo.jpg"
    width="800"
    height="600"
    sizes="(max-width: 768px) 100vw, 800px"
    alt="A beautiful landscape"
/>

This renders a <picture> element with <source> tags for AVIF and WebP, a fallback <img> with JPEG srcset, and an inline blur placeholder — all automatically. Placeholders are opt-in: without the placeholders entry, images render without one (see Placeholders).

Documentation

Everything else is on picasso-bundle.silarhi.dev:

Contributing

See CONTRIBUTING.md. Release notes are in CHANGELOG.md.

License

MIT License. See LICENSE for details.


Built with care by SILARHI.
If PicassoBundle saves you time, consider giving it a star on GitHub.

About

Responsive images for Symfony: one Twig component for AVIF/WebP srcset, blur placeholders, Glide/Imgix, inspired by next/image

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages