With this commit https://github.com/lovell/sharp/commit/3f5e38bb62e63d473a1a2f33d47d3a6b7263aead in v0.17 these helper functions were removed in favor of using options object with the intended output. For toBuffer, the earlier behavior was to choose the input file format as the output format as well automatically. How does one specify such parameters like quality, adaptiveFiltering, subsampling etc. with toBuffer() since that still accepts just a callback function?
Hello, the quality, adaptiveFiltering, subsampling etc. options have moved to their respective output format, e.g.:
sharp(input)
.jpeg({ quality: ... , chromaSubsampling: ... })
.toBuffer( ... )
To set options whilst maintaining input format, set the force attribute for these to false, e.g.:
sharp(input)
.jpeg({ quality: ... , chromaSubsampling: ... , force: false })
.png({ adaptiveFiltering: ... , force: false })
.toBuffer( ... )
http://sharp.dimens.io/en/stable/api-output/#jpeg
http://sharp.dimens.io/en/stable/api-output/#png
I understand this change. But force: false is a hack to set these parameters if we do not intend to fix the output format. Wanted to understand the intention behind deprecating the direct utility functions()?
I do not consider adding a force option to be a "hack". It allows backwards compatibility with the existing format-specifying functions (such as jpeg()) whilst grouping options relating to a given format with that format.
Consider a case where I am supposed to look at 1000's of images, resize them to 100x100 at quality 75 and continue with the other tasks. Because there is no restriction if the original image is jpeg, WebP or png, I do not really need any of the options that are associated with the output format. Instead I just want the image to be resized.
Code prior to v0.17
pipeline.resize(100,100).quality(75).toBuffer(function(){})
Code post v0.17
pipeline.resize(100,100).jpeg({quality : 75, force : false}).toBuffer(function(){})
If this code is read by a developer out of context, it kind of implies that the output format is jpeg. What does the force: false imply? Does it imply that the quality is not forced upon? One would have to come back to the docs to understand what it actually does. The first one, prior to 0.17, in my opinion, is cleaner to read and understand.
Also, consider the case where an option like chromaSubsampling has to be set. Post v0.17, this is available only as an option in jpeg() (which it actually is no doubt), But it then makes it mandatory for me to use jpeg() when the image is in JPEG format or png() when the image is in PNG format. How does one determine the original image format in this case? Does one fetch metadata for each image to identify the actual input format? Prior to v0.17, chroma subsampling, if not applicable to an image format, would have been handled internally. Now it has to be handled before handing it off to sharp.
"If this code is read by a developer out of context, it kind of implies that the output format is jpeg."
If there is code designed to support multiple input formats then I'd expect the processing pipeline to include options for multiple output formats.
In the case where both JPEG and PNG images are to be supported as both input and output, code previously written using v0.16.x as:
sharp(jpegOrPngInput)
.resize(100, 100)
.quality(75)
.compressionLevel(9)
.toBuffer()
.then( (jpegOrPngOutput) => { ... } );
in v0.17.x becomes:
sharp(jpegOrPngInput)
.resize(100, 100)
.jpeg({ quality: 75, force: false })
.png({ compressionLevel: 9, force: false })
.toBuffer()
.then( (jpegOrPngOutput) => { ... } );
which makes it clearer which option applies to which format.
Things that could improve:
The name of the "force" attribute could perhaps be made more explicit. Thoughts very much welcome here.
As soon as more than one format is specified then "force" could be assumed to be false, so the above example would reduce to:
sharp(jpegOrPngInput)
.resize(100, 100)
.jpeg({ quality: 75 })
.png({ compressionLevel: 9 })
.toBuffer()
.then( (jpegOrPngOutput) => { ... } );
"Prior to v0.17, chroma subsampling, if not applicable to an image format, would have been handled internally. Now it has to be handled before handing it off to sharp."
There should be no need to do this; the following are equivalent.
v0.16.x:
sharp(jpegOrPngInput)
.resize(100, 100)
.withoutChromaSubsampling()
.toBuffer()
.then( (jpegOrPngOutput) => { ... } );
v0.17.x:
sharp(jpegOrPngInput)
.resize(100, 100)
.jpeg({ chromaSubsampling: '4:4:4', force: false })
.toBuffer()
.then( (jpegOrPngOutput) => { ... } );
@rnanwani Any thoughts on possible improvements to the force parameter?
Stumbled over this discussion. What if we had a well-named function that was equivalent to jpeg(… force: false) (and similar for other formats)? That might turn out clearer than both the old and the new syntax:
pipeline.resize(100,100).whenJpeg({quality : 75}).toBuffer(function(){})
So this would do the same as either of these:
pipeline.resize(100,100).quality(75).toBuffer(function(){})
pipeline.resize(100,100).jpeg({quality : 75, force : false}).toBuffer(function(){})
Alternative function names could be ifJpeg or jpegOptions.
@henrik I like your suggestion - please can you create a new feature request for this via https://github.com/lovell/sharp/issues/new?labels=enhancement&template=feature_request.md
Thanks :) Sure thing – done!
Most helpful comment
Hello, the quality, adaptiveFiltering, subsampling etc. options have moved to their respective output format, e.g.:
To set options whilst maintaining input format, set the
forceattribute for these to false, e.g.:http://sharp.dimens.io/en/stable/api-output/#jpeg
http://sharp.dimens.io/en/stable/api-output/#png