handler: function (request, reply) { var fileInfo = request.payload.userPhoto; var extension = ".jpg"; var personId = request.params.id; switch (fileInfo.headers['content-type']) { case 'image/png': extension = '.png'; break; case "image/jpeg": case 'image/jpg': default: extension = '.jpg'; break; } var gm = gma.subClass({ imageMagick: true }); gm(fileInfo.path).size(function (err, value) { if (err || !value) { console.log("Error getting image size", err, value); return reply(err); } var width = Math.min(value.width, value.height); var resizeAndSave = function (path, size, outPath, callback) { gm(path) .resize(size, size) .stream(function (err, stdout, stderr) { var writeStream = Fs.createWriteStream(outPath); stdout.pipe(writeStream) .on('close', function () { callback(); }); }); } gm(fileInfo.path).crop(width, width, (value.width - width) / 2, (value.height - width) / 2) .stream(function (err, stdout, stderr) { var cropName = uploadFolder + personId + "_crop" + extension; var writeStream = Fs.createWriteStream(cropName); stdout.pipe(writeStream) .on('close', function () { async.parallel([ function (cb) { resizeAndSave(cropName, Math.min(600, width), uploadFolder + personId + '_large' + extension, cb); }, function (cb) { resizeAndSave(cropName, Math.min(300, width), uploadFolder + personId + '_medium' + extension, cb); }, function (cb) { resizeAndSave(cropName, Math.min(150, width), uploadFolder + personId + '_small' + extension, cb); } ], function (err) { Fs.unlink(cropName); Fs.unlink(fileInfo.path); People.update({id: personId, hasPhoto: true}, function (err, person) { reply(); }) }); }); }); }) }
var fs=require('fs'); var images=require('gm'); var gm=images.subClass({imageMagick:true}); module.exports=exports=function(path){ var apath=path.split('/'); var name=apath.pop(); var dir=apath.join('/'); gm(path).resize(null,300).write(dir+'/small-'+name,function(err){ if(err)console.log(err); }); }
function getGm() { return gmExists? _gm : _gm.subClass({ imageMagick: true }); }
var imageInfoTask = function() { var options = this.options({ mapSrcToName: function(src) { var fullname = path.basename(src); var nameParts = fullname.split('.'); // If there is are more than 2 parts, pop the last one if (nameParts.length >= 2) { nameParts.pop(); } return nameParts.join('.'); }, mapSrcToUrl: function(src) { return src; } }), srcFiles = this.filesSrc, cssTemplate = options.cssTemplate, cssVarMap = options.cssVarMap || function noop () {}, that = this; var gmInstance = options.imageMagick ? gm.subClass({ imageMagick: true }) : gm; // Verify all properties are here if (this.files.length === 0) { return grunt.fatal("this task requires 'files'"); } // Create an async callback var done = this.async(); var processFile = function(file, callback) { if (!file.dest || file.src.length === 0) { callback("missing 'dest' or 'src'"); return; } var cleanCoords = []; var processSrc = function(src, callback) { // obtain the size of an image gmInstance(src).size(function(err, size) { if (err) { callback(err); return; } var coords = { name: options.mapSrcToName(src), image: options.mapSrcToUrl(src), x: 0, y: 0, offset_x: 0, offset_y: 0, width: size.width, height: size.height, total_width: size.width, total_height: size.height, }; cleanCoords.push(coords); callback(); }); }; // Hitting spawn EMFILE without this. var maxGmConcurrency = 10; async.eachLimit(file.src, maxGmConcurrency, processSrc, function(err) { if (err) { callback(err); } var cssFormat = 'spritesmith-custom'; var cssOptions = options.cssOpts || {}; // If there's a custom template, use it if (cssTemplate) { json2css.addMustacheTemplate(cssFormat, fs.readFileSync(cssTemplate, 'utf8')); } else { // Otherwise, override the cssFormat and fallback to 'json' cssFormat = options.cssFormat || cssFormats.get(file.dest) || 'json'; } cleanCoords[cleanCoords.length - 1].last = true; cleanCoords.sort(function(a, b) { var x = a['name']; var y = b['name']; return ((x < y) ? -1 : ((x > y) ? 1 : 0)); }); // Render the variables via json2css var cssStr = json2css(cleanCoords, {'format': cssFormat, 'formatOpts': cssOptions}); // Write it out to the CSS file var destCSSDir = path.dirname(file.dest); grunt.file.mkdir(destCSSDir); fs.writeFileSync(file.dest, cssStr, 'utf8'); // Fail task if errors were logged. if (that.errorCount) { callback('error count ' + that.errorCount); } grunt.verbose.writeln('File "' + file.dest + '" created.'); callback(); }); }; async.each(this.files, processFile, function(err) { if (err) { grunt.fatal(err); done(false); } done(true); }); };
grunt.registerMultiTask('base64Less', 'Base64 encode files. Into less file format.', function() { var data = this.data, done = this.async(), cwd = './', filesToProcess = grunt.file.expand({cwd: cwd},data.process); output = ""; if(!data.prefix){ data.prefix = ""; } if(!data.dest){ grunt.warn("dest needs to be set."); return false; } if(data.resize && data.resize.imageMagick){ gm = gm.subClass({ imageMagick: true }); } if(!filesToProcess.length){ grunt.log.writeln("Nothing to process in "+data.process); done(); }else{ grunt.log.writeln("Processing "+filesToProcess.length+" files..."); for(var i = 0; i < filesToProcess.length; i++){ var lessFileName = filesToProcess[i].substring(filesToProcess[i].lastIndexOf("/")+1), lessSafeFileName = lessFileName.replace(".","_"), fileName = filesToProcess[i]; if(data.resize){ var dimensions = sizer(fileName); function doneCallback(error){ pending.push(lessSafeFileName); errorResize(error,data.prefix,lessSafeFileName,fileName,data.dimensions); } if(data.resize.width && !data.resize.height){ if(dimensions.width !== data.resize.width){ gm(fileName).resize(data.resize.width).write(fileName,doneCallback); grunt.log.writeln('Resizing file '+fileName+' to width '+data.resize.width); }else{ output += create(data.prefix,lessSafeFileName,fileName,data.dimensions); } }else if(!data.resize.width && data.resize.height){ if(dimensions.height !== data.resize.height){ gm(fileName).resize(null,data.resize.height).write(fileName,doneCallback); grunt.log.writeln('Resizing file '+fileName+' to height '+data.resize.height); }else{ output += create(data.prefix,lessSafeFileName,fileName,data.dimensions); } }else if(data.resize.width && data.resize.height){ if(dimensions.width !== data.resize.width && dimensions.height !== data.resize.height){ if(data.resize.force){ gm(fileName).resize(data.resize.width,data.resize.height,"!").write(fileName,doneCallback); }else{ gm(fileName).resize(data.resize.width,data.resize.height).write(fileName,doneCallback); } grunt.log.writeln('Resizing file '+fileName+' to width '+data.resize.width+' height '+data.resize.height+' force: '+data.resize.force); }else{ output += create(data.prefix,lessSafeFileName,fileName,data.dimensions); } } }else{ output += create(data.prefix,lessSafeFileName,fileName,data.dimensions); } } completeTimer = setInterval(function checkIfDone(){ if(pending.length === 0){ grunt.file.write(data.dest, output); clearInterval(completeTimer); done(); } }, 1000); } });
var express = require('express'), fs = require('fs'), router = express.Router(), crypto = require('crypto'), moment = require("moment"), config = require("../server/config"), path = require('path'), gm = require('gm'), imageMagick = gm.subClass({ imageMagick : true }); /** * path: /captcha/get * 获取验证码 */ router.get('/get', function(req, res) { var staticPath = path.join(siteDir, 'public'), bg = "/captcha/", bgName = "bg.jpg", readPath = path.join(staticPath, bg, bgName), str = ['a','b','c','d','e','f','g','h','i','j','k','m','l','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'], code = str[Math.round(Math.random() * (str.length-1))]; // width = req.query.width, // height = req.query.height; code += str[Math.round(Math.random() * (str.length-1))]; code += str[Math.round(Math.random() * (str.length-1))]; code += str[Math.round(Math.random() * (str.length-1))]; // code += str[Math.round(Math.random() * (str.length-1))]; // 绘制验证码图片 var _img = imageMagick(readPath) /* 比较模糊的
import fs from 'fs-extra' import gm from 'gm' import path from 'path' import { flow, map } from 'lodash/fp' import data from '../data.js' const im = gm.subClass({ imageMagick: true }); const outputPath = path.resolve(__dirname, '../Game/assets/') const writeTitle = (entry) => { return new Promise((resolve, reject) => { const year = entry.period && entry.period[0] ? `(${entry.period[0]})` : '' im(800, 600) .background('none') .font('Press-Start-2P-Regular', 8) .fill('#fff') .out(`caption: ${entry.label} ${year}`) .trim() .write(`${outputPath}/title_${entry.id}.png`, function (err) { err ? Promise.reject(err) : Promise.resolve() }) }) } const writeTitles = flow( map(writeTitle), )
module.exports = function config(opts, callback) { opts = opts || {}; // already done if (opts && opts.__cfg) { return callback(null, opts); } // convert negatives (already done by CLI, but not vor module) if (opts.noFix) { opts.fix = false; delete opts.noFix; } if (opts.noNine) { opts.nine = false; delete opts.noNine; } if (opts.noCrop) { opts.crop = false; delete opts.noCrop; } var cfg = _.extend({ __cfg: true, type: undefined, cli: false, input: undefined, platforms: undefined, radius: 0, locale: undefined, minDpi: constants.dpi.mdpi, maxDpi: constants.dpi.xxhdpi, orientation: undefined, fix: true, nine: true, crop: true, label: false, outputDir: undefined, assetsDir: undefined, alloy: undefined, trace: false, inputWidth: undefined, inputHeight: undefined, inputRatio: undefined }, opts); // validate radius if (cfg.radius !== 0) { cfg.radius = parseInt(cfg.radius, 10); if (cfg.radius < 0 || cfg.radius > 50) { return callback('The `radius` percentage should be between 0 and 50.'); } } var isProject = false, isWidget = false; // no outputDir given if (!cfg.outputDir) { isProject = fs.existsSync(path.join(process.cwd(), 'tiapp.xml')); isWidget = fs.existsSync(path.join(process.cwd(), 'widget.json')); // CWD is no project if (!isProject && !isWidget) { return callback('Either specify `outputDir` or run in a project root'); } cfg.outputDir = process.cwd(); } // detect Alloy if (cfg.alloy === undefined) { cfg.alloy = fs.existsSync(path.join(cfg.outputDir, 'app', 'config.json')); } // detect widget if (cfg.widget === undefined) { cfg.widget = isWidget; } if (cfg.widget && cfg.type !== 'asset') { return callback('You can only target a widget using the `assets` command.') } // set assetsDir if (!cfg.assetsDir) { if (cfg.widget) { cfg.assetsDir = 'assets'; } else if (cfg.alloy) { cfg.assetsDir = path.join('app', 'assets'); } else { cfg.assetsDir = 'Resources'; } } // convert dpi constants if (cfg.minDpi && !_.isNumber(cfg.minDpi)) { cfg.minDpi = constants.dpi[cfg.minDpi] || undefined; } if (cfg.maxDpi && !_.isNumber(cfg.maxDpi)) { cfg.maxDpi = constants.dpi[cfg.maxDpi] || undefined; } // get platforms from widgets // widget.json if (isWidget) { try { var widgetjson = JSON.parse(fs.readFileSync(path.join(cfg.outputDir, 'widget.json'))); if (_.isObject(widgetjson) && widgetjson.platforms) { cfg.platforms = widgetjson.platforms.split(','); } // no widget.json } catch (err) {} } var tiappxml, match; // no platforms if (!cfg.platforms) { var deploymentTargets = []; // tiapp.xml found try { // convert to string tiappxml = '' + fs.readFileSync(path.join(cfg.outputDir, 'tiapp.xml')); var re = /<target[^>]+device="([a-z]+)"[^>]*>true<\/target>/gi; // add each deployment target while ((match = re.exec(tiappxml)) !== null) { deploymentTargets.push(match[1]); } } // no tiapp.xml catch (err) {} // use deployment targets if (_.size(deploymentTargets) > 0) { cfg.platforms = deploymentTargets; } // use all else { cfg.platforms = _.clone(constants.platforms); } } // parse string else if (_.isString(cfg.platforms)) { // use all if (cfg.platforms === 'all') { cfg.platforms = _.clone(constants.platforms); } // split else { cfg.platforms = cfg.platforms.split(','); } } // convert platforms to short-hand flags _.each(constants.platforms, function(platform) { cfg[platform] = _.indexOf(cfg.platforms, platform) !== -1; }); if (cfg.ios) { cfg.iphone = cfg.ipad = true; } else { cfg.ios = cfg.iphone || cfg.ipad; } // no orientation if (!cfg.orientation && cfg.type === 'splash') { var orientation; // tiapp.xml found try { // convert to string tiappxml = tiappxml || '' + fs.readFileSync(path.join(cfg.outputDir, 'tiapp.xml')); // mobileweb if (cfg.mobileweb) { // always mixed orientation = 'all'; } // iphone if (cfg.iphone && orientation !== 'all') { // splash is always portrait on iphone orientation = 'portrait'; } // ipad if (cfg.ipad && orientation !== 'all') { var landscape = !!tiappxml.match(/UISupportedInterfaceOrientations~ipad((?!~iphone)[\s\S])+UIInterfaceOrientationLandscape/); var portrait = !!tiappxml.match(/UISupportedInterfaceOrientations~ipad((?!~iphone)[\s\S])+UIInterfaceOrientationPortrait/); if (landscape != portrait) { orientation = landscape ? 'landscape' : 'portrait'; } else { orientation = 'all'; } } // android if (cfg.android && orientation !== 'all') { // main activity locked if ((match = tiappxml.match(/android:screenOrientation="(landscape|portrait)"((?!<activity)[\s\S])+android.intent.action.MAIN/))) { if (!orientation) { orientation = match[1]; } else if (orientation !== match[1]) { orientation = 'all'; } } } // blackberry if (cfg.blackberry && orientation !== 'all') { // locked if ((match = tiappxml.match(/<blackberry>[\s\S]*<orientation>(landscape|portrait)<\/orientation>[\s\S]*<\/blackberry>/))) { if (!orientation) { orientation = match[1]; } else if (orientation !== match[1]) { orientation = 'all'; } } } } // no tiapp.xml catch (err) {} // orientation locked for all platforms if (orientation && orientation !== 'all') { cfg.orientation = orientation; } } // all else if (cfg.orientation === 'all') { cfg.orientation = undefined; } // normalize input path - if any if (cfg.input) { try { cfg.input = fs.realpathSync(cfg.input); } catch (err) { return callback('could not find `input` path: ' + cfg.input); } } // no input if (cfg.type && !cfg.input) { var def; if (cfg.type === 'asset') { _.some([ path.join(cfg.outputDir, cfg.assetsDir, 'iphone', 'images'), path.join(cfg.outputDir, cfg.assetsDir, 'android', 'images', 'res-xxxhdpi'), path.join(cfg.outputDir, cfg.assetsDir, 'android', 'images', 'res-xxhdpi') ], function(potentialDef) { if (fs.existsSync(potentialDef)) { def = potentialDef; return true; } return false; }); if (!def) { return callback('missing required argument `input` or one of the default paths'); } } else { var potentialDef = path.join(cfg.outputDir, cfg.assetsDir, 'iphone', (cfg.type === 'splash') ? '*****@*****.**' : 'iTunesArtwork@2x'); if (fs.existsSync(potentialDef)) { def = potentialDef; } else { return callback('missing required argument `input` or default: ' + potentialDef); } } // use default cfg.input = def; } // requires original dimensions if (cfg.type !== 'asset') { if (cfg.cli) { logger.info('Reading input dimensions'); } var im = gm.subClass({ imageMagick: true }); // read input im(cfg.input).ping().size(function(err, size) { if (err) { return callback(err); } cfg.inputWidth = size.width; cfg.inputHeight = size.height; finish(cfg, callback); }); } else { finish(cfg, callback); } };
import 'babel-polyfill' import AWS from 'aws-sdk' import _gm from 'gm' const gm = _gm.subClass({ imageMagick: true, appPath: '/usr/local/bin/' }) function s3Get(bucket, key) { const s3 = new AWS.S3() const params = { Bucket: bucket, Key: key } return new Promise((resolve, reject) => { s3.getObject(params, (err, data) => { if (err) { reject(err) } else { resolve(data) } }) }) } function s3Put(bucket, key, data) { const s3 = new AWS.S3() const params = { Bucket: bucket, Key: key, Body: data } return new Promise((resolve, reject) => {
//预处理完成后,方可生成各种规格的缩略图文件 function 预处理图片(file) { console.log('开始预处理,图片格式为:' + file.format) switch (file.format) { //对于jpeg,提供一个原比例90压缩率的版本 case 'jpg': var qualityPath = file.path + '_quality80' gm(file.path).interlace('Line').noProfile().quality(80).write(qualityPath, function (err) { var fileName = file.fileId + '_quality' + '_' + file.width + 'x' + file.height + '.' + file.format options.type = '优化后的原图' var gs = new GridStore(DB.dbServer, fileName, fileName, "w", options) gs.writeFile(qualityPath, function (err) { if (!err) { //开始生成并保存各种缩略图 resize(file, ownerID) unlink(qualityPath) } else { unlink(file.path) } }) }) break; //对于gif,不优化直接进行压缩 case 'gif': resize(file, ownerID) break; case 'psd': var dstPath = file.path + '_psd_to_jpg.jpg' console.log('开始预处理PSD', file.path) gm.subClass({ imageMagick: true })(file.path + '[0]').setFormat('jpg').interlace('Line').quality(90).write(dstPath, function (err) { if (!err) { unlink(file.path) file.path = dstPath file.format = 'jpg' var fileName = file.fileId + '_quality' + '_' + file.width + 'x' + file.height + '.' + file.format //注意case jpg中也使用相同的type options.metadata.type = "优化后的原图" var gs = new GridStore(DB.dbServer, fileName, fileName, "w", options) gs.writeFile(dstPath, function (err) { if (!err) { //开始生成并保存各种缩略图 resize(file, ownerID) } else { uploadInfo.err.push('无法保存' + file.name) unlink(dstPath) } }) } else { console.log(err) unlink(file.path) } }) break; //直接进行尺寸压缩,不进行任何优化 case 'png': resize(file, ownerID) break; } }
var fs = require('fs'); var gm = require('gm') // Promise.promisifyAll(require('fs-extra')); var Promise = require('bluebird'); var PSD = require('psd'); // already promise enabled var jsonfile = Promise.promisifyAll(require('jsonfile')); var im = Promise.promisifyAll(gm.subClass({ imageMagick: true })); var nsg = require('node-sprite-generator'); var _ = require('lodash'); var img = "img/085_rasterized.psd"; var imgOutput = "img/output/085_layer.png"; var imgLayerMeta = "json/085.json"; var spriteMeta = "json/085_sprite.json"; var data = {}; PSD.open(img) .then(function(psd) { // write metadata data.layers = psd.tree().export().children; data.layers.forEach(function(d,i){ // make an index thats the reverse of what this lists // imagemagick reverses layer order parsing d.plateIndex = i; d.imIndex = (data.layers.length) - i;
constructor (gmPath) { this.gm = gmPath // Add trailing separator ('/' on Posix, '\\' on Windows) ? graphicsMagick.subClass({ appPath: path.normalize(gmPath + path.sep) }) : graphicsMagick }
"use strict"; /* global module: false, console: false, __dirname: false, process: false */ var express = require('express'); var upload = require('jquery-file-upload-middleware'); var bodyParser = require('body-parser'); var fs = require('fs'); var _ = require('lodash'); var app = express(); var gmagic = require('gm'); var gm = gmagic.subClass({imageMagick: true}); var config = require('../server-config.js'); var extend = require('util')._extend; var url = require('url'); app.use(require('connect-livereload')({ ignore: [/^\/dl/, /^\/img/] })); // app.use(require('morgan')('dev')); app.use(bodyParser.json({limit: '5mb'})); app.use(bodyParser.urlencoded({ // to support URL-encoded bodies limit: '5mb', extended: true })); var listFiles = function (req, options, callback) { var files = []; var counter = 1; var finish = function () { if (!--counter) callback(files);
'use strict'; var gmLib = require('gm'), fs = require('fs'), lib = require('grunt-ez-frontend/lib/lib.js'), path = require('path'), mkdirp = require('mkdirp'), async = require('async'), Deferred = require( "JQDeferred" ), gm = gmLib.subClass({ imageMagick : true }); var doResize = function (imagePath, opts) { var dfd = Deferred(); async.each(opts.sizes, function (size, cb) { var imgStream = fs.createReadStream(imagePath), basename = path.basename(imagePath), sizeInText = lib.format('_{0}_', size), outputPath = path.join(opts.outputFolder, sizeInText, path.relative(opts.relativePath, imagePath) ); mkdirp(path.dirname(outputPath), function (err) { if (err) { throw err; }
module.exports = function({base = 2, to = 1, copy = false, im = false} = {}) { let baseRatio = (3 === parseInt(base, 10)) ? 3 : 2; let toRatio = (Array.isArray(to) ? to.map(i => parseInt(i, 10)) : [parseInt(to, 10)]).filter(i => (base !== i) && -1 < [3, 2, 1].indexOf(i)); toRatio = toRatio.length ? toRatio : [1]; const cvtBase = baseRatio; const cvtCopy = Boolean(copy); const cvtOne = -1 < toRatio.indexOf(1); const cvtTwo = -1 < toRatio.indexOf(2); const cvtGm = im ? graphicsMagick.subClass({imageMagick: true}) : graphicsMagick; function getImage(path) { return new Promise(function(resolve, reject) { return cvtGm(path).identify(function(err, info) { if(err) { return reject(err); } return resolve(new Image(info)); }); }); } const createBuffer = function(image, to) { const { width: baseWidth, height: baseHeight, path } = image; const width = Math.ceil(baseWidth / cvtBase * to); const height = Math.ceil(baseHeight / cvtBase * to); const borderWidth = Math.ceil(width / to) * to - width; const borderHeight = Math.ceil(height / to) * to - height; let flow = cvtGm(path).resize(width, height, '!'); if(borderWidth || borderHeight) { flow = flow .borderColor('transparent') .border(borderWidth, borderHeight) .crop(width + borderWidth, height + borderHeight, Math.floor(borderWidth / 2), Math.floor(borderHeight /2)); } return new Promise(function(resolve, reject) { return flow.toBuffer(function(err, buffer) { if(err) { return reject(err); } const name = image.nameRetina(to); return resolve({buffer, name}); }); }); } const createImages = function(image) { const promises = []; cvtOne && promises.push(createBuffer(image, 1)); cvtTwo && promises.push(createBuffer(image, 2)); cvtCopy && promises.push(createBuffer(image, cvtBase)); return Promise.all(promises); }; const addImagesTo = function(context) { return function(images) { images.forEach(image => context.push(new CreateFile({ path : image.name, contents: Buffer.concat([image.buffer]) }))); return null; } }; return through.obj(function(file, encoding, callback) { if(!file.isBuffer() && !file.isStream()) { return callback(); } return getImage(file.path).then(createImages).then(addImagesTo(this)).then(callback).catch(console.warn.bind(console)); }); };
//server routing dependencies var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var session = require('express-session'); var bodyParser = require('body-parser'); //for image processing var fs = require('fs'); var im = require('gm'); var gm = im.subClass({imageMagic:true}); //application dependencies var routes = require('./routes/index'); var users = require('./routes/users'); var app = express(); var http = require('http').Server(app); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public app.use(favicon(__dirname + '/public/favico.ico')); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser());
fs.exists(cfg.input, function(exists) { // input doesn't exist if (!exists) { return callback('Input not found: ' + cfg.input); } // NOTE: non-sync version didn't work in paralel fs.createDirSync(path.dirname(spec.output)); var im = gm.subClass({ imageMagick: true }); // read var convert = im(cfg.input); var flatten = !spec.alpha && !(cfg.nine && spec.ninePath); // flatten if (flatten) { convert = convert.flatten(); } var specRatio = spec.width / spec.height; var containWidth, containHeight; // nine or fill if (!cfg.crop || (cfg.nine && spec.ninePath)) { // only scale down if (cfg.inputWidth > spec.width || cfg.inputHeight > spec.height) { if (cfg.inputRatio > specRatio) { containWidth = spec.width; containHeight = Math.round(spec.width / cfg.inputRatio); } else { containWidth = Math.round(spec.height * cfg.inputRatio); containHeight = spec.height; } // resize fitting dimensions (using in() or order will be wrong for fill) convert = convert .in('-resize').in(spec.width + 'x' + spec.height); } else { containWidth = cfg.inputWidth; containHeight = cfg.inputHeight; } // nine if (cfg.nine && spec.ninePath) { // extent with 1px transparent border convert = convert .borderColor('none') .border(1, 1); // draw black pixels convert = convert .fill('black') // stretchable area .drawPoint(1, 0) .drawPoint(containWidth, 0) .drawPoint(0, 1) .drawPoint(0, containHeight) // padding box (required since API 21) .drawLine(containWidth + 1, 1, containWidth + 1, containHeight) .drawLine(1, containHeight + 1, containWidth, containHeight + 1); // fill } else { // calculate required padding var padLeft = Math.floor((spec.width - containWidth) / 2); var padTop = Math.floor((spec.height - containHeight) / 2); // enlarge canvas using outer pixel to fill (all using in() or order will be wrong) convert = convert .in('-define') .in('distort:viewport=' + spec.width + 'x' + spec.height + '-' + padLeft + '-' + padTop) .in('-distort').in('SRT').in('0') .in('+repage'); } // crop } else { var resize = (function() { var contentRatio, z, smallerWidth, smallerHeight, factor, result = { width: spec.width, height: spec.height }; // user has given content dimensions if (cfg.width && cfg.height) { contentRatio = cfg.width / cfg.height; // e.g. specs landscape, content is portrait if (specRatio > contentRatio) { z = spec.height / cfg.height; // e.g. specs portrait, content is landscape } else { z = spec.width / cfg.width; } // don't scale up if (z > 1) { logger.warn('Target size is bigger then content: ' + spec.output.cyan); } else { smallerWidth = Math.round(cfg.inputWidth * z); smallerHeight = Math.round(cfg.inputHeight * z); // width or height won't cover specs anymore if content needs to fit as well if (smallerWidth < spec.width || smallerHeight < spec.height) { factor = Math.max(spec.width / smallerWidth, spec.height / smallerHeight); logger.warn('For '.white + (spec.width + 'x' + spec.height).cyan + ' to contain '.white + (cfg.width + 'x' + cfg.height).cyan + ' the input needs to be at least: '.white + (Math.ceil(cfg.inputWidth * factor) + 'x' + Math.ceil(cfg.inputHeight * factor)).cyan); } else { result.width = smallerWidth; result.height = smallerHeight; } } } return result; })(); // resize covering dimensions convert = convert.resize(resize.width, resize.height, '^'); // crop from center to exact dimensions convert = convert .gravity('Center') .crop(spec.width, spec.height, 0, 0); } // border radius (http://www.rubblewebs.co.uk/imagemagick/display_example.php?example=69) if (spec.type === 'icon' && !flatten && cfg.radius > 0 && _.size(_.difference(spec.platforms, ['ios', 'ipad', 'iphone', 'apple-watch'])) > 0) { var radius = Math.ceil((spec.width / 100) * cfg.radius); // in convert = convert .in('-size').in(spec.width + 'x' + spec.height) .in('xc:none') .in('-fill').in('white') .in('-draw').in('roundRectangle 0,0 ' + (spec.width - 1) + ',' + (spec.height - 1) + ' ' + radius + ',' + radius); // out convert = convert .compose('SrcIn') .out('-composite'); } // annotate if (cfg.label) { var fontSize = Math.round((containWidth || spec.width) / 11); convert = convert .fill('#F00') .font(path.join(__dirname, 'Calibri.ttf')) .fontSize(fontSize); if (cfg.nine && spec.ninePath) { convert = convert.drawText(1, (containHeight || spec.height) / 2, spec.name); } else { convert = convert.drawText(0, 0, spec.name); } } // headers convert = convert .noProfile() .units('PixelsPerInch') .density(spec.dpi, spec.dpi); // rotate if (spec.rotate) { convert = convert.rotate('white', spec.rotate); } // remove alpha if (flatten) { convert = convert.out('-background', 'white', '-alpha', 'off'); } // write convert.write(spec.output, function(err) { if (err) { return callback(err.code === 'ENOENT' ? 'Please install ImageMagick.' : err); } // async feedback for CLI if (cfg.cli) { logger.info('Generated: ' + spec.output.cyan); } // pass back output callback(null, spec.output); }); // show command if (cfg.trace) { logger.debug('Executing: ' + convert.args().join(' ').cyan); } });
'use strict'; var async = require('async'); var GM = require('gm'); var gm = GM.subClass({ imageMagick: true }); //## Doesn't seem to work. Filesize or something is wrong which results in gray bottom in images exports.resize = function resize (source, sizes, callback) { var name = source.filename; async.map(sizes, function (size, done) { gm(source, name + size.suffix + '.jpg') .resize(size.width, size.height, '>') .filesize({ bufferStream: true }, function (err, filesize) { if(err) { return done(err); } var image = this.stream('jpg'); image.filesize = parseInt(filesize); image.filename = name + size.suffix + '.jpg'; done(null, image); }); }, callback); };
var db = require('./middleware/db').db var fs = require('fs'); var gm = require('gm'); var im = gm.subClass({imageMagick: true}) var conf = require('./middleware/config'); var Email = require('email').Email; db.query('SELECT * FROM photo WHERE processed = 0', function(err, photos) { photos.forEach(function(photo) { var parts = photo.path.split('/'); photo.path = parts[parts.length -1]; waterMark(photo.path, function(err) { if (err) throw err; db.query('UPDATE photo SET processed = 1 WHERE id = ' + photo.id, function(err) { if(err) throw err; }) db.query('UPDATE photo SET path=? WHERE id = ' + photo.id, '/pictures/photos/' + photo.path, function(err) { if(err) throw err; }) }); }); email(function(err) { if(err) throw err; }); }) function waterMark (file, cb) { var origin = __dirname + '/img/tmp/' + file; var dest = __dirname + '/public/pictures/photos/' + file;
var plugin = function(schema, options) { options = options || {}; if (typeof(options.directory) !== 'string') throw new Error('option "directory" is required'); if (typeof(options.properties) !== 'object') throw new Error('option "properties" is required'); if (typeof(options.storage) !== 'object') throw new Error('option "storage" is required'); _.defaults(options, { idAsDirectory: false, gm: {} }); _.defaults(options.gm, { }); var gm = gmSuper.subClass(options.gm); var storageOptions = options.storage; storageOptions.schema = schema; if (typeof(storageOptions.providerName) !== 'string') throw new Error('option "storage.providerName" is required'); var ProviderPrototype = findProvider(storageOptions.providerName); var providerOptions = storageOptions.options || {}; var providerInstance = new ProviderPrototype(providerOptions); if (typeof providerInstance.getUrl !== 'function') { throw new Error('Provider ' + storageOptions.providerName + ' does not have a method getUrl'); } if (typeof providerInstance.createOrReplace !== 'function') { throw new Error('Provider ' + storageOptions.providerName + ' does not have a method createOrReplace'); } var propertyNames = Object.keys(options.properties); propertyNames.forEach(function(propertyName) { var propertyOptions = options.properties[propertyName]; if (!propertyOptions) throw new Error('property "' + propertyName + '" requires an specification'); var styles = propertyOptions.styles || {}; var styleNames = Object.keys(styles); if (styleNames.length === 0) { throw new Error('property "' + propertyName + '" needs to define at least one style'); } var addOp = {}; var propSchema = addOp[propertyName] = {}; styleNames.forEach(function(styleName) { propSchema[styleName] = { size: Number, // Size of the File oname: String, // Original name of the file mtime: Date, ctime: Date, path: String, // Storage Path defaultUrl: String, // Default (non-secure, most of the time public) Url format: String, // Format of the File(provided by identify). dims: { // Dimensions of the Image h: Number, // Height w: Number // Width } }; }); // Add the Property schema.add(addOp); }); // for each property name // Finally we set the method 'attach' // => propertyName: String. Name of the property to attach the file to. // => attachmentInfo: { // path: String(required). Path to the file in the file system. // name: String(optional). Original Name of the file. // mime: String(optional). Mime type of the file. // } schema.methods.attach = function(propertyName, attachmentInfo, cb) { var selfModel = this; if (propertyNames.indexOf(propertyName) == -1) return cb(new Error('property "' + propertyName + '" was not registered as an attachment property')); var propertyOptions = options.properties[propertyName]; var styles = propertyOptions.styles || {}; if (!attachmentInfo || typeof(attachmentInfo) !== 'object') return cb(new Error('attachmentInfo is not valid')); if (typeof(attachmentInfo.path) !== 'string') return cb(new Error('attachmentInfo has no valid path')); if (!attachmentInfo.name) { // No original name provided? We infer it from the path attachmentInfo.name = path.basename(attachmentInfo.path); } existsFn(attachmentInfo.path, function(exists) { if (!exists) { return cb(new Error('file to attach at path "' + attachmentInfo.path + '" does not exists')); } fs.stat(attachmentInfo.path, function(err, stats) { if (!stats.isFile()) { return cb(new Error('path to attach from "' + attachmentInfo.path + '" is not a file')); } var getFileExtension = Promise.promisify(gm.prototype.format, gm(attachmentInfo.path)); Promise.resolve(mime.extension(mime.lookup(attachmentInfo.path))) .then(function(format) { // First we need to check whether or not the format is supported. // If it's not, throw an error return supportedDecodingFormats.indexOf(format.toUpperCase()) !== -1; }) .catch(function(err) { // Failing here means that the file format is not a supported image. // So return false for `canTransform` return false; }) .then(function(canTransform) { var fileExt = path.extname(attachmentInfo.path); var styles = propertyOptions.styles || {}; return Promise.all(_.map(styles, function(style, name) { _.defaults(style, { options: {}, transform: function(i) { return i; } }); return Promise.resolve({ image: canTransform ? style.transform(gm(attachmentInfo.path)) : null, file: canTransform ? null : fs.createReadStream(attachmentInfo.path), style: style, styleName: name, attachmentInfo: attachmentInfo, fileExt: fileExt }); })); }) .then(function(variants) { // Now write files to the temporary path. // @todo: in the future, this should probably just pass the gm image/stream // object to the provider. return Promise.all(_.map(variants, function(variant) { var styleFileExt = variant.style.options.format ? ('.' + variant.style.options.format) : variant.fileExt; var styleFileName = path.basename(variant.attachmentInfo.path, variant.fileExt); styleFileName += '-' + variant.styleName + styleFileExt; var styleFilePath = path.join(path.dirname(variant.attachmentInfo.path), styleFileName); var writeImageToFile = Promise.promisify(gm.prototype.write, variant.image); return ( variant.image ? writeImageToFile(styleFilePath) : (function() { return new Promise(function(resolve) { variant.file.pipe(fs.createWriteStream(styleFilePath)) .on('finish', resolve); }); })() ) .catch(function(err) { console.log(err); }) .then(function() { return _.merge(variant, { styleFilePath: styleFilePath }); }); })); }) .then(function(variants) { // Pass each individual file off to the registered provider return Promise.all(_.map(variants, function(variant) { var ext = path.extname(variant.styleFilePath); var filenameId = options.filenameId ? selfModel[options.filenameId] : selfModel.id; var storageStylePath = path.join( options.directory, propertyName, [filenameId, variant.styleName + ext].join(options.idAsDirectory ? '/':'-') ); // if (storageStylePath[0] != '/') { // storageStylePath = '/' + storageStylePath; // } var getFileStats = Promise.promisify(fs.stat); var getImageStats = Promise.promisify(gm(variant.styleFilePath).identify); var createOrReplaceFile = Promise.promisify(providerInstance.createOrReplace, providerInstance); // Providers expect both stat and identify results for the output image return Promise.all([ getFileStats(variant.styleFilePath), getImageStats() .catch(function() { return null; }) ]) .spread(function(stats, atts) { return { style: { name: variant.styleName, options: variant.style }, filename: variant.styleFilePath, stats: stats, propertyName: propertyName, model: selfModel, path: storageStylePath, defaultUrl: null, // let the storage assign this features: atts }; }) .then(function(providerInput) { return createOrReplaceFile(providerInput); }) .then(function(storageResult) { return _.merge(variant, { storageResult: storageResult, propertyName: propertyName }); }); })); }) .then(function(variants) { _.forEach(variants, function(variant) { var propModel = selfModel[variant.propertyName]; var modelStyle = propModel[variant.storageResult.style.name]; _.merge(modelStyle, { defaultUrl: variant.storageResult.defaultUrl, path: variant.storageResult.path, size: variant.storageResult.stats.size, mime: variant.storageResult.mime, ctime: variant.storageResult.stats.ctime, mtime: variant.storageResult.stats.mtime, oname: variant.attachmentInfo.name, // original name of the file }, variant.storageResult.features ? { format: variant.storageResult.features.format, depth: variant.storageResult.features.depth, dims: { h: variant.storageResult.features.size.height, w: variant.storageResult.features.size.width, } } : {}); }); return variants; }) .then(function() { cb(null); }) .catch(function(err) { return cb(err); }) .done(); }); }); }; // method attach };