Closed saltpeanuts closed 7 years ago
forgive me if I'm misunderstanding you.. but you want to prevent upscaling of images correct?
if that's the case you can use a fit of 'max' see http://glide.thephpleague.com/1.0/api/size/#fit-fit
as an example from the config. Here our source image is 700px wide. in the "large" section use a fit of 'max' and that 700 px image will be used.
srcset:
widthDensity: 'w'
sizes: [ '100vw' ]
modifications:
small:
w: 175
fit': stretch
medium:
w: 350
fit: stretch
large:
w: 700
fit: 'max'
xlarge:
w: 1400
fit: stretch
As for a true "pass through" no there isn't a way to do that currently.
I just looked through Glide's PNG processing and their docs and quality is only relevant for jpeg images so it looks like it's maybe adding transparency to PNG images (even if there is none) so even with a config like:
srcset:
widthDensity: 'w'
sizes: [ '100vw' ]
modifications:
small:
w: 200
fit: 'crop'
fm: 'jpg'
medium:
w: 350
fit: 'crop'
fm: 'jpg'
large:
w: 800
fit: 'max'
With a PNG image that is 800px wide (and ~745KB) it will be 800px wide and ~830KB for the "large" image.
Let me know if that's what you were looking for.
As for the PNG file size "issues" if I find some time maybe I'll see if i can put together a custom manipulator (or a size comparison check? but that might add a bit of overhead getting the image from the cache since file names aren't actual names) that merges JPG quality with PNG quality similar to how Bolt's thumbnail handler does it https://github.com/bolt/bolt-thumbs/blob/9e55c0a5389e17811d9f5954c297437c6a5e8cb9/src/ImageResource.php#L509-L523
Yes, I was thinking more of a pass-through. fit: max
seems to work the same as Bolt's allow_upscale: false
which is great. But in some instances it would be useful to leave the original file completely untouched.
If the original file has been exported from a graphics package already at the largest pixel-size it's ever going to be used on the site, and the image has already been optimised at the best quality, lowest filesize and sharpened just right for it's content, it would be best if that file is left untouched. Instead I'd prefer to just generate smaller versions from it.
I think this would be true regardless of format, but using .png causes extra complications because it seems that GD inflates the file-size significantly. That's a separate but related issue.
Here's a .png test case to clarify:
I have an original 640px wide png image. That's the maximum size it will be used. It was resized and sharpened in photoshop, then optimised in pngquant. It's the best balance of image quality and file size I can get. it's 52k
Now for my srcset I'd like a version at 320, 480 and say 580
If I set things up like this and stick to the .png format:
small:
w: 320
fit: max
fm: png
medium:
w: 480
fit: max
fm: png
large:
w: 580
fit: max
fm: png
orig:
w: 640
fit: max
fm: png
File sizes come out like this:
small: 81k medium: 186k large: 273k orig: 242k
So the original 640px version now has a dramatically larger file size and even the smallest 320px size is significantly larger than the original.
I've read around a little bit and it looks like others have experienced this problem with GD and .png, there's a few suggestions like this: http://stackoverflow.com/questions/13257405/why-is-resized-png-image-so-much-bigger-than-original-image
Next approach was to accept the problem and look for a workaround: to use the original .png and save the srcset images as .jpg, This works out ok for the smaller versions, each saw a decent saving in file size while still looking ok, but the original would need a much higher file size to look decent as a .jpg than as a .png. Being able to use the untouched .png at the 640 size would provide a useful workaround
So to recap, I guess having a fix for the .png problem would be ideal. But the pass-through would be a workaround, and also really useful in cases where the user wants to make sure their original large image is used totally untouched, whatever the file format.
I could toy with a passthrough since every image passed through this extension is at least opened and saved to glides cache (which leads to the PNG file bloat).
It'll take some time because you'd have to either compare the original source image to the sizes passed in by the modifications, which might add some overhead for a config block with lots of sizes or set a flag in the relevant modifications block like use_original: true
and instead of being served from img/file.jpg?modifications
it would be served from disk @ /files/file.jpg
That final one right now seems best / more perfomant since I have no control over glide not opening and re-saving an image passed to it. I'd just have to remove that from the array of images and then merge it after the modifications are done.
When I get some other things knocked out on my to-do list I'll look into it and see if it doesn't cause other issues :)
The second solution with use_original: true
serving the original from /files sounds perfect.
The only other approach I thought of was maybe a config option to output just the paths to the resized images, instead of wrapping them in the full srcset tags. Then a developer could use those to build the srcset themselves however they wanted, if they had more esoteric requirements.
use_original
definitely sounds like a tidier solution, though.
Thanks for the work so far, it's a really useful extension.
@saltpeanuts ok.. I've added an option to allow an original image to be passed through. Its still in dev mode but if you grab the master release you can play with it.
To use it with a width descriptor. Place the width of your image after use_original.
srcset:
widthDensity: 'w'
sizes: [ '100vw' ]
use_original: 800
modifications:
small:
w: 175
fit': stretch
medium:
w: 350
fit: stretch
xlarge:
w: 1400
fit: stretch
will give you
<img sizes="100vw"
srcset="/img/original-file.jpg?w=175&s=32566d6ed62dc4d87a44c099033650d5 175w ,
/img/original-file.jpg?w=350&s=dd1374de85dd1e5c6eafb394309cc950 350w ,
/files/original-file.jpg 800w ,
/img/original-file.jpg?w=1400&s=5f48fd674c5ad3214f63b1150c16c611 1400w "
src="/img/original-file.jpg?w=200&s=32566d6ed62dc4d87a44c099033650d5"
alt="">;
To use it with density descriptor place the density after use_original
. If you have the density in your resolutions settings already just remove it and place it after use_original
srcset:
widthDensity: 'x'
resolutions: [ 1 2 ]
use_original: 2.5
modifications:
small:
w: 175
fit': stretch
medium:
w: 350
fit: stretch
<img sizes="100vw"
srcset="/img/original-file.jpg?w=175&s=32566d6ed62dc4d87a44c099033650d5 1x ,
/img/original-file.jpg?w=350&s=dd1374de85dd1e5c6eafb394309cc950 2x ,
/files/original-file.jpg 2.5x"
src="/img/original-file.jpg?w=200&s=32566d6ed62dc4d87a44c099033650d5"
alt="">;
If you use it let me know if you run into any bugs/edge cases/ooooo cory you done messed up situations haha.
Thanks!
Working fine for me, I haven't managed to break it so far.
Thanks Cory.
Is there currently any way to choose to use the original image at a specific width? Or an option to prevent an image being processed if it already matches the w value?
For example, it would be useful when the original is a .png and a user only needs to generate smaller sizes as .jpg files
My experience with using GD to process .png files is that they invariably come back much larger than the original.
Just tested with a 51k .png file which came back at 220k