Amazon Lambda 函数合并多个 s3 图像并放入目标存储桶
Amazon Lambda function merge multiple s3 images and put to a destination bucket
我正在研究一个 lambda 函数,它将通过 amazon rest api.
触发
我创建了以下
- REST API 控制台上的
POST
端点
- 链接到 REST 的 lambda 函数 API
现在,作为第一次尝试,我创建了函数,使其接受参数为
{
"userProfileImagePath":"facebook users profile image path via GET /{user-id}/picture"
}
lambda 函数将使用 request
模块获取图像,然后上传到存储桶。
因为我使用了多个模块,所以我在本地创建了所有内容并将它们压缩,包括 node_modules
并通过指定 Handler
名称将它们上传到 lambda 函数控制台。
到目前为止还不错,效果很好。
现在为了扩展这个,我尝试发送 2 张个人资料图片
- 一个来自用户
- 另一个是 his/her 朋友之一
- 将两个图像合并为一个,然后将合并后的图像上传到目标文件。
我尝试了不同的合并方法,但没有任何效果。在这里找到了一些解决方案,似乎他们真的不喜欢流
这是我目前所做的,正如我所提到的,两张图片都被上传到一个存储桶中,但是合并似乎失败了,我 运行 没想到要完成这个,如果你可以给我一些指导。
目前它使用异步模块来完成单独的任务
- 首先将两张图片并行上传到s3
- 然后使用s3.getObject并行下载它们
- 最后在完成第二个任务时尝试合并并推回 s3
基本上会有一个模板图像,在模板图像上将放置(合并)多个图像,在下面的代码中,我正在考虑将 userProfileImagePath
作为主模板并尝试将另一个图像合并到它。
如果有其他方法,请告诉我。
这是我目前所做的
/**
* This is a test script which runs as a lambda function on amazon
* The lamda function is linked with an amazon end point
* The script will accept a image url (facebook/gravator) etc and will upload to a destination s3 bucket and returns the url
* The param looks like
{
"userProfileImagePath":"https://fbcdn-profile-a.......",
"friendProfileImagePath":"https://fbcdn-profile-a......."
}
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
gm = require('gm'),
imageMagick = gm.subClass({ imageMagick: true }),
aws = require('aws-sdk');
exports.handler = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'destination_bucket',
response = {} ,
s3 = new aws.S3();
if (req.userProfileImagePath === '') {
errMsg = 'Missing the userProfileImage';
}
if (req.friendProfileImagePath === '') {
errMsg = 'Missing the friendProfileImagePath ';
}
if (errMsg === '') {
async.auto({
copyUserImageToS3 : function(autoCallback) {
console.log('MyImage :'+req.userProfileImagePath);
//var myImageData = {} ;
request({
url: req.userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: userProfileImageName+'.jpg',
ContentType: res.headers['content-type'],
ContentLength: res.headers['content-length'],
Body: body, // buffer
ACL:'public-read'
}, autoCallback);
});
},
copyFriendImageToS3 : function(autoCallback) {
console.log('FriendImage :'+req.friendProfileImagePath);
//var friendImageData = {} ;
request({
url: req.friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: friendProfileImageName+'.jpg',
ContentType: res.headers['content-type'],
ContentLength: res.headers['content-length'],
Body: body, // buffer
ACL:'public-read'
}, autoCallback);
});
},
getUserImageFromS3 : ['copyUserImageToS3', function(autoCallback,results) {
s3.getObject({
Bucket: destinationBucket,
Key: userProfileImageName+'.jpg',
}, autoCallback);
}],
getFriendImageFromS3 : ['copyFriendImageToS3', function(autoCallback,results) {
s3.getObject({
Bucket: destinationBucket,
Key: friendProfileImageName+'.jpg',
}, autoCallback);
}],
mergeImages : ['getUserImageFromS3','getFriendImageFromS3', function(autoCallback,results) {
console.log('Here');
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(results.getUserImageFromS3.body)
.in('-page', '+100+100')
.in(results.getFriendImageFromS3.body)
.minify()
.mosaic()
.toBuffer('JPG', function (err, buffer) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: mergedImageName+'.jpg',
ContentType: results.getUserImageFromS3.headers['content-type'],
ContentLength: results.getUserImageFromS3.headers['content-length'],
Body: buffer, // buffer
ACL:'public-read'
}, autoCallback);
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
context.done(null,response);
} else {
response = {
"stat":"ok",
"imageUrl":"https://s3-................../"+mergedImageName+".jpg"
} ;
context.done(null,response);
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
context.done(null,response);
}
};
更新
我尝试在进行一些更改后在本地获取代码 运行,并使用文件系统进行操作,它似乎可以正常工作,但不确定如何使用 s3 使其在 lamba 上也能正常工作
这是使用文件系统在本地工作的代码
/**
* This will download both the images locally and then merge them
* We can merge multiple images as we need on a base template specifiying the position as shown in the code
* need to make sure that the graphicsmagick is inatalled
* sudo apt-get install graphicsmagick
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
fs = require('fs'),
gm = require('gm'),
imageMagick = gm.subClass({ imageMagick: true }),
userProfileImagePath ='https://fbcdn-profile-a.akamaihd.net...',
friendProfileImagePath ='https://fbcdn-profile-a.akamaihd.net..';
exports.mergeFile = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'testimagemanipulator',
response = {} ;
if (errMsg === '') {
async.auto({
copyUserImage : function(autoCallback) {
request({
url: userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile(__dirname +'/public/images/'+userProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
copyFriendImage : function(autoCallback) {
request({
url: friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile(__dirname +'/public/images/'+friendProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
mergeImages : ['copyUserImage','copyFriendImage', function(autoCallback,results) {
console.log('Here');
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(__dirname +'/public/images/'+userProfileImageName+'.jpg')
.in('-page', '+140+50')
.in(__dirname +'/public/images/'+friendProfileImageName+'.jpg')
.minify() // Halves the size, 512x512 -> 256x256
.mosaic() // Merges the images as a matrix
.write(__dirname +'/public/images/'+mergedImageName+'.jpg', function (err) {
if (err) { return autoCallback(err); }
fs.unlink(__dirname +'/public/images/'+userProfileImageName+'.jpg');
fs.unlink(__dirname +'/public/images/'+friendProfileImageName+'.jpg');
return autoCallback() ;
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
console.log(response) ;
} else {
response = {
"stat":"ok",
"imageUrl":__dirname +'/public/images/'+mergedImageName+'.jpg'
} ;
console.log(response) ;
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
console.log(response) ;
}
};
module.exports.mergeFile() ;
好的,看起来很难实现我在上述问题中所解释的目标。然而,在尝试了几次之后,尝试的不同模块 none 成功了。
如前所述,lambda 函数的目的是
获取 public 图片 url (facebook)
下载并合并,也可以通过图片模板合并
- 在合并后的图像中写入一些文本。
到目前为止,最好的图像处理模块是 gm
,它可以在 aws lambda 上使用,我们需要确保它是 Image Magic
的子类
接下来是合并操作可以通过使用 aws /tmp
文件夹来完成,图像可以临时放置在文件夹中,合并完成后可以将它们从那里删除。
这是一个链接到 aws REST 的工作 lambda 脚本 API
/**
* This is a test script which runs as a lambda function on amazon
* The lamda function is linked with an amazon end point
* The script will accept a image url (facebook/gravator) etc and will upload to a destination s3 bucket and returns the url
* The param looks like
{
"userProfileImagePath":"https://fbcdn-profile-a.akamaihd.net/....",
"friendProfileImagePath":"https://fbcdn-profile-a.akamaihd.net/...."
}
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
gm = require('gm').subClass({ imageMagick: true }),
fs = require('fs'),
aws = require('aws-sdk');
exports.handler = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'mybucket',
response = {} ,
s3 = new aws.S3();
if (req.userProfileImagePath === '') {
errMsg = 'Missing the userProfileImage';
}
if (req.friendProfileImagePath === '') {
errMsg = 'Missing the friendProfileImagePath ';
}
if (errMsg === '') {
async.auto({
copyUserImage : function(autoCallback) {
request({
url: req.userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile('/tmp/'+userProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
copyFriendImage : function(autoCallback) {
request({
url: req.friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile('/tmp/'+friendProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
mergeImages : ['copyUserImage','copyFriendImage', function(autoCallback,results) {
var bgImage = '/tmp/'+userProfileImageName+'.jpg',
frontImage = '/tmp/'+friendProfileImageName+'.jpg';
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(bgImage)
.in('-page', '+140+50')
.in(frontImage)
.mosaic() // Merges the images as a matrix
.font("Arial")
.fontSize(50)
.fill('black')
.drawText(1, 1, 'Hello World', 'Center')
.fill('blue')
.drawText(0, 0, 'Hello World', 'Center')
.write('/tmp/'+mergedImageName+'.jpg', function (err) {
if (err) { return autoCallback(err); }
var stream = fs.createReadStream('/tmp/'+mergedImageName+'.jpg');
var stats = fs.statSync('/tmp/'+mergedImageName+'.jpg');
console.log('Merged File size :'+stats['size']);
s3.upload({
Bucket: destinationBucket,
Key: mergedImageName+'.jpg',
ContentType: 'image/jpeg',
ContentLength: stats['size'],
Body: stream, // buffer
ACL:'public-read'
}, autoCallback);
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
context.done(null,response);
} else {
response = {
"stat":"ok",
"imageUrl":"https://domain.amazonaws.com/mybucket/"+mergedImageName+".jpg"
} ;
context.done(null,response);
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
context.done(null,response);
}
};
我正在研究一个 lambda 函数,它将通过 amazon rest api.
触发我创建了以下
- REST API 控制台上的
POST
端点 - 链接到 REST 的 lambda 函数 API
现在,作为第一次尝试,我创建了函数,使其接受参数为
{
"userProfileImagePath":"facebook users profile image path via GET /{user-id}/picture"
}
lambda 函数将使用 request
模块获取图像,然后上传到存储桶。
因为我使用了多个模块,所以我在本地创建了所有内容并将它们压缩,包括 node_modules
并通过指定 Handler
名称将它们上传到 lambda 函数控制台。
到目前为止还不错,效果很好。
现在为了扩展这个,我尝试发送 2 张个人资料图片 - 一个来自用户 - 另一个是 his/her 朋友之一 - 将两个图像合并为一个,然后将合并后的图像上传到目标文件。
我尝试了不同的合并方法,但没有任何效果。在这里找到了一些解决方案,似乎他们真的不喜欢流
这是我目前所做的,正如我所提到的,两张图片都被上传到一个存储桶中,但是合并似乎失败了,我 运行 没想到要完成这个,如果你可以给我一些指导。
目前它使用异步模块来完成单独的任务
- 首先将两张图片并行上传到s3
- 然后使用s3.getObject并行下载它们
- 最后在完成第二个任务时尝试合并并推回 s3
基本上会有一个模板图像,在模板图像上将放置(合并)多个图像,在下面的代码中,我正在考虑将 userProfileImagePath
作为主模板并尝试将另一个图像合并到它。
如果有其他方法,请告诉我。
这是我目前所做的
/**
* This is a test script which runs as a lambda function on amazon
* The lamda function is linked with an amazon end point
* The script will accept a image url (facebook/gravator) etc and will upload to a destination s3 bucket and returns the url
* The param looks like
{
"userProfileImagePath":"https://fbcdn-profile-a.......",
"friendProfileImagePath":"https://fbcdn-profile-a......."
}
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
gm = require('gm'),
imageMagick = gm.subClass({ imageMagick: true }),
aws = require('aws-sdk');
exports.handler = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'destination_bucket',
response = {} ,
s3 = new aws.S3();
if (req.userProfileImagePath === '') {
errMsg = 'Missing the userProfileImage';
}
if (req.friendProfileImagePath === '') {
errMsg = 'Missing the friendProfileImagePath ';
}
if (errMsg === '') {
async.auto({
copyUserImageToS3 : function(autoCallback) {
console.log('MyImage :'+req.userProfileImagePath);
//var myImageData = {} ;
request({
url: req.userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: userProfileImageName+'.jpg',
ContentType: res.headers['content-type'],
ContentLength: res.headers['content-length'],
Body: body, // buffer
ACL:'public-read'
}, autoCallback);
});
},
copyFriendImageToS3 : function(autoCallback) {
console.log('FriendImage :'+req.friendProfileImagePath);
//var friendImageData = {} ;
request({
url: req.friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: friendProfileImageName+'.jpg',
ContentType: res.headers['content-type'],
ContentLength: res.headers['content-length'],
Body: body, // buffer
ACL:'public-read'
}, autoCallback);
});
},
getUserImageFromS3 : ['copyUserImageToS3', function(autoCallback,results) {
s3.getObject({
Bucket: destinationBucket,
Key: userProfileImageName+'.jpg',
}, autoCallback);
}],
getFriendImageFromS3 : ['copyFriendImageToS3', function(autoCallback,results) {
s3.getObject({
Bucket: destinationBucket,
Key: friendProfileImageName+'.jpg',
}, autoCallback);
}],
mergeImages : ['getUserImageFromS3','getFriendImageFromS3', function(autoCallback,results) {
console.log('Here');
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(results.getUserImageFromS3.body)
.in('-page', '+100+100')
.in(results.getFriendImageFromS3.body)
.minify()
.mosaic()
.toBuffer('JPG', function (err, buffer) {
if (err) { return autoCallback(err); }
s3.putObject({
Bucket: destinationBucket,
Key: mergedImageName+'.jpg',
ContentType: results.getUserImageFromS3.headers['content-type'],
ContentLength: results.getUserImageFromS3.headers['content-length'],
Body: buffer, // buffer
ACL:'public-read'
}, autoCallback);
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
context.done(null,response);
} else {
response = {
"stat":"ok",
"imageUrl":"https://s3-................../"+mergedImageName+".jpg"
} ;
context.done(null,response);
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
context.done(null,response);
}
};
更新
我尝试在进行一些更改后在本地获取代码 运行,并使用文件系统进行操作,它似乎可以正常工作,但不确定如何使用 s3 使其在 lamba 上也能正常工作 这是使用文件系统在本地工作的代码
/**
* This will download both the images locally and then merge them
* We can merge multiple images as we need on a base template specifiying the position as shown in the code
* need to make sure that the graphicsmagick is inatalled
* sudo apt-get install graphicsmagick
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
fs = require('fs'),
gm = require('gm'),
imageMagick = gm.subClass({ imageMagick: true }),
userProfileImagePath ='https://fbcdn-profile-a.akamaihd.net...',
friendProfileImagePath ='https://fbcdn-profile-a.akamaihd.net..';
exports.mergeFile = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'testimagemanipulator',
response = {} ;
if (errMsg === '') {
async.auto({
copyUserImage : function(autoCallback) {
request({
url: userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile(__dirname +'/public/images/'+userProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
copyFriendImage : function(autoCallback) {
request({
url: friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile(__dirname +'/public/images/'+friendProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
mergeImages : ['copyUserImage','copyFriendImage', function(autoCallback,results) {
console.log('Here');
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(__dirname +'/public/images/'+userProfileImageName+'.jpg')
.in('-page', '+140+50')
.in(__dirname +'/public/images/'+friendProfileImageName+'.jpg')
.minify() // Halves the size, 512x512 -> 256x256
.mosaic() // Merges the images as a matrix
.write(__dirname +'/public/images/'+mergedImageName+'.jpg', function (err) {
if (err) { return autoCallback(err); }
fs.unlink(__dirname +'/public/images/'+userProfileImageName+'.jpg');
fs.unlink(__dirname +'/public/images/'+friendProfileImageName+'.jpg');
return autoCallback() ;
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
console.log(response) ;
} else {
response = {
"stat":"ok",
"imageUrl":__dirname +'/public/images/'+mergedImageName+'.jpg'
} ;
console.log(response) ;
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
console.log(response) ;
}
};
module.exports.mergeFile() ;
好的,看起来很难实现我在上述问题中所解释的目标。然而,在尝试了几次之后,尝试的不同模块 none 成功了。 如前所述,lambda 函数的目的是
获取 public 图片 url (facebook)
下载并合并,也可以通过图片模板合并
- 在合并后的图像中写入一些文本。
到目前为止,最好的图像处理模块是 gm
,它可以在 aws lambda 上使用,我们需要确保它是 Image Magic
接下来是合并操作可以通过使用 aws /tmp
文件夹来完成,图像可以临时放置在文件夹中,合并完成后可以将它们从那里删除。
这是一个链接到 aws REST 的工作 lambda 脚本 API
/**
* This is a test script which runs as a lambda function on amazon
* The lamda function is linked with an amazon end point
* The script will accept a image url (facebook/gravator) etc and will upload to a destination s3 bucket and returns the url
* The param looks like
{
"userProfileImagePath":"https://fbcdn-profile-a.akamaihd.net/....",
"friendProfileImagePath":"https://fbcdn-profile-a.akamaihd.net/...."
}
*/
var exec = require('child_process').exec,
async = require('async'),
request = require('request'),
gm = require('gm').subClass({ imageMagick: true }),
fs = require('fs'),
aws = require('aws-sdk');
exports.handler = function(req, context) {
var errMsg = '',
userProfileImageName = 'user_profile',
friendProfileImageName = 'friend_profile',
mergedImageName = 'final_image',
destinationBucket = 'mybucket',
response = {} ,
s3 = new aws.S3();
if (req.userProfileImagePath === '') {
errMsg = 'Missing the userProfileImage';
}
if (req.friendProfileImagePath === '') {
errMsg = 'Missing the friendProfileImagePath ';
}
if (errMsg === '') {
async.auto({
copyUserImage : function(autoCallback) {
request({
url: req.userProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile('/tmp/'+userProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
copyFriendImage : function(autoCallback) {
request({
url: req.friendProfileImagePath,
encoding: null
}, function(err, res, body) {
if (err) { return autoCallback(err); }
fs.writeFile('/tmp/'+friendProfileImageName+'.jpg', body, 'binary', function(err) {
if(err) { return autoCallback(err); }
return autoCallback();
});
});
},
mergeImages : ['copyUserImage','copyFriendImage', function(autoCallback,results) {
var bgImage = '/tmp/'+userProfileImageName+'.jpg',
frontImage = '/tmp/'+friendProfileImageName+'.jpg';
gm()
.in('-page', '+0+0') // Custom place for each of the images
.in(bgImage)
.in('-page', '+140+50')
.in(frontImage)
.mosaic() // Merges the images as a matrix
.font("Arial")
.fontSize(50)
.fill('black')
.drawText(1, 1, 'Hello World', 'Center')
.fill('blue')
.drawText(0, 0, 'Hello World', 'Center')
.write('/tmp/'+mergedImageName+'.jpg', function (err) {
if (err) { return autoCallback(err); }
var stream = fs.createReadStream('/tmp/'+mergedImageName+'.jpg');
var stats = fs.statSync('/tmp/'+mergedImageName+'.jpg');
console.log('Merged File size :'+stats['size']);
s3.upload({
Bucket: destinationBucket,
Key: mergedImageName+'.jpg',
ContentType: 'image/jpeg',
ContentLength: stats['size'],
Body: stream, // buffer
ACL:'public-read'
}, autoCallback);
});
}],
},
function(err, results) {
if (err) {
response = {
"stat":"error",
"msg":"Error manipulating the image :: "+err
} ;
context.done(null,response);
} else {
response = {
"stat":"ok",
"imageUrl":"https://domain.amazonaws.com/mybucket/"+mergedImageName+".jpg"
} ;
context.done(null,response);
}
});
} else {
response = {
"stat":"error",
"msg": errMsg
} ;
context.done(null,response);
}
};