Skip to content

Instantly share code, notes, and snippets.

@codediodeio
Created June 28, 2017 15:54
Show Gist options
  • Save codediodeio/d4cdcfc16f02d369d6943471727c6062 to your computer and use it in GitHub Desktop.
Save codediodeio/d4cdcfc16f02d369d6943471727c6062 to your computer and use it in GitHub Desktop.
Firebase Cloud Functions image thumbnail generator using Sharp for 4x faster resizing
const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')();
const sharp = require('sharp')
const _ = require('lodash');
const path = require('path');
const os = require('os');
exports.generateThumbnail = functions.storage.object('uploads/{imageId}').onChange(event => {
const object = event.data; // The Storage object.
console.log(object)
const fileBucket = object.bucket; // The Storage bucket that contains the file.
const filePath = object.name; // File path in the bucket.
const contentType = object.contentType; // File content type.
const resourceState = object.resourceState; // The resourceState is 'exists' or 'not_exists' (for file/folder deletions).
const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
const SIZES = [64, 256, 512]; // Resize target width in pixels
if (!contentType.startsWith('image/') || resourceState == 'not_exists') {
console.log('This is not an image.');
return;
}
if (_.includes(filePath, '_thumb')) {
console.log('already processed image');
return;
}
const fileName = filePath.split('/').pop();
const bucket = gcs.bucket(fileBucket);
const tempFilePath = path.join(os.tmpdir(), fileName);
return bucket.file(filePath).download({
destination: tempFilePath
}).then(() => {
_.each(SIZES, (size) => {
let newFileName = `${fileName}_${size}_thumb.png`
let newFileTemp = path.join(os.tmpdir(), newFileName);
let newFilePath = `thumbs/${newFileName}`
sharp(tempFilePath)
.resize(size, null)
.toFile(newFileTemp, (err, info) => {
bucket.upload(newFileTemp, {
destination: newFilePath
});
});
})
})
})
{
"name": "functions",
"description": "Cloud Functions for Firebase",
"dependencies": {
"@google-cloud/storage": "^0.4.0",
"firebase-admin": "^4.1.2",
"firebase-functions": "^0.5",
"lodash": "^4.17.4",
"request-promise": "^2.0.0",
"sharp": "^0.18.1"
},
"private": true
}
@ix-xerri
Copy link

ix-xerri commented Nov 1, 2017

I'm trying to use your example but to generate thumbnails inside Firebase Storage. I am not restricting to the uploads/ folder as I want it in different folder ({user}/avatar/{imageId}) in my case. I am getting an error in the Firebase functions log ApiError: Forbidden at new util.ApiError (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:107:10)
Do I have to add a certificate as mentioned here?

@amitbravo
Copy link

cloud function with sharp , it takes around 8-10 seconds to generate a single thumbnail from a single image file . tell me this is normal .

@itwasmattgregg
Copy link

onChange() is now deprecated. you should change it to onFinalize()

@psanders
Copy link

cloud function with sharp , it takes around 8-10 seconds to generate a single thumbnail from a single image file . tell me this is normal .

I'm having the same issue.

@ProdigyMaster
Copy link

TypeError: gcs.bucket is not a function
at exports.generateThumbnail.functions.storage.object.onFinalize (/user_code/index.js:33:22)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:769:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

@wobsoriano
Copy link

wobsoriano commented Apr 21, 2020

UPDATE 2020:

This still works, you have to change some code:

1 . Change

const gcs = require('@google-cloud/storage')();

to

const { Storage }  = require('@google-cloud/storage');
const gcs = new Storage()
  1. onChange() is now deprecated. Change it to onFinalize().

  2. If you are using "fs-extra": "^9.0.0", downgrade it to version 8.1.0. Why? v9.0.0 requires node version >= 10 it seems, whereas cloud functions are still stable only for node v8 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment