mirror of
https://github.com/lovell/sharp.git
synced 2025-12-19 15:25:07 +01:00
Add support for GIF output using cgif in prebuilt binaries
This commit is contained in:
@@ -13,7 +13,7 @@ const debuglog = util.debuglog('sharp');
|
||||
/**
|
||||
* Constructor factory to create an instance of `sharp`, to which further methods are chained.
|
||||
*
|
||||
* JPEG, PNG, WebP, AVIF or TIFF format image data can be streamed out from this object.
|
||||
* JPEG, PNG, WebP, GIF, AVIF or TIFF format image data can be streamed out from this object.
|
||||
* When using Stream based output, derived attributes are available from the `info` event.
|
||||
*
|
||||
* Non-critical problems encountered during processing are emitted as `warning` events.
|
||||
@@ -246,6 +246,9 @@ const Sharp = function (input, options) {
|
||||
webpNearLossless: false,
|
||||
webpSmartSubsample: false,
|
||||
webpReductionEffort: 4,
|
||||
gifBitdepth: 8,
|
||||
gifEffort: 7,
|
||||
gifDither: 1,
|
||||
tiffQuality: 80,
|
||||
tiffCompression: 'jpeg',
|
||||
tiffPredictor: 'horizontal',
|
||||
|
||||
@@ -22,14 +22,15 @@ const formats = new Map([
|
||||
['j2c', 'jp2']
|
||||
]);
|
||||
|
||||
const errMagickSave = new Error('GIF output requires libvips with support for ImageMagick');
|
||||
const errJp2Save = new Error('JP2 output requires libvips with support for OpenJPEG');
|
||||
|
||||
const bitdepthFromColourCount = (colours) => 1 << 31 - Math.clz32(Math.ceil(Math.log2(colours)));
|
||||
|
||||
/**
|
||||
* Write output image data to a file.
|
||||
*
|
||||
* If an explicit output format is not selected, it will be inferred from the extension,
|
||||
* with JPEG, PNG, WebP, AVIF, TIFF, DZI, and libvips' V format supported.
|
||||
* with JPEG, PNG, WebP, AVIF, TIFF, GIF, DZI, and libvips' V format supported.
|
||||
* Note that raw pixel data is only supported for buffer output.
|
||||
*
|
||||
* By default all metadata will be removed, which includes EXIF-based orientation.
|
||||
@@ -63,8 +64,6 @@ function toFile (fileOut, callback) {
|
||||
err = new Error('Missing output file path');
|
||||
} else if (is.string(this.options.input.file) && path.resolve(this.options.input.file) === path.resolve(fileOut)) {
|
||||
err = new Error('Cannot use same file for input and output');
|
||||
} else if (this.options.formatOut === 'input' && fileOut.toLowerCase().endsWith('.gif') && !this.constructor.format.magick.output.file) {
|
||||
err = errMagickSave;
|
||||
}
|
||||
if (err) {
|
||||
if (is.fn(callback)) {
|
||||
@@ -81,9 +80,9 @@ function toFile (fileOut, callback) {
|
||||
|
||||
/**
|
||||
* Write output to a Buffer.
|
||||
* JPEG, PNG, WebP, AVIF, TIFF and raw pixel data output are supported.
|
||||
* JPEG, PNG, WebP, AVIF, TIFF, GIF and raw pixel data output are supported.
|
||||
*
|
||||
* If no explicit format is set, the output format will match the input image, except GIF and SVG input which become PNG output.
|
||||
* If no explicit format is set, the output format will match the input image, except SVG input which becomes PNG output.
|
||||
*
|
||||
* By default all metadata will be removed, which includes EXIF-based orientation.
|
||||
* See {@link withMetadata} for control over this.
|
||||
@@ -412,7 +411,7 @@ function png (options) {
|
||||
const colours = options.colours || options.colors;
|
||||
if (is.defined(colours)) {
|
||||
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
||||
this.options.pngBitdepth = 1 << 31 - Math.clz32(Math.ceil(Math.log2(colours)));
|
||||
this.options.pngBitdepth = bitdepthFromColourCount(colours);
|
||||
} else {
|
||||
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
||||
}
|
||||
@@ -495,13 +494,40 @@ function webp (options) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use these GIF options for output image.
|
||||
* Use these GIF options for the output image.
|
||||
*
|
||||
* Requires libvips compiled with support for ImageMagick or GraphicsMagick.
|
||||
* The prebuilt binaries do not include this - see
|
||||
* {@link https://sharp.pixelplumbing.com/install#custom-libvips installing a custom libvips}.
|
||||
* The first entry in the palette is reserved for transparency.
|
||||
*
|
||||
* @example
|
||||
* // Convert PNG to GIF
|
||||
* await sharp(pngBuffer)
|
||||
* .gif()
|
||||
* .toBuffer());
|
||||
*
|
||||
* @example
|
||||
* // Convert animated WebP to animated GIF
|
||||
* await sharp('animated.webp', { animated: true })
|
||||
* .toFile('animated.gif');
|
||||
*
|
||||
* @example
|
||||
* // Create 128x128, non-dithered thumbnail of an animated GIF
|
||||
* const { pages } = await sharp('animated.gif').metadata();
|
||||
* const gif = await sharp('animated.gif', { animated: true })
|
||||
* .resize({
|
||||
* width: 128,
|
||||
* height: 128 * pages
|
||||
* })
|
||||
* .gif({
|
||||
* pageHeight: 128,
|
||||
* dither: 0
|
||||
* })
|
||||
* .toBuffer();
|
||||
*
|
||||
* @param {Object} [options] - output options
|
||||
* @param {number} [options.colours=256] - maximum number of palette entries, including transparency, between 2 and 256
|
||||
* @param {number} [options.colors=256] - alternative spelling of `options.colours`
|
||||
* @param {number} [options.effort=7] - CPU effort, between 1 (fastest) and 10 (slowest)
|
||||
* @param {number} [options.dither=1.0] - level of Floyd-Steinberg error diffusion, between 0 (least) and 1 (most)
|
||||
* @param {number} [options.pageHeight] - page height for animated output
|
||||
* @param {number} [options.loop=0] - number of animation iterations, use 0 for infinite animation
|
||||
* @param {number[]} [options.delay] - list of delays between animation frames (in milliseconds)
|
||||
@@ -509,10 +535,30 @@ function webp (options) {
|
||||
* @returns {Sharp}
|
||||
* @throws {Error} Invalid options
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
function gif (options) {
|
||||
if (!this.constructor.format.magick.output.buffer) {
|
||||
throw errMagickSave;
|
||||
if (is.object(options)) {
|
||||
const colours = options.colours || options.colors;
|
||||
if (is.defined(colours)) {
|
||||
if (is.integer(colours) && is.inRange(colours, 2, 256)) {
|
||||
this.options.gifBitdepth = bitdepthFromColourCount(colours);
|
||||
} else {
|
||||
throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
|
||||
}
|
||||
}
|
||||
if (is.defined(options.effort)) {
|
||||
if (is.number(options.effort) && is.inRange(options.effort, 1, 10)) {
|
||||
this.options.gifEffort = options.effort;
|
||||
} else {
|
||||
throw is.invalidParameterError('effort', 'integer between 1 and 10', options.effort);
|
||||
}
|
||||
}
|
||||
if (is.defined(options.dither)) {
|
||||
if (is.number(options.dither) && is.inRange(options.dither, 0, 1)) {
|
||||
this.options.gifDither = options.dither;
|
||||
} else {
|
||||
throw is.invalidParameterError('dither', 'number between 0.0 and 1.0', options.dither);
|
||||
}
|
||||
}
|
||||
}
|
||||
trySetAnimationOptions(options, this.options);
|
||||
return this._updateFormatOut('gif', options);
|
||||
|
||||
Reference in New Issue
Block a user