159 lines
3.7 KiB
JavaScript
159 lines
3.7 KiB
JavaScript
"use strict";
|
|
|
|
const {
|
|
promisify
|
|
} = require(`bluebird`);
|
|
|
|
const crypto = require(`crypto`);
|
|
|
|
const _ = require(`lodash`);
|
|
|
|
const tmpDir = require(`os`).tmpdir();
|
|
|
|
const sharp = require(`./safe-sharp`);
|
|
|
|
const duotone = require(`./duotone`);
|
|
|
|
const {
|
|
getPluginOptions,
|
|
healOptions
|
|
} = require(`./plugin-options`);
|
|
|
|
const {
|
|
reportError
|
|
} = require(`./report-error`);
|
|
|
|
exports.notMemoizedPrepareTraceSVGInputFile = async ({
|
|
file,
|
|
options,
|
|
tmpFilePath,
|
|
reporter
|
|
}) => {
|
|
let pipeline;
|
|
|
|
try {
|
|
pipeline = sharp(file.absolutePath);
|
|
|
|
if (!options.rotate) {
|
|
pipeline.rotate();
|
|
}
|
|
} catch (err) {
|
|
reportError(`Failed to process image ${file.absolutePath}`, err, reporter);
|
|
return;
|
|
}
|
|
|
|
pipeline.resize(options.width, options.height, {
|
|
position: options.cropFocus
|
|
}).png({
|
|
compressionLevel: options.pngCompressionLevel,
|
|
adaptiveFiltering: false,
|
|
force: options.toFormat === `png`
|
|
}).jpeg({
|
|
quality: options.quality,
|
|
progressive: options.jpegProgressive,
|
|
force: options.toFormat === `jpg`
|
|
}); // grayscale
|
|
|
|
if (options.grayscale) {
|
|
pipeline = pipeline.grayscale();
|
|
} // rotate
|
|
|
|
|
|
if (options.rotate && options.rotate !== 0) {
|
|
pipeline = pipeline.rotate(options.rotate);
|
|
} // duotone
|
|
|
|
|
|
if (options.duotone) {
|
|
pipeline = await duotone(options.duotone, options.toFormat, pipeline);
|
|
}
|
|
|
|
await new Promise((resolve, reject) => pipeline.toFile(tmpFilePath, err => {
|
|
if (err) {
|
|
return reject(err);
|
|
}
|
|
|
|
return resolve();
|
|
}));
|
|
};
|
|
|
|
const optimize = svg => {
|
|
const SVGO = require(`svgo`);
|
|
|
|
const svgo = new SVGO({
|
|
multipass: true,
|
|
floatPrecision: 0
|
|
});
|
|
return svgo.optimize(svg).then(({
|
|
data
|
|
}) => data);
|
|
};
|
|
|
|
exports.notMemoizedtraceSVG = async ({
|
|
file,
|
|
args,
|
|
fileArgs,
|
|
reporter
|
|
}) => {
|
|
const options = healOptions(getPluginOptions(), Object.assign({}, fileArgs && fileArgs.maxWidth && fileArgs.maxHeight ? {
|
|
height: fileArgs.maxHeight,
|
|
width: fileArgs.maxWidth
|
|
} : {}, fileArgs), file.extension);
|
|
const tmpFilePath = `${tmpDir}/${file.internal.contentDigest}-${file.name}-${crypto.createHash(`md5`).update(JSON.stringify(options)).digest(`hex`)}.${file.extension}`;
|
|
|
|
try {
|
|
await exports.memoizedPrepareTraceSVGInputFile({
|
|
tmpFilePath,
|
|
file,
|
|
options,
|
|
reporter
|
|
});
|
|
|
|
const svgToMiniDataURI = require(`mini-svg-data-uri`);
|
|
|
|
const potrace = require(`potrace`);
|
|
|
|
const trace = promisify(potrace.trace);
|
|
const defaultArgs = {
|
|
color: `lightgray`,
|
|
optTolerance: 0.4,
|
|
turdSize: 100,
|
|
turnPolicy: potrace.Potrace.TURNPOLICY_MAJORITY
|
|
};
|
|
|
|
const optionsSVG = _.defaults(args, defaultArgs); // `srcset` attribute rejects URIs with literal spaces
|
|
|
|
|
|
const encodeSpaces = str => str.replace(/ /gi, `%20`);
|
|
|
|
return trace(tmpFilePath, optionsSVG).then(optimize).then(svgToMiniDataURI).then(encodeSpaces);
|
|
} catch (e) {
|
|
throw e;
|
|
}
|
|
};
|
|
|
|
let memoizedPrepareTraceSVGInputFile, memoizedTraceSVG;
|
|
|
|
const createMemoizedFunctions = () => {
|
|
exports.memoizedPrepareTraceSVGInputFile = memoizedPrepareTraceSVGInputFile = _.memoize(exports.notMemoizedPrepareTraceSVGInputFile, ({
|
|
tmpFilePath
|
|
}) => tmpFilePath);
|
|
exports.memoizedTraceSVG = memoizedTraceSVG = _.memoize(exports.notMemoizedtraceSVG, ({
|
|
file,
|
|
args,
|
|
fileArgs
|
|
}) => `${file.internal.contentDigest}${JSON.stringify(args)}${JSON.stringify(fileArgs)}`);
|
|
}; // This is very hacky, but memoized function are pretty tricky to spy on
|
|
// in tests ;(
|
|
|
|
|
|
createMemoizedFunctions();
|
|
|
|
exports.createMemoizedFunctions = () => {
|
|
createMemoizedFunctions();
|
|
};
|
|
|
|
exports.clearMemoizeCaches = () => {
|
|
memoizedTraceSVG.cache.clear();
|
|
memoizedPrepareTraceSVGInputFile.cache.clear();
|
|
}; |