Skip to content

Commit e16253e

Browse files
authored
Merge pull request #33 from jolicode/feat/avif-support
Add avif support
2 parents 22f1f41 + 904bc20 commit e16253e

File tree

22 files changed

+279
-55
lines changed

22 files changed

+279
-55
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# Changelog
22

3+
## [0.1.1] - 2025-11-12
4+
5+
### Added
6+
7+
- Support for AVIF and HEIF image formats
8+
9+
### Fixed
10+
11+
- Fixed the URL of variations displayed in the admin bridges when the image format has an alternative format defined (e.g., tiff or heic to jpeg)
12+
313
## [0.1.0] - 2025-11-03
414

515
This is the initial release of the bundle.
@@ -18,3 +28,4 @@ This is the initial release of the bundle.
1828
- debug toolbar and profiler panel to monitor media processing in your application
1929

2030
[0.1.0]: https://github.com/jolicode/mediabundle/releases/tag/v0.1.0
31+
[0.1.1]: https://github.com/jolicode/mediabundle/releases/tag/v0.1.1

doc/bridges/easy-admin.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
EasyAdmin Integration
22
=====================
33

4-
The ``JoliMediaBundle`` provides seamless integration with EasyAdmin, enabling you to manage media directly within your EasyAdmin interface. This integration includes features such as a media library, media browser, and media preview capabilities.
4+
The ``JoliMediaBundle`` provides seamless integration with `EasyAdmin <https://symfony.com/bundles/EasyAdminBundle/current/index.html>`_, enabling you to manage media directly within your EasyAdmin interface. This integration includes features such as a media library, media browser, and media preview capabilities.
55

66
.. image:: ../images/bridges/easyadmin/grid-view.png
77
:alt: The EasyAdmin media library grid view

doc/bridges/sonata-admin.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Sonata Admin Integration
22
========================
33

4-
The ``JoliMediaBundle`` provides seamless integration with Sonata Admin, enabling you to manage media directly within your Sonata Admin interface. This integration includes features such as a media library, media browser, and media preview capabilities.
4+
The ``JoliMediaBundle`` provides seamless integration with `Sonata Admin <https://symfony.com/bundles/SonataAdminBundle/current/index.html>`_, enabling you to manage media directly within your Sonata Admin interface. This integration includes features such as a media library, media browser, and media preview capabilities.
55

66
.. image:: ../images/bridges/sonata-admin/grid-view.png
77
:alt: The Sonata Admin media library grid view

doc/getting-started/dependencies-and-tooling.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@ A typical Debian-based system can install the required dependencies using the fo
2424
gifsicle \
2525
imagemagick \
2626
jpegoptim \
27+
libheif1 \
28+
libheif-plugins-all \
2729
libimage-exiftool-perl \
2830
libmagickcore-dev \
2931
pngquant
3032
33+
.. note::
34+
35+
The ``libheif1`` and ``libheif-plugins-all`` packages are required to handle AVIF and HEIF images with ImageMagick. Depending on your system, the versions provided by the package manager might be outdated and not (fully) support these formats. In this case, you will need to compile ImageMagick from source with HEIF support.
36+
3137
Some tools are not available in the default repositories, so you will need to install them manually. The following commands will install all such tools:
3238

3339
.. code-block:: bash

doc/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ The JoliMediaBundle provides a set of tools to manage media in Symfony applicati
55

66
It proposes multiple features:
77

8-
- `EasyAdmin <https://symfony.com/bundles/EasyAdminBundle/current/index.html>`_ and `SonataAdmin <https://symfony.com/bundles/SonataAdminBundle/current/index.html>`_ integrations
8+
- `EasyAdmin <bridges/easy-admin.rst>`_ and `SonataAdmin <bridges/sonata-admin.rst>`_ integrations
99
- abstract media storage
1010
- processors to transform media (crop / resize / etc.)
1111
- post processors to optimize the media size
@@ -22,7 +22,7 @@ It proposes multiple features:
2222
🤓 Goals and approach
2323
--------------------
2424

