use -auto-orient with imagemagick in Firebase functions
I followed the Firebase functions tutorials from the firecasts: https://www.youtube.com/watch?v=pDLpEn3PbmE&t=338s to use firebase to create a thumbnail when I upload an image.
This all works well but when I upload an image that has been taken with an iPhone it's rotated (vertical image is saved horizontally). So I did some research about that and I came across the -auto-orient
parameter from ImageMagick (http://magick.imagemagick.org/script/command-line-options.php#auto-orient)
But I'm not sure how I add this parameter to the spawn function to take this parameter into account
My working code (just the part of it that is relevant) without the -auto-orient
...
return bucket.file(filePath).download({
destination: tempFilePath
})
.then(() => {
console.log('Image downloaded locally to', tempFilePath);
return spawn('convert', [tempFilePath, '-thumbnail', '200x200>', tempFilePath]);
})
.then(() => {
console.log('Thumbnail created!');
const thumbFilePath = filePath.replace(/(\/)?([^\/]*)$/, '$1thumb_$2');
console.log(`thumbFilePath: ${thumbFilePath}`);
return bucket.upload(tempFilePath, {
destination: thumbFilePath
});
})
...
the code that I tried with the -auto-orient
parameter
...
return bucket.file(filePath).download({
destination: tempFilePath
})
.then(() => {
console.log('Image downloaded locally to', tempFilePath);
return spawn('convert', ['-auto-orient', tempFilePath, '-thumbnail', '200x200>', tempFilePath]);
})
.then(() => {
console.log('Thumbnail created!');
const thumbFilePath = filePath.replace(/(\/)?([^\/]*)$/, '$1thumb_$2');
console.log(`thumbFilePath: ${thumbFilePath}`);
return bucket.upload(tempFilePath, {
destination: thumbFilePath
});
})
...
But when I deploy this to firebase and I try to upload an image I get the following error message which doesn't give me a lot of information about why it is not working
Function execution took 6227 ms, finished with status: 'connection error'
any ideas?
I was also experiencing the "Connection Error" message inside GCF. I did 3 things to fix it, though I am not entirely sure if only 1 was the cause or if it was all 3. They were:
- Unresolved Promises
- Lack of using the
callback()
function provided by GCF - Using
require('child-process-promise').exec
instead ofrequire('child-process-promise').spawn
Here's my code, which has been running 2x/second for 12 hours now without encountering the "Connection Error" message.
const Storage = require('@google-cloud/storage');
const exec = require('child-process-promise').exec;
const uuidv1 = require('uuid/v1');
const _ = require('lodash');
exports.processFile = (event, callback) => {
const file = event.data;
if(file.contentType.indexOf('image/') !== 0) {
console.log(file.name + ' is not an image');
callback();
} else if(!_.isUndefined(file.metadata) && !_.isUndefined(file.metadata['x-processed'])) {
console.log(file.name + ' was already processed');
callback();
} else if(file.resourceState === 'not_exists') {
console.log('This is a deletion event.');
callback();
} else if (file.resourceState === 'exists' && file.metageneration > 1) {
console.log('This is a metadata change event.');
callback();
} else {
const storage = new Storage();
const bucket = storage.bucket(file.bucket);
const parts = file.name.split('.');
const tempFilePath = '/tmp/' + uuidv1() + '.' + _.last(parts);
const tempFinalPath = '/tmp/' + uuidv1() + '.' + _.last(parts);
console.log('Processing file: ' + file.name);
return bucket.file(file.name).download({
destination: tempFilePath
})
.then(() => {
console.log('Image downloaded locally to ', tempFilePath);
return exec(`convert -auto-orient "${tempFilePath}" "${tempFinalPath}"`)
})
.then(() => {
console.log('uploading modified file to ' + file.name);
return bucket.upload(tempFinalPath, {
destination: file.name,
contentType: file.contentType,
metadata: {
metadata: {
"x-processed": "yes"
}
}
})
})
.then(() => {
console.log('file uploaded successfully to ' + file.name);
callback()
})
.catch((err) => {
callback(err);
})
}
}