├── .editorconfig ├── .gitignore ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── gulpfile.js ├── index.js ├── package.json └── test ├── fixtures └── wikipedia.png └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | pids 12 | logs 13 | results 14 | examples 15 | 16 | npm-debug.log 17 | node_modules 18 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "boss": true, 11 | "eqnull": true, 12 | "node": true, 13 | "esnext": true 14 | } 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | 4 | node_js: 5 | - "node" 6 | 7 | before_install: 8 | - npm install -g gulp 9 | - sudo apt-get install graphicsmagick 10 | 11 | install: 12 | - npm install 13 | 14 | os: 15 | #- osx 16 | - linux 17 | 18 | script: npm test 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 scalable minds 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [gulp](https://github.com/gulpjs/gulp)-gm [![Build Status](https://travis-ci.org/scalableminds/gulp-gm.svg?branch=master)](https://travis-ci.org/scalableminds/gulp-gm) 2 | 3 | > Image manipulation with [gm](https://github.com/aheckmann/gm). Refer to [gm's documentation](http://aheckmann.github.io/gm/docs.html) for details. 4 | 5 | 6 | # Install 7 | 8 | Install with [npm](https://npmjs.org/package/gulp-gm) 9 | 10 | ``` 11 | npm install --save-dev gulp-gm 12 | ``` 13 | 14 | ### GraphicsMagick or ImageMagick 15 | `gulp-gm` works best with GraphicsMagick. 16 | However, it also supports ImageMagick, but you'll need to set the option `imageMagick: true`. 17 | 18 | Make sure GraphicsMagick or ImageMagick is installed on your system and properly set up in your `PATH`. 19 | 20 | Ubuntu: 21 | 22 | ```shell 23 | apt-get install imagemagick 24 | apt-get install graphicsmagick 25 | ``` 26 | 27 | Mac OS X (using [Homebrew](http://brew.sh/)): 28 | 29 | ```shell 30 | brew install imagemagick 31 | brew install graphicsmagick 32 | ``` 33 | 34 | Windows & others: 35 | - GraphicsMagick: [http://www.graphicsmagick.org/download.html](http://www.graphicsmagick.org/download.html) 36 | - ImageMagick: [http://www.imagemagick.org/script/binary-releases.php](http://www.imagemagick.org/script/binary-releases.php) 37 | 38 | Confirm that GraphicsMagick or ImageMagick is properly set up by executing `gm -version` or `convert -version` in a terminal. 39 | 40 | 41 | ## Example 42 | 43 | ```js 44 | var gulp = require('gulp'); 45 | var gm = require('gulp-gm'); 46 | 47 | gulp.task('default', function () { 48 | gulp.src('test.png') 49 | 50 | .pipe(gm(function (gmfile) { 51 | 52 | return gmfile.resize(100, 100); 53 | 54 | })) 55 | 56 | .pipe(gulp.dest('dist')); 57 | }); 58 | ``` 59 | 60 | ### Convert png to jpg 61 | 62 | ```js 63 | gulp.src('test.png') 64 | .pipe(gm(function (gmfile) { 65 | 66 | return gmfile.setFormat('jpg'); 67 | 68 | })) 69 | .pipe(gulp.dest('dist')); 70 | ``` 71 | 72 | ### Async manipulation 73 | 74 | ```js 75 | gulp.src('test.png') 76 | .pipe(gm(function (gmfile, done) { 77 | 78 | gmfile.size(function (err, size) { 79 | 80 | done(null, gmfile 81 | .stroke("blue", 6) 82 | .fill("transparent") 83 | .drawRectangle(0, 0, size.width, size.height)); 84 | 85 | }); 86 | 87 | })) 88 | .pipe(gulp.dest('dist')); 89 | ``` 90 | 91 | ### Using ImageMagick 92 | 93 | ```js 94 | gulp.src('test.png') 95 | 96 | .pipe(gm(function (gmfile) { 97 | 98 | return gmfile.resize(100, 100); 99 | 100 | }, { 101 | imageMagick: true 102 | })) 103 | 104 | .pipe(gulp.dest('dist')); 105 | ``` 106 | 107 | ## API 108 | 109 | ### gm(modifier, options) 110 | 111 | #### modifier(gmfile, [done]) 112 | 113 | Type: `Function` 114 | 115 | Supply a callback that manipulates the image. The first argument will the `gm` object with all original properties. [Read more in the gm documentation](http://aheckmann.github.io/gm/docs.html). 116 | 117 | ##### Sync 118 | Make sure to return your modified `gm` object. 119 | 120 | ```js 121 | gulp.src('test.png') 122 | .pipe(gm(function (gmfile) { 123 | return gmfile.blur(10); 124 | })) 125 | .pipe(gulp.dest('dist')); 126 | ``` 127 | 128 | ##### Async 129 | If your call back accepts a second argument (`done`), it will be treated asynchronously. Your code will then need to call `done(err, gmfile)` at some point. 130 | 131 | ```js 132 | gulp.src('test.png') 133 | .pipe(gm(function (gmfile, done) { 134 | gmfile.size(function (err, size) { 135 | 136 | done(null, gmfile.resize( 137 | size.width * 0.5, 138 | size.height * 0.5 139 | )); 140 | 141 | }); 142 | })) 143 | .pipe(gulp.dest('dist')); 144 | ``` 145 | 146 | 147 | #### options.imageMagick 148 | 149 | Type: `Boolean` 150 | Default value: `false` 151 | 152 | Set to `true` when using ImageMagick instead of GraphicsMagick. 153 | 154 | 155 | ## Known Issues 156 | 157 | * `gm.thumb(...)` is not supported because it writes to the file system directly. Consider using [gulp-image-resize](https://github.com/scalableminds/gulp-image-resize) instead. 158 | 159 | 160 | ## Tests 161 | 162 | 1. You need both ImageMagick and GraphicsMagick installed on your system to run the tests. 163 | 2. Install all npm dev dependencies `npm install` 164 | 3. Install gulp globally `npm install -g gulp` 165 | 4. Run `gulp test` 166 | 167 | 168 | ## License 169 | 170 | MIT © [scalable minds](http://scm.io) 171 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var mocha = require("gulp-mocha"); 3 | var jshint = require("gulp-jshint"); 4 | var rename = require("gulp-rename"); 5 | var stylish = require("jshint-stylish"); 6 | 7 | var gm = require("./index"); 8 | 9 | 10 | gulp.task("jshint", function () { 11 | gulp.src(["gulpfile.js", "index.js", "test/*.js"]) 12 | .pipe(jshint()) 13 | .pipe(jshint.reporter(stylish)); 14 | }); 15 | 16 | gulp.task("mocha", function () { 17 | return gulp.src("test/test.js") 18 | .pipe(mocha({ reporter: "spec" })); 19 | }); 20 | 21 | 22 | gulp.task("test", ["jshint", "mocha"]); 23 | 24 | 25 | gulp.task("example1", function () { 26 | return gulp.src("test/fixtures/wikipedia.png") 27 | .pipe(gm(function (gmfile, done) { 28 | 29 | gmfile.size(function (err, size) { 30 | 31 | done(null, gmfile 32 | .stroke("blue", 6) 33 | .fill("transparent") 34 | .drawRectangle(0, 0, size.width, size.height)); 35 | 36 | }); 37 | 38 | })) 39 | .pipe(rename(function (path) { path.basename += "-drawing"; })) 40 | .pipe(gulp.dest("examples")); 41 | 42 | }); 43 | 44 | gulp.task("example2", function () { 45 | 46 | gulp.src("test/fixtures/wikipedia.png") 47 | .pipe(gm(function (gmfile) { 48 | 49 | return gmfile.setFormat('jpg'); 50 | 51 | })) 52 | .pipe(gulp.dest("examples")); 53 | 54 | }); 55 | 56 | gulp.task("example3", function () { 57 | gulp.src("test/fixtures/wikipedia.png") 58 | .pipe(gm(function (gmfile) { 59 | return gmfile.blur(40); 60 | })) 61 | .pipe(rename(function (path) { path.basename += "-blur"; })) 62 | .pipe(gulp.dest("examples")); 63 | }); 64 | 65 | gulp.task("example4", function () { 66 | gulp.src("test/fixtures/wikipedia.png") 67 | .pipe(gm(function (gmfile) { 68 | return gmfile.resize(100, 100); 69 | })) 70 | .pipe(rename(function (path) { path.basename += "-resize"; })) 71 | .pipe(gulp.dest("examples")); 72 | }); 73 | 74 | gulp.task("example5", function () { 75 | gulp.src("test/fixtures/wikipedia.png") 76 | .pipe(gm(function (gmfile, done) { 77 | gmfile.size(function (err, size) { 78 | 79 | done(null, gmfile.resize( 80 | size.width * 0.5, 81 | size.height * 0.5 82 | )); 83 | 84 | }); 85 | })) 86 | .pipe(rename(function (path) { path.basename += "-resize2"; })) 87 | .pipe(gulp.dest("examples")); 88 | }); 89 | 90 | gulp.task("examples", [ 91 | "example1", 92 | "example2", 93 | "example3", 94 | "example4", 95 | "example5" 96 | ]); 97 | 98 | gulp.task("default", ["examples", "test"]); 99 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var gm = require("gm"); 2 | var through = require("through2"); 3 | var path = require("path"); 4 | var PluginError = require("plugin-error"); 5 | 6 | const PLUGIN_NAME = "gulp-gm"; 7 | 8 | var gulpGm = function (modifier, options) { 9 | 10 | if (!options) { 11 | options = {}; 12 | } 13 | 14 | var _gm = gm; 15 | 16 | if (options.imageMagick) { 17 | _gm = gm.subClass({ imageMagick : true }); 18 | } 19 | 20 | return through.obj(function (originalFile, enc, done) { 21 | 22 | var file = originalFile.clone({contents: false}); 23 | 24 | if (file.isNull()) { 25 | return done(null, file); 26 | } 27 | 28 | if (file.isStream()) { 29 | return done(new PluginError(PLUGIN_NAME, "Streaming not supported")); 30 | } 31 | 32 | var passthrough = through(); 33 | var gmFile = _gm(file.contents, file.path); 34 | 35 | 36 | var finish = function (err, modifiedGmFile) { 37 | if (err) { 38 | return done(new PluginError(PLUGIN_NAME, err.toString())); 39 | } else if (modifiedGmFile == null) { 40 | return done(new PluginError(PLUGIN_NAME, "Modifier callback didn't return anything.")); 41 | } else { 42 | modifiedGmFile.toBuffer(function (err, buffer) { 43 | if (err) { 44 | return done(new PluginError(PLUGIN_NAME, err)); 45 | } else { 46 | if (modifiedGmFile._outputFormat) { 47 | file.path = file.path.replace(path.extname(file.path), "." + modifiedGmFile._outputFormat); 48 | } 49 | file.contents = buffer; 50 | done(null, file); 51 | } 52 | }); 53 | } 54 | }; 55 | 56 | if (modifier.length === 2) { 57 | modifier(gmFile, finish); 58 | } else { 59 | finish(null, modifier(gmFile)); 60 | } 61 | 62 | }); 63 | 64 | }; 65 | 66 | gulpGm.imageMagick = function (modifier, options) { 67 | 68 | if (!options) { 69 | options = {}; 70 | } 71 | options.imageMagick = true; 72 | 73 | return gulpGm(modifier, options); 74 | }; 75 | 76 | module.exports = gulpGm; 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-gm", 3 | "version": "0.0.9", 4 | "description": "Image manipulation with GraphicsMagick for gulp.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "gulp test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/scalableminds/gulp-gm.git" 12 | }, 13 | "keywords": [ 14 | "gulpplugin", 15 | "gulpfriendly", 16 | "graphicsmagick", 17 | "image" 18 | ], 19 | "author": "Norman Rzepka (http://scm.io)", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/scalableminds/gulp-gm/issues" 23 | }, 24 | "homepage": "https://github.com/scalableminds/gulp-gm", 25 | "dependencies": { 26 | "gm": "^1.14.2", 27 | "plugin-error": "^1.0.1", 28 | "through2": "^0.4.1" 29 | }, 30 | "devDependencies": { 31 | "gulp-mocha": "^0.4.1", 32 | "gulp": "^3.5.5", 33 | "jshint-stylish": "^0.1.5", 34 | "gulp-jshint": "^1.5.0", 35 | "gulp-rename": "^1.2.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/fixtures/wikipedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalableminds/gulp-gm/c083918edb87edfb668b1c2ded4e7a0f5edb0140/test/fixtures/wikipedia.png -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*global describe, it, before, beforeEach, after, afterEach */ 2 | 3 | var assert = require("assert"); 4 | var fs = require("fs"); 5 | var path = require("path"); 6 | var gm = require("gm"); 7 | var util = require("gulp-util"); 8 | var File = util.File; 9 | 10 | var gulpGm = require("../index"); 11 | 12 | 13 | var fixtureFile = function () { 14 | return new File({ 15 | path : "test/fixtures/wikipedia.png", 16 | contents : fs.readFileSync("test/fixtures/wikipedia.png") 17 | }); 18 | }; 19 | 20 | var checkImageSize = function (stream, done, sizes) { 21 | 22 | if (!sizes) { 23 | sizes = [ 100, 91 ]; 24 | } 25 | 26 | stream.on("data", function(file) { 27 | 28 | gm(file.contents).size(function (err, features) { 29 | assert.equal(features.width, sizes[0]); 30 | assert.equal(features.height, sizes[1]); 31 | done(); 32 | }); 33 | 34 | }); 35 | 36 | stream.write(fixtureFile()); 37 | 38 | }; 39 | 40 | 41 | it('should work', function (done) { 42 | 43 | var stream = gulpGm(function (gmfile) { 44 | return gmfile 45 | .resize(100, 100); 46 | }); 47 | 48 | checkImageSize(stream, done); 49 | 50 | }); 51 | 52 | 53 | it('should work with ImageMagick', function (done) { 54 | 55 | var stream = gulpGm(function (gmfile) { 56 | return gmfile 57 | .resize(100, 100); 58 | }, { 59 | imageMagick : true 60 | }); 61 | 62 | checkImageSize(stream, done); 63 | 64 | }); 65 | 66 | it('should work async', function (done) { 67 | 68 | var stream = gulpGm(function (gmfile, done) { 69 | 70 | process.nextTick(function () { 71 | done(null, gmfile.resize(100, 100)); 72 | }); 73 | 74 | }); 75 | 76 | checkImageSize(stream, done); 77 | 78 | }); 79 | 80 | 81 | it('should work with size checking', function (done) { 82 | 83 | var stream = gulpGm(function (gmfile, done) { 84 | 85 | gmfile.size(function (err, features) { 86 | assert.equal(features.width, 500); 87 | assert.equal(features.height, 456); 88 | done(null, gmfile.resize( 89 | features.width * 0.5, 90 | features.height * 0.5)); 91 | }); 92 | 93 | }); 94 | 95 | checkImageSize(stream, done, [ 250, 228 ]); 96 | 97 | }); 98 | 99 | it('should resize with percentage options', function (done) { 100 | 101 | var stream = gulpGm(function (gmfile, done) { 102 | 103 | gmfile.size(function (err, features) { 104 | assert.equal(features.width, 500); 105 | assert.equal(features.height, 456); 106 | done(null, gmfile.resize("50%", "50%")); 107 | }); 108 | 109 | }); 110 | 111 | checkImageSize(stream, done, [ 250, 228 ]); 112 | 113 | }); 114 | 115 | it('should crop with percentage options', function (done) { 116 | 117 | var stream = gulpGm(function (gmfile, done) { 118 | 119 | gmfile.size(function (err, features) { 120 | assert.equal(features.width, 500); 121 | assert.equal(features.height, 456); 122 | done(null, gmfile.crop("50%", "50%", 0, 0)); 123 | }); 124 | 125 | }); 126 | 127 | checkImageSize(stream, done, [ 250, 228 ]); 128 | 129 | }); 130 | 131 | it('should convert png to jpg', function (done) { 132 | 133 | var stream = gulpGm(function (gmfile) { 134 | 135 | return gmfile.setFormat("jpg"); 136 | 137 | }); 138 | 139 | stream.on('data', function (file) { 140 | assert.equal(path.extname(file.path), ".jpg"); 141 | done(); 142 | }); 143 | 144 | stream.write(fixtureFile()); 145 | 146 | }); 147 | --------------------------------------------------------------------------------