25-
The JoliMediaBundle aims to provide numerous facilities to manage media in Symfony applications, by using the best tools available, and following best practices. It is built on top of the [Flysystem](https://flysystem.thephpleague.com/) library to provide an abstraction layer for file storage, and multiple media processing libraries to handle media transformations and optimizations.
25+
The JoliMediaBundle aims to provide numerous facilities to manage media in Symfony applications, by using the best tools available, and following best practices. It is built on top of the `Flysystem <https://flysystem.thephpleague.com/>`_ library to provide an abstraction layer for file storage, and multiple media processing libraries to handle media transformations and optimizations.
2626

2727
The project seeks to provide:
2828

doc/variations/processors.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The main processors configuration is defined in the ``processors`` key of the ``
1111
- ``cwebp``: the processor to convert images to WebP format
1212
- ``gif2webp``: the processor to convert GIF images to WebP format
1313
- ``gifsicle``: the processor to convert GIF images into other GIF files
14-
- ``imagimagineick``: the processor to convert images using the Imagine library
14+
- ``imagine``: the processor to convert images using the Imagine library
1515

1616
.. tip::
1717

@@ -69,9 +69,9 @@ The ``imagine`` processor does not use a binary, it uses the Imagine library to
6969
cwebp processor options
7070
~~~~~~~~~~~~~~~~~~~~~~~
7171

72-
The ``gif2webp`` processor is used to convert JPEG, PNG, TIFF or WEBP images to WebP format. It supports two presets: ``near_lossless`` and ``lossy``.
72+
The ``cwebp`` processor is used to convert JPEG, PNG, TIFF or WEBP images to WebP format. It supports two presets: ``near_lossless`` and ``lossy``.
7373

74-
The ``near_lossless`` configuration preset is used for images that you want to convert to WebP with minimal quality loss. Under the hood, the bundle never uses the ``near_lossless`` preset for JPEG or TIFF images or for imahgs that contain more than 20000 colors.
74+
The ``near_lossless`` configuration preset is used for images that you want to convert to WebP with minimal quality loss. Under the hood, the bundle never uses the ``near_lossless`` preset for JPEG or TIFF images or for images that contain more than 20000 colors.
7575

7676
The ``lossy`` configuration preset is the default preset, it offers a good balance between quality and file size for most images.
7777

@@ -89,7 +89,7 @@ The various configuration keys are mapped to `the official cwebp options <https:
8989
gif2webp processor options
9090
~~~~~~~~~~~~~~~~~~~~~~~~~~
9191

92-
The ``gif2webp`` processor is used to convert GIF images to WebP format. Its configuration keys are mapped to `the official gif2webp options <https://developers.google.com/speed/webp/docs/gif2webp>`_:
92+
The ``gif2webp`` processor is used to convert (animated) GIF images to WebP format. Its configuration keys are mapped to `the official gif2webp options <https://developers.google.com/speed/webp/docs/gif2webp>`_:
9393

9494
- ``lossy``: ``-lossy``
9595
- ``metadata``: ``-metadata``
@@ -107,12 +107,16 @@ The ``gifsicle`` processor is used to convert GIF images into other GIF files. I
107107
imagine processor options
108108
~~~~~~~~~~~~~~~~~~~~~~~~~
109109

110-
The ``imagine`` processor is used to convert GIF, HEIF, JPEG, PNG, TIFF or WEBP images to the GIF, JPEG, PNG or TIFF format using `the Imagine library <https://github.com/php-imagine/Imagine>`_. It supports the following configuration keys:
110+
The ``imagine`` processor is used to convert AVIF, GIF, HEIF, JPEG, PNG, TIFF or WEBP images to the AVIF, GIF, JPEG, PNG or TIFF format using `the Imagine library <https://github.com/php-imagine/Imagine>`_. It supports the following configuration keys:
111111

112112
- ``jpeg_quality``: the quality of the JPEG images, from 0 to 100 (default: 80). It is mapped to Imagine's ``jpeg_quality`` option
113113
- ``png_quality``: the quality of the PNG images, from 0 to 100 (default: 80). It is mapped to Imagine's ``png_compression_level`` and ``png_compression_filter`` options
114114
- ``quality``: the quality of the images, from 0 to 100 (default: 80). It is mapped to Imagine's ``quality`` option
115115

116+
.. note::
117+
118+
The AVIF support is still a bit limited in Imagine. In particular, it does not work with animated AVIF images. As a consequence, converting an animated GIF to AVIF will only keep the first frame of the GIF image.
119+
116120
Customizing processor options for a library or a variation
117121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118122

src/Bridge/EasyAdmin/src/Controller/MediaAdminController.php

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use JoliCode\MediaBundle\Exception\MediaInUseException;
2020
use JoliCode\MediaBundle\Library\Library;
2121
use JoliCode\MediaBundle\Library\LibraryContainer;
22+
use JoliCode\MediaBundle\Model\MediaVariation;
2223
use JoliCode\MediaBundle\Resolver\Resolver;
2324
use JoliCode\MediaBundle\Storage\OriginalStorage;
2425
use League\Flysystem\PathTraversalDetected;
@@ -383,18 +384,28 @@ public function regenerateVariation(string $key, string $variation): RedirectRes
383384
));
384385

385386
$media = $this->resolver->resolveMedia($key);
386-
$variation = $this->getLibrary()->getVariation($variation);
387-
$mediaVariation = $variation->getForMedia($media);
388-
$this->converter->convertMediaVariation($mediaVariation);
387+
$mediaVariation = $this->resolver->resolveMediaVariation($media, $variation, $this->getLibrary()->getName());
389388

