grunt-responsive-images
Advanced tools
Comparing version 0.0.7 to 0.1.0
152
Gruntfile.js
@@ -42,2 +42,18 @@ /* | ||
options: { | ||
sizes: [{ | ||
aspectRatio: false, | ||
height: 240, | ||
name: 'small', | ||
width: 320 | ||
},{ | ||
aspectRatio: false, | ||
height: 480, | ||
name: 'medium', | ||
width: 640 | ||
},{ | ||
aspectRatio: false, | ||
height: 768, | ||
name: 'large', | ||
width: 1024 | ||
}] | ||
}, | ||
@@ -56,10 +72,10 @@ files: [{ | ||
name: "small", | ||
quality: 0.4 | ||
quality: 40 | ||
},{ | ||
width: 220, | ||
quality: 1 | ||
quality: 100 | ||
},{ | ||
width: 330, | ||
name: "large", | ||
quality: 0.8 | ||
quality: 80 | ||
},{ | ||
@@ -69,3 +85,3 @@ width: 660, | ||
suffix: "_x2", // retina gfx | ||
quality: 0.5 | ||
quality: 50 | ||
}] | ||
@@ -80,9 +96,125 @@ }, | ||
}, | ||
pixel_sizes: { | ||
options: { | ||
sizes: [{ | ||
aspectRatio: false, | ||
width: '10px' | ||
},{ | ||
aspectRatio: false, | ||
height: '50px', | ||
width: '50px' | ||
},{ | ||
aspectRatio: false, | ||
height: '500px', | ||
width: '200px' | ||
}] | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: ['pixel_sizes/**/*.{jpg,gif,png}'], | ||
cwd: 'test/assets/', | ||
dest: 'tmp/' | ||
}] | ||
}, | ||
pixel_sizes_custom_unit: { | ||
options: { | ||
units: { | ||
pixel: 'abc123' | ||
}, | ||
sizes: [{ | ||
aspectRatio: false, | ||
width: '20px', | ||
},{ | ||
aspectRatio: false, | ||
height: '50px', | ||
width: '80px', | ||
},{ | ||
aspectRatio: false, | ||
height: '500px', | ||
width: '500px' | ||
}] | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: ['pixel_sizes_custom_unit/**/*.{jpg,gif,png}'], | ||
cwd: 'test/assets/', | ||
dest: 'tmp/' | ||
}] | ||
}, | ||
percentage_sizes: { | ||
options: { | ||
sizes: [{ | ||
width: '10%', | ||
},{ | ||
height: '50%', | ||
width: '50%', | ||
},{ | ||
height: '80%', | ||
width: '200%' | ||
}] | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: ['percentage_sizes/**/*.{jpg,gif,png}'], | ||
cwd: 'test/assets/', | ||
dest: 'tmp/' | ||
}] | ||
}, | ||
percentage_sizes_custom_unit: { | ||
options: { | ||
units: { | ||
percentage: 'abc123' | ||
}, | ||
sizes: [{ | ||
width: '10%', | ||
},{ | ||
height: '50%', | ||
width: '50%', | ||
},{ | ||
height: '80%', | ||
width: '200%' | ||
}] | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: ['percentage_sizes_custom_unit/**/*.{jpg,gif,png}'], | ||
cwd: 'test/assets/', | ||
dest: 'tmp/' | ||
}] | ||
}, | ||
custom_multiply_unit: { | ||
options: { | ||
units: { | ||
multiply: 'abc123' | ||
}, | ||
sizes: [{ | ||
width: '10%', | ||
},{ | ||
height: '50%', | ||
width: '50%', | ||
},{ | ||
height: '450px', | ||
width: '800px' | ||
}] | ||
}, | ||
files: [{ | ||
expand: true, | ||
src: ['custom_multiply_unit/**/*.{jpg,gif,png}'], | ||
cwd: 'test/assets/', | ||
dest: 'tmp/' | ||
}] | ||
}, | ||
custom_dest_width: { | ||
options: { | ||
sizes: [{ | ||
aspectRatio: false, | ||
upscale: true, | ||
width: 320 | ||
},{ | ||
aspectRatio: false, | ||
upscale: true, | ||
width: 640 | ||
},{ | ||
aspectRatio: false, | ||
upscale: true, | ||
width: 1024 | ||
@@ -121,8 +253,8 @@ }] | ||
sizes: [{ | ||
width: 320, | ||
},{ | ||
width: 640, | ||
},{ | ||
width: 1024, | ||
}] | ||
width: 320 | ||
},{ | ||
width: 640 | ||
},{ | ||
width: 1024 | ||
}] | ||
}, | ||
@@ -129,0 +261,0 @@ files: [{ |
{ | ||
"name": "grunt-responsive-images", | ||
"description": "Produces images at different sizes", | ||
"version": "0.0.7", | ||
"description": "Produce images at different sizes for responsive websites.", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/andismith/grunt-responsive-images", | ||
@@ -32,6 +32,7 @@ "author": { | ||
"dependencies": { | ||
"async": "~0.2.8", | ||
"gm": "~1.14.2", | ||
"grunt": "~0.4.1", | ||
"lodash": "~1.0.0", | ||
"node-imagemagick": "~0.1.8", | ||
"async": "~0.2.8", | ||
"grunt": "~0.4.1" | ||
"node-imagemagick": "~0.1.8" | ||
}, | ||
@@ -41,7 +42,18 @@ "devDependencies": { | ||
"grunt-contrib-clean": "~0.4.0", | ||
"grunt-contrib-nodeunit": "~0.2.0" | ||
"grunt-contrib-nodeunit": "~0.2.0", | ||
"q": "~0.9.7" | ||
}, | ||
"keywords": [ | ||
"gruntplugin" | ||
"grunt", | ||
"gruntplugin", | ||
"img", | ||
"image", | ||
"images", | ||
"picturefill", | ||
"responsive", | ||
"responsivedesign", | ||
"srcset", | ||
"imagemagick", | ||
"graphicsmagick" | ||
] | ||
} |
212
README.md
@@ -1,2 +0,2 @@ | ||
# grunt-responsive-images [![NPM version](https://badge.fury.io/js/grunt-responsive-images.png)](http://badge.fury.io/js/grunt-responsive-images) | ||
# grunt-responsive-images [![NPM version](https://badge.fury.io/js/grunt-responsive-images.png)](http://badge.fury.io/js/grunt-responsive-images) [![Travis-CI Build](https://api.travis-ci.org/andismith/grunt-responsive-images.png?branch=master)](https://travis-ci.org/andismith/grunt-responsive-images) | ||
@@ -6,3 +6,3 @@ > Produces images at different sizes | ||
## Getting Started | ||
This plugin requires Grunt `~0.4.0` | ||
This plugin requires Grunt `~0.4.0`. | ||
@@ -15,9 +15,19 @@ If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: | ||
You'll also need to install Imagemagick CLI Tools. | ||
You also need to install either GraphicsMagick or Imagemagick CLI tools. | ||
**Installing GraphicsMagick (Recommended)** | ||
```shell | ||
brew install GraphicsMagick | ||
``` | ||
Otherwise, please visit the [GraphicsMagick downloads page](http://sourceforge.net/projects/graphicsmagick/files/graphicsmagick/). | ||
**Or installing ImageMagick** | ||
If you're a Mac user and have [Homebrew](http://brew.sh/) installed, simply type: | ||
```shell | ||
brew install ImageMagick | ||
``` | ||
Otherwise, please visit the [ImageMagick downloads page](http://www.imagemagick.org/script/binary-releases.php). | ||
Once both the plugin and ImageMagick have been installed, it may be enabled inside your Gruntfile with this line of JavaScript: | ||
Once both the plugin and graphics engine have been installed, it may be enabled inside your Gruntfile with this line of JavaScript: | ||
@@ -28,2 +38,5 @@ ```js | ||
## Important | ||
v0.1.0 changes some of the default settings for Grunt Responsive Images. Before updating, please ensure you check the readme for changes. | ||
## The "responsive_images" task | ||
@@ -37,4 +50,2 @@ | ||
Some slides about the plugin are [available here](http://slid.es/andismith/grunt-responsive-images). | ||
In your project's Gruntfile, add a section named `responsive_images` to the data object passed into `grunt.initConfig()`. | ||
@@ -57,44 +68,129 @@ | ||
#### options.sizes | ||
Type: `Array` | ||
* **options.engine**<br /> | ||
*Type:* `String`<br /> | ||
*Default:* `gm`<br /> | ||
*Available Values:* `gm` || `im`<br /> | ||
*Version:* 0.1.0 and above | ||
Default value: | ||
Chooses which graphics engine to use when resizing images. To use GraphicsMagick, set this to `gm`. To use ImageMagick, set this to `im`. You'll need the relevant engine installed. | ||
```js | ||
[{ | ||
name: "small", | ||
width: 320, | ||
height: 240, | ||
quality: 1 | ||
* **options.sizes**<br /> | ||
*Type:* `Array`<br /> | ||
*Default:* `[{ name: 'small', width: 320 },{ name: 'medium', width: 640 },{ name: 'large', width: 1024 }]`<br /> | ||
*Version:* 0.0.1 and above | ||
An array of objects containing the sizes and settings we want to resize our image to. | ||
For example: | ||
```js | ||
sizes: [{ | ||
name: "small", | ||
width: 480 | ||
},{ | ||
name: "medium", | ||
width: 640, | ||
height: 480, | ||
quality: 1 | ||
},{ | ||
name: "large", | ||
width: 1024, | ||
height: 768, | ||
quality: 1 | ||
}] | ||
name: "large", | ||
width: 1024 | ||
}] | ||
``` | ||
An array of objects containing the sizes we want to resize our image to. | ||
The settings available are as follows: | ||
If both width and height are specified, then the image will be resized and cropped. | ||
* **width**<br /> | ||
*Type:* `Number` or `String`<br /> | ||
*Version:* 0.0.1 and above | ||
If a `name` is specified, then the file will be suffixed with this name. e.g. my-image-small.jpg | ||
`width` can either be in pixels or percentages. Please note both width and height need to use the same units, so if width is a percentage value and you wish to specify a height this must also be a percentage. | ||
If a `name` is not specified, then the file will be suffixed with the width and/or height. e.g. my-image-320x240.jpg | ||
The following values are examples of valid widths: `1`, `'1px'`, `'1'`, `'1%'`, `'1.1%'`, `'11.11111%'`, `'111111%'`<br /> | ||
The following values are examples of invalid values for width: `-1`, `1.1`, `1.1px`, `'1.1.1%'`, `'1a'`, `'a1'` | ||
Use `suffix` for retina graphic filenames. e.g. my-image-320x240_x2.jpg | ||
* **height**<br /> | ||
*Type:* `Number` or `String`<br /> | ||
*Version:* 0.0.1 and above | ||
Use `quality` to change the quality of an image (0.1, 0.2 ... 0.9, 1). | ||
`height` can either be in pixels or percentages. Please note both width and height need to use the same units, so if height is a percentage value and you wish to specify a width this must also be a percentage.<br /> | ||
`height` accepts the same values as width. | ||
#### options.separator | ||
Type: `String` | ||
Default value: `-` | ||
* **name**<br /> | ||
*Type:* `String`<br /> | ||
*Default:* none<br /> | ||
*Version:* 0.0.1 and above | ||
The character used to separate the image filename from the size name. | ||
If a `name` is specified, then the file will be suffixed with this name. e.g. `my-image-small.jpg`<br /> | ||
If a `name` is not specified, then the file will be suffixed with the width and/or height specified in the size options. e.g. `my-image-320x240.jpg` | ||
* **quality**<br /> | ||
*Type:* `Number`<br /> | ||
*Default:* `100`<br /> | ||
*Available Values:* `1` - `100`<br /> | ||
*Version:* 0.0.4 and above | ||
JPEG format only. The quality of the image, 100 being the highest quality and 1 being the lowest. | ||
Please note: In versions below 0.1.0, quality is specified between 0 and 1. | ||
* **suffix**<br /> | ||
*Type:* `String`<br /> | ||
*Default:* none<br /> | ||
*Version:* 0.0.1 and above | ||
Use `suffix` for retina graphic filenames. e.g. `my-image-320x240_x2.jpg` | ||
* **aspectRatio**<br /> | ||
*Type:* `Boolean`<br /> | ||
*Default:* `true`<br /> | ||
*Available Values:* `true` || `false`<br /> | ||
*Version:* 0.1.0 and above | ||
Maintains the aspect ratio of the image. The width and the height are treated as maximum values, | ||
so the image is expanded or contracted to fit the width and height value while maintaining the aspect ratio of the image. | ||
If `aspectRatio` is set to `false` and both width and height are specified, the image will be cropped. | ||
* **gravity**<br /> | ||
*Type:* `String`<br /> | ||
*Default:* `Center`<br /> | ||
*Available Values:* `NorthWest` || `North` || `NorthEast` || `West` || `Center` || `East` || `SouthWest` || `South` || `SouthEast`<br /> | ||
*Version:* 0.1.0 and above | ||
`gravity` determines the placement of the image within the crop. The default is `Center`. | ||
This setting only applies if an image is cropped. Cropping occurs when the aspectRatio is set to `false` and both width and height are specified. | ||
* **upscale**<br /> | ||
*Type:* `Boolean`<br /> | ||
*Default:* `false`<br /> | ||
*Available Values:* `true` || `false`<br /> | ||
*Version:* 0.1.0 and above. | ||
If the requested size is larger than the source image should the image be upscaled? | ||
* **options.separator**<br /> | ||
*Type:* `String`<br /> | ||
*Default:* `-`<br /> | ||
*Version:* 0.0.1 and above | ||
The character used to separate the image filename from the size name. | ||
* **options.units**<br /> | ||
*Type:* 'Object'<br /> | ||
*Default:* `{ percentage: 'pc', pixel: '', multiply: 'x' }`<br /> | ||
*Version:* 0.0.1 and above | ||
'units' contains the strings that should be used to represent the size units in an image 'name' when `name` has not been specified. e.g. `my-image-50pcx50pc.jpg` | ||
* **pixel** | ||
*Type:* `String`<br /> | ||
*Default:* ``<br /> | ||
*Version:* 0.0.1 and above | ||
* **percentage** | ||
*Type:* `String`<br /> | ||
*Default:* `pc`<br /> | ||
*Version:* 0.0.1 and above | ||
Please note `%` cannot be used as a valid character in an image name. | ||
* **multiply** | ||
*Type:* `String`<br /> | ||
*Default:* `x`<br /> | ||
*Version:* 0.0.1 and above | ||
### Usage Examples | ||
@@ -136,3 +232,3 @@ | ||
suffix: "_x2", | ||
quality: 0.6 | ||
quality: 60 | ||
}] | ||
@@ -199,14 +295,34 @@ }, | ||
* *Receiving a `fatal error: spawn ENOENT`* - Ensure Imagemagick CLI tools are installed. Try uninstalling and reinstalling them if you are having issues. | ||
* **I'm receiving a `fatal error: spawn ENOENT` error. Any ideas?** | ||
## Contributing | ||
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). | ||
Ensure either Graphicsmagick or Imagemagick tools are installed, and that you are using the correct engine in your Grunt file options. The default engine is Graphicsmagick. If you'd rather use Imagemagick, the engine value should be changed to `im` as documented above. | ||
Try uninstalling and reinstalling Graphicsmagick or Imagemagick if you are having issues. | ||
* **How do I only process recently added images?** | ||
Use this task in combination with [Grunt Newer](https://npmjs.org/package/grunt-newer). | ||
## Release History | ||
*0.0.6* | ||
*0.1.0* | ||
* Added path value to custom_dest to allow for persistent directory structures (thanks to [maslen](https://github.com/maslen)) | ||
* Started list of sites using Grunt Responsive Images plugin (contact [@andismith](http://www.twitter.com/andismith) to add yours) | ||
* Added [GraphicsMagick](http://www.graphicsmagick.org/)! GraphicsMagick is now the default imaging library, although it easy to change to ImageMagick if you'd prefer. | ||
* Added percentage re-sizing! Specify percentage sizes as strings, like this: '42%'. A percentage dimension cannot be mixed with a pixel dimension as the graphics engines do not allow it, sorry. | ||
* Keep aspect ratios, so your images are no longer squished or cropped by default. | ||
* More control over cropping images with gravity. | ||
* Customise units! Added pixel (default: ''), percentage (default: 'pc') and multiply (default: 'x') units. | ||
* Now handles missing configuration target more gracefully. | ||
* Complete re-write of the plugin's unit tests. No more failing Travis builds! | ||
* Re-write of quite a lot of the plugin itself! | ||
* Added nice JSDoc comments :) | ||
* Removed height values from default. If you used the default settings, you'll need to update your configuration. | ||
* Added Flux Capacitor. | ||
*0.0.7* | ||
* Added path value to custom_dest to allow for persistent directory structures. | ||
* Started list of sites using Grunt Responsive Images plugin ([contact @andismith](http://www.twitter.com/andismith) to add yours). | ||
* Said goodbye to the dolphins. | ||
*0.0.5* | ||
@@ -219,5 +335,5 @@ | ||
* Fixed issue with quality setting not producing correct quality output. (thanks to [pdud](https://github.com/pdud)). | ||
* Reduced the amount of logging when running the task (thanks to [tnguyen](https://github.com/tnguyen14)). | ||
* Allowed images of different sizes to be uploaded to different directories with custom_dest (thanks to [maslen](https://github.com/maslen) and [oncletom](https://github.com/oncletom)). | ||
* Fixed issue with quality setting not producing correct quality output. | ||
* Reduced the amount of logging when running the task. | ||
* Allowed images of different sizes to be uploaded to different directories with custom_dest. | ||
@@ -236,4 +352,6 @@ *0.0.3* | ||
## Roadmap | ||
## Contributing | ||
* The ability to resize images by a percentage of their original size. | ||
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). | ||
Thanks to [all the contributors](https://github.com/andismith/grunt-responsive-images/graphs/contributors) who've submitted a pull request; and everyone who's raised issues or contributed to issue resolution. |
@@ -1,7 +0,12 @@ | ||
/* | ||
/** | ||
* grunt-responsive-images | ||
* https://github.com/andismith/grunt-responsive-images | ||
* | ||
* Copyright (c) 2013 andismith | ||
* Copyright (c) 2014 andismith | ||
* Licensed under the MIT license. | ||
* | ||
* Create images at different sizes for responsive websites. | ||
* | ||
* @author Andi Smith (http://twitter.com/andismith) | ||
* @version 0.1.0 | ||
*/ | ||
@@ -11,169 +16,417 @@ | ||
var _ = require('lodash'), | ||
im = require('node-imagemagick'), | ||
async = require('async'), | ||
path = require('path'); | ||
module.exports = function(grunt) { | ||
var DEFAULT_OPTIONS = { | ||
var _ = require('lodash'); | ||
var async = require('async'); | ||
var gm = require('gm'); | ||
var path = require('path'); | ||
var DEFAULT_OPTIONS = { | ||
engine: 'gm', // gm or im - DEFAULT CHANGED | ||
separator: '-', | ||
sizes: [{ | ||
name: 'small', | ||
width: 320, | ||
height: 240 | ||
},{ | ||
name: 'medium', | ||
width: 640, | ||
height: 480 | ||
},{ | ||
name: 'large', | ||
width: 1024, | ||
height: 768 | ||
}] | ||
name: 'small', | ||
width: 320 | ||
},{ | ||
name: 'medium', | ||
width: 640 | ||
},{ | ||
name: 'large', | ||
width: 1024 | ||
}] | ||
}; | ||
// check if there are any items in our array | ||
function isValidArray(obj) { | ||
return (_.isArray(obj) && obj.length > 0); | ||
} | ||
var DEFAULT_SIZE_OPTIONS = { | ||
aspectRatio: true, // DEFAULT CHANGED - maintain the aspect ratio of the image (when width and height are supplied) | ||
gravity: 'Center', // gravity for cropped images: NorthWest, North, NorthEast, West, Center, East, SouthWest, South, or SouthEast | ||
quality: 100, // value between 1 and 100 | ||
upscale: false // DEFAULT CHANGED - true/false | ||
}; | ||
// check whether we've been given any valid size values | ||
function isValidSize(obj) { | ||
return (_.isNumber(obj.width) || _.isNumber(obj.height)); | ||
} | ||
var DEFAULT_UNIT_OPTIONS = { | ||
percentage: 'pc', | ||
pixel: '', | ||
multiply: 'x' | ||
}; | ||
// create a name to suffix to our file. | ||
function getName(name, width, height, separator, suffix) { | ||
// details about the GFX rendering engines being used | ||
var GFX_ENGINES = { | ||
im: { | ||
name: 'ImageMagick', | ||
brewurl: 'imagemagick', | ||
url: 'http://www.imagemagick.org/script/binary-releases.php', | ||
alternative: { | ||
code: 'gm', | ||
name: 'GraphicsMagick' | ||
} | ||
}, | ||
gm: { | ||
name: 'GraphicsMagick', | ||
brewurl: 'graphicsmagick', | ||
url: 'http://www.graphicsmagick.org/download.html', | ||
alternative: { | ||
code: 'im', | ||
name: 'ImageMagick' | ||
} | ||
} | ||
}; | ||
// handle empty separator as no separator | ||
if (typeof separator === 'undefined') { | ||
separator = ''; | ||
/** | ||
* Set the engine to ImageMagick or GraphicsMagick | ||
* | ||
* @private | ||
* @param {string} engine im for ImageMagick, gm for GraphicsMagick | ||
*/ | ||
var setEngine = function(engine) { | ||
if (typeof GFX_ENGINES[engine] === 'undefined') { | ||
return grunt.fail.warn('Invalid render engine specified'); | ||
} | ||
grunt.verbose.ok('Using render engine: ' + GFX_ENGINES[engine].name); | ||
gm.subClass({ imageMagick: (engine === 'im') }); | ||
}; | ||
// handle empty suffix as no suffix | ||
if (typeof suffix === 'undefined') { | ||
suffix = ''; | ||
/** | ||
* Checks for a valid array, and that there are items in the array. | ||
* | ||
* @private | ||
* @param {object} obj The object to check | ||
* @return {boolean} Whether it is a valid array with items. | ||
*/ | ||
var isValidArray = function(obj) { | ||
return (_.isArray(obj) && obj.length > 0); | ||
}; | ||
/** | ||
* Checks for a valid width and/or height. | ||
* We do not need both - one is sufficient, but if a value is supplied it must be a valid value. | ||
* If width is a percentage, height must also be a percentage - they cannot be mixed. | ||
* | ||
* @private | ||
* @param {number/string} width The width, either as a number or a percentage (or as undefined) | ||
* @param {number/string} height The height, either as a number or a percentage (or as undefined) | ||
* @return {boolean} Whether the size is valid. | ||
*/ | ||
var isValidSize = function(width, height) { | ||
// Valid values = 1, '1px', '1', '1%', '1.1%', '11.11111%', '111111%' | ||
// Invalid values = -1, '1.1.1%', '1a', 'a1' | ||
var pcRegExp = /^[0-9]*\.?[0-9]+%?$/, | ||
pxRegExp = /^[0-9]+(?:px)?$/, | ||
isValid = false; | ||
if ((width || height)) { | ||
// check if we have a valid percentage value | ||
if (!!(width || 0).toString().match(pcRegExp) && | ||
!!(height || 0).toString().match(pcRegExp)) { | ||
isValid = true; | ||
// check if we have a valid pixel value | ||
} else if (!!(width || 0).toString().match(pxRegExp) && | ||
!!(height || 0).toString().match(pxRegExp)) { | ||
isValid = true; | ||
} else { | ||
grunt.log.error('Width/height value is not valid. Percentages and pixels cannot be mixed.'); | ||
} | ||
} else { | ||
grunt.log.error('Either width and/or height must be specified.'); | ||
} | ||
if (name) { | ||
return separator + name + suffix; | ||
return isValid; | ||
}; | ||
/** | ||
* Create a name to suffix to our file. | ||
* | ||
* @private | ||
* @param {object} properties Contains properties for name, width, height (where applicable) | ||
* @return {string} A new name | ||
*/ | ||
var getName = function(properties, options) { | ||
//name, width, height, separator, suffix | ||
var filename = '', | ||
widthUnit = '', | ||
heightUnit = ''; | ||
// name takes precedence | ||
if (properties.name) { | ||
return properties.name; | ||
} else { | ||
if (width && height) { | ||
return separator + width + 'x' + height + suffix; | ||
// figure out the units for width and height (they can be different) | ||
widthUnit = ((properties.width || 0).toString().indexOf('%') > 0) ? options.units.percentage : options.units.pixel; | ||
heightUnit = ((properties.height || 0 ).toString().indexOf('%') > 0) ? options.units.percentage : options.units.pixel; | ||
if (properties.width && properties.height) { | ||
return parseFloat(properties.width) + widthUnit + options.units.multiply + parseFloat(properties.height) + heightUnit; | ||
} else { | ||
return separator + (width || height) + suffix; | ||
return (properties.width) ? parseFloat(properties.width) + widthUnit : parseFloat(properties.height) + heightUnit; | ||
} | ||
} | ||
} | ||
}; | ||
grunt.registerMultiTask('responsive_images', 'Images at various responsive sizes', function() { | ||
// Merge task-specific and/or target-specific options with these defaults. | ||
/** | ||
* Add a prefix and/or a suffix to a value. | ||
* | ||
* @private | ||
* @param {string} value The value to prefix/suffix | ||
* @param {string} prefix The required prefix (optional) | ||
* @param {string} suffix The required suffix (optional) | ||
*/ | ||
var addPrefixSuffix = function(value, prefix, suffix) { | ||
return (prefix || '') + value + (suffix || ''); | ||
}; | ||
/** | ||
* Check the target has been set up properly in Grunt. | ||
* Graceful handling of https://github.com/andismith/grunt-responsive-images/issues/2 | ||
* | ||
* @private | ||
* @param {object} files The files object | ||
*/ | ||
var checkForValidTarget = function(files) { | ||
var test; | ||
try { | ||
test = files.src; | ||
} catch (exception) { | ||
grunt.fail.fatal('Unable to read configuration.\n' + | ||
'Have you specified a target? See: http://gruntjs.com/configuring-tasks'); | ||
} | ||
}; | ||
/** | ||
* Check that there is only one source file in compact/files object format. | ||
* | ||
* @private | ||
* @param {object} files The files object | ||
*/ | ||
var checkForSingleSource = function(files) { | ||
// more than 1 source. | ||
if (files.src.length > 1) { | ||
return grunt.fail.warn('Unable to resize more than one image in compact or files object format.\n'+ | ||
'For multiple files please use the files array format.\nSee http://gruntjs.com/configuring-tasks'); | ||
} | ||
}; | ||
/** | ||
* Check if a directory exists, and create it if it doesn't. | ||
* | ||
* @private | ||
* @param {string} dirPath The path we want to check | ||
*/ | ||
var checkDirectoryExists = function(dirPath) { | ||
if (!grunt.file.isDir(dirPath)) { | ||
grunt.file.mkdir(dirPath); | ||
} | ||
}; | ||
/** | ||
* Removes characters from the values of the object keys specified | ||
* | ||
* @private | ||
* @param {object} obj The object to inspect. | ||
* @param {array} keys The keys to check the values of. | ||
* @param {string} remove The string to remove. | ||
*/ | ||
var removeCharsFromObjectValue = function(obj, keys, remove) { | ||
var i = 0, | ||
l = keys.length; | ||
for (i = 0; i < l; i++) { | ||
if (obj[keys[i]] && obj[keys[i]].toString().indexOf(remove) > -1) { | ||
obj[keys[i]] = obj[keys[i]].toString().replace(remove, ''); | ||
} | ||
} | ||
return obj; | ||
}; | ||
/** | ||
* Handle showing errors to the user. | ||
* | ||
* @private | ||
* @param {string} error The error message. | ||
* @param {string} engine The graphics engine being used. | ||
*/ | ||
var handleImageErrors = function(error, engine) { | ||
if (error.message.indexOf('ENOENT') > -1) { | ||
grunt.log.error(error.message); | ||
grunt.fail.warn('\nPlease ensure ' + GFX_ENGINES[engine].name + ' is installed correctly.\n' + | ||
'`brew install ' + GFX_ENGINES[engine].brewurl + '` or see ' + GFX_ENGINES[engine].url + ' for more details.\n' + | ||
'Alternatively, set options.engine to \'' + GFX_ENGINES[engine].alternative.code + '\' to use ' + GFX_ENGINES[engine].alternative.name + '.\n'); | ||
} else { | ||
grunt.fail.warn(error.message); | ||
} | ||
}; | ||
/** | ||
* Outputs the result of the tally. | ||
* | ||
* @private | ||
* @param {number} count The file count. | ||
* @param {string} name Name of the image. | ||
*/ | ||
var outputResult = function(count, name) { | ||
if (count) { | ||
grunt.log.writeln('Resized ' + count.toString().cyan + ' ' + | ||
grunt.util.pluralize(count, 'file/files') + ' for ' + name); | ||
} | ||
}; | ||
/** | ||
* Gets the destination path | ||
* | ||
* @private | ||
* @param {string} srcPath The source path | ||
* @param {string} filename Image Filename | ||
* @param {object} sizeOptions | ||
* @param {string} customDest | ||
* @param {string} origCwd | ||
*/ | ||
var getDestination = function(srcPath, dstPath, sizeOptions, customDest, origCwd) { | ||
var baseName = '', | ||
dirName = '', | ||
extName = ''; | ||
extName = path.extname(dstPath); | ||
baseName = path.basename(srcPath, extName); // filename without extension | ||
if (customDest) { | ||
sizeOptions.path = srcPath.replace(new RegExp(origCwd), "").replace(new RegExp(path.basename(srcPath)+"$"), ""); | ||
grunt.template.addDelimiters('size', '{%', '%}'); | ||
dirName = grunt.template.process(customDest, { | ||
delimiters: 'size', | ||
data: sizeOptions | ||
}); | ||
checkDirectoryExists(path.join(dirName)); | ||
return path.join(dirName, baseName + extName); | ||
} else { | ||
dirName = path.dirname(dstPath); | ||
checkDirectoryExists(path.join(dirName)); | ||
return path.join(dirName, baseName + sizeOptions.outputName + extName); | ||
} | ||
}; | ||
// let's get this party started | ||
grunt.registerMultiTask('responsive_images', 'Create images at different sizes for responsive websites.', function() { | ||
var done = this.async(); | ||
var i = 0; | ||
var series = []; | ||
var options = this.options(DEFAULT_OPTIONS); | ||
var that = this; | ||
var options = this.options(DEFAULT_OPTIONS); // Merge task-specific and/or target-specific options with these defaults. | ||
var tally = {}; | ||
var task = this; | ||
if (!isValidArray(options.sizes)) { | ||
return grunt.fail.warn('No sizes have been defined.'); | ||
return grunt.fail.fatal('No sizes have been defined.'); | ||
} | ||
setEngine(options.engine); | ||
options.units = _.extend(_.clone(DEFAULT_UNIT_OPTIONS), options.units); | ||
options.sizes.forEach(function(s) { | ||
// consts | ||
var DEFAULT_SIZE_OPTIONS = { | ||
quality: 1 | ||
}; | ||
var sizeOptions = _.extend(_.clone(DEFAULT_SIZE_OPTIONS), s); | ||
// variable | ||
var sizeOptions = _.clone(_.extend(DEFAULT_SIZE_OPTIONS, s)); | ||
var sizingMethod = 'resize'; | ||
if (!isValidSize(s)) { | ||
return grunt.fail.warn('Size is invalid'); | ||
if (!isValidSize(sizeOptions.width, sizeOptions.height)) { | ||
return grunt.fail.fatal('Size is invalid (' + sizeOptions.width + ', ' + sizeOptions.height + ')'); | ||
} | ||
// use crop if both width and height are specified. | ||
if (s.width && s.height) { | ||
sizingMethod = 'crop'; | ||
if (sizeOptions.quality < 1) { | ||
return grunt.fail.warn('Quality configuration has changed to values between 1 - 100. Please update your configuration'); | ||
} | ||
// create a name suffix for our image, called outputName so we can still use name | ||
sizeOptions.outputName = getName(s.name, s.width, s.height, options.separator, s.suffix); | ||
sizeOptions.id = i; | ||
i++; | ||
// set name to outputName if one does not exist | ||
if (typeof sizeOptions.name === 'undefined') { | ||
sizeOptions.name = sizeOptions.outputName; | ||
} | ||
tally[sizeOptions.id] = 0; | ||
tally[sizeOptions.name] = 0; | ||
if (task.files.length === 0) { | ||
return grunt.fail.warn('Unable to compile; no valid source files were found.'); | ||
} else { | ||
// Iterate over all specified file groups. | ||
that.files.forEach(function(f) { | ||
// Iterate over all specified file groups. | ||
task.files.forEach(function(f) { | ||
var extName = path.extname(f.dest), | ||
srcPath = f.src[0], | ||
baseName = path.basename(srcPath, extName), // filename without extension | ||
dirName, | ||
dstPath, | ||
subDir = ""; | ||
var srcPath = '', | ||
dstPath = ''; | ||
if (f.custom_dest) { | ||
sizeOptions.path = f.src[0].replace(new RegExp(f.orig.cwd), "").replace(new RegExp(path.basename(srcPath)+"$"), ""); | ||
grunt.template.addDelimiters('size', '{%', '%}'); | ||
dirName = grunt.template.process(f.custom_dest, { | ||
delimiters: 'size', | ||
data: sizeOptions | ||
}); | ||
dstPath = path.join(dirName, subDir, baseName + extName); | ||
} | ||
checkForValidTarget(f); | ||
checkForSingleSource(f); | ||
else { | ||
dirName = path.dirname(f.dest); | ||
dstPath = path.join(dirName, subDir, baseName + sizeOptions.outputName + extName); | ||
} | ||
// create a name for our image based on name, width, height | ||
sizeOptions.name = getName({ name: sizeOptions.name, width: sizeOptions.width, height: sizeOptions.height }, options); | ||
var imageOptions = {}; | ||
// more than 1 source. | ||
if (f.src.length > 1) { | ||
return grunt.fail.warn('Unable to resize more than one image in compact or files object format.\n'+ | ||
'For multiple files please use the files array format.\nSee http://gruntjs.com/configuring-tasks'); | ||
} | ||
// create an output name with prefix, suffix | ||
sizeOptions.outputName = addPrefixSuffix(sizeOptions.name, options.separator, sizeOptions.suffix); | ||
// Make directory if it doesn't exist. | ||
if (!grunt.file.isDir(path.join(dirName, subDir))) { | ||
grunt.file.mkdir(path.join(dirName, subDir)); | ||
} | ||
srcPath = f.src[0]; | ||
dstPath = getDestination(srcPath, f.dest, sizeOptions, f.custom_dest, f.orig.cwd); | ||
imageOptions = { | ||
srcPath: srcPath, | ||
dstPath: dstPath, | ||
format: extName.replace('.', '') | ||
}; | ||
// remove pixels from the value so the gfx process doesn't complain | ||
sizeOptions = removeCharsFromObjectValue(sizeOptions, ['width', 'height'], 'px'); | ||
// combine image options with size options. | ||
imageOptions = _.extend(imageOptions, sizeOptions); | ||
series.push(function(callback) { | ||
series.push(function(callback) { | ||
im[sizingMethod](imageOptions, function(error, stdout, stderr) { | ||
if (error) { | ||
grunt.fail.warn(error.message); | ||
} else { | ||
grunt.verbose.ok('Responsive Image: ' + srcPath + ' now '+ dstPath); | ||
tally[sizeOptions.name]++; | ||
} | ||
return callback(); | ||
var image = gm(srcPath); | ||
image.size(function(error, size) { | ||
var sizingMethod = ''; | ||
var mode = 'resize'; | ||
if (error) { | ||
handleImageErrors(error, options.engine); | ||
} else { | ||
// crop image | ||
if (!sizeOptions.aspectRatio && sizeOptions.width && sizeOptions.height) { | ||
sizingMethod = '^'; | ||
mode = 'crop'; | ||
} | ||
// upscale | ||
if (sizeOptions.upscale && (sizeOptions.width > size.width || sizeOptions.height > size.height)) { | ||
sizingMethod = '^'; | ||
} | ||
image | ||
.resize(sizeOptions.width, sizeOptions.height, sizingMethod) | ||
.quality(sizeOptions.quality); | ||
if (mode === 'crop') { | ||
image | ||
.gravity(sizeOptions.gravity) | ||
.crop(sizeOptions.width, sizeOptions.height, 0, 0); | ||
} | ||
image.write(dstPath, function (error) { | ||
if (error) { | ||
handleImageErrors(error, options.engine); | ||
} else { | ||
grunt.verbose.ok('Responsive Image: ' + srcPath + ' now '+ dstPath); | ||
tally[sizeOptions.id]++; | ||
} | ||
return callback(); | ||
}); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
series.push(function(callback) { | ||
if (tally[sizeOptions.name]) { | ||
grunt.log.writeln('Created ' + tally[sizeOptions.name].toString().cyan + ' files for size ' + sizeOptions.name); | ||
} | ||
return callback(); | ||
}); | ||
series.push(function(callback) { | ||
outputResult(tally[sizeOptions.id], sizeOptions.name); | ||
return callback(); | ||
}); | ||
} | ||
}); | ||
@@ -183,2 +436,3 @@ | ||
}); | ||
}; | ||
}; |
@@ -1,6 +0,14 @@ | ||
'use strict'; | ||
/** | ||
* grunt-responsive-images | ||
* https://github.com/andismith/grunt-responsive-images | ||
* | ||
* Copyright (c) 2013 andismith | ||
* Licensed under the MIT license. | ||
* | ||
* Test suite for Grunt Responsive Images | ||
* | ||
* @author Andi Smith (http://twitter.com/andismith) | ||
* @version 1.0 | ||
*/ | ||
var grunt = require('grunt'), | ||
im = require('node-imagemagick'), | ||
async = require('async'); | ||
@@ -27,238 +35,241 @@ /* | ||
exports.responsive_images = { | ||
setUp: function(done) { | ||
// setup here if necessary | ||
done(); | ||
}, | ||
default_options: function(test) { | ||
(function() { | ||
'use strict'; | ||
var actual = {}, | ||
expected = {}; | ||
var async = require('async'), | ||
grunt = require('grunt'), | ||
im = require('node-imagemagick'), | ||
q = require('q'); | ||
var files = [{ | ||
filename: 'minions-small.jpg', | ||
expected: 'test/expected/default_options/', | ||
actual: 'tmp/default_options/' | ||
}, | ||
{ | ||
filename: 'minions-medium.jpg', | ||
expected: 'test/expected/default_options/', | ||
actual: 'tmp/default_options/' | ||
}, | ||
{ | ||
filename: 'minions-large.jpg', | ||
expected: 'test/expected/default_options/', | ||
actual: 'tmp/default_options/' | ||
}]; | ||
/** | ||
* Compare the created image against the expected image. | ||
* | ||
* @private | ||
* @param {string} filename The name of the file | ||
* @param {string} actual The actual file path | ||
* @param {string} expected The expected file path | ||
* @return {object} promise Either resolved rejected with an error message. | ||
*/ | ||
var compareImageProperties = function(filename, actualPath, expectedPath) { | ||
var deferred = q.defer(); | ||
// load created image | ||
im.identify(actualPath + filename, function(error, actualProp) { | ||
if (error) { | ||
deferred.reject('Failed to load actual (created) image "' + actualPath + filename + '"'); | ||
} else { | ||
// load expected image | ||
im.identify(expectedPath + filename, function(error, expectedProp) { | ||
if (error) { | ||
deferred.reject('Failed to load expected image "' + expectedPath + filename + '"'); | ||
} else { | ||
// check if we have a match | ||
if ((actualProp.compression === expectedProp.compression) && | ||
(actualProp.width === expectedProp.width) && | ||
(actualProp.height === expectedProp.height) && | ||
(actualProp.quality === expectedProp.quality)) { | ||
deferred.resolve(true); | ||
} else { | ||
deferred.reject(filename + ': ' + | ||
'actual image (' + actualProp.compression + ' ' + actualProp.width + | ||
'x' + actualProp.height + ' - Q:' + actualProp.quality + | ||
') and ' + | ||
'expected image (' + expectedProp.compression + ' ' + expectedProp.width + | ||
'x' + expectedProp.height + ' - Q:' + expectedProp.quality + | ||
') should match'); | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
return deferred.promise; | ||
}; | ||
test.expect(files.length); | ||
/** | ||
* Inspect and handle test results from inspecting an image | ||
* | ||
* @private | ||
* @param {object} file The file object | ||
* @param {object} test Test instance | ||
* @param {string} callback Async callback, to be run when the test is complete | ||
*/ | ||
var inspectImage = function(file, test, callback) { | ||
compareImageProperties(file.filename, file.actual, file.expected) | ||
.then(function(result) { | ||
test.ok(true); | ||
}, function(error) { | ||
test.ok(false, error); | ||
}) | ||
.done(function() { | ||
return callback(); | ||
}); | ||
}; | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
} | ||
test.done(); | ||
}, | ||
file_wildcard_options: function(test) { | ||
var actual = {}, | ||
expected = {}, | ||
series = []; | ||
var files = [{ | ||
filename: 'sonic-small.png', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'sonic-medium.png', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'sonic-large.png', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mario-yoshi-small.jpg', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mario-yoshi-medium.jpg', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mario-yoshi-large.jpg', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mickey-mouse-small.gif', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mickey-mouse-medium.gif', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}, | ||
{ | ||
filename: 'mickey-mouse-large.gif', | ||
expected: 'test/expected/file_wildcard_options/', | ||
actual: 'tmp/file_wildcard_options/' | ||
}]; | ||
/** | ||
* Run through the array of files and add them to the queue of images to be tested | ||
* | ||
* @private | ||
* @param {array} files List of files to check (with filename, expected and actual paths) | ||
* @param {object} test Test instance | ||
*/ | ||
var checkImages = function(actual, expected, files, test) { | ||
var series = [], | ||
file = {}; | ||
test.expect(files.length); | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
files.forEach(function(filename) { | ||
var file = { | ||
actual: actual, | ||
expected: expected, | ||
filename: filename | ||
}; | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
} | ||
series.push(function(callback) { | ||
inspectImage(file, test, callback); | ||
}); | ||
}); | ||
async.series(series, test.done); | ||
async.series(series, function() { | ||
test.done(); | ||
}); | ||
}; | ||
}, | ||
custom_options: function(test) { | ||
// List of tests to be run | ||
exports.responsive_images = { | ||
default_options: function(test) { | ||
var actualPath = 'tmp/default_options/', | ||
expectedPath = 'test/expected/default_options/', | ||
files = [ | ||
'minions-small.jpg', | ||
'minions-medium.jpg', | ||
'minions-large.jpg' | ||
]; | ||
var actual = {}, | ||
expected = {}; | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
file_wildcard_options: function(test) { | ||
var actualPath = 'tmp/file_wildcard_options/', | ||
expectedPath = 'test/expected/file_wildcard_options/', | ||
files = [ | ||
'sonic-small.png', | ||
'sonic-medium.png', | ||
'sonic-large.png', | ||
'mario-yoshi-small.jpg', | ||
'mario-yoshi-medium.jpg', | ||
'mario-yoshi-large.jpg', | ||
'mickey-mouse-small.gif', | ||
'mickey-mouse-medium.gif', | ||
'mickey-mouse-large.gif' | ||
]; | ||
var files = [{ | ||
filename: 'panther-small.jpg', | ||
expected: 'test/expected/custom_options/', | ||
actual: 'tmp/custom_options/' | ||
}, | ||
{ | ||
filename: 'panther-220.jpg', | ||
expected: 'test/expected/custom_options/', | ||
actual: 'tmp/custom_options/' | ||
},{ | ||
filename: 'panther-large.jpg', | ||
expected: 'test/expected/custom_options/', | ||
actual: 'tmp/custom_options/' | ||
}, | ||
{ | ||
filename: 'panther-large_x2.jpg', | ||
expected: 'test/expected/custom_options/', | ||
actual: 'tmp/custom_options/' | ||
}]; | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
custom_options: function(test) { | ||
var actualPath = 'tmp/custom_options/', | ||
expectedPath = 'test/expected/custom_options/', | ||
files = [ | ||
'panther-small.jpg', | ||
'panther-220.jpg', | ||
'panther-large.jpg', | ||
'panther-large_x2.jpg' | ||
]; | ||
test.expect(files.length); | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
pixel_sizes: function(test) { | ||
var actualPath = 'tmp/pixel_sizes/', | ||
expectedPath = 'test/expected/pixel_sizes/', | ||
files = [ | ||
'magikarp-10.png', | ||
'magikarp-50x50.png', | ||
'magikarp-200x500.png', | ||
'meowth-10.jpg', | ||
'meowth-50x50.jpg', | ||
'meowth-200x500.jpg' | ||
]; | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
pixel_sizes_custom_unit: function(test) { | ||
var actualPath = 'tmp/pixel_sizes_custom_unit/', | ||
expectedPath = 'test/expected/pixel_sizes_custom_unit/', | ||
files = [ | ||
'popeye-20abc123.jpg', | ||
'popeye-80abc123x50abc123.jpg', | ||
'popeye-500abc123x500abc123.jpg' | ||
]; | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
percentage_sizes: function(test) { | ||
var actualPath = 'tmp/percentage_sizes/', | ||
expectedPath = 'test/expected/percentage_sizes/', | ||
files = [ | ||
'captain-planet-10pc.jpg', | ||
'captain-planet-50pcx50pc.jpg', | ||
'captain-planet-200pcx80pc.jpg' | ||
]; | ||
} | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
percentage_sizes_custom_unit: function(test) { | ||
var actualPath = 'tmp/percentage_sizes_custom_unit/', | ||
expectedPath = 'test/expected/percentage_sizes_custom_unit/', | ||
files = [ | ||
'transformers-10abc123.jpg', | ||
'transformers-50abc123x50abc123.jpg', | ||
'transformers-200abc123x80abc123.jpg' | ||
]; | ||
test.done(); | ||
}, | ||
custom_dest_width: function(test) { | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
custom_multiply_unit: function(test) { | ||
var actualPath = 'tmp/custom_multiply_unit/', | ||
expectedPath = 'test/expected/custom_multiply_unit/', | ||
files = [ | ||
'scooby-doo-10pc.jpg', | ||
'scooby-doo-50pcabc12350pc.jpg', | ||
'scooby-doo-800abc123450.jpg' | ||
]; | ||
var actual = {}, | ||
expected = {}; | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
custom_dest_width: function(test) { | ||
var actualPath = 'tmp/custom_dest_width/', | ||
expectedPath = 'test/expected/custom_dest_width/', | ||
files = [ | ||
'320/cedric_sneer.jpg', | ||
'640/cedric_sneer.jpg', | ||
'1024/cedric_sneer.jpg' | ||
]; | ||
var files = [{ | ||
filename: 'cedric_sneer.jpg', | ||
expected: 'test/expected/custom_dest_width/320/', | ||
actual: 'tmp/custom_dest_width/320/' | ||
}, | ||
{ | ||
filename: 'cedric_sneer.jpg', | ||
expected: 'test/expected/custom_dest_width/640/', | ||
actual: 'tmp/custom_dest_width/640/' | ||
}, | ||
{ | ||
filename: 'cedric_sneer.jpg', | ||
expected: 'test/expected/custom_dest_width/1024/', | ||
actual: 'tmp/custom_dest_width/1024/' | ||
}]; | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
custom_dest_name: function(test) { | ||
var actualPath = 'tmp/custom_dest_name/', | ||
expectedPath = 'test/expected/custom_dest_name/', | ||
files = [ | ||
'leo/tmnt.png', | ||
'donnie/tmnt.png', | ||
'raph/tmnt.png' | ||
]; | ||
test.expect(files.length); | ||
checkImages(actualPath, expectedPath, files, test); | ||
}, | ||
custom_dest_path: function (test) { | ||
var actualPath = 'tmp/custom_dest_path/', | ||
expectedPath = 'test/expected/custom_dest_path/', | ||
files = [ | ||
'320/battle-cat.jpg', | ||
'640/sub_directory/battle-dog.jpg' | ||
]; | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
checkImages(actualPath, expectedPath, files, test); | ||
} | ||
}; | ||
test.done(); | ||
// It works! I finally invent something that works! | ||
}, | ||
custom_dest_name: function(test) { | ||
var actual = {}, | ||
expected = {}; | ||
var files = [{ | ||
filename: 'tmnt.png', | ||
expected: 'test/expected/custom_dest_name/leo/', | ||
actual: 'tmp/custom_dest_name/leo/' | ||
}, | ||
{ | ||
filename: 'tmnt.png', | ||
expected: 'test/expected/custom_dest_name/donnie/', | ||
actual: 'tmp/custom_dest_name/donnie/' | ||
},{ | ||
filename: 'tmnt.png', | ||
expected: 'test/expected/custom_dest_name/raph/', | ||
actual: 'tmp/custom_dest_name/raph/' | ||
}]; | ||
test.expect(files.length); | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
} | ||
test.done(); | ||
}, | ||
custom_dest_path: function (test) { | ||
var actual = {}, | ||
expected = {}; | ||
var files = [{ | ||
filename: 'battle-cat.jpg', | ||
expected: 'test/expected/custom_dest_path/320/', | ||
actual: 'tmp/custom_dest_path/320/' | ||
}, | ||
{ | ||
filename: 'battle-dog.jpg', | ||
expected: 'test/expected/custom_dest_path/640/sub_directory/', | ||
actual: 'tmp/custom_dest_path/640/sub_directory/' | ||
}]; | ||
test.expect(files.length); | ||
for (var i = 0, l = files.length; i < l; i++) { | ||
actual = grunt.file.read(files[i].actual + files[i].filename); | ||
expected = grunt.file.read(files[i].expected + files[i].filename); | ||
test.equal(actual, expected, 'should be the same image.'); | ||
} | ||
test.done(); | ||
} | ||
}; | ||
}()); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18920889
117
1190
349
5
4
+ Addedgm@~1.14.2
+ Addedarray-parallel@0.1.3(transitive)
+ Addedarray-series@0.1.5(transitive)
+ Addeddebug@0.7.0(transitive)
+ Addedgm@1.14.2(transitive)
+ Addedstream-to-buffer@0.0.1(transitive)
+ Addedthrough@2.3.8(transitive)