Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Sometimes Photoshop is a damn fool and you need an export process that sucks less at color palette selection and dithering.
//REQUIREMENTS: The following programs must be installed and accessible in your PATH
// node > 6
// imagemagick's command line tool "convert"
// giflossy - which can be installed with `npm install -g giflossy`, but only on mac and linux??
//USAGE: Change params at the top to your liking. `node gif_process.js` starts it up.
// EXECUTES ALL TASKS IN PARALEL.
// If you run it like this, it will CONSUME YOUR WHOLE COMPUTER (100% cpu, 100% memory) for a few minutes while it works.
//DISCLOSURE: I was running terribly low on sleep when I wrote this. It's a tool. It gets a job done like ten times ever. Don't judge me on this. The code I write for my day job is like way better and I care a lot more about it because I have to maintain it all the time.
//LICENSE: MIT
let imPath = 'script_output-imagemagick/';
let gsPath = 'script_output-giflossy/';
let seriesName = 'electric_flower';
let inputPngFolderList = [
'08-comp_a',
];
let outputParams = [ //<-- only do like 1 set at a time for sanity
{width: 1920, height: 1080},
{width: 1080},
{width: 960, height: 540, lossy: 10},
{width: 480, lossy: 10},
{width: 480, height: 270, lossy: 5},
{width: 400, colors: 128, lossy: 35},
{width: 400, height: 225, colors: 256, lossy: 5},
];
let sourceWidth = 1920;
let sourceHeight = 1080;
let sourceAspect = sourceWidth / sourceHeight;
let backgroundColor = '#000000';
/*------------------------------------------------*/
const fs = require('fs');
const child_process = require('child_process');
let makePath = function(path){
if(!fs.existsSync(path)){
fs.mkdirSync(path);
}
};
makePath(imPath);
makePath(gsPath);
let timeTask = function(taskName, callback){
var start = Date.now();
return function(err, stdout, stderr) {
var time = (Date.now() - start);
console.log([taskName, stdout, time, 'ms'].join(' ').replace(/\n/g, ' '));
if (err) {
console.error(err);
return;
} else if(callback) {
callback();
}
};
};
let hellYeahGifProcess = function(x, y, scale, c, l){
let width = x;
let height = y || x;
let resize = scale || width > height ? width : height;
let colors = c || 256;
let lossy = l || 0;
let targetAspect = width / height;
let leftRight = (width - resize) / 2;
let topBottom = (height - resize) / 2;
let scaledCount = 0;
let sourceCropWidth = Math.ceil(targetAspect * sourceHeight);
let sourceCropHeight = Math.ceil((targetAspect * sourceHeight) / targetAspect);
let leftRightCrop = (sourceWidth - sourceCropWidth) / 2;
let topBottomCrop = (sourceHeight - sourceCropHeight) / 2;
let crop = `-crop ${sourceCropWidth}x${sourceCropHeight}+${leftRightCrop}+${topBottomCrop}`;
let dimensionsLabel = `${width}x${height}`;
if(scale){
dimensionsLabel += `x${scale}`;
}
if(c){
dimensionsLabel += `-colors_${c}`;
}
let imSizePath = imPath + dimensionsLabel + '/';
let gsSizePath = gsPath + dimensionsLabel + '/';
makePath(imSizePath);
makePath(gsSizePath);
let imList = [];
let gsList = [];
let gifSicleImagesWhenDone = function(){
imList.forEach(function(outputFileNameIM, index){
let outputFileNameGS = gsList[index];
let lossyArg = lossy ? `--lossy=${lossy}` : '';
child_process.exec(
[
'giflossy',
'-O3',
lossyArg,
`-o ${outputFileNameGS}`,
outputFileNameIM
].join(' '),
timeTask(outputFileNameGS)
);
});
};
let onComplete = function(){
scaledCount++;
if(scaledCount === inputPngFolderList.length){
gifSicleImagesWhenDone();
}
};
inputPngFolderList.forEach(function(inputFileName){
let name = `${seriesName}-${inputFileName}-${dimensionsLabel}`;
let nameLossy = lossy ? `-lossy_${lossy}` : '';
name += '-imagemagick';
let outputFileNameIM = imSizePath + name + '.gif';
let outputFileNameGS = gsSizePath + name + `-giflossy${nameLossy}.gif`;
let argument = [
'convert',
'-dispose 2',
'-delay 1/24',
inputFileName + '/*.png',
'-coalesce',
crop,
'-resize ' + resize,
`-background "${backgroundColor}"`,
'-alpha remove',
`-bordercolor "${backgroundColor}"`,
//`-border ${leftRight}x${topBottom}`,
'-dither FloydSteinberg',
//'-ordered-dither o8x8,64',
//'-ordered-dither o2x2,128,128,64',
//'-ordered-dither checks,128',
`-colors ${colors}`,
'+repage',
outputFileNameIM
].join(' ');
console.log(argument);
imList.push(outputFileNameIM);
gsList.push(outputFileNameGS);
child_process.exec(
argument,
timeTask(outputFileNameIM, onComplete)
);
});
};
outputParams.forEach(function(params){
hellYeahGifProcess(params.width, params.height, params.resize, params.colors, params.lossy);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.