390-
$this->addFlash(
391-
'success',
392-
$this->translator->trans(
393-
'variation.regenerated_success',
394-
['%variation%' => $variation->getName(), '%media%' => $media->getPath()],
395-
'JoliMediaEasyAdminBundle'
396-
)
397-
);
389+
if (!$mediaVariation instanceof MediaVariation) {
390+
$this->addFlash(
391+
'danger',
392+
$this->translator->trans(
393+
'variation.regenerated_failure',
394+
['%variation%' => $variation, '%media%' => $media->getPath()],
395+
'JoliMediaEasyAdminBundle'
396+
)
397+
);
398+
} else {
399+
$this->converter->convertMediaVariation($mediaVariation);
400+
$this->addFlash(
401+
'success',
402+
$this->translator->trans(
403+
'variation.regenerated_success',
404+
['%variation%' => $variation, '%media%' => $media->getPath()],
405+
'JoliMediaEasyAdminBundle'
406+
)
407+
);
408+
}
398409

399410
return $this->redirect($this->adminUrlGenerator
400411
->setRoute('joli_media_easy_admin_show', [
@@ -544,7 +555,7 @@ public function show(AdminContext $adminContext, Request $request, string $key):
544555
}
545556

546557
if ($variation->canBeAppliedTo($media)) {
547-
$media->createVariation($variation);
558+
$this->resolver->resolveMediaVariation($media, $variation, $this->getLibrary()->getName());
548559
}
549560
}
550561
}

src/Bridge/EasyAdmin/translations/JoliMediaEasyAdminBundle.en.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ root: 'Root'
105105
variation:
106106
label: 'Variation'
107107
label_plural: 'Variations'
108+
regenerated_failure: 'Failed to regenerate the variation "%variation%" for the media "%media%"'
108109
regenerated_success: 'Variation "%variation%" regenerated successfully for the media "%media%"'
109110
stored: 'Stored?'
110111
view:

src/Bridge/EasyAdmin/translations/JoliMediaEasyAdminBundle.fr.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,10 @@ preview:
103103
unavailable: 'Aperçu non disponible.'
104104
root: 'Racine'
105105
variation:
106-
label: 'Variante'
107-
label_plural: 'Variantes'
108-
regenerated_success: 'La variante "%variation%" a été régénérée avec succès pour le média "%media%"'
106+
label: 'Variation'
107+
label_plural: 'Variations'
108+
regenerated_failure: 'Échec de la régénération de la variation "%variation%" pour le média "%media%"'
109+
regenerated_success: 'La variation "%variation%" a été régénérée avec succès pour le média "%media%"'
109110
stored: 'Stockée ?'
110111
view:
111112
grid: 'Vue grille'

src/Bridge/SonataAdmin/src/Controller/MediaAdminController.php

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use JoliCode\MediaBundle\Exception\MediaInUseException;
1717
use JoliCode\MediaBundle\Library\Library;
1818
use JoliCode\MediaBundle\Library\LibraryContainer;
19+
use JoliCode\MediaBundle\Model\MediaVariation;
1920
use JoliCode\MediaBundle\Resolver\Resolver;
2021
use JoliCode\MediaBundle\Storage\OriginalStorage;
2122
use League\Flysystem\PathTraversalDetected;
@@ -353,18 +354,28 @@ public function regenerateVariation(string $key, string $variation): RedirectRes
353354
));
354355

355356
$media = $this->resolver->resolveMedia($key);
356-
$variation = $this->getLibrary()->getVariation($variation);
357-
$mediaVariation = $variation->getForMedia($media);
358-
$this->converter->convertMediaVariation($mediaVariation);
357+
$mediaVariation = $this->resolver->resolveMediaVariation($media, $variation, $this->getLibrary()->getName());
359358

360-
$this->addFlash(
361-
'sonata_flash_success',
362-
$this->translator->trans(
363-
'variation.regenerated_success',
364-
['%variation%' => $variation->getName(), '%media%' => $media->getPath()],
365-
'JoliMediaSonataAdminBundle'
366-
)
367-
);
359+
if (!$mediaVariation instanceof MediaVariation) {
360+
$this->addFlash(
361+
'sonata_flash_error',
362+
$this->translator->trans(
363+
'variation.regenerated_failure',
364+
['%variation%' => $variation, '%media%' => $media->getPath()],
365+
'JoliMediaSonataAdminBundle'
366+
)
367+
);
368+
} else {
369+
$this->converter->convertMediaVariation($mediaVariation);
370+
$this->addFlash(
371+
'sonata_flash_success',
372+
$this->translator->trans(
373+
'variation.regenerated_success',
374+
['%variation%' => $variation, '%media%' => $media->getPath()],
375+
'JoliMediaSonataAdminBundle'
376+
)
377+
);
378+
}
368379

369380
return $this->redirectToRoute('joli_media_sonata_admin_show', [
370381
'key' => $key,
@@ -503,7 +514,7 @@ public function show(Request $request, string $key): Response
503514
}
504515

505516
if ($variation->canBeAppliedTo($media)) {
506-
$media->createVariation($variation);
517+
$this->resolver->resolveMediaVariation($media, $variation, $this->getLibrary()->getName());
507518
}
508519
}
509520
}

0 commit comments

Comments
 (0)