diff --git a/.gitignore b/.gitignore index 3c3629e..de9c70a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +sample +.eslintrc.json diff --git a/bin/psd.js b/bin/psd.js index 8cb2a97..6024889 100755 --- a/bin/psd.js +++ b/bin/psd.js @@ -8,16 +8,22 @@ var fileType = require('file-type'); var readChunk = require('read-chunk'); var chalk = require('chalk'); var fs = require('fs'); +var Path = require('path'); +var filenamify = require('filenamify'); +var mkdirp = require('mkdirp'); var filesProcessed = []; +var outputDir = null; // setup Commander program program .version(require('../package.json').version) .arguments('') .option('-c, --convert', 'Convert to PNG file named .png') + .option('-l, --layers', 'Convert layers to PNG files named .png') .option('-t, --text', 'Extract text content to .txt') .option('-o, --open', 'Preview file after conversion (triggers -c option)') + .option('-d, --dir ', 'Write output file(s) to ') .action(processFiles) .parse(process.argv); @@ -25,6 +31,10 @@ program function convertFile(filepath, psdPromise, cb) { var filePng = filepath.replace(/\.psd$/, '.png'); + if (outputDir) { + filePng = Path.join(outputDir, Path.basename(filePng)); + } + psdPromise.then(function(psd) { return psd.image.saveAsPng(filePng); }).then(function(err) { @@ -39,11 +49,39 @@ function convertFile(filepath, psdPromise, cb) { }); } +// save layers to PNG +function convertLayers(filepath, psdPromise, cb) { + var fileDir = Path.dirname(filepath); + + if (outputDir) { + fileDir = outputDir; + } + + try { + psdPromise.then(function(psd) { + psd.tree().descendants().forEach(function(node) { + saveLayer(node, fileDir, cb); + }); + }); + } catch (err) { + console.log( + chalk.red.bold('Error while extracting layers from %s'), filepath); + return cb(err); + } + + filesProcessed.push(filepath); + cb(null, filepath); +} + // extract text from PSD file function extractTextFromFile(filepath, psdPromise, cb) { var fileText = filepath.replace(/\.psd$/, '.txt'); var fileString = ''; + if (outputDir) { + fileText = Path.join(outputDir, Path.basename(fileText)); + } + psdPromise.then(function(psd) { psd.tree().export().children.forEach(function(child) { @@ -101,14 +139,51 @@ function processFiles(files, env) { convertFile(filepath, psdPromise, cb); }); } + if (program.layers) { + asyncTasks.push(function(cb) { + convertLayers(filepath, psdPromise, cb); + }); + } // extract text data if (program.text) { asyncTasks.push(function(cb) { extractTextFromFile(filepath, psdPromise, cb); }); } + // set output directory + if (program.dir) { + outputDir = Path.resolve(program.dir); + } + + if (program.dir) { + // check that directory exists and is a directory + try { + if (fs.statSync(outputDir).isDirectory()) { + async.series(asyncTasks, cb); + } else { + console.log(chalk.red.bold('%s is not a directory'), outputDir); + return cb(); + } + } catch (err) { + if (err.code === 'ENOENT') { + // make directory + mkdirp(outputDir, function(error) { + if (error) { + console.log(chalk.red.bold('Error while creating %s'), outputDir); + return cb(); + } - async.series(asyncTasks, cb); + console.log(chalk.gray('Created directory %s'), outputDir); + async.series(asyncTasks, cb); + }); + } else { + console.log(chalk.red.bold('Error accessing %s'), outputDir); + return cb(); + } + } + } else { + async.series(asyncTasks, cb); + } }, processDone); } @@ -180,3 +255,22 @@ function PSDLayer(path, element) { } } } + +function saveLayer(node, fileDir, cb) { + + if (node && node.hasChildren()) { + node.children().forEach(function(child) { + saveLayer(child, fileDir, cb); + }); + } else if (node) { + var filepath = Path.join( + fileDir, filenamify(node.layer.name, {replacement: '-'}) + '.png'); + node.layer.image.saveAsPng(filepath).then(function(err) { + if (err) { + console.log(chalk.red.bold("Error while saving %s"), filepath); + } + + console.log(chalk.gray("PNG saved to %s"), filepath); + }); + } +} diff --git a/package.json b/package.json index 65e500c..ead4913 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,9 @@ "commander": "2.9.0", "file-type": "3.3.0", "psd": "3.1.0", - "read-chunk": "1.0.1" + "read-chunk": "1.0.1", + "filenamify": "2.1.0", + "mkdirp": "0.5.1" }, "devDependencies": {}, "preferGlobal": true,