问题描述
我让用户使用Multer-S3将 多个图像 直接上传到Amazon-S3,然后通过循环在前端显示这些图像。所有的作品完美。然而,当通过手机上传图片(在iPhone或Android上拍摄的图片)时,手机的方向是正确的,但在桌面上没有正确的方向。主要问题。
这是由于我相信图像的EXIF数据。
看起来像ImageMagick或Kraken JS 可能是解决这个问题的一种方法,但是对于我来说,我无法弄清楚如何实现上传和显示下面显示的图像。
如何更改我的代码以自动定位图片?注意:它必须适用于多个图像。 感谢您的帮助! 如何让用户一次将多个图片直接上传到Amazon-S3: 我如何显示图像在前端。 Listings.currentimages是一个包含所有图像链接的数组。 // awspath 是我的Amazon-S3路径的文件路径 问题在于iOS设置了图片的EXIF元数据导致此行为。您可以使用可以读取EXIF元数据并为您旋转图像的库。
aws。 config.update({
secretAccessKey:'AccessKey',
accessKeyId:'KeyID',
region:'us-east-2'
});
var s3 = new aws.S3();
var storage = multerS3({
limits:{files:25},
s3:s3,
bucket:'files',
key:函数(req,file,cb){
var fileExtension = file.originalname.split(。)[1];
var path =uploads /+ req.user._id + Date。 now()+。+ fileExtension;
cb(null,path);
},
})
var upload = multer {storage:storage})。any(images,25);
router.post(/,middleware.isLoggedIn,function(req,res,next){
upload(req,res,function(err){
$ if(err){
console.log(err);
res.redirect('/')
}
Listing.findById(req.params.id,function(err,foundListings){
var allimages = []
if(typeof req.files! ==undefined){
for(var i = 0; i< req.files.length; i ++){
allimages.push(req.files [i] .key);
var currentimages = allimages;
var newListings = {currentimages:currentimages}
//移除了其他模型方面
列表。 create(newListings,function(err,newlyCreated){
if(err){
console.log(err);
} else {
res.redirect / listing);
}
});
});
app.locals.awspath =https://s3.us-east-2.amazonaws.com/myfiles/ ;
< div id ='allimages'>
<%for(var i = 0; i< listings.currentimages.length; i ++){%>
< div class ='smallerImages'>
< img class =smallsrc =<%= url2%>>
< / div>
<%}%>
< / div>
$ b jpeg-autorotate ()是一个简单的 有很好的文档(你应该检查出来)。
示例
var jo = require('jpeg-autorotate');
var fs = require('fs');
// var options = {quality:85};
var options = {};
var path ='/tmp/Portrait_8.jpg'; //你也可以使用Buffer
jo.rotate(path,options,function(error,buffer,orientation){
if(error){
console.log('An error发生在旋转文件时:'+ error.message);
return;
}
console.log('Orientation was:'+ orientation);
/上传缓冲区到s3,保存到磁盘或更多...
fs.writeFile(/ tmp / output.jpg,buffer,function(err){
if(err){
return console.log(err);
}
console.log(The file was saved!);
});
});
您可以从)
确保您拥有正确的权限(读写),正确的函数触发器,正确的Handler在创建函数的时候!确保在CloudWatch中检出功能日志,使调试更容易。如果开始超时,请增加功能超时并增加内存。
I'm letting users upload multiple images directly to Amazon-S3 using Multer-S3 and then displaying those images on the front end via a loop. All works perfectly.
However when the images are uploaded via mobile (image taken on an iPhone or Android) the orientation is correct on mobile but does NOT have correct orientation on desktops. Major problem.
This is due to the images EXIF data I believe.
Seems like ImageMagick or Kraken JS https://kraken.io/docs/storage-s3 might be a way to solve it but for the life of me I cannot figure out how to implement either with the way I'm uploading and showing images shown below.
How would I change my code below to auto-orient the images? Note: It must work for multiple images.
Thanks for any help!
Heres's how I'm letting users upload multiple images at a time directly to Amazon-S3:
aws.config.update({
secretAccessKey: 'AccessKey',
accessKeyId: 'KeyID',
region: 'us-east-2'
});
var s3 = new aws.S3();
var storage = multerS3({
limits : { files: 25 },
s3: s3,
bucket: 'files',
key: function (req, file, cb) {
var fileExtension = file.originalname.split(".")[1];
var path = "uploads/" + req.user._id + Date.now() + "." + fileExtension;
cb(null, path);
},
})
var upload = multer({storage: storage}).any("images", 25);
router.post("/", middleware.isLoggedIn, function(req, res, next){
upload(req,res,function(err) {
if(err) {
console.log(err);
res.redirect('/')
}
Listings.findById(req.params.id, function(err, foundListings){
var allimages = []
if(typeof req.files !== "undefined") {
for(var i = 0; i < req.files.length; i++) {
allimages.push(req.files[i].key);
}
}
var currentimages = allimages;
var newListings = {currentimages:currentimages}
//Removed the other Model aspects
Listings.create(newListings, function(err, newlyCreated){
if(err){
console.log(err);
} else {
res.redirect("/listings");
}
});
});
How I'm displaying the images on the front end. Listings.currentimages is an array containing all image links.
app.locals.awspath = "https://s3.us-east-2.amazonaws.com/myfiles/";
// awspath is the file path to my Amazon-S3 path
<div id='allimages'>
<% for(var i = 0; i < listings.currentimages.length; i++ ) { %>
<div class='smallerImages'>
<% var url2 = awspath + listings.currentimages[i] %>
<img class="small" src="<%= url2 %>">
</div>
<% } %>
</div>
The problem is that iOS sets the image's EXIF metadata which causes this behavior. You can use a library that can read the EXIF metadata and rotate the image for you.
jpeg-autorotate (https://github.com/johansatge/jpeg-autorotate) is a very simple lib and has very nice documentation (you should check it out).
Example
var jo = require('jpeg-autorotate');
var fs = require('fs');
// var options = {quality: 85};
var options = {};
var path = '/tmp/Portrait_8.jpg'; // You can use a Buffer, too
jo.rotate(path, options, function(error, buffer, orientation) {
if (error) {
console.log('An error occurred when rotating the file: ' + error.message);
return;
}
console.log('Orientation was: ' + orientation);
// upload the buffer to s3, save to disk or more ...
fs.writeFile("/tmp/output.jpg", buffer, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
});
You can find some sample images with different EXIF rotation metadata from here
Converted as an AWS Lambda Function
// Name this file index.js and zip it + the node_modules then upload to AWS Lambda
console.log('Loading function');
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var jo = require('jpeg-autorotate');
// Rotate an image given a buffer
var autorotateImage = function(data, callback) {
jo.rotate(data, {}, function(error, buffer, orientation) {
if (error) {
console.log('An error occurred when rotating the file: ' + error.message);
callback(error, null);
} else {
console.log('Orientation was: ' + orientation);
callback(null, buffer);
}
});
};
// AWS Lambda runs this on every new file upload to s3
exports.handler = function(event, context, callback) {
console.log('Received event:', JSON.stringify(event, null, 2));
// Get the object from the event and show its content type
var bucket = event.Records[0].s3.bucket.name;
var key = event.Records[0].s3.object.key;
s3.getObject({Bucket: bucket, Key: key}, function(err, data) {
if (err) {
console.log("Error getting object " + key + " from bucket " + bucket +
". Make sure they exist and your bucket is in the same region as this function.");
callback("Error getting file: " + err, null);
} else {
// log the content type, should be an image
console.log('CONTENT TYPE:', data.ContentType);
// rotate the image
autorotateImage(data.Body, function(error, image) {
if (error) {
callback("Error rotating image: " + error, null);
}
const params = {
Bucket: bucket,
Key: 'rotated/' + key,
Body: image
};
// Upload new image, careful not to upload it in a path that will trigger the function again!
s3.putObject(params, function (err, data) {
if (error) {
callback("Error uploading rotated image: " + error, null);
} else {
console.log("Successfully uploaded image on S3", data);
// call AWS Lambda's callback, function was successful!!!
callback(null, data);
}
});
});
}
});
};
Notes This function upload the rotated images to the same bucket but you can easily change that. If you are just starting with AWS Lambda, I'd suggest you learn more about it (https://www.youtube.com/watch?v=eOBq__h4OJ4, https://www.youtube.com/watch?v=PEatXsXIkLc)
Make sure you've the right permissions (read and write), correct function trigger, correct "Handler" when creating the function! Make sure to checkout the function logs in CloudWatch too, makes debugging a lot easier. If it starts timing out, increase the function timeout and increase it's memory.
这篇关于上传时错误的图像方向 - Amazon S3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!