Opened 8 years ago
Last modified 3 weeks ago
#40415 assigned enhancement
Imagick resize filter hook
Reported by: |
|
Owned by: |
|
---|---|---|---|
Milestone: | Future Release | Priority: | normal |
Severity: | normal | Version: | 4.7.3 |
Component: | Media | Keywords: | has-patch has-test-info dev-feedback |
Focuses: | Cc: |
Description (last modified by )
As of ticket #33642, WordPress 4.5 introduces the thumbnail_image()
function within the WP_Image_Editor_Imagick
class.
This function uses the default imagick filter FILTER_TRIANGLE
to assists the image resizing process.
Within the thumbnail_image()
is even declared a list of allowed filters that actually are absolute unsued due to the fact that wordpress uses only the default filter FILTER_TRIANGLE
. The filter list is
'FILTER_POINT' 'FILTER_BOX' 'FILTER_TRIANGLE' 'FILTER_HERMITE' 'FILTER_HANNING' 'FILTER_HAMMING' 'FILTER_BLACKMAN' 'FILTER_GAUSSIAN' 'FILTER_QUADRATIC' 'FILTER_CUBIC' 'FILTER_CATROM' 'FILTER_MITCHELL' 'FILTER_LANCZOS' 'FILTER_BESSEL' 'FILTER_SINC'
Resizing image using the default filter often gives as a result a softly blurry thumbnail image. this blur effect became more visible as the thumbnail size increase.
Using filter like FILTER_HAMMING
or FILTER_SINC
the blur effect disappear, giving a great resizing result.
To better improve the use of the resizing process and to give any users the ability to choose which type of filter to use, I think that could be implemented the following filter hook:
$filter_name = apply_filters('image_resize_filter', $filter_name);
that will give an opportunity to change this filter before the resizing process will perform.
This filter should be implemented at the beginning (line 1) of the thumbnail_image()
function.
This way everyone can, optionally, change the imagick resize filter easily.
Attachments (7)
Change History (44)
#2
@
7 years ago
- Keywords has-patch added
I made a website to see differences between filters : https://test-im-filters.unikmedia.fr/
I think the filter HAMMING
is the better even if it is a little bigger (sometimes).
So i made a first patch to use it.
#3
@
7 years ago
- Description modified (diff)
- Keywords needs-testing added
- Milestone changed from Awaiting Review to 5.0
Hi!
I'd say we also need to add FILTER_HAMMING
to default filter fallback. See 40415.1.diff
:)
Cheers,
Jb
@
7 years ago
Use a windowed resizing filter (Lanczos). Improve sharpening for better quality images. Use progressive compression for smaller size images.
#5
@
7 years ago
We have added a few images test results in a github page for anyone to see.
The settings of method 6 (which are included in 40415.2.diff) produce a much sharper image with smaller size at the same time for jpg images uploaded to Media Library.
Resize: Lanczos Sharpening: unsharpMask( Radius 1, Sigma 0.45, Amount 3, Threshold 0 ) Compression: Interlace_Plane Quality: 60
https://greenpeace.github.io/planet4-imagestest-results/ Here you can see results for 2 different images in 3 different sizes.
- Method 1 is the currently used one.
- Method 6 seems to produce best quality and size (up to -47%) combination.
- Method 7 (the one used in 40415.1.diff) produces lower quality resized jpg images and at the same time larger in size. This is more evident in retina-large size images.
You can find also info in imagemagick's website https://www.imagemagick.org/Usage/filter/#lanczos
#6
@
7 years ago
Hi @losangelos – Thanks for sharing the planet4 image option. When we implemented the current solution in #33642 one of the constraints we needed to balance was the output quality against the resources consumed by each compression method in order to reduce/avoid resize failures on underpowered shared hosting.
I'd love to see some performance data based on the current recommended WordPress hosting requirements to see if we can improve the defaults.
This ticket was mentioned in Slack in #core-media by joemcgill. View the logs.
7 years ago
#8
@
7 years ago
Hi @joemcgill @audrasjb and thanks for the quick responds!
We 'll be happy to look into performance/resources cost and provide you with data soon!
#9
@
7 years ago
Not sure if we should change now the default imagick filter. This would not be backward compatible, and it will affect image quality creating differences between images. I think that the first thing to do is to provide a filter hook. Changing the default filter need more data and testing about image quality (for big and small thumbnails) as well as resource usage.
This ticket was mentioned in Slack in #core-media by joemcgill. View the logs.
7 years ago
#11
@
7 years ago
- Milestone changed from 5.0 to 5.1
Moving to the 5.1 milestone due to the WordPress 5.0 focus on the new
editor (Gutenberg).
This ticket was mentioned in Slack in #core-media by mike. View the logs.
7 years ago
#14
@
6 years ago
Hello all, since this has gotten postponed to future releases, is there a way to load a modified version of class-wp-image-editor-imagick.php without modding the original file in place. The difference in quality is quite ridiculuous so I really want to use my parameters as I mostly work with artists for their portfolios. The method above does not work to extend the class. I'd like to change the filter and sharpening both. Also on topic, can someone detail what is going on with the section that resizes the image to 5x the destination before resampling? Is it using a more efficient algorithm to make it to an intermediate size before resampling with more expensive algorithms?
#15
in reply to:
↑ 1
;
follow-up:
↓ 16
@
6 years ago
Replying to dpacmittal:
+1 for this. Triangle is a really bad default filter. WP should provide a filter hook, or better default.
In the meanwhile I'm using this workaround:
in your functions.php:
[... truncated ...]
Unfortunately, this workaround does not work (tested in 5.2.2).
Is it possible to get more attention to this? We have dozens of clients who are reporting that their resized images are blurry - this is not ideal, especially since our sites are hosted on platforms that can handle the expensive algorithms to result in sharp images.
I have submitted a diff to this issue (class-wp-image-editor-imagick.php.patch) which adds just the apply_filters call before processing the image resize function. This should allow for backwards compatibility as it does not change the existing filters or any of the other Imagick options.
#16
in reply to:
↑ 15
;
follow-up:
↓ 17
@
6 years ago
Replying to robertark:
I have submitted a diff to this issue (class-wp-image-editor-imagick.php.patch) which adds just the apply_filters call before processing the image resize function. This should allow for backwards compatibility as it does not change the existing filters or any of the other Imagick options.
If you are going to add a filter for the resize function, we should add one for the sharpening that happens below as well since it does better with different sharpening parameters once you use a better resizing algorithm.
#17
in reply to:
↑ 16
@
6 years ago
Replying to pinktank:
Replying to robertark:
I have submitted a diff to this issue (class-wp-image-editor-imagick.php.patch) which adds just the apply_filters call before processing the image resize function. This should allow for backwards compatibility as it does not change the existing filters or any of the other Imagick options.
If you are going to add a filter for the resize function, we should add one for the sharpening that happens below as well since it does better with different sharpening parameters once you use a better resizing algorithm.
Thank you for your reply - I agree. I am unsure of which or what parameters work best with, say Lanczos, but in my testing what was already defined in the unsharpMaskImage()
appeared to be fine. How would you go about providing options for the sharpening?
PS: It's my understanding that there is no universal setting for sharpening, including any based on a specific algorithm. Digging into this scientific answer here is mind boggling to say the least, but it may be helpful to others: http://www.imagemagick.org/Usage/filter/nicolas/
This resource may also be helpful: http://www.imagemagick.org/discourse-server/viewtopic.php?f=22&t=25935
#18
follow-up:
↓ 19
@
6 years ago
I don't know what the best implementation would be but we could add variables like so, amount should be dropped a bit with lanczos 8>4 maybe , and threshold is better around 0.04
unsharpMaskImage( radius, sigma, amount, threshold );
#19
in reply to:
↑ 18
@
6 years ago
Replying to pinktank:
I don't know what the best implementation would be but we could add variables like so, amount should be dropped a bit with lanczos 8>4 maybe , and threshold is better around 0.04
unsharpMaskImage( radius, sigma, amount, threshold );
I totally agree. Is it possible to have a filter that can control all 4 parameters? Or would it require 4 separate filters? Or does it make sense to control the image object in a filter and apply any Imagick functions there?
#20
@
5 years ago
As a recent WordPress user, I was also very surprised to see that the generated images are so blurry. I searched for some plugins, but as I started to understand the code, I realized that these had to make an unsharpMask over WP's own unsharpMask, in addition to having to work on a resized image with the much worse TRIANGLE filter.
So, besides the imagick_resize_filter patch some people mentioned here (thanks for sharing it), I also added a new filter named imagick_unsharp_settings in class-wp-image-editor-imagick.php (near the unsharpMaskImage function):
<?php $unsharp_settings = []; $unsharp_settings[9999] = ['radius' => 0.25, 'sigma' => 0.25, 'amount' => 8, 'threshold' => 0.065]; $unsharp_settings = apply_filters( 'imagick_unsharp_settings', $unsharp_settings ); // Set appropriate quality settings after resizing. if ( 'image/jpeg' === $this->mime_type ) { if ( is_callable( array( $this->image, 'unsharpMaskImage' ) ) ) { foreach( $unsharp_settings as $width => $unsharp_set ) { if ( $dst_w < $width ) break; } $this->image->unsharpMaskImage( $unsharp_set['radius'], $unsharp_set['sigma'], $unsharp_set['amount'], $unsharp_set['threshold'] ); } $this->image->setOption( 'jpeg:fancy-upsampling', 'off' ); }
This allows to set several unsharp settings in functions.php:
<?php add_filter ('imagick_unsharp_settings', function() { $sets = []; $sets[200] = ['radius' => 0, 'sigma' => 0.5, 'amount' => 1, 'threshold' => 0]; $sets[500] = ['radius' => 0, 'sigma' => 0.75, 'amount' => 0.75, 'threshold' => 0.008]; $sets[9999] = ['radius' => 1.5, 'sigma' => 1, 'amount' => 0.7, 'threshold' => 0.02]; return $sets; } );
Meaning that for images below the width indicated in the key of the array (200, 500 and 9999) the corresponding unsharp settings will be applied. It seems that different settings might be a good approach for images of different sizes (http://www.imagemagick.org/Usage/resize/#resize_unsharp)
#21
@
5 years ago
I really wish that we had this addressable by theme or plugin already, I still have to edit core files.
This ticket was mentioned in Slack in #core-media by nosilver4u. View the logs.
4 years ago
#23
@
4 years ago
I totally agree to the need for filters, on top of better default settings. Giving developers filters means that WordPress can use a reasonable default, and developers can tweak based on the original images, and the site's visual needs.
Another thing that should help is the use of adaptiveResizeImage()
, instead of resizeImage()
, because it sharpens the subject/foreground of the image, while not sharpening the background (as much).
I've tested adaptiveResizeImage()
with various sigma values, and 1 got me a nice enough result. However, it would be good to test ranges of image sizes and ranges of scaling ratios (original size / thumbnail size) to find out more.
Possible option: add image sharpening values to the definition of image sizes for better developer control without filters.
Possible option: add image sharpening values to the customizer for better reach by non-developer site builders.
This ticket was mentioned in Slack in #core-media by nosilver4u. View the logs.
3 years ago
#25
@
3 years ago
- Milestone changed from Future Release to 6.0
Would like to take a look at this one for 6.0. I think changing the values may not be in scope of adding a filter. With that change reverted, this seems much safer to get into a release and save changing the default values for its own ticket.
This ticket was mentioned in Slack in #core-media by antpb. View the logs.
3 years ago
#27
@
3 years ago
How about adding a filter for which functions to use? The filter can evaluate to 1
or true
for using adaptiveResizeImage()
(0
or false
being the default), or it can be evaluated to the string adaptiveResizeImage
(with resizeImage
being the default).
Alternatively, the function resizeImage()
can be wrapped inside something like wp_resize_image()
, which will be used for resizing images, so that it can be superseded, likes this:
<?php if ( ! function_exists( 'wp_resize_image' ) ) { function wp_resize_image( $this, ARGUMENTS ) { $this->image->resizeImage( ARGUMENTS ); } }
ARGUMENTS should be elaborated, of course.
This way, developers can override this function with a call to adaptiveResizeImage()
if that's what they prefer.
#28
@
3 years ago
The issue of sharpening seems to be best handled separately, so rather than complicating this ticket (sorry about that), I've started a new one (#55036). Please cast your votes and share your comments there.
This ticket was mentioned in Slack in #core by chaion07. View the logs.
3 years ago
#30
@
3 years ago
Updated the patch's spacing and comments in 40415.3.diff.
While looking at this, I noticed that it looks like there's a way to choose the resizing method with GD, so it might be worthwhile to add support for this sort of thing there too.
Maybe worth a second ticket?
Or considering as part of explorations in #55036?
#31
@
3 years ago
- Milestone changed from 6.0 to Future Release
As patch 40415.3.diff still needs testing and Beta 1 is today, I'm moving this off the 6.0 milestone to Future Release.
If anyone has time to test this and get it committed, feel free to add it back into the milestone.
#32
@
13 months ago
+1 for this filter fix.
Being able to use a different Imagick filter such as the FILTER_SINC filter would greatly benefit the end result of fullscreen image sizes used in portfolio sites for Photographers, Interior or Landscape architects, etc.
This ticket was mentioned in PR #8836 on WordPress/wordpress-develop by @SirLouen.
4 weeks ago
#33
I've been playing around a ton lately with the Image_Editor_Imagick
class in #63448, and I was a little confused on why thumbnail_image
method was using this filter_name
defined parameter if It's never actually used anywhere else and basically perma-defaulting to FILTER TRIANGLE
, plus all those "allowed_filters" array as if any of them could be actually used (or ever actually used). I understood that could be simply a future proofing strategy, which it's always adequate.
Moreover, the target of $filter_name
is to set $filter
and there is a forced conditional in the case that $filter_name
doesn't even exist, to again, default to FILTER_TRIANGLE
, so feels redundant and unnecessary (again, only one call and forced assignation, which happens to be the problem discussed here).
Doesn't make more sense, to simply remove default to thumbnail_image
, pass it to the real function, resize
that semantically actually needs it (which happens to be public), in the end you are passing the arguments that are actually needed for the resize (i.e. size and resizing method), and given that its public, anyone could simply instantiate and the Image_Editor_Imagick
and define whatever they want?
And if you want to add a redundant hook just for those users that simply would like to stick to the standard flow without instantiations, why not? All in!
For example, as a use-case, WPML in src/wp-content/plugins/sitepress-multilingual-cms/classes/ajax/endpoints/Upload.php
L40 instantiates a Image_Editor_Imagick
calling to resize. In this case, if they wanted some extra "quality" they could have simply added the extra paremeter, without having to deal with a cumbersome hook.
Trac ticket: https://core.trac.wordpress.org/ticket/40415
#34
@
4 weeks ago
- Keywords has-test-info dev-feedback added; needs-testing reporter-feedback removed
Test Report
Description
✅ This report validates that the indicated patch works as expected.
Patch tested: https://github.com/WordPress/wordpress-develop/pull/8836.diff
Environment
- WordPress: 6.9-alpha-60093-src
- PHP: 8.2.28
- Server: nginx/1.27.5
- Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
- Browser: Chrome 137.0.0.0
- OS: Windows 10/11
- Theme: Twenty Twenty-Five 1.2
- MU Plugins: None activated
- Plugins:
- Imagick Resize Filter Demo 1.0.0
- Test Reports 1.2.0
Testing instructions
- I'm providing the following plugin that showcases the functionality of the report.
- Add an image to the library (try to use a big sized image to better see more details). Take note of the image ID
- Go to Imagick Resize
- Use the image ID of the picture you uploaded
- Check the results.
- The Plugin Testing Use Case tests both the use of the newly public function and the filter, to showcase results.
Actual Results
- ✅ Issue resolved with patch.
Additional Notes
- The tested patch is based on the last provided patch (adding public to
thumbnail_image
method). After several visual tests with my plugin provided, I've found that the proposal by @losangelos is the most solid among all, and this is the one that I have integrated, the best performance in terms of crispness, sometimes size and not a coincidence that @adamsilverstein introduced theINTERLACE_PLANE
idea in the last patch of Imagick processing [57607], which was part of this patch.
- Based on the idea provided previously, the problem here is that the
resize
function, is not only a "resizer function", but it's actually the function thatresize_and_crop
. In fact, the function per se is not even resizing nor cropping but calling one or the other accordingly. The actual resizer function isthumbnail_image
, which happens to be, as the description says, the reimplementation of Imagick'sthumbnailImage
; hence it's fair to have it public as it's a much more specific need of resizing. Yes, we can actually resize withresize
also, but for all the reasons given, we have two options
- Passing onwards this filter as a parameter, from
resize
tothumbnail_image
and to preserve the optionality of the parameter (mainly for backward compatibility) in both methods. - Setting
thumbnail_image
as public.
- Whatever of these two options are chosen, aligns with the concept of filter selection (specially given that there are no practical cases of using such filter) without having to do the trick of setting and unsetting the filter on
resize
function call, which seriously dirty. For this purpose, I created the attached plugin that showcases thisuse-case
- I agree with some previous comments, the whole system as-is currently, is convoluted. It requires a refactor, the problem is that it will seriously affect things from a backwards compatibility perspective. For now, this patch solves the current situation without committing into such required refactor, and given it was proposed several versions away, I believe it's mostly ready to get into 6.9
- Conclusion: With the current state of the patch, we have the option to: A) Set a global filter, to perma-use a filter that adapts to our preferences (i.e. Media Gallery processing). B) We have more extensibility without compromising backwards compatibility, geared towards plugins, without having to set and unset the filter every time
resize
method is called, thanks to the public method upgrade tothumbnail_image
, providing more usefulness to the entire image filtering logic.
Supplemental Artifacts
Link to the plugin: https://github.com/SirLouen/imagick-resize-filter-demo/
This ticket was mentioned in Slack in #core-test by sirlouen. View the logs.
3 weeks ago
#37
@
3 weeks ago
Test Report
Description
This report validates whether the indicated patch works as expected.
Patch tested: https://patch-diff.githubusercontent.com/raw/WordPress/wordpress-develop/pull/8836.diff
Environment
- WordPress: 6.8.1
- PHP: 8.2.23
- Server: nginx/1.26.1
- Database: mysqli (Server: 8.0.35 / Client: mysqlnd 8.2.23)
- Browser: Chrome 137.0.0.0
- OS: Windows 10/11
- Theme: Twenty Twenty-Five 1.2
- MU Plugins: None activated
- Plugins:
- Imagick Resize Filter Demo 1.0.0
- Test Reports 1.2.0
Actual Results
- ✅ The patch applies cleanly.
- ✅ thumbnail_image() is now public and accessible externally.
- ✅ imagick_resize_filter hook is available and functions correctly.
- ✅ Plugin successfully overrides the default Imagick filter using the new hook.
- ✅ Custom filter results in crisper, more optimized thumbnails without manually toggling filters globally.
- ✅ No issues with media uploads, image cropping, or other editor functionality.
Additional Notes
Patch test with the plugin: https://raw.githubusercontent.com/SirLouen/imagick-resize-filter-demo/refs/tags/1.0.0/imagick-resize-filter-demo.php
The patch introduces two key improvements:
- Makes the thumbnail_image() method public, allowing plugin developers to directly invoke the core Imagick-based resize routine.
- Adds a new filter hook imagick_resize_filter, enabling developers to dynamically customize the Imagick filter used for resizing operations.
+1 for this. Triangle is a really bad default filter. WP should provide a filter hook, or better default.
In the meanwhile I'm using this workaround:
in your functions.php:
class-imagick-modded.php: