2020-02-28 10:33:39 -08:00

163 lines
4.7 KiB
JavaScript

const path = require('path');
const fs = require('fs-extra');
const gm = require('gm');
const Promise = require('bluebird');
const fetch = require('make-fetch-happen');
const ico = require('png-to-ico');
const { resolve, readFile } = require('./resolve');
const actions = {
async copy ({ input, output }) {
await fs.copy(resolve(input), resolve(output));
return readFile(input);
},
async transcode ({ input, output }) {
const result = await actions.image({
input,
output,
format: 'jpeg',
});
return result;
},
async fetch ({ input, output }) {
const res = await fetch(input);
if (res.status !== 200) {
throw new Error(`File could not be fetched (${res.status}): "${input}"`);
}
const body = await res.buffer();
output = resolve(output);
await fs.ensureDir(path.dirname(output));
await fs.writeFile(output, body);
return body;
},
async write ({ output, content }) {
output = resolve(output);
await fs.ensureDir(path.dirname(output));
await fs.writeFile(output, content);
return Buffer.from(content);
},
async image (options) {
const output = resolve(options.output);
const contents = await readFile(options.input);
let gmfile = gm(contents, resolve(options.input));
const size = await Promise.fromCallback((cb) => gmfile.size(cb));
if (options.height || options.width) {
// if upscale is not requested, restrict size
if (!options.upscale) {
if (!isNaN(options.width)) {
options.width = Math.min(options.width, size.width);
}
if (!isNaN(options.height)) {
options.height = Math.min(options.height, size.height);
}
}
// if one dimension is not set - we fill it proportionally
if (!options.height) {
if (options.crop) {
options.height = size.height;
} else {
options.height = Math.ceil((options.width / size.width) * size.height);
}
}
if (!options.width) {
if (options.crop) {
options.width = size.width;
} else {
options.width = Math.ceil((options.height / size.height) * size.width);
}
}
if (options.fill === 'crop') {
if (size.height < options.height || size.width < options.width) {
gmfile = gmfile
.geometry(options.width, options.height, '^')
.borderColor(options.bgColor || '#FFFFFF')
.border(options.width, options.height)
.gravity(options.gravity)
.crop(options.width, options.height);
} else {
gmfile = gmfile
.geometry(options.width, options.height, '^')
.gravity(options.gravity)
.crop(options.width, options.height);
}
} else if (options.fill === 'cover') {
gmfile = gmfile
.geometry(options.width, options.height, '^');
} else if (options.fill === 'box') {
gmfile = gmfile
.geometry(options.width, options.height)
.borderColor(options.bgColor || '#FFFFFF')
.border(options.width, options.height)
.gravity(options.gravity)
.crop(options.width, options.height);
} else if (options.fill === 'contain') {
gmfile = gmfile
.geometry(options.width, options.height);
} else {
gmfile = gmfile
.geometry(options.width, options.height, '!');
}
} else if (options.percentage) {
gmfile = gmfile
.geometry(options.percentage, null, '%');
}
if (options.format) {
gmfile = gmfile
.setFormat(options.format === 'ico' ? 'png' : options.format);
}
if (options.quality) {
gmfile = gmfile.quality(Math.floor(options.quality));
} else {
gmfile = gmfile.quality(Math.floor(95));
}
if (options.samplingFactor) {
gmfile = gmfile
.samplingFactor(options.samplingFactor[0], options.samplingFactor[1]);
}
if (options.sharpen) {
options.sharpen = (typeof options.sharpen === 'string') ? options.sharpen : '1.5x1+0.7+0.02';
gmfile = gmfile.unsharp(options.sharpen);
}
if (options.flatten) {
gmfile = gmfile.flatten();
}
if (options.interlace) {
gmfile = gmfile.interlace('Line');
}
if (options.background) {
gmfile = gmfile.background(options.background);
}
if (options.noProfile) {
gmfile = gmfile.noProfile();
}
await fs.ensureDir(path.dirname(output));
let result = await Promise.fromCallback((cb) => gmfile.toBuffer(cb));
if (options.format === 'ico') result = await ico(result);
await fs.writeFile(output, result);
return result;
},
};
module.exports = exports = actions;