UNPKG

immp

Version:

Image Manipulation Middleware Proxy

658 lines (474 loc) 16.5 kB
var async = require('async'), cluster = require('cluster'), crypto = require('crypto'), cwd = process.cwd(), fs = require('fs'), gm = require('gm'), http = require('http'), path = require('path'), should = require('should'); var immpPath = path.join(cwd, '/.tmp/immp'), gmOptions = { bufferStream: true, imageMagick: false, graphicsMagick: true }, serverImmpConfig = { // ttl: 0, // ttl: 1000 * 60 * 60 * 24 * 7, // 1 week imageMagick: false, graphicsMagick: true, cacheFolder: process.cwd() + '/.tmp/immp', // allowProxy: true, imageDir: process.cwd() + '/public' }, server, serverPort = process.env.PORT || 3000, serverUrl = 'http://localhost:' + serverPort; describe('immp', function () { before(function (_done) { // Set up the test server. var debug = require('debug')('gm'); var app = require('../app')(serverImmpConfig); app.set('port', serverPort); server = app.listen(app.get('port'), function () { debug('Express server listening on port ' + serverPort); _done(); }); }); after(function () { var immpFiles = fs.readdirSync(immpPath); immpFiles.forEach(function (_file) { fs.unlinkSync(path.join(immpPath, '/', _file)); }); }); it('should resize by width', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=200x0', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(200); _done(); }); }); }); it('should not crash on multple params', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=200x200&resize=200x200&sx=0&sx=0&sy=0&sy=0&sw=100&sw=100&sh=100&sh=100&crop=1x1&crop=1x1', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(200); _done(); }); }); }); it('should resize by height', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=0x200', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.height.should.equal(200); _done(); }); }); }); it('should not upscale by default', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=2000x2000', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(1920); _size.height.should.equal(1080); _done(); }); }); }); it('should upscale when upscaling is true', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=2000x2000&upscale=true', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(2000); _size.height.should.equal(1125); _done(); }); }); }); it('should resize by width and height and retain the aspect ratio', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&resize=100x200', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(100); _size.height.should.equal(56); _done(); }); }).on('error', function (_error) { _done(_error); }); }); it('should crop to a square', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&crop=1x1', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(1080); _size.height.should.equal(1080); _done(); }); }); }); it('should do a custom crop and round exponents', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&sx=0.4&sy=5.798028723802416e-15&sw=100.4&sh=111.4', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(100); _size.height.should.equal(111); _done(); }); }); }); it('should do a custom crop with a ratio crop', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&sx=0&sy=0&sw=100&sh=111&crop=1x1', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(100); _size.height.should.equal(100); _done(); }); }); }); it('should do a custom crop with an offset', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&sx=100&sy=100&sw=222&sh=111', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(222); _size.height.should.equal(111); _done(); }); }); }); describe('with invalid operators', function () { [ [0, 0, 0, 0], // No image [99999, 99999, 100, 100], // Outside bounds ['a', 0, 0, 0], // Non-numeric [-1, 0, 0, 0], // Not positive ['', 0, 0, 0], // Not defined ].forEach(function (params) { it('should not do a custom crop with ' + params, function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&sx=' + params[0] + '&sy=' + params[1] + '&sw=' + params[2] + '&sh=' + params[3] + '', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); // Default image size _size.width.should.equal(1920); _size.height.should.equal(1080); _done(); }); }); }); }); }); it('should crop to a short width big height ratio', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&crop=9x16', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(608); _size.height.should.equal(1080); _done(); }); }); }); it('should crop to a big width short height ratio', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&crop=16x9', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(1920); _size.height.should.equal(1080); _done(); }); }); }); it('should crop and resize', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/robot.jpg&crop=1x1&resize=50x100', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(50); _size.height.should.equal(50); _done(); }); }); }); it('should set the quality', function (_done) { this.slow(5000); this.timeout(10000); async.waterfall([ // Get the size without compression function (_callback) { http.get(serverUrl + '/im/?image=/images/robot.jpg&quality=invalidQualityValue', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .filesize(function (_error, _filesize) { if(_error) return _callback(_error); _callback(null, parseInt(_filesize)); }); }); }, // Get the size with compression function (_fileSizeWithoutCompression, _callback) { http.get(serverUrl + '/im/?image=/images/robot.jpg&quality=50', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .filesize(function (_error, _filesize) { if(_error) return _callback(_error); var filesize = parseInt(_filesize); filesize.should.be.lessThan(_fileSizeWithoutCompression); (filesize / _fileSizeWithoutCompression).should.be.greaterThan(0.5).and.lessThan(0.8); _callback(null, filesize); }); }); } ], function (_error) { _done(_error); }); }); it('should respect the orientation information', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=/images/Landscape_8.jpg&quality=50', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(600); _size.height.should.equal(450); _done(); }); }); }); it('should work for http images', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=' + serverUrl + '/images/robot.jpg&crop=1x1&resize=50x100', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(50); _size.height.should.equal(50); _done(); }); }); }); it('should work for https images', function (_done) { this.slow(5000); this.timeout(10000); http.get(serverUrl + '/im/?image=https://www.google.com/images/srpr/logo11w.png&crop=1x1&resize=50x100', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/png'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(50); _size.height.should.equal(50); _done(); }); }); }); it('should still have the right content-type & size when cached', function (_done) { http.get(serverUrl + '/im/?image=/images/Landscape_8.jpg&quality=50', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(600); _size.height.should.equal(450); _done(); }); }); }); it('should return gifs', function (_done) { http.get(serverUrl + '/im/?image=/images/captainplanet.gif', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/gif'); _done(); }); }); describe('proxy file caching', function () { var robotImage; before(function (_done) { // Clear file cache. var immpFiles = fs.readdirSync(immpPath); immpFiles.forEach(function (_file) { fs.unlinkSync(path.join(immpPath, '/', _file)); }); _done(); }); it('should work with no cached image', function (_done) { http.get(serverUrl + '/im/?image=/images/robot.jpg', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); _done(); }); }); it('should have created a cached image', function (_done) { var cachedFileName = path.join(immpPath, 'source-' + crypto.createHash('sha1').update(serverUrl + '/images/robot.jpg').digest('hex')); fs.readFile(cachedFileName, function (error, data) { _done(error); }); }); it('should work with a cached image', function (_done) { http.get(serverUrl + '/im/?image=/images/robot.jpg', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/jpeg'); _done(); }); }); it('should work with http proxied image', function (_done) { http.get(serverUrl + '/im/?image=https://www.google.com/images/srpr/logo11w.png&crop=1x1&resize=50x100', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/png'); gm(_httpResponse) .options(gmOptions) .size(function (_error, _size) { if(_error) return _done(_error); _size.width.should.equal(50); _size.height.should.equal(50); _done(); }); }); }); it('should have cached a proxied image', function (_done) { var cachedFileName = path.join(immpPath, 'source-' + crypto.createHash('sha1').update('https://www.google.com/images/srpr/logo11w.png').digest('hex')); fs.readFile(cachedFileName, function (error, data) { _done(error); }); }); }); describe('with convertTo set', function () { before(function (_done) { // Clear file cache. var immpFiles = fs.readdirSync(immpPath); immpFiles.forEach(function (_file) { fs.unlinkSync(path.join(immpPath, '/', _file)); }); // Recreate server with new config option/s. server.on('close', function () { serverImmpConfig.convertTo = { gif: { fileType: 'png32', mimeType: 'png' } }; // Set up the test server. var debug = require('debug')('gm'); var app = require('../app')(serverImmpConfig); app.set('port', serverPort); server = app.listen(app.get('port'), function () { debug('Express server listening on port ' + serverPort); _done(); }); }); server.close(); }); it('should return in the appropriate format', function (_done) { http.get(serverUrl + '/im/?image=/images/captainplanet.gif', function (_httpResponse) { _httpResponse.statusCode.should.eql(200); _httpResponse.headers['content-type'].should.eql('image/png'); gm(_httpResponse) .options(gmOptions).format(function (error, format) { format.should.eql('PNG'); _done(); }); }); }); }); });