将节点 gm 与承诺和缓冲区一起使用
Use node gm with promises and buffers
我一直在尝试像这样将 gm 与 Bluebird 一起使用:
var gm = require('gm');
var bluebird = require('bluebird');
gm = bluebird.promisifyAll(gm);
但是,当我尝试这样的事情时:
gm(req.file.buffer)
.crop(tWidth, tHeight, tWidth/2, tHeight/2)
.gravity('Center')
.toBuffer()
.then(...)
我收到此错误:
gm().toBuffer() expects a callback.
如果我只承诺缓冲方法:
bluebird.promisify(gm(req.file.buffer)
.crop(tWidth, tHeight, tWidth/2, tHeight/2)
.gravity('Center')
.toBuffer)()
.then(buff => {...})
我收到这个错误:
TypeError: this.stream is not a function
6:36:21 AM web.1 | at toBuffer (/Users/danielrvt/IdeaProjects/twe-backend/node_modules/gm/lib/command.js:162:17)
如果我不使用 promises,它工作得很好。
这并不是您应该如何使用 gm
模块,因为它旨在提供工厂 gm()
和许多可级联的突变函数,例如 .resize()
。
Bluebird 的 .promisifyAll()
仅适用于接受回调的函数,gm
的大多数函数不接受回调。
如果您希望将 gm
与 promise 一起使用,您需要自己 "promisify" 将调用包装为
function mutateAndSave() {
return new Promise( function(resolve,reject) {
try {
gm(image)
.doSomething()
.write(outputPath, function(err) {
if(err) {
throw(err);
}
resolve();
});
}
catch (err) {
reject(err);
}
});
}
之后,您可以
mutateAndSave()
.then(...)
.catch(...);
更新
这里有两种方法可以满足您的需求,但是...
您会注意到,两者都比仅按预期使用 gm
复杂得多。 ;)
这是一种使用事件状态机执行所需操作的方法。
const gm = requre('gm');
const EventEmitter = require('events');
const input_path = './image.jpg'
const output_path = './newimage.jpg';
const worker = new EventEmitter(); // create an event worker
// define the worker states - note: NO error checking! Muy mal!
const event_states={
start:() => worker.emit('resize',gm(input_path)), // creates a new gm image instance
resize:(img) => worker.emit('crop', img.resize(100,100)), // resizes the image
crop:(img) => worker.emit('write', img.crop(2,2,50,50)), // crops it
write:(img) => { // and writes it to the filesystem
img.write(output_path, err => {
if(err) {
worker.emit('error',err);
return;
}
worker.emit('complete');
});
},
error: (err) => console.error(err.toString()), // report error
complete: () => console.log('complete') // alert on completion
};
// add the states to the worker as event handlers
Object.keys(event_states).forEach(k => worker.on(k, event_states[k]));
// and fire it up...
worker.emit('start');
或者,如果您真的非常想使用 Promises...
const writer = function (img) {
return new Promise( (resolve, reject) => {
img.write(output_path,err => {
if(err) {
reject(err);
return;
}
resolve(true);
});
});
};
const reader = function (input_path) {
return new Promise( (resolve,reject) => {
let img;
try {
img = gm(input_path);
}
catch (err) {
reject(err);
return;
}
resolve(img);
});
};
reader('./image.jpg')
.then( img => { return img.resize(100,100) }) // the return here is for illustration only
.then( img => img.crop(2,2,50,50)) // since this does exactly the same thing with less typing!
.then( writer )
.then( res => console.log('complete'))
.catch( err => console.error(err.toString()));
同样,更多的输入和复杂性都是为了使用最新的 "shiny" 东西。 ;)
我一直在尝试像这样将 gm 与 Bluebird 一起使用:
var gm = require('gm');
var bluebird = require('bluebird');
gm = bluebird.promisifyAll(gm);
但是,当我尝试这样的事情时:
gm(req.file.buffer)
.crop(tWidth, tHeight, tWidth/2, tHeight/2)
.gravity('Center')
.toBuffer()
.then(...)
我收到此错误:
gm().toBuffer() expects a callback.
如果我只承诺缓冲方法:
bluebird.promisify(gm(req.file.buffer)
.crop(tWidth, tHeight, tWidth/2, tHeight/2)
.gravity('Center')
.toBuffer)()
.then(buff => {...})
我收到这个错误:
TypeError: this.stream is not a function 6:36:21 AM web.1 | at toBuffer (/Users/danielrvt/IdeaProjects/twe-backend/node_modules/gm/lib/command.js:162:17)
如果我不使用 promises,它工作得很好。
这并不是您应该如何使用 gm
模块,因为它旨在提供工厂 gm()
和许多可级联的突变函数,例如 .resize()
。
Bluebird 的 .promisifyAll()
仅适用于接受回调的函数,gm
的大多数函数不接受回调。
如果您希望将 gm
与 promise 一起使用,您需要自己 "promisify" 将调用包装为
function mutateAndSave() {
return new Promise( function(resolve,reject) {
try {
gm(image)
.doSomething()
.write(outputPath, function(err) {
if(err) {
throw(err);
}
resolve();
});
}
catch (err) {
reject(err);
}
});
}
之后,您可以
mutateAndSave()
.then(...)
.catch(...);
更新
这里有两种方法可以满足您的需求,但是...
您会注意到,两者都比仅按预期使用 gm
复杂得多。 ;)
这是一种使用事件状态机执行所需操作的方法。
const gm = requre('gm');
const EventEmitter = require('events');
const input_path = './image.jpg'
const output_path = './newimage.jpg';
const worker = new EventEmitter(); // create an event worker
// define the worker states - note: NO error checking! Muy mal!
const event_states={
start:() => worker.emit('resize',gm(input_path)), // creates a new gm image instance
resize:(img) => worker.emit('crop', img.resize(100,100)), // resizes the image
crop:(img) => worker.emit('write', img.crop(2,2,50,50)), // crops it
write:(img) => { // and writes it to the filesystem
img.write(output_path, err => {
if(err) {
worker.emit('error',err);
return;
}
worker.emit('complete');
});
},
error: (err) => console.error(err.toString()), // report error
complete: () => console.log('complete') // alert on completion
};
// add the states to the worker as event handlers
Object.keys(event_states).forEach(k => worker.on(k, event_states[k]));
// and fire it up...
worker.emit('start');
或者,如果您真的非常想使用 Promises...
const writer = function (img) {
return new Promise( (resolve, reject) => {
img.write(output_path,err => {
if(err) {
reject(err);
return;
}
resolve(true);
});
});
};
const reader = function (input_path) {
return new Promise( (resolve,reject) => {
let img;
try {
img = gm(input_path);
}
catch (err) {
reject(err);
return;
}
resolve(img);
});
};
reader('./image.jpg')
.then( img => { return img.resize(100,100) }) // the return here is for illustration only
.then( img => img.crop(2,2,50,50)) // since this does exactly the same thing with less typing!
.then( writer )
.then( res => console.log('complete'))
.catch( err => console.error(err.toString()));
同样,更多的输入和复杂性都是为了使用最新的 "shiny" 东西。 ;)