caravaggio
Advanced tools
Comparing version 2.6.0 to 2.7.0
@@ -5,8 +5,23 @@ { | ||
"rules": { | ||
"no-unused-vars": ["error", {"argsIgnorePattern": "^_" }], | ||
"no-unused-vars": [ | ||
"error", | ||
{ | ||
"argsIgnorePattern": "^_" | ||
} | ||
], | ||
"no-nested-ternary": 0, | ||
"no-multiple-empty-lines": ["error", | ||
{ "max": 2, "maxEOF": 1 } | ||
"no-multiple-empty-lines": [ | ||
"error", | ||
{ | ||
"max": 2, | ||
"maxEOF": 1 | ||
} | ||
], | ||
"no-plusplus": [ | ||
"error", | ||
{ | ||
"allowForLoopAfterthoughts": true | ||
} | ||
] | ||
} | ||
} |
# Changelog | ||
## 2.7.0 | ||
- ✨ New `duotone` effect. Shift your images to two color tones | ||
- Pipeline faster and more powerful | ||
## 2.6.0 | ||
@@ -4,0 +8,0 @@ - ⚖️ Use new licesezero.com prosperity license |
{ | ||
"name": "caravaggio", | ||
"version": "2.6.0", | ||
"version": "2.7.0", | ||
"description": "A blazing fast image processor service", | ||
@@ -55,3 +55,3 @@ "main": "index.js", | ||
"jest": "^24.1.0", | ||
"jest-image-snapshot": "^2.7.0", | ||
"jest-image-snapshot": "^2.9.0", | ||
"micro-dev": "^3.0.0", | ||
@@ -58,0 +58,0 @@ "request-promise": "^4.2.2", |
@@ -14,3 +14,3 @@ const cohercer = require('../cohercer'); | ||
name: 'blur', | ||
operation: 'blur', | ||
fn: async sharp => sharp.blur(v), | ||
params: [v], | ||
@@ -17,0 +17,0 @@ }, |
@@ -25,16 +25,14 @@ const cohercer = require('../cohercer'); | ||
name: 'extract', | ||
operation: async (pipeline) => { | ||
const { width: iw, height: ih } = await pipeline.getMetadata(); | ||
return [ | ||
{ | ||
name: 'extract', | ||
operation: 'extract', | ||
params: [{ | ||
left: isPercentage(left) ? percentageToPixel(left, iw) : left, | ||
top: isPercentage(top) ? percentageToPixel(top, ih) : top, | ||
width: isPercentage(width) ? percentageToPixel(width, iw) : width, | ||
height: isPercentage(height) ? percentageToPixel(height, ih) : height, | ||
}], | ||
}, | ||
]; | ||
params: [{ | ||
left, top, width, height, | ||
}], | ||
fn: async (sharp) => { | ||
const { width: iw, height: ih } = await sharp.metadata(); | ||
const extractOptions = { | ||
left: isPercentage(left) ? percentageToPixel(left, iw) : left, | ||
top: isPercentage(top) ? percentageToPixel(top, ih) : top, | ||
width: isPercentage(width) ? percentageToPixel(width, iw) : width, | ||
height: isPercentage(height) ? percentageToPixel(height, ih) : height, | ||
}; | ||
return sharp.extract(extractOptions); | ||
}, | ||
@@ -41,0 +39,0 @@ }, |
@@ -10,2 +10,4 @@ const cohercer = require('../cohercer'); | ||
const method = !operation || operation === 'x' ? 'flop' : 'flip'; | ||
return { | ||
@@ -15,3 +17,3 @@ transformations: [ | ||
name: 'flip', | ||
operation: !operation || operation === 'x' ? 'flop' : 'flip', | ||
fn: async sharp => sharp[method](), | ||
params: [true], | ||
@@ -18,0 +20,0 @@ }, |
const blurNormalizer = require('./blur'); | ||
const duotoneNormalizer = require('./duotone'); | ||
const extractNormalizer = require('./extract'); | ||
@@ -16,2 +17,3 @@ const flipNormalizer = require('./flip'); | ||
blur: blurNormalizer, | ||
duotone: duotoneNormalizer, | ||
ex: extractNormalizer, | ||
@@ -18,0 +20,0 @@ extract: extractNormalizer, |
@@ -10,34 +10,27 @@ const cohercer = require('../cohercer'); | ||
let fn; | ||
switch (format) { | ||
case 'jpg': | ||
case 'jpeg': | ||
return { | ||
o: format, | ||
output: [ | ||
{ | ||
name: 'o', | ||
operation: 'jpeg', | ||
params: [], | ||
}, | ||
], | ||
}; | ||
fn = async sharp => sharp.jpeg(); | ||
break; | ||
case 'png': | ||
case 'webp': | ||
case 'tiff': | ||
return { | ||
o: format, | ||
output: [ | ||
{ | ||
name: 'o', | ||
operation: format, | ||
params: [], | ||
}, | ||
], | ||
}; | ||
fn = async sharp => sharp[format](); | ||
break; | ||
default: | ||
return { | ||
o: 'original', | ||
}; | ||
return {}; | ||
} | ||
return { | ||
o: format, | ||
output: [{ | ||
name: 'o', | ||
fn, | ||
params: [format], | ||
}], | ||
}; | ||
}; | ||
@@ -37,3 +37,4 @@ const cohercer = require('../cohercer'); | ||
name: 'overlay', | ||
operation: async (pipeline) => { | ||
params: [overlayUrl, ...params], | ||
fn: async (sharp) => { | ||
let overlay; | ||
@@ -45,3 +46,3 @@ try { | ||
} | ||
const { width: iw, height: ih } = await pipeline.getMetadata(); | ||
const { width: iw, height: ih } = await sharp.metadata(); | ||
@@ -64,7 +65,3 @@ const options = { | ||
} | ||
return [{ | ||
name: 'overlay', | ||
operation: 'overlayWith', | ||
params: [overlay, options], | ||
}]; | ||
return sharp.overlayWith(overlay, options); | ||
}, | ||
@@ -71,0 +68,0 @@ }, |
const cohercer = require('../cohercer'); | ||
const { getOutputType } = require('./utils'); | ||
const getOutputType = async pipeline => (pipeline.getOptions().o !== 'original' | ||
? pipeline.getOptions().o | ||
: (await pipeline.getMetadata()).format); | ||
module.exports = (value) => { | ||
@@ -12,36 +8,24 @@ const progressive = cohercer(value, 'Progressive value is not valid.', 'progressive.html') | ||
.value(); | ||
const fn = async (sharp, pipeline) => { | ||
const format = await getOutputType(sharp, pipeline); | ||
switch (format) { | ||
case 'jpeg': | ||
case 'jpg': | ||
return sharp.jpeg({ progressive }); | ||
case 'png': | ||
return sharp.png({ progressive }); | ||
default: | ||
return sharp; | ||
} | ||
}; | ||
return { | ||
output: [ | ||
{ | ||
name: 'progressive', | ||
operation: async (pipeline) => { | ||
const format = await getOutputType(pipeline); | ||
switch (format) { | ||
case 'jpeg': | ||
case 'jpg': | ||
return [ | ||
{ | ||
name: 'progressive', | ||
operation: 'jpeg', | ||
params: [{ progressive }], | ||
}, | ||
]; | ||
case 'png': | ||
return [ | ||
{ | ||
name: 'progressive', | ||
operation: 'png', | ||
params: [{ progressive }], | ||
}, | ||
]; | ||
default: | ||
return []; | ||
} | ||
}, | ||
params: [], | ||
}, | ||
], | ||
output: [{ | ||
name: 'progressive', | ||
fn, | ||
params: [progressive], | ||
}], | ||
}; | ||
}; | ||
const cohercer = require('../cohercer'); | ||
const { getOutputType } = require('./utils'); | ||
const normalizeQ = value => Math.round((value * 80) / 100); | ||
const getOutputType = async pipeline => (pipeline.getOptions().o !== 'original' | ||
? pipeline.getOptions().o | ||
: (await pipeline.getMetadata()).format); | ||
const subOperationGenerator = value => async (pipeline) => { | ||
const format = await getOutputType(pipeline); | ||
switch (format) { | ||
case 'jpeg': | ||
case 'jpg': | ||
return [ | ||
{ | ||
name: 'q', | ||
operation: 'jpeg', | ||
params: [{ quality: normalizeQ(value) }], | ||
}, | ||
]; | ||
case 'webp': | ||
case 'tiff': | ||
return [ | ||
{ | ||
name: 'q', | ||
operation: format, | ||
params: [{ quality: normalizeQ(value) }], | ||
}, | ||
]; | ||
default: | ||
return []; | ||
} | ||
}; | ||
module.exports = (value) => { | ||
@@ -45,3 +17,15 @@ const v = cohercer(value, 'Quality must be a value between 1 and 100.', 'quality.html') | ||
name: 'q', | ||
operation: subOperationGenerator(v), | ||
fn: async (sharp, pipeline) => { | ||
const format = await getOutputType(sharp, pipeline); | ||
switch (format) { | ||
case 'jpeg': | ||
case 'jpg': | ||
return sharp.jpeg({ quality: normalizeQ(v) }); | ||
case 'webp': | ||
case 'tiff': | ||
return sharp[format]({ quality: normalizeQ(v) }); | ||
default: | ||
return sharp; | ||
} | ||
}, | ||
params: [], | ||
@@ -48,0 +32,0 @@ }, |
const { getGravityFromParameter } = require('./gravity'); | ||
module.exports = (/* pipeline */) => async (width, height, gravity) => { | ||
module.exports = sharp => async (width, height, gravity) => { | ||
const gravityValue = getGravityFromParameter(gravity, { acceptAuto: true }); | ||
const operations = [ | ||
{ | ||
name: 'resize_downfill', | ||
operation: 'resize', | ||
params: [width, height, { position: gravityValue, withoutEnlargement: true }], | ||
}, | ||
]; | ||
return operations; | ||
return sharp.resize( | ||
width, | ||
height, | ||
{ position: gravityValue, withoutEnlargement: true }, | ||
); | ||
}; | ||
@@ -1,12 +0,3 @@ | ||
module.exports = (/* pipeline */) => async (width, height/* , ...modeParams */) => { | ||
const operations = [ | ||
{ | ||
name: 'resize_downfit', | ||
operation: 'resize', | ||
params: [width, height, { fit: 'inside', withoutEnlargement: true }], | ||
}, | ||
]; | ||
module.exports = sharp => async (width, height/* , ...modeParams */) => sharp | ||
.resize(width, height, { fit: 'inside', withoutEnlargement: true }); | ||
return operations; | ||
}; | ||
const { getGravityFromParameter } = require('./gravity'); | ||
const { getColorFromParameter } = require('./color'); | ||
module.exports = (/* pipeline */) => async (width, height, ...params) => { | ||
module.exports = sharp => async (width, height, ...params) => { | ||
let color = { | ||
@@ -15,12 +15,5 @@ r: 0, g: 0, b: 0, alpha: 1, | ||
} | ||
const operations = [ | ||
{ | ||
name: 'resize_embed', | ||
operation: 'resize', | ||
params: [width, height, { fit: 'contain', position: gravity, background: color }], | ||
}, | ||
]; | ||
return operations; | ||
return sharp.resize(width, height, { fit: 'contain', position: gravity, background: color }); | ||
}; | ||
const { getGravityFromParameter } = require('./gravity'); | ||
module.exports = (/* pipeline */) => async (width, height, gravity) => { | ||
module.exports = sharp => async (width, height, gravity) => { | ||
const gravityValue = getGravityFromParameter(gravity, { acceptAuto: true }); | ||
const operations = [ | ||
{ | ||
name: 'resize_fill', | ||
operation: 'resize', | ||
params: [width, height, { fit: 'cover', position: gravityValue }], | ||
}, | ||
]; | ||
return operations; | ||
return sharp.resize(width, height, { fit: 'cover', position: gravityValue }); | ||
}; | ||
@@ -1,12 +0,2 @@ | ||
module.exports = (/* pipeline */) => async (width, height/* , modeParams */) => { | ||
const operations = [ | ||
{ | ||
name: 'resize_fit', | ||
operation: 'resize', | ||
params: [width, height, { fit: 'inside' }], | ||
}, | ||
]; | ||
module.exports = sharp => async (width, height/* , modeParams */) => sharp.resize(width, height, { fit: 'inside' }); | ||
return operations; | ||
}; | ||
@@ -24,4 +24,4 @@ const cohercer = require('../../cohercer'); | ||
const percentageToPixel = async ({ width, height }, pipeline) => { | ||
const metadata = await pipeline.getMetadata(); | ||
const percentageToPixel = async ({ width, height }, sharp) => { | ||
const metadata = await sharp.metadata(); | ||
const w = width && (width < 1 ? Math.round(width * metadata.width) : width); | ||
@@ -32,3 +32,3 @@ const h = height && (height < 1 ? Math.round(height * metadata.height) : height); | ||
const getWidthAndHeight = async (sizes, pipeline) => { | ||
const getWidthAndHeight = async (sizes, sharp) => { | ||
let width = null; | ||
@@ -44,3 +44,3 @@ let height = null; | ||
if (isPercentage) { | ||
({ width, height } = await percentageToPixel({ width, height }, pipeline)); | ||
({ width, height } = await percentageToPixel({ width, height }, sharp)); | ||
} else { | ||
@@ -75,6 +75,7 @@ width = width && Math.round(width); | ||
name: 'resize', | ||
operation: async (pipeline) => { | ||
const [width, height] = await getWidthAndHeight(size, pipeline); | ||
return MODES[mode](pipeline)(width, height, ...modeParams); | ||
fn: async (sharp, pipeline) => { | ||
const [width, height] = await getWidthAndHeight(size, sharp); | ||
return MODES[mode](sharp, pipeline)(width, height, ...modeParams); | ||
}, | ||
params: [mode, size], | ||
}, | ||
@@ -81,0 +82,0 @@ ], |
@@ -1,2 +0,2 @@ | ||
module.exports = (/* pipeline */) => async (width, height, modeParams) => { | ||
module.exports = sharp => async (width, height, modeParams) => { | ||
const params = [width, height]; | ||
@@ -6,11 +6,4 @@ if (modeParams === 'iar') { | ||
} | ||
const operations = [ | ||
{ | ||
name: 'resize', | ||
operation: 'resize', | ||
params, | ||
}, | ||
]; | ||
return operations; | ||
return sharp.resize(...params); | ||
}; | ||
@@ -1,14 +0,8 @@ | ||
module.exports = pipeline => async (width, height/* , ...modeParams */) => { | ||
const { width: iw, height: ih } = await pipeline.getMetadata(); | ||
module.exports = sharp => async (width, height/* , ...modeParams */) => { | ||
const { width: iw, height: ih } = await sharp.metadata(); | ||
if (iw < width && ih < height) { | ||
return [ | ||
{ | ||
name: 'resize_upfit', | ||
operation: 'resize', | ||
params: [width, height, { fit: 'inside' }], | ||
}, | ||
]; | ||
return sharp.resize(width, height, { fit: 'inside' }); | ||
} | ||
return []; | ||
return sharp; | ||
}; | ||
@@ -21,3 +21,3 @@ const cohercer = require('../cohercer'); | ||
name: 'rotate', | ||
operation: 'rotate', | ||
fn: async sharp => sharp.rotate(...params), | ||
params, | ||
@@ -24,0 +24,0 @@ }, |
const config = require('config'); | ||
const input = require('./input'); | ||
// const input = require('./input'); | ||
const transformations = require('./transformations'); | ||
@@ -10,11 +10,5 @@ const output = require('./output'); | ||
const createPipeline = (url, options) => { | ||
let metadata = null; | ||
let sharp = null; | ||
const pipeline = { | ||
load: () => image.getImageHandler(url.toString()) | ||
.then((loadedSharp) => { | ||
sharp = loadedSharp; | ||
return pipeline; | ||
}), | ||
.then(loadedSharp => loadedSharp), | ||
@@ -24,21 +18,2 @@ getUrl: () => url, | ||
getOptions: () => options, | ||
getMetadata: () => { | ||
if (metadata) { | ||
return Promise.resolve(metadata); | ||
} | ||
return sharp.metadata() | ||
.then((data) => { | ||
metadata = data; | ||
return metadata; | ||
}); | ||
}, | ||
toBuffer: (...params) => sharp.toBuffer(...params), | ||
hasOperation: operation => sharp && !!sharp[operation], | ||
applyOperation: (operation, ...params) => { | ||
sharp[operation](...params); | ||
return pipeline; | ||
}, | ||
}; | ||
@@ -50,9 +25,11 @@ | ||
module.exports = { | ||
convert: (url, options) => createPipeline(url, options) | ||
.load() | ||
.then(input) | ||
.then(transformations) | ||
.then(output) | ||
.then(pipeline => pipeline.toBuffer()), | ||
convert: (url, options) => { | ||
const pipeline = createPipeline(url, options); | ||
return pipeline.load() | ||
// .then(input) | ||
.then(transformations(pipeline)) | ||
.then(output(pipeline)) | ||
.then(result => result.toBuffer()); | ||
}, | ||
}; | ||
const logger = require('../logger'); | ||
const { getPipelineOperationSortFunction } = require('../utils'); | ||
const { getPipelineOperationSortFunction, stringifyParams } = require('../utils'); | ||
@@ -11,19 +11,13 @@ const OPERATION_ORDER = [ | ||
const reducer = async (acc, { name, operation, params }) => acc.then(async (pipeline) => { | ||
if (operation instanceof Function) { | ||
return (await operation(pipeline)).reduce(reducer, Promise.resolve(pipeline)); | ||
} | ||
if (!pipeline.hasOperation(operation)) { | ||
throw new Error(`Invalid operation: ${operation}`); | ||
} | ||
logger.debug(`Applying output operation "${name}:${operation}" with parameters: ${JSON.stringify(params, null, '')}`); | ||
return pipeline.applyOperation(operation, ...params); | ||
}); | ||
const reducer = pipeline => async (acc, { name, fn, params }) => { | ||
logger.debug(`Applying output operation "${name}":"${stringifyParams(params)}"`); | ||
return acc.then(sharp => fn(sharp, pipeline)); | ||
}; | ||
module.exports = pipeline => pipeline.getOptions().output | ||
module.exports = pipeline => sharp => pipeline.getOptions().output | ||
.sort(sortFunction) | ||
.reduce( | ||
reducer, | ||
Promise.resolve(pipeline), | ||
reducer(pipeline), | ||
Promise.resolve(sharp), | ||
); | ||
const logger = require('../logger'); | ||
const { stringifyParams } = require('../utils'); | ||
const reducer = async (acc, { name, operation, params }) => acc.then(async (pipeline) => { | ||
if (operation instanceof Function) { | ||
return (await operation(pipeline)).reduce(reducer, Promise.resolve(pipeline)); | ||
} | ||
// console.log(acc, operation); | ||
if (!pipeline.hasOperation(operation)) { | ||
throw new Error(`Invalid operation: ${name}:${operation}`); | ||
} | ||
logger.debug(`Applying transformation "${name}:${operation}" with parameters: ${stringifyParams(params)}`); | ||
return pipeline.applyOperation(operation, ...params); | ||
}); | ||
const reducer = pipeline => async (acc, { name, fn, params }) => { | ||
logger.debug(`Applying output operation "${name}":"${stringifyParams(params)}"`); | ||
return acc.then(sharp => fn(sharp, pipeline)); | ||
}; | ||
module.exports = pipeline => pipeline.getOptions().transformations | ||
module.exports = pipeline => sharp => pipeline.getOptions().transformations | ||
.reduce( | ||
reducer, | ||
Promise.resolve(pipeline), | ||
reducer(pipeline), | ||
Promise.resolve(sharp), | ||
); |
@@ -23,2 +23,3 @@ const jsonReplacer = (key, value) => { | ||
isPercentage: percentage => `${percentage}`.indexOf('.') !== -1, | ||
percentageToPixel: (percentage, size) => Math.round(percentage * size), | ||
@@ -25,0 +26,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71151
66
1661