123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809 |
- 'use strict';
- const is = require('./is');
- const sharp = require('../build/Release/sharp.node');
- const formats = new Map([
- ['heic', 'heif'],
- ['heif', 'heif'],
- ['jpeg', 'jpeg'],
- ['jpg', 'jpeg'],
- ['png', 'png'],
- ['raw', 'raw'],
- ['tiff', 'tiff'],
- ['webp', 'webp']
- ]);
- function toFile (fileOut, callback) {
- if (!fileOut || fileOut.length === 0) {
- const errOutputInvalid = new Error('Missing output file path');
- if (is.fn(callback)) {
- callback(errOutputInvalid);
- } else {
- return Promise.reject(errOutputInvalid);
- }
- } else {
- if (this.options.input.file === fileOut) {
- const errOutputIsInput = new Error('Cannot use same file for input and output');
- if (is.fn(callback)) {
- callback(errOutputIsInput);
- } else {
- return Promise.reject(errOutputIsInput);
- }
- } else {
- this.options.fileOut = fileOut;
- return this._pipeline(callback);
- }
- }
- return this;
- }
- function toBuffer (options, callback) {
- if (is.object(options)) {
- this._setBooleanOption('resolveWithObject', options.resolveWithObject);
- } else if (this.options.resolveWithObject) {
- this.options.resolveWithObject = false;
- }
- return this._pipeline(is.fn(options) ? options : callback);
- }
- function withMetadata (options) {
- this.options.withMetadata = is.bool(options) ? options : true;
- if (is.object(options)) {
- if (is.defined(options.orientation)) {
- if (is.integer(options.orientation) && is.inRange(options.orientation, 1, 8)) {
- this.options.withMetadataOrientation = options.orientation;
- } else {
- throw is.invalidParameterError('orientation', 'integer between 1 and 8', options.orientation);
- }
- }
- }
- return this;
- }
- function toFormat (format, options) {
- const actualFormat = formats.get(is.object(format) && is.string(format.id) ? format.id : format);
- if (!actualFormat) {
- throw is.invalidParameterError('format', `one of: ${[...formats.keys()].join(', ')}`, format);
- }
- return this[actualFormat](options);
- }
- function jpeg (options) {
- if (is.object(options)) {
- if (is.defined(options.quality)) {
- if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
- this.options.jpegQuality = options.quality;
- } else {
- throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
- }
- }
- if (is.defined(options.progressive)) {
- this._setBooleanOption('jpegProgressive', options.progressive);
- }
- if (is.defined(options.chromaSubsampling)) {
- if (is.string(options.chromaSubsampling) && is.inArray(options.chromaSubsampling, ['4:2:0', '4:4:4'])) {
- this.options.jpegChromaSubsampling = options.chromaSubsampling;
- } else {
- throw is.invalidParameterError('chromaSubsampling', 'one of: 4:2:0, 4:4:4', options.chromaSubsampling);
- }
- }
- const trellisQuantisation = is.bool(options.trellisQuantization) ? options.trellisQuantization : options.trellisQuantisation;
- if (is.defined(trellisQuantisation)) {
- this._setBooleanOption('jpegTrellisQuantisation', trellisQuantisation);
- }
- if (is.defined(options.overshootDeringing)) {
- this._setBooleanOption('jpegOvershootDeringing', options.overshootDeringing);
- }
- const optimiseScans = is.bool(options.optimizeScans) ? options.optimizeScans : options.optimiseScans;
- if (is.defined(optimiseScans)) {
- this._setBooleanOption('jpegOptimiseScans', optimiseScans);
- if (optimiseScans) {
- this.options.jpegProgressive = true;
- }
- }
- const optimiseCoding = is.bool(options.optimizeCoding) ? options.optimizeCoding : options.optimiseCoding;
- if (is.defined(optimiseCoding)) {
- this._setBooleanOption('jpegOptimiseCoding', optimiseCoding);
- }
- const quantisationTable = is.number(options.quantizationTable) ? options.quantizationTable : options.quantisationTable;
- if (is.defined(quantisationTable)) {
- if (is.integer(quantisationTable) && is.inRange(quantisationTable, 0, 8)) {
- this.options.jpegQuantisationTable = quantisationTable;
- } else {
- throw is.invalidParameterError('quantisationTable', 'integer between 0 and 8', quantisationTable);
- }
- }
- }
- return this._updateFormatOut('jpeg', options);
- }
- function png (options) {
- if (is.object(options)) {
- if (is.defined(options.progressive)) {
- this._setBooleanOption('pngProgressive', options.progressive);
- }
- if (is.defined(options.compressionLevel)) {
- if (is.integer(options.compressionLevel) && is.inRange(options.compressionLevel, 0, 9)) {
- this.options.pngCompressionLevel = options.compressionLevel;
- } else {
- throw is.invalidParameterError('compressionLevel', 'integer between 0 and 9', options.compressionLevel);
- }
- }
- if (is.defined(options.adaptiveFiltering)) {
- this._setBooleanOption('pngAdaptiveFiltering', options.adaptiveFiltering);
- }
- if (is.defined(options.palette)) {
- this._setBooleanOption('pngPalette', options.palette);
- if (this.options.pngPalette) {
- if (is.defined(options.quality)) {
- if (is.integer(options.quality) && is.inRange(options.quality, 0, 100)) {
- this.options.pngQuality = options.quality;
- } else {
- throw is.invalidParameterError('quality', 'integer between 0 and 100', options.quality);
- }
- }
- const colours = options.colours || options.colors;
- if (is.defined(colours)) {
- if (is.integer(colours) && is.inRange(colours, 2, 256)) {
- this.options.pngColours = colours;
- } else {
- throw is.invalidParameterError('colours', 'integer between 2 and 256', colours);
- }
- }
- if (is.defined(options.dither)) {
- if (is.number(options.dither) && is.inRange(options.dither, 0, 1)) {
- this.options.pngDither = options.dither;
- } else {
- throw is.invalidParameterError('dither', 'number between 0.0 and 1.0', options.dither);
- }
- }
- }
- }
- }
- return this._updateFormatOut('png', options);
- }
- function webp (options) {
- if (is.object(options) && is.defined(options.quality)) {
- if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
- this.options.webpQuality = options.quality;
- } else {
- throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
- }
- }
- if (is.object(options) && is.defined(options.alphaQuality)) {
- if (is.integer(options.alphaQuality) && is.inRange(options.alphaQuality, 0, 100)) {
- this.options.webpAlphaQuality = options.alphaQuality;
- } else {
- throw is.invalidParameterError('alphaQuality', 'integer between 0 and 100', options.alphaQuality);
- }
- }
- if (is.object(options) && is.defined(options.lossless)) {
- this._setBooleanOption('webpLossless', options.lossless);
- }
- if (is.object(options) && is.defined(options.nearLossless)) {
- this._setBooleanOption('webpNearLossless', options.nearLossless);
- }
- if (is.object(options) && is.defined(options.smartSubsample)) {
- this._setBooleanOption('webpSmartSubsample', options.smartSubsample);
- }
- if (is.object(options) && is.defined(options.reductionEffort)) {
- if (is.integer(options.reductionEffort) && is.inRange(options.reductionEffort, 0, 6)) {
- this.options.webpReductionEffort = options.reductionEffort;
- } else {
- throw is.invalidParameterError('reductionEffort', 'integer between 0 and 6', options.reductionEffort);
- }
- }
- return this._updateFormatOut('webp', options);
- }
- function tiff (options) {
- if (is.object(options)) {
- if (is.defined(options.quality)) {
- if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
- this.options.tiffQuality = options.quality;
- } else {
- throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
- }
- }
- if (is.defined(options.squash)) {
- this._setBooleanOption('tiffSquash', options.squash);
- }
-
- if (is.defined(options.tile)) {
- this._setBooleanOption('tiffTile', options.tile);
- }
- if (is.defined(options.tileWidth)) {
- if (is.integer(options.tileWidth) && options.tileWidth > 0) {
- this.options.tiffTileWidth = options.tileWidth;
- } else {
- throw is.invalidParameterError('tileWidth', 'integer greater than zero', options.tileWidth);
- }
- }
- if (is.defined(options.tileHeight)) {
- if (is.integer(options.tileHeight) && options.tileHeight > 0) {
- this.options.tiffTileHeight = options.tileHeight;
- } else {
- throw is.invalidParameterError('tileHeight', 'integer greater than zero', options.tileHeight);
- }
- }
-
- if (is.defined(options.pyramid)) {
- this._setBooleanOption('tiffPyramid', options.pyramid);
- }
-
- if (is.defined(options.xres)) {
- if (is.number(options.xres) && options.xres > 0) {
- this.options.tiffXres = options.xres;
- } else {
- throw is.invalidParameterError('xres', 'number greater than zero', options.xres);
- }
- }
- if (is.defined(options.yres)) {
- if (is.number(options.yres) && options.yres > 0) {
- this.options.tiffYres = options.yres;
- } else {
- throw is.invalidParameterError('yres', 'number greater than zero', options.yres);
- }
- }
-
- if (is.defined(options.compression)) {
- if (is.string(options.compression) && is.inArray(options.compression, ['lzw', 'deflate', 'jpeg', 'ccittfax4', 'none'])) {
- this.options.tiffCompression = options.compression;
- } else {
- throw is.invalidParameterError('compression', 'one of: lzw, deflate, jpeg, ccittfax4, none', options.compression);
- }
- }
-
- if (is.defined(options.predictor)) {
- if (is.string(options.predictor) && is.inArray(options.predictor, ['none', 'horizontal', 'float'])) {
- this.options.tiffPredictor = options.predictor;
- } else {
- throw is.invalidParameterError('predictor', 'one of: none, horizontal, float', options.predictor);
- }
- }
- }
- return this._updateFormatOut('tiff', options);
- }
- function heif (options) {
- if (!this.constructor.format.heif.output.buffer) {
- throw new Error('The heif operation requires libvips to have been installed with support for libheif');
- }
- if (is.object(options)) {
- if (is.defined(options.quality)) {
- if (is.integer(options.quality) && is.inRange(options.quality, 1, 100)) {
- this.options.heifQuality = options.quality;
- } else {
- throw is.invalidParameterError('quality', 'integer between 1 and 100', options.quality);
- }
- }
- if (is.defined(options.lossless)) {
- if (is.bool(options.lossless)) {
- this.options.heifLossless = options.lossless;
- } else {
- throw is.invalidParameterError('lossless', 'boolean', options.lossless);
- }
- }
- if (is.defined(options.compression)) {
- if (is.string(options.compression) && is.inArray(options.compression, ['hevc', 'avc', 'jpeg', 'av1'])) {
- this.options.heifCompression = options.compression;
- } else {
- throw is.invalidParameterError('compression', 'one of: hevc, avc, jpeg, av1', options.compression);
- }
- }
- }
- return this._updateFormatOut('heif', options);
- }
- function raw () {
- return this._updateFormatOut('raw');
- }
- function tile (options) {
- if (is.object(options)) {
-
- if (is.defined(options.size)) {
- if (is.integer(options.size) && is.inRange(options.size, 1, 8192)) {
- this.options.tileSize = options.size;
- } else {
- throw is.invalidParameterError('size', 'integer between 1 and 8192', options.size);
- }
- }
-
- if (is.defined(options.overlap)) {
- if (is.integer(options.overlap) && is.inRange(options.overlap, 0, 8192)) {
- if (options.overlap > this.options.tileSize) {
- throw is.invalidParameterError('overlap', `<= size (${this.options.tileSize})`, options.overlap);
- }
- this.options.tileOverlap = options.overlap;
- } else {
- throw is.invalidParameterError('overlap', 'integer between 0 and 8192', options.overlap);
- }
- }
-
- if (is.defined(options.container)) {
- if (is.string(options.container) && is.inArray(options.container, ['fs', 'zip'])) {
- this.options.tileContainer = options.container;
- } else {
- throw is.invalidParameterError('container', 'one of: fs, zip', options.container);
- }
- }
-
- if (is.defined(options.layout)) {
- if (is.string(options.layout) && is.inArray(options.layout, ['dz', 'google', 'iiif', 'zoomify'])) {
- this.options.tileLayout = options.layout;
- } else {
- throw is.invalidParameterError('layout', 'one of: dz, google, iiif, zoomify', options.layout);
- }
- }
-
- if (is.defined(options.angle)) {
- if (is.integer(options.angle) && !(options.angle % 90)) {
- this.options.tileAngle = options.angle;
- } else {
- throw is.invalidParameterError('angle', 'positive/negative multiple of 90', options.angle);
- }
- }
-
- this._setBackgroundColourOption('tileBackground', options.background);
-
- if (is.defined(options.depth)) {
- if (is.string(options.depth) && is.inArray(options.depth, ['onepixel', 'onetile', 'one'])) {
- this.options.tileDepth = options.depth;
- } else {
- throw is.invalidParameterError('depth', 'one of: onepixel, onetile, one', options.depth);
- }
- }
-
- if (is.defined(options.skipBlanks)) {
- if (is.integer(options.skipBlanks) && is.inRange(options.skipBlanks, -1, 65535)) {
- this.options.tileSkipBlanks = options.skipBlanks;
- } else {
- throw is.invalidParameterError('skipBlanks', 'integer between -1 and 255/65535', options.skipBlanks);
- }
- } else if (is.defined(options.layout) && options.layout === 'google') {
- this.options.tileSkipBlanks = 5;
- }
- }
-
- if (is.inArray(this.options.formatOut, ['jpeg', 'png', 'webp'])) {
- this.options.tileFormat = this.options.formatOut;
- } else if (this.options.formatOut !== 'input') {
- throw is.invalidParameterError('format', 'one of: jpeg, png, webp', this.options.formatOut);
- }
- return this._updateFormatOut('dz');
- }
- function _updateFormatOut (formatOut, options) {
- if (!(is.object(options) && options.force === false)) {
- this.options.formatOut = formatOut;
- }
- return this;
- }
- function _setBooleanOption (key, val) {
- if (is.bool(val)) {
- this.options[key] = val;
- } else {
- throw is.invalidParameterError(key, 'boolean', val);
- }
- }
- function _read () {
-
- if (!this.options.streamOut) {
- this.options.streamOut = true;
- this._pipeline();
- }
- }
- function _pipeline (callback) {
- if (typeof callback === 'function') {
-
- if (this._isStreamInput()) {
-
- this.on('finish', () => {
- this._flattenBufferIn();
- sharp.pipeline(this.options, callback);
- });
- } else {
-
- sharp.pipeline(this.options, callback);
- }
- return this;
- } else if (this.options.streamOut) {
-
- if (this._isStreamInput()) {
-
- this.once('finish', () => {
- this._flattenBufferIn();
- sharp.pipeline(this.options, (err, data, info) => {
- if (err) {
- this.emit('error', err);
- } else {
- this.emit('info', info);
- this.push(data);
- }
- this.push(null);
- });
- });
- if (this.streamInFinished) {
- this.emit('finish');
- }
- } else {
-
- sharp.pipeline(this.options, (err, data, info) => {
- if (err) {
- this.emit('error', err);
- } else {
- this.emit('info', info);
- this.push(data);
- }
- this.push(null);
- });
- }
- return this;
- } else {
-
- if (this._isStreamInput()) {
-
- return new Promise((resolve, reject) => {
- this.once('finish', () => {
- this._flattenBufferIn();
- sharp.pipeline(this.options, (err, data, info) => {
- if (err) {
- reject(err);
- } else {
- if (this.options.resolveWithObject) {
- resolve({ data, info });
- } else {
- resolve(data);
- }
- }
- });
- });
- });
- } else {
-
- return new Promise((resolve, reject) => {
- sharp.pipeline(this.options, (err, data, info) => {
- if (err) {
- reject(err);
- } else {
- if (this.options.resolveWithObject) {
- resolve({ data: data, info: info });
- } else {
- resolve(data);
- }
- }
- });
- });
- }
- }
- }
- module.exports = function (Sharp) {
- Object.assign(Sharp.prototype, {
-
- toFile,
- toBuffer,
- withMetadata,
- toFormat,
- jpeg,
- png,
- webp,
- tiff,
- heif,
- raw,
- tile,
-
- _updateFormatOut,
- _setBooleanOption,
- _read,
- _pipeline
- });
- };
|