Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Function - Resize and overwrite existing image on upload to Storage

So I have followed the Google's official sample for creating a Cloud Storage triggered Firebase Function that will create resized thumbnails from uploaded images and upload them to the Storage as well. Here it is simplified:

exports.generateThumbnail = functions.storage.object().onChange(event => {

    // get the uploaded file data (bucket, name, type...)

    // return if the file is not an image or name begins with "thumb_"

    // download the uploaded image in a temporary local file,
    // resize it using ImageMagick
    // upload it to storage with the name "thumb_<filename>"

}

However, when the new thumbnail uploads, the function gets triggered again and so forth in a loop. They have avoided that by returning if the uploaded file has a "thumb_" prefix.

You then end up with two images (the original and the thumbnail) and I want to rewrite the existing image with the thumbnail so I only have one image with the original path.

I don't know how to go about this because I don't know how to evade the reupload loop without a name change. I can delete the original image after uploading the thumbnail but the link pointing to the original image is already returned and saved in the Realtime Database (these images are profile pictures for users).

like image 829
mj3c Avatar asked Dec 14 '22 21:12

mj3c


1 Answers

After looking at the bucket.js documentation in the @google-cloud/storage npm module, I have finally managed to overwrite the original file/path with the thumbnail image and also avoid the loop,

It can be done by attaching custom metadata when uploading the thumbnail, and testing for that metadata when the function triggers the next time.

I will just post the changes I made, the rest is the same as in the linked sample.

Here's the testing:

const filePath = event.data.name
const metadata = event.data.metadata

if (metadata.isThumb) {
    console.log('Exiting: Already a thumbnail')
    return
}

And here's the part when the spawn promise returns:

    return spawn(/* ... */)
}).then(_ => {
    console.log('Thumbnail created locally.')
    metadata.isThumb = true  // We add custom metadata
    const options = {
        destination: filePath,  // Destination is the same as original
        metadata: { metadata: metadata }
    }
    // We overwrite the (bigger) original image but keep the path
    return bucket.upload(/* localThumb */, options)
})
like image 51
mj3c Avatar answered Dec 21 '22 10:12

mj3c