impro
Advanced tools
Comparing version 0.9.0 to 0.10.0
{ | ||
"name": "impro", | ||
"version": "0.9.0", | ||
"version": "0.10.0", | ||
"description": "Image processing engine", | ||
@@ -41,5 +41,4 @@ "author": "Andreas Lind <andreaslindpetersen@gmail.com>", | ||
"inkscape": "3.0.0", | ||
"jpegtran": "1.0.6", | ||
"jsdom": "^15.1.1", | ||
"memoizesync": "0.5.0", | ||
"jpegtran": "2.0.0", | ||
"memoizesync": "^1.1.1", | ||
"mocha": "^8.2.1", | ||
@@ -52,21 +51,17 @@ "nyc": "^14.1.1", | ||
"prettier": "~2.2.1", | ||
"sharp": "~0.27.0", | ||
"sinon": "1.17.7", | ||
"svgfilter": "3.0.0", | ||
"unexpected": "10.40.2", | ||
"unexpected-dom": "4.13.1", | ||
"unexpected-image": "3.1.0", | ||
"unexpected-resemble": "4.2.0", | ||
"unexpected-sinon": "10.6.0", | ||
"unexpected-stream": "4.0.0" | ||
"sharp": "~0.28.0", | ||
"sinon": "^9.2.4", | ||
"svgfilter": "4.1.0", | ||
"unexpected": "^12.0.1", | ||
"unexpected-dom": "^5.0.0", | ||
"unexpected-image": "^4.0.0", | ||
"unexpected-resemble": "^5.0.0", | ||
"unexpected-sinon": "^11.0.1" | ||
}, | ||
"dependencies": { | ||
"combine-stream": "0.0.4", | ||
"createerror": "1.1.0", | ||
"exif-reader": "^1.0.3", | ||
"icc": "^1.0.0", | ||
"lodash": "^4.17.15", | ||
"mime": "^1.6.0", | ||
"require-or": "0.0.2" | ||
"mime": "^2.5.2" | ||
} | ||
} |
@@ -15,12 +15,16 @@ # Impro | ||
- Sharp | ||
- Gifsicle | ||
- JpegTran | ||
- Inkscape | ||
- OptiPNG | ||
- Pngquant | ||
- Pngcrush | ||
- SvgFilter | ||
- GraphicsMagick (install "gm" module) | ||
``` | ||
- Gifsicle (npm install gifsicle-stream@^1.0.0) | ||
- GraphicsMagick (npm install gm-papandreou@^1.23.0-patch1) | ||
- Inkscape (npm install inkscape@^3.0.0) | ||
- JpegTran (npm install jpegtran@^2.0.0) | ||
- OptiPNG (npm install optipng@^2.1.0) | ||
- Pngcrush (npm install pngcrush@^2.0.1) | ||
- Pngquant (npm install pngquant@^3.0.0) | ||
- Sharp (npm install sharp@~0.28.0) | ||
- SvgFilter (npm install svgfilter@^4.1.0) | ||
``` | ||
> callers must install the libraries and if present they will be enabled | ||
## Introduction | ||
@@ -27,0 +31,0 @@ |
@@ -1,5 +0,6 @@ | ||
const requireOr = require('require-or'); | ||
const Gifsicle = requireOr('gifsicle-stream'); | ||
const errors = require('../errors'); | ||
const requireOr = require('../requireOr'); | ||
const Gifsicle = requireOr('gifsicle-stream'); | ||
function isNumberWithin(num, min, max) { | ||
@@ -6,0 +7,0 @@ return typeof num === 'number' && num >= min && num <= max; |
@@ -1,6 +0,8 @@ | ||
const requireOr = require('require-or'); | ||
const Stream = require('stream'); | ||
const gm = requireOr('gm-papandreou'); | ||
const errors = require('../errors'); | ||
const requireOr = require('../requireOr'); | ||
const gm = requireOr('gm-papandreou'); | ||
function createGmOperations(pipeline, operations) { | ||
@@ -7,0 +9,0 @@ const gmOperations = []; |
@@ -1,5 +0,10 @@ | ||
const fs = require('fs'); | ||
fs.readdirSync(__dirname).forEach((fileName) => { | ||
module.exports[fileName.replace(/\.js$/, '')] = require('./' + fileName); | ||
}); | ||
exports.gifsicle = require('./gifsicle'); | ||
exports.gm = require('./gm'); | ||
exports.inkscape = require('./inkscape'); | ||
exports.jpegtran = require('./jpegtran'); | ||
exports.metadata = require('./metadata'); | ||
exports.optipng = require('./optipng'); | ||
exports.pngcrush = require('./pngcrush'); | ||
exports.pngquant = require('./pngquant'); | ||
exports.sharp = require('./sharp'); | ||
exports.svgfilter = require('./svgfilter'); |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const Inkscape = requireOr('inkscape'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const JpegTran = requireOr('jpegtran'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,10 +0,20 @@ | ||
const requireOr = require('require-or'); | ||
const sharp = requireOr('sharp'); | ||
const Stream = require('stream'); | ||
const createAnimatedGifDetector = requireOr('animated-gif-detector'); | ||
const mime = require('mime'); | ||
const exifReader = require('exif-reader'); | ||
const icc = require('icc'); | ||
const _ = require('lodash'); | ||
const mime = require('../mime'); | ||
const requireOr = require('../requireOr'); | ||
const createAnimatedGifDetector = requireOr('animated-gif-detector'); | ||
const sharp = requireOr('sharp'); | ||
function defaultProperties(obj, source) { | ||
for (const key in source) { | ||
if (typeof obj[key] === 'undefined') { | ||
obj[key] = source[key]; | ||
} | ||
} | ||
return obj; | ||
} | ||
module.exports = { | ||
@@ -72,6 +82,6 @@ name: 'metadata', | ||
contentType: | ||
pipeline.targetContentType || mime.types[pipeline.targetType], | ||
pipeline.targetContentType || mime.getType(pipeline.targetType), | ||
}; | ||
if (pipeline._streams.length === 0) { | ||
_.extend(alreadyKnownMetadata, pipeline.sourceMetadata); | ||
Object.assign(alreadyKnownMetadata, pipeline.sourceMetadata); | ||
} | ||
@@ -81,3 +91,3 @@ duplexStream._read = (size) => { | ||
if (err) { | ||
metadata = _.defaults({ error: err.message }, alreadyKnownMetadata); | ||
metadata = { error: err.message }; | ||
} | ||
@@ -91,3 +101,3 @@ if (metadata.format === 'magick') { | ||
} | ||
_.defaults(metadata, alreadyKnownMetadata); | ||
defaultProperties(metadata, alreadyKnownMetadata); | ||
if (metadata.exif) { | ||
@@ -117,3 +127,3 @@ let exifData; | ||
} | ||
_.defaults(metadata, exifData); | ||
defaultProperties(metadata, exifData); | ||
} | ||
@@ -120,0 +130,0 @@ } |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const OptiPng = requireOr('optipng'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const PngCrush = requireOr('pngcrush'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const PngQuant = requireOr('pngquant'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,5 +0,6 @@ | ||
const requireOr = require('require-or'); | ||
const sharp = requireOr('sharp'); | ||
const errors = require('../errors'); | ||
const requireOr = require('../requireOr'); | ||
const sharp = requireOr('sharp'); | ||
function isNumberWithin(num, min, max) { | ||
@@ -6,0 +7,0 @@ return typeof num === 'number' && num >= min && num <= max; |
@@ -1,2 +0,3 @@ | ||
const requireOr = require('require-or'); | ||
const requireOr = require('../requireOr'); | ||
const SvgFilter = requireOr('svgfilter'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,8 +0,11 @@ | ||
const _ = require('lodash'); | ||
const mime = require('mime'); | ||
const Pipeline = require('./Pipeline'); | ||
mime.define({ | ||
'image/vnd.microsoft.icon': ['ico'], | ||
}); | ||
function pickProperties(obj, properties) { | ||
if (!obj) return {}; | ||
const ret = {}; | ||
for (const property of properties) { | ||
ret[property] = obj[property]; | ||
} | ||
return ret; | ||
} | ||
@@ -25,3 +28,2 @@ module.exports = class Impro { | ||
this.supportedOptions = [ | ||
'defaultEngineName', | ||
'allowOperation', | ||
@@ -36,8 +38,2 @@ 'maxInputPixels', | ||
_.extend( | ||
this, | ||
{ defaultEngineName: Impro.defaultEngineName }, | ||
_.pick(options, this.supportedOptions) | ||
); | ||
this._Pipeline = class extends Pipeline {}; | ||
@@ -61,3 +57,3 @@ | ||
...options, | ||
engines: _.pick(options, Object.keys(this.engineByName)), // Allow disabling via createPipeline({<engineName>: false}) | ||
engines: pickProperties(options, Object.keys(this.engineByName)), // Allow disabling via createPipeline({<engineName>: false}) | ||
supportedOptions: this.supportedOptions, | ||
@@ -116,3 +112,2 @@ }); | ||
} | ||
this.defaultEngineName = this.defaultEngineName || engineName; | ||
@@ -119,0 +114,0 @@ this.engineByName[options.name] = options; |
const Stream = require('stream'); | ||
const mime = require('mime'); | ||
const Path = require('path'); | ||
const mime = require('./mime'); | ||
module.exports = class Pipeline extends Stream.Duplex { | ||
@@ -9,2 +10,3 @@ constructor(impro, options) { | ||
this._flushed = false; | ||
this._onError = (err) => this._fail(err); | ||
@@ -18,2 +20,3 @@ this._queuedOperations = []; | ||
this.options = {}; | ||
this.usedEngines = []; | ||
@@ -62,3 +65,3 @@ options = options || {}; | ||
this._flushed = true; | ||
this.usedEngines = this.usedEngines || []; | ||
let startIndex = 0; | ||
@@ -116,3 +119,3 @@ let lastSelectedEngineName; | ||
if (isStream) { | ||
this._fail(e, this.usedEngines.length + 1); | ||
this._fail(e, true); | ||
} else { | ||
@@ -169,3 +172,3 @@ throw e; | ||
this.targetType = operation.name; | ||
this.targetContentType = mime.types[operation.name]; | ||
this.targetContentType = mime.getType(operation.name); | ||
} | ||
@@ -185,3 +188,3 @@ | ||
this.targetType = operation.name; | ||
this.targetContentType = mime.types[operation.name]; | ||
this.targetContentType = mime.getType(operation.name); | ||
} | ||
@@ -207,11 +210,23 @@ | ||
this._queuedOperations = undefined; | ||
this._streams.push(new Stream.PassThrough()); | ||
// Account for stream implementation differences by making | ||
// sure the stream which interfaces with the Pipeline (i.e. | ||
// the Duplex steam ultimate handed out to callers) is also | ||
// a 'standard' internal stream. | ||
const lastStream = new Stream.PassThrough(); | ||
lastStream | ||
.on('readable', () => this.push(lastStream.read())) | ||
.on('end', () => this.push(null)) | ||
.on('error', (err) => this._fail(err, true)); | ||
this._streams.push(lastStream); | ||
// Wire the streams to each other | ||
this._streams.forEach(function (stream, i) { | ||
if (i < this._streams.length - 1) { | ||
stream.pipe(this._streams[i + 1]); | ||
} else { | ||
stream | ||
.on('readable', () => this.push(stream.read())) | ||
.on('end', () => this.push(null)); | ||
if (stream === lastStream) { | ||
// ignore given it is wired to the pipeline separately | ||
return; | ||
} | ||
stream.pipe(this._streams[i + 1]); | ||
// protect against filters emitting errors more than once | ||
@@ -221,3 +236,2 @@ stream.once('error', (err) => { | ||
if ( | ||
i < this._streams.length - 1 && | ||
(commandArgs = err.commandArgs || this.usedEngines[i].commandArgs) | ||
@@ -228,3 +242,3 @@ ) { | ||
} | ||
this._fail(err, i); | ||
this._fail(err, true); | ||
}); | ||
@@ -277,3 +291,3 @@ }, this); | ||
_fail(err, streamIndex = -1) { | ||
_fail(err, isErrorFromStream = false) { | ||
if (this.ended) { | ||
@@ -311,3 +325,3 @@ return; | ||
if (streamIndex > -1) { | ||
if (isErrorFromStream) { | ||
// unhook pipeline error handler to avoid re-entry | ||
@@ -354,3 +368,2 @@ this.removeListener('error', this._onError); | ||
this._attach(stream); | ||
this.usedEngines = this.usedEngines || []; | ||
this.usedEngines.push({ name: '_stream' }); | ||
@@ -366,5 +379,5 @@ return this; | ||
this.sourceType = this.targetType = type; | ||
this.targetContentType = mime.types[type]; | ||
this.targetContentType = mime.getType(type); | ||
} else { | ||
const extension = mime.extensions[type.replace(/\s*;.*$/, '')]; | ||
const extension = mime.getExtension(type); | ||
if (extension) { | ||
@@ -371,0 +384,0 @@ if (this.impro.isTypeByName[extension]) { |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
4
31
22
1805
141
1
68421
+ Addedmime@2.6.0(transitive)
- Removedcombine-stream@0.0.4
- Removedlodash@^4.17.15
- Removedrequire-or@0.0.2
- Removedcombine-stream@0.0.4(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removedinherits@2.0.4(transitive)
- Removedisarray@0.0.1(transitive)
- Removedlodash@4.17.21(transitive)
- Removedmime@1.6.0(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedrequire-or@0.0.2(transitive)
- Removedstring_decoder@0.10.31(transitive)
Updatedmime@^2.5.2