├── .babelrc ├── .editorconfig ├── .gitignore ├── .npmignore ├── .snyk ├── .travis.yml ├── LICENSE ├── README.md ├── package.json ├── src ├── BaseImage.js ├── GraphicsMagick.js ├── ImageMagick.js └── index.js └── test ├── fixtures └── thailand.jpg ├── mocha.opts └── unit ├── BaseImage.test.js ├── GraphicsMagick.test.js ├── ImageMagick.test.js └── index.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"], 3 | "plugins": ["add-module-exports"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | node_modules 27 | 28 | # Babel compiled sources 29 | lib 30 | 31 | # Miscellaneous 32 | *~ 33 | *# 34 | .DS_STORE 35 | .netbeans 36 | nbproject 37 | .idea 38 | .node_history 39 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage 2 | src 3 | test 4 | .idea 5 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.14.1 3 | ignore: {} 4 | # patches apply the minimum changes required to fix a vulnerability 5 | patch: 6 | SNYK-JS-LODASH-567746: 7 | - lodash: 8 | patched: '2020-05-01T07:19:37.495Z' 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | addons: 4 | apt: 5 | packages: 6 | - graphicsmagick 7 | - imagemagick 8 | cache: 9 | directories: 10 | - node_modules 11 | notifications: 12 | email: true 13 | node_js: 14 | - stable 15 | - 5 16 | - 4 17 | - 0.12 18 | - 0.10 19 | before_install: 20 | - npm install -g npm@latest 21 | before_script: 22 | - npm prune 23 | after_success: 24 | - 'curl -Lo travis_after_all.py https://git.io/travis_after_all' 25 | - python travis_after_all.py 26 | - 'export $(cat .to_export_back) &> /dev/null' 27 | - npm run coveralls 28 | - npm run semantic-release 29 | branches: 30 | except: 31 | - "/^v\\d+\\.\\d+\\.\\d+$/" 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Eugene Obrezkov 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sails-service-image 2 | 3 | ![Build Status](https://img.shields.io/travis/ghaiklor/sails-service-image.svg) 4 | ![Coverage](https://img.shields.io/coveralls/ghaiklor/sails-service-image.svg) 5 | 6 | ![Downloads](https://img.shields.io/npm/dm/sails-service-image.svg) 7 | ![Downloads](https://img.shields.io/npm/dt/sails-service-image.svg) 8 | ![npm version](https://img.shields.io/npm/v/sails-service-image.svg) 9 | ![License](https://img.shields.io/npm/l/sails-service-image.svg) 10 | 11 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 12 | [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) 13 | ![dependencies](https://img.shields.io/david/ghaiklor/sails-service-image.svg) 14 | ![dev dependencies](https://img.shields.io/david/dev/ghaiklor/sails-service-image.svg) 15 | 16 | Service for Sails framework with image features. 17 | 18 | ## List of supported image processors 19 | 20 | - GraphicsMagick 21 | - ImageMagick 22 | 23 | ## Getting Started 24 | 25 | Install this module. 26 | 27 | ```shell 28 | npm install sails-service-image 29 | ``` 30 | 31 | Then require it in your service and create image instance. 32 | 33 | ```javascript 34 | // api/services/ImageService.js 35 | import ImageService from 'sails-service-image'; 36 | 37 | export default ImageService('gm'); 38 | 39 | // api/controllers/ImageController.js 40 | export default { 41 | crop: function(req, res) { 42 | ImageService 43 | .crop(req.param('file'), { 44 | x: req.param('x'), 45 | y: req.param('y'), 46 | width: req.param('width'), 47 | height: req.param('height') 48 | }) 49 | .then(StorageService.upload) 50 | .then(res.ok) 51 | .catch(res.negotiate); 52 | } 53 | }; 54 | ``` 55 | 56 | ## API 57 | 58 | Each of image instances has following methods: 59 | 60 | ### iptc(image) 61 | 62 | Get IPTC information from image. Returns Promise. 63 | 64 | `image` - {String|Buffer|Stream} From what image you want to get IPTC information. 65 | 66 | ### resize(image, [config]) 67 | 68 | Resize image and get buffer. Returns Promise. 69 | 70 | `image` - {String|Buffer|Stream} What image you want to resize. 71 | 72 | `config` - {Object} 73 | 74 | - `config.width` - {Number|String} Resulting width of image 75 | - `config.height` - {Number|String} Resulting height of image 76 | - `config.direction` - {String} In what direction make the resize (see GM docs) 77 | - `config.format` - {String} Resulting image format 78 | 79 | ### crop(image, [config]) 80 | 81 | Crop image and get buffer. Returns Promise. 82 | 83 | `image` - {String|Buffer|Stream} What image you want to crop. 84 | 85 | `config` - {Object} 86 | 87 | - `config.width` - {Number|String} Resulting width of image 88 | - `config.height` - {Number|String} Resulting height of image 89 | - `config.x` - {Number} Start X coordinate for cropping 90 | - `config.y` - {Number} Start Y coordinate for cropping 91 | - `config.format` - {String} Resulting image format 92 | 93 | ### thumbnail(image) 94 | 95 | Just shortcut for `crop` and `resize` with predefined options. Creates thumbnail for image and returns Promise. 96 | 97 | `image` - {String|Buffer|Stream} For what image you want to create thumbnail. 98 | 99 | ## Examples 100 | 101 | ### GraphicsMagick 102 | 103 | ```javascript 104 | let gm = ImageService('gm'); 105 | 106 | // Get IPTC information from image 107 | gm 108 | .iptc('my-image.jpg') 109 | .then(console.log.bind(console)) 110 | .catch(console.error.bind(console)); 111 | 112 | // Resize image 113 | gm 114 | .resize('my-image.jpg', { 115 | width: '50%' 116 | }) 117 | .then(StorageService.upload) 118 | .then(console.log.bind(console)) 119 | .catch(console.error.bind(console)) 120 | 121 | // Crop image 122 | gm 123 | .crop('my-image.jpg', { 124 | x: 100, 125 | y: 50, 126 | width: 200 127 | }) 128 | .then(StorageService.upload) 129 | .then(console.log.bind(console)) 130 | .catch(console.error.bind(console)) 131 | 132 | // Create thumbnail 133 | gm 134 | .thumbnail('my-image.jpg') 135 | .then(StorageService.upload) 136 | .then(console.log.bind(console)) 137 | .catch(console.error.bind(console)) 138 | ``` 139 | 140 | ### ImageMagick 141 | 142 | ```javascript 143 | let im = ImageService.create('im'); 144 | 145 | // Get IPTC information from image 146 | im 147 | .iptc('my-image.jpg') 148 | .then(console.log.bind(console)) 149 | .catch(console.error.bind(console)); 150 | 151 | // Resize image 152 | im 153 | .resize('my-image.jpg', { 154 | width: '50%' 155 | }) 156 | .then(StorageService.upload) 157 | .then(console.log.bind(console)) 158 | .catch(console.error.bind(console)) 159 | 160 | // Crop image 161 | im 162 | .crop('my-image.jpg', { 163 | x: 100, 164 | y: 50, 165 | width: 200 166 | }) 167 | .then(StorageService.upload) 168 | .then(console.log.bind(console)) 169 | .catch(console.error.bind(console)) 170 | 171 | // Create thumbnail 172 | im 173 | .thumbnail('my-image.jpg') 174 | .then(StorageService.upload) 175 | .then(console.log.bind(console)) 176 | .catch(console.error.bind(console)) 177 | ``` 178 | 179 | ## License 180 | 181 | The MIT License (MIT) 182 | 183 | Copyright (c) 2015 Eugene Obrezkov 184 | 185 | Permission is hereby granted, free of charge, to any person obtaining a copy 186 | of this software and associated documentation files (the "Software"), to deal 187 | in the Software without restriction, including without limitation the rights 188 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 189 | copies of the Software, and to permit persons to whom the Software is 190 | furnished to do so, subject to the following conditions: 191 | 192 | The above copyright notice and this permission notice shall be included in all 193 | copies or substantial portions of the Software. 194 | 195 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 196 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 198 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 199 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 200 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 201 | SOFTWARE. 202 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sails-service-image", 3 | "version": "0.0.0-semantic-release", 4 | "description": "Service for Sails framework with Image features", 5 | "license": "MIT", 6 | "main": "lib/index.js", 7 | "author": "ghaiklor", 8 | "homepage": "https://github.com/ghaiklor/sails-service-image#readme", 9 | "scripts": { 10 | "compile": "babel src --out-dir lib", 11 | "coveralls": "cat coverage/lcov.info | coveralls", 12 | "prepublish": "npm run snyk-protect && npm run compile", 13 | "semantic-release": "semantic-release pre && npm publish && semantic-release post", 14 | "test": "babel-node ./node_modules/.bin/isparta cover _mocha", 15 | "snyk-protect": "snyk protect" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/ghaiklor/sails-service-image.git" 20 | }, 21 | "keywords": [ 22 | "sails", 23 | "service", 24 | "image" 25 | ], 26 | "bugs": { 27 | "url": "https://github.com/ghaiklor/sails-service-image/issues" 28 | }, 29 | "dependencies": { 30 | "bluebird": "3.7.2", 31 | "gm": "1.23.1", 32 | "lodash": "4.17.21", 33 | "snyk": "^1.316.1" 34 | }, 35 | "devDependencies": { 36 | "babel-cli": "6.26.0", 37 | "babel-plugin-add-module-exports": "1.0.1", 38 | "babel-preset-es2015": "6.24.1", 39 | "chai": "4.1.2", 40 | "coveralls": "3.0.8", 41 | "cz-conventional-changelog": "3.1.0", 42 | "isparta": "4.1.1", 43 | "mocha": "7.1.0", 44 | "semantic-release": "15.13.29", 45 | "sinon": "7.4.0" 46 | }, 47 | "config": { 48 | "commitizen": { 49 | "path": "./node_modules/cz-conventional-changelog" 50 | } 51 | }, 52 | "publishConfig": { 53 | "tag": "latest" 54 | }, 55 | "release": { 56 | "branch": "master" 57 | }, 58 | "snyk": true 59 | } 60 | -------------------------------------------------------------------------------- /src/BaseImage.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | export default class BaseImage { 4 | constructor(_config) { 5 | this._config = {}; 6 | this._provider = {}; 7 | 8 | _.assign(this._config, _config); 9 | } 10 | 11 | /** 12 | * Get configuration value 13 | * @param {String} [path] 14 | * @returns {*} 15 | */ 16 | get(path) { 17 | return typeof path === 'undefined' ? this._config : _.get(this._config, path); 18 | } 19 | 20 | /** 21 | * Set configuration value 22 | * @param {String} path 23 | * @param {*} value 24 | * @returns {BaseImage} 25 | */ 26 | set(path, value) { 27 | _.set(this._config, path, value); 28 | return this; 29 | } 30 | 31 | /** 32 | * Get image provider 33 | * @returns {*} 34 | */ 35 | getProvider() { 36 | return this._provider; 37 | } 38 | 39 | /** 40 | * Set new provider 41 | * @param {*} provider 42 | * @returns {BaseImage} 43 | */ 44 | setProvider(provider) { 45 | this._provider = provider; 46 | return this; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/GraphicsMagick.js: -------------------------------------------------------------------------------- 1 | import gm from 'gm'; 2 | import Promise from 'bluebird'; 3 | import BaseImage from './BaseImage'; 4 | 5 | export default class GraphicsMagick extends BaseImage { 6 | constructor(config) { 7 | super(config); 8 | 9 | this.setProvider(gm); 10 | } 11 | 12 | /** 13 | * Get title from IPTC 14 | * @param {String|Buffer|Stream} image Source image 15 | * @returns {Promise} 16 | */ 17 | getTitle(image) { 18 | return new Promise((resolve, reject) => { 19 | this.getProvider()(image).identify('%[IPTC:2:05]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 20 | }); 21 | } 22 | 23 | /** 24 | * Get description from IPTC 25 | * @param {String|Buffer|Stream} image Source image 26 | * @returns {Promise} 27 | */ 28 | getDescription(image) { 29 | return new Promise((resolve, reject) => { 30 | this.getProvider()(image).identify('%[IPTC:2:120]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 31 | }); 32 | } 33 | 34 | /** 35 | * Get keywords from IPTC 36 | * @param {String|Buffer|Stream} image Source image 37 | * @returns {Promise} 38 | */ 39 | getKeywords(image) { 40 | return new Promise((resolve, reject) => { 41 | this.getProvider()(image).identify('%[IPTC:2:25]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight().split(';').join(','))); 42 | }); 43 | } 44 | 45 | /** 46 | * Get category from IPTC 47 | * @param {String|Buffer|Stream} image Source image 48 | * @returns {Promise} 49 | */ 50 | getCategory(image) { 51 | return new Promise((resolve, reject) => { 52 | this.getProvider()(image).identify('%[IPTC:2:15]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 53 | }); 54 | } 55 | 56 | /** 57 | * Get image format 58 | * @param {String|Buffer|Stream} image Source image 59 | * @returns {Promise} 60 | */ 61 | getFormat(image) { 62 | return new Promise((resolve, reject) => { 63 | this.getProvider()(image).identify((error, data) => error ? reject(error) : resolve(data.format)); 64 | }); 65 | } 66 | 67 | /** 68 | * Get IPTC information from image 69 | * @param {String|Buffer|Stream} image Source image 70 | * @returns {Promise} 71 | */ 72 | iptc(image) { 73 | return Promise.all([ 74 | this.getTitle(image), 75 | this.getDescription(image), 76 | this.getKeywords(image), 77 | this.getCategory(image), 78 | this.getFormat(image) 79 | ]).spread((title, description, keywords, category, format) => Promise.resolve({ 80 | title, 81 | description, 82 | keywords, 83 | category, 84 | format 85 | })); 86 | } 87 | 88 | /** 89 | * Resize image 90 | * @param {String|Buffer|Stream} image Source image 91 | * @param {Object} [_config] Configuration object 92 | * @returns {Promise} 93 | */ 94 | resize(image, _config) { 95 | let config = _config || {}; 96 | 97 | return new Promise((resolve, reject) => { 98 | this.getProvider()(image) 99 | .resize(config.width || 200, config.height, config.direction || '>') 100 | .setFormat(config.format || 'jpg') 101 | .toBuffer((error, buffer) => error ? reject(error) : resolve(buffer)); 102 | }); 103 | } 104 | 105 | /** 106 | * Crop image 107 | * @param {String|Buffer|Stream} image Source image 108 | * @param {Object} [_config] Configuration object 109 | * @returns {Promise} 110 | */ 111 | crop(image, _config) { 112 | let config = _config || {}; 113 | 114 | return new Promise((resolve, reject) => { 115 | this.getProvider()(image) 116 | .crop(config.width || '100%', config.height || '100%', config.x || 0, config.y || 0) 117 | .setFormat(config.format || 'jpg') 118 | .toBuffer((error, buffer) => error ? reject(error) : resolve(buffer)); 119 | }); 120 | } 121 | 122 | /** 123 | * Create thumbnail for image 124 | * @param {String|Buffer|Stream} image Source image 125 | * @param {Object} [_config] 126 | * @returns {Promise} 127 | */ 128 | thumbnail(image, _config) { 129 | return this.resize(image, _config); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/ImageMagick.js: -------------------------------------------------------------------------------- 1 | import gm from 'gm'; 2 | import Promise from 'bluebird'; 3 | import BaseImage from './BaseImage'; 4 | 5 | export default class GraphicsMagick extends BaseImage { 6 | constructor(config) { 7 | super(config); 8 | 9 | this.setProvider(gm.subClass({imageMagick: true})); 10 | } 11 | 12 | /** 13 | * Get title from IPTC 14 | * @param {String|Buffer|Stream} image Source image 15 | * @returns {Promise} 16 | */ 17 | getTitle(image) { 18 | return new Promise((resolve, reject) => { 19 | this.getProvider()(image).identify('%[IPTC:2:05]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 20 | }); 21 | } 22 | 23 | /** 24 | * Get description from IPTC 25 | * @param {String|Buffer|Stream} image Source image 26 | * @returns {Promise} 27 | */ 28 | getDescription(image) { 29 | return new Promise((resolve, reject) => { 30 | this.getProvider()(image).identify('%[IPTC:2:120]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 31 | }); 32 | } 33 | 34 | /** 35 | * Get keywords from IPTC 36 | * @param {String|Buffer|Stream} image Source image 37 | * @returns {Promise} 38 | */ 39 | getKeywords(image) { 40 | return new Promise((resolve, reject) => { 41 | this.getProvider()(image).identify('%[IPTC:2:25]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight().split(';').join(','))); 42 | }); 43 | } 44 | 45 | /** 46 | * Get category from IPTC 47 | * @param {String|Buffer|Stream} image Source image 48 | * @returns {Promise} 49 | */ 50 | getCategory(image) { 51 | return new Promise((resolve, reject) => { 52 | this.getProvider()(image).identify('%[IPTC:2:15]', (error, metadata) => error ? reject(error) : resolve(metadata.trimRight())); 53 | }); 54 | } 55 | 56 | /** 57 | * Get image format 58 | * @param {String|Buffer|Stream} image Source image 59 | * @returns {Promise} 60 | */ 61 | getFormat(image) { 62 | return new Promise((resolve, reject) => { 63 | this.getProvider()(image).identify((error, data) => error ? reject(error) : resolve(data.format)); 64 | }); 65 | } 66 | 67 | /** 68 | * Get IPTC information from image 69 | * @param {String|Buffer|Stream} image Source image 70 | * @returns {Promise} 71 | */ 72 | iptc(image) { 73 | return Promise.all([ 74 | this.getTitle(image), 75 | this.getDescription(image), 76 | this.getKeywords(image), 77 | this.getCategory(image), 78 | this.getFormat(image) 79 | ]).spread((title, description, keywords, category, format) => Promise.resolve({ 80 | title, 81 | description, 82 | keywords, 83 | category, 84 | format 85 | })); 86 | } 87 | 88 | /** 89 | * Resize image 90 | * @param {String|Buffer|Stream} image Source image 91 | * @param {Object} [_config] Configuration object 92 | * @returns {Promise} 93 | */ 94 | resize(image, _config) { 95 | let config = _config || {}; 96 | 97 | return new Promise((resolve, reject) => { 98 | this.getProvider()(image) 99 | .resize(config.width || 200, config.height, config.direction || '>') 100 | .setFormat(config.format || 'jpg') 101 | .toBuffer((error, buffer) => error ? reject(error) : resolve(buffer)); 102 | }); 103 | } 104 | 105 | /** 106 | * Crop image 107 | * @param {String|Buffer|Stream} image Source image 108 | * @param {Object} [_config] Configuration object 109 | * @returns {Promise} 110 | */ 111 | crop(image, _config) { 112 | let config = _config || {}; 113 | 114 | return new Promise((resolve, reject) => { 115 | this.getProvider()(image) 116 | .crop(config.width || '100%', config.height || '100%', config.x || 0, config.y || 0) 117 | .setFormat(config.format || 'jpg') 118 | .toBuffer((error, buffer) => error ? reject(error) : resolve(buffer)); 119 | }); 120 | } 121 | 122 | /** 123 | * Create thumbnail for image 124 | * @param {String|Buffer|Stream} image Source image 125 | * @param {Object} [_config] 126 | * @returns {Promise} 127 | */ 128 | thumbnail(image, _config) { 129 | return this.resize(image, _config); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import GraphicsMagick from './GraphicsMagick'; 2 | import ImageMagick from './ImageMagick'; 3 | 4 | const image = { 5 | gm: GraphicsMagick, 6 | im: ImageMagick 7 | }; 8 | 9 | /** 10 | * Create specified images instance 11 | * @param {String} type 12 | * @param {Object} [config] 13 | * @returns {*} 14 | */ 15 | export default function (type, config) { 16 | if (image[type.toLowerCase()] instanceof Function) { 17 | return new image[type.toLowerCase()](config); 18 | } else { 19 | throw new Error('Unrecognized type -> ' + type); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/thailand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghaiklor/sails-service-image/6a1700eeba8a5fce5e7c2d86a734c8ca2946c57a/test/fixtures/thailand.jpg -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | ./test/unit/**/*.test.js 2 | --reporter nyan 3 | --recursive 4 | -------------------------------------------------------------------------------- /test/unit/BaseImage.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import BaseImage from '../../src/BaseImage'; 3 | 4 | describe('BaseImage', () => { 5 | it('Should properly export', () => { 6 | assert.isFunction(BaseImage); 7 | }); 8 | 9 | it('Should properly make objects configurable', () => { 10 | let image = new BaseImage(); 11 | 12 | assert.notOk(image.get('foo')); 13 | assert.instanceOf(image.set('foo', 'bar'), BaseImage); 14 | assert.instanceOf(image.set('obj', {foo: 'bar'}), BaseImage); 15 | assert.deepEqual(image.get(), {foo: 'bar', obj: {foo: 'bar'}}); 16 | assert.deepEqual(image.get('obj'), {foo: 'bar'}); 17 | assert.equal(image.get('obj.foo'), 'bar'); 18 | assert.equal(image.get('foo'), 'bar'); 19 | }); 20 | 21 | it('Should properly create image with pre-defined config', () => { 22 | let image = new BaseImage({ 23 | foo: 'bar', 24 | obj: { 25 | foo: 'bar' 26 | } 27 | }); 28 | 29 | assert.equal(image.get('foo'), 'bar'); 30 | assert.equal(image.get('obj.foo'), 'bar'); 31 | assert.deepEqual(image.get('obj'), {foo: 'bar'}); 32 | assert.notOk(image.get('NOT_EXISTS')); 33 | }); 34 | 35 | it('Should properly get/set provider', () => { 36 | let image = new BaseImage(); 37 | 38 | assert.deepEqual(image.getProvider(), {}); 39 | assert.instanceOf(image.setProvider('PROVIDER'), BaseImage); 40 | assert.equal(image.getProvider(), 'PROVIDER'); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/unit/GraphicsMagick.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import path from 'path'; 3 | import sinon from 'sinon'; 4 | import GraphicsMagick from '../../src/GraphicsMagick'; 5 | 6 | describe('GraphicsMagick', () => { 7 | it('Should properly export', () => { 8 | assert.isFunction(GraphicsMagick); 9 | }); 10 | 11 | it('Should properly get IPTC information', done => { 12 | let gm = new GraphicsMagick(); 13 | 14 | sinon.spy(gm.getProvider().prototype, 'identify'); 15 | 16 | gm 17 | .iptc(path.resolve(__dirname, '../fixtures/thailand.jpg')) 18 | .then(iptc => { 19 | assert.equal(gm.getProvider().prototype.identify.callCount, 5); 20 | assert.equal(gm.getProvider().prototype.identify.getCall(0).args[0], '%[IPTC:2:05]'); 21 | assert.equal(gm.getProvider().prototype.identify.getCall(1).args[0], '%[IPTC:2:120]'); 22 | assert.equal(gm.getProvider().prototype.identify.getCall(2).args[0], '%[IPTC:2:25]'); 23 | assert.equal(gm.getProvider().prototype.identify.getCall(3).args[0], '%[IPTC:2:15]'); 24 | assert.isFunction(gm.getProvider().prototype.identify.getCall(4).args[0]); 25 | assert.deepEqual(iptc, { 26 | title: '', 27 | description: '', 28 | keywords: '', 29 | category: '', 30 | format: 'JPEG' 31 | }); 32 | 33 | gm.getProvider().prototype.identify.restore(); 34 | 35 | done(); 36 | }) 37 | .catch(done); 38 | }); 39 | 40 | it('Should properly reject on getting IPTC information', done => { 41 | let gm = new GraphicsMagick(); 42 | 43 | sinon.stub(gm.getProvider().prototype, 'identify', (section, cb) => section instanceof Function ? section('ERROR') : cb('ERROR')); 44 | 45 | gm 46 | .iptc(path.resolve(__dirname, '../fixtures/thailand.jpg')) 47 | .then(done) 48 | .catch(error => { 49 | assert.equal(error, 'ERROR'); 50 | assert.equal(gm.getProvider().prototype.identify.callCount, 5); 51 | assert.equal(gm.getProvider().prototype.identify.getCall(0).args[0], '%[IPTC:2:05]'); 52 | assert.equal(gm.getProvider().prototype.identify.getCall(1).args[0], '%[IPTC:2:120]'); 53 | assert.equal(gm.getProvider().prototype.identify.getCall(2).args[0], '%[IPTC:2:25]'); 54 | assert.equal(gm.getProvider().prototype.identify.getCall(3).args[0], '%[IPTC:2:15]'); 55 | assert.isFunction(gm.getProvider().prototype.identify.getCall(4).args[0]); 56 | 57 | gm.getProvider().prototype.identify.restore(); 58 | 59 | done(); 60 | }); 61 | }); 62 | 63 | it('Should properly resize image with default options', done => { 64 | let gm = new GraphicsMagick(); 65 | 66 | sinon.spy(gm.getProvider().prototype, 'resize'); 67 | 68 | gm 69 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg')) 70 | .then(result => { 71 | assert.instanceOf(result, Buffer); 72 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 73 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 74 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 75 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 76 | 77 | gm.getProvider().prototype.resize.restore(); 78 | 79 | done(); 80 | }) 81 | .catch(done); 82 | }); 83 | 84 | it('Should properly resize image with custom options', done => { 85 | let gm = new GraphicsMagick(); 86 | 87 | sinon.spy(gm.getProvider().prototype, 'resize'); 88 | 89 | gm 90 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg'), { 91 | width: 100, 92 | height: 100, 93 | direction: '<', 94 | format: 'png' 95 | }) 96 | .then(result => { 97 | assert.instanceOf(result, Buffer); 98 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 99 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 100); 100 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], 100); 101 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '<'); 102 | 103 | gm.getProvider().prototype.resize.restore(); 104 | 105 | done(); 106 | }) 107 | .catch(done); 108 | }); 109 | 110 | it('Should properly reject on resize image', done => { 111 | let gm = new GraphicsMagick(); 112 | 113 | sinon.spy(gm.getProvider().prototype, 'resize'); 114 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 115 | 116 | gm 117 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg')) 118 | .then(done) 119 | .catch(error => { 120 | assert.equal(error, 'ERROR'); 121 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 122 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 123 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 124 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 125 | 126 | gm.getProvider().prototype.resize.restore(); 127 | gm.getProvider().prototype.toBuffer.restore(); 128 | 129 | done(); 130 | }); 131 | }); 132 | 133 | it('Should properly crop image with default options', done => { 134 | let gm = new GraphicsMagick(); 135 | 136 | sinon.spy(gm.getProvider().prototype, 'crop'); 137 | 138 | gm 139 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg')) 140 | .then(result => { 141 | assert.instanceOf(result, Buffer); 142 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 143 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], '100%'); 144 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], '100%'); 145 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 0); 146 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 0); 147 | 148 | gm.getProvider().prototype.crop.restore(); 149 | 150 | done(); 151 | }) 152 | .catch(done); 153 | }); 154 | 155 | it('Should properly crop image with custom options', done => { 156 | let gm = new GraphicsMagick(); 157 | 158 | sinon.spy(gm.getProvider().prototype, 'crop'); 159 | 160 | gm 161 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg'), { 162 | width: 100, 163 | height: 100, 164 | x: 200, 165 | y: 200, 166 | format: 'png' 167 | }) 168 | .then(result => { 169 | assert.instanceOf(result, Buffer); 170 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 171 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], 100); 172 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], 100); 173 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 200); 174 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 200); 175 | 176 | gm.getProvider().prototype.crop.restore(); 177 | 178 | done(); 179 | }) 180 | .catch(done); 181 | }); 182 | 183 | it('Should properly reject on crop image', done => { 184 | let gm = new GraphicsMagick(); 185 | 186 | sinon.spy(gm.getProvider().prototype, 'crop'); 187 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 188 | 189 | gm 190 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg')) 191 | .then(done) 192 | .catch(error => { 193 | assert.equal(error, 'ERROR'); 194 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 195 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], '100%'); 196 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], '100%'); 197 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 0); 198 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 0); 199 | 200 | gm.getProvider().prototype.crop.restore(); 201 | gm.getProvider().prototype.toBuffer.restore(); 202 | 203 | done(); 204 | }); 205 | }); 206 | 207 | it('Should properly create thumbnail', done => { 208 | let gm = new GraphicsMagick(); 209 | 210 | sinon.spy(gm.getProvider().prototype, 'resize'); 211 | 212 | gm 213 | .thumbnail(path.resolve(__dirname, '../fixtures/thailand.jpg')) 214 | .then(result => { 215 | assert.instanceOf(result, Buffer); 216 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 217 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 218 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 219 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 220 | 221 | gm.getProvider().prototype.resize.restore(); 222 | 223 | done(); 224 | }) 225 | .catch(done); 226 | }); 227 | 228 | it('Should properly reject on creating thumbnail', done => { 229 | let gm = new GraphicsMagick(); 230 | 231 | sinon.spy(gm.getProvider().prototype, 'resize'); 232 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 233 | 234 | gm 235 | .thumbnail(path.resolve(__dirname, '../fixtures/thailand.jpg')) 236 | .then(done) 237 | .catch(error => { 238 | assert.equal(error, 'ERROR'); 239 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 240 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 241 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 242 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 243 | 244 | gm.getProvider().prototype.resize.restore(); 245 | gm.getProvider().prototype.toBuffer.restore(); 246 | 247 | done(); 248 | }); 249 | }); 250 | }); 251 | -------------------------------------------------------------------------------- /test/unit/ImageMagick.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import path from 'path'; 3 | import sinon from 'sinon'; 4 | import ImageMagick from '../../src/ImageMagick'; 5 | 6 | describe('ImageMagick', () => { 7 | it('Should properly export', () => { 8 | assert.isFunction(ImageMagick); 9 | }); 10 | 11 | it('Should properly get IPTC information', done => { 12 | let gm = new ImageMagick(); 13 | 14 | sinon.spy(gm.getProvider().prototype, 'identify'); 15 | 16 | gm 17 | .iptc(path.resolve(__dirname, '../fixtures/thailand.jpg')) 18 | .then(iptc => { 19 | assert.equal(gm.getProvider().prototype.identify.callCount, 5); 20 | assert.equal(gm.getProvider().prototype.identify.getCall(0).args[0], '%[IPTC:2:05]'); 21 | assert.equal(gm.getProvider().prototype.identify.getCall(1).args[0], '%[IPTC:2:120]'); 22 | assert.equal(gm.getProvider().prototype.identify.getCall(2).args[0], '%[IPTC:2:25]'); 23 | assert.equal(gm.getProvider().prototype.identify.getCall(3).args[0], '%[IPTC:2:15]'); 24 | assert.isFunction(gm.getProvider().prototype.identify.getCall(4).args[0]); 25 | assert.deepEqual(iptc, { 26 | title: '', 27 | description: '', 28 | keywords: '', 29 | category: '', 30 | format: 'JPEG' 31 | }); 32 | 33 | gm.getProvider().prototype.identify.restore(); 34 | 35 | done(); 36 | }) 37 | .catch(done); 38 | }); 39 | 40 | it('Should properly reject on getting IPTC information', done => { 41 | let gm = new ImageMagick(); 42 | 43 | sinon.stub(gm.getProvider().prototype, 'identify', (section, cb) => section instanceof Function ? section('ERROR') : cb('ERROR')); 44 | 45 | gm 46 | .iptc(path.resolve(__dirname, '../fixtures/thailand.jpg')) 47 | .then(done) 48 | .catch(error => { 49 | assert.equal(error, 'ERROR'); 50 | assert.equal(gm.getProvider().prototype.identify.callCount, 5); 51 | assert.equal(gm.getProvider().prototype.identify.getCall(0).args[0], '%[IPTC:2:05]'); 52 | assert.equal(gm.getProvider().prototype.identify.getCall(1).args[0], '%[IPTC:2:120]'); 53 | assert.equal(gm.getProvider().prototype.identify.getCall(2).args[0], '%[IPTC:2:25]'); 54 | assert.equal(gm.getProvider().prototype.identify.getCall(3).args[0], '%[IPTC:2:15]'); 55 | assert.isFunction(gm.getProvider().prototype.identify.getCall(4).args[0]); 56 | 57 | gm.getProvider().prototype.identify.restore(); 58 | 59 | done(); 60 | }); 61 | }); 62 | 63 | it('Should properly resize image with default options', done => { 64 | let gm = new ImageMagick(); 65 | 66 | sinon.spy(gm.getProvider().prototype, 'resize'); 67 | 68 | gm 69 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg')) 70 | .then(result => { 71 | assert.instanceOf(result, Buffer); 72 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 73 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 74 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 75 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 76 | 77 | gm.getProvider().prototype.resize.restore(); 78 | 79 | done(); 80 | }) 81 | .catch(done); 82 | }); 83 | 84 | it('Should properly resize image with custom options', done => { 85 | let gm = new ImageMagick(); 86 | 87 | sinon.spy(gm.getProvider().prototype, 'resize'); 88 | 89 | gm 90 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg'), { 91 | width: 100, 92 | height: 100, 93 | direction: '<', 94 | format: 'png' 95 | }) 96 | .then(result => { 97 | assert.instanceOf(result, Buffer); 98 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 99 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 100); 100 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], 100); 101 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '<'); 102 | 103 | gm.getProvider().prototype.resize.restore(); 104 | 105 | done(); 106 | }) 107 | .catch(done); 108 | }); 109 | 110 | it('Should properly reject on resize image', done => { 111 | let gm = new ImageMagick(); 112 | 113 | sinon.spy(gm.getProvider().prototype, 'resize'); 114 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 115 | 116 | gm 117 | .resize(path.resolve(__dirname, '../fixtures/thailand.jpg')) 118 | .then(done) 119 | .catch(error => { 120 | assert.equal(error, 'ERROR'); 121 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 122 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 123 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 124 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 125 | 126 | gm.getProvider().prototype.resize.restore(); 127 | gm.getProvider().prototype.toBuffer.restore(); 128 | 129 | done(); 130 | }); 131 | }); 132 | 133 | it('Should properly crop image with default options', done => { 134 | let gm = new ImageMagick(); 135 | 136 | sinon.spy(gm.getProvider().prototype, 'crop'); 137 | 138 | gm 139 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg')) 140 | .then(result => { 141 | assert.instanceOf(result, Buffer); 142 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 143 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], '100%'); 144 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], '100%'); 145 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 0); 146 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 0); 147 | 148 | gm.getProvider().prototype.crop.restore(); 149 | 150 | done(); 151 | }) 152 | .catch(done); 153 | }); 154 | 155 | it('Should properly crop image with custom options', done => { 156 | let gm = new ImageMagick(); 157 | 158 | sinon.spy(gm.getProvider().prototype, 'crop'); 159 | 160 | gm 161 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg'), { 162 | width: 100, 163 | height: 100, 164 | x: 200, 165 | y: 200, 166 | format: 'png' 167 | }) 168 | .then(result => { 169 | assert.instanceOf(result, Buffer); 170 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 171 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], 100); 172 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], 100); 173 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 200); 174 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 200); 175 | 176 | gm.getProvider().prototype.crop.restore(); 177 | 178 | done(); 179 | }) 180 | .catch(done); 181 | }); 182 | 183 | it('Should properly reject on crop image', done => { 184 | let gm = new ImageMagick(); 185 | 186 | sinon.spy(gm.getProvider().prototype, 'crop'); 187 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 188 | 189 | gm 190 | .crop(path.resolve(__dirname, '../fixtures/thailand.jpg')) 191 | .then(done) 192 | .catch(error => { 193 | assert.equal(error, 'ERROR'); 194 | assert.ok(gm.getProvider().prototype.crop.calledOnce); 195 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[0], '100%'); 196 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[1], '100%'); 197 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[2], 0); 198 | assert.equal(gm.getProvider().prototype.crop.getCall(0).args[3], 0); 199 | 200 | gm.getProvider().prototype.crop.restore(); 201 | gm.getProvider().prototype.toBuffer.restore(); 202 | 203 | done(); 204 | }); 205 | }); 206 | 207 | it('Should properly create thumbnail', done => { 208 | let gm = new ImageMagick(); 209 | 210 | sinon.spy(gm.getProvider().prototype, 'resize'); 211 | 212 | gm 213 | .thumbnail(path.resolve(__dirname, '../fixtures/thailand.jpg')) 214 | .then(result => { 215 | assert.instanceOf(result, Buffer); 216 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 217 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 218 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 219 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 220 | 221 | gm.getProvider().prototype.resize.restore(); 222 | 223 | done(); 224 | }) 225 | .catch(done); 226 | }); 227 | 228 | it('Should properly reject on creating thumbnail', done => { 229 | let gm = new ImageMagick(); 230 | 231 | sinon.spy(gm.getProvider().prototype, 'resize'); 232 | sinon.stub(gm.getProvider().prototype, 'toBuffer', cb => cb('ERROR')); 233 | 234 | gm 235 | .thumbnail(path.resolve(__dirname, '../fixtures/thailand.jpg')) 236 | .then(done) 237 | .catch(error => { 238 | assert.equal(error, 'ERROR'); 239 | assert.ok(gm.getProvider().prototype.resize.calledOnce); 240 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[0], 200); 241 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[1], undefined); 242 | assert.equal(gm.getProvider().prototype.resize.getCall(0).args[2], '>'); 243 | 244 | gm.getProvider().prototype.resize.restore(); 245 | gm.getProvider().prototype.toBuffer.restore(); 246 | 247 | done(); 248 | }); 249 | }); 250 | }); 251 | -------------------------------------------------------------------------------- /test/unit/index.test.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import ImageService from '../../src/index'; 3 | import GraphicsMagick from '../../src/GraphicsMagick'; 4 | import ImageMagick from '../../src/ImageMagick'; 5 | 6 | describe('ImageService', () => { 7 | it('Should properly export', () => { 8 | assert.isFunction(ImageService); 9 | }); 10 | 11 | it('Should properly create image instances', () => { 12 | assert.instanceOf(ImageService('gm'), GraphicsMagick); 13 | assert.instanceOf(ImageService('im'), ImageMagick); 14 | }); 15 | 16 | it('Should properly throw error on unrecognized type', () => { 17 | assert.throws(() => ImageService('NOT_EXISTS'), Error); 18 | }); 19 | }); 20 | --------------------------------------------------------------------------------