Skip to content

Instantly share code, notes, and snippets.

@steelx steelx/generateThumb.js
Last active May 14, 2018

What would you like to do?
firebase functions thumbnail
const mkdirp = require('mkdirp-promise');
const gcs = require('@google-cloud/storage')({ keyFilename: 'service-account-key.json' });
const admin = require('firebase-admin');
var serviceAccount = require('./service-account-key.json');
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://<PROJECT_ID>'
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');
// Max height and width of the thumbnail in pixels.
const THUMB_MAX_HEIGHT = 640;
const THUMB_MAX_WIDTH = 640;
// Thumbnail prefix added to file names.
const THUMB_PREFIX = 'thumb_';
* When an image is uploaded in the Storage bucket We generate a thumbnail automatically using
* ImageMagick.
* After the thumbnail has been generated and uploaded to Cloud Storage,
* we write the public URL to the Firebase Realtime Database.
module.exports = (object) => {
const getUIDFromName = (name) => {
const str = name; // "users/u1xuI9dazWY3U2Ru6ljJEG3v2AD3/90342bac-5028-461d-8bc2-eb2e6b9592f7";
const regex = /users\/\s*(.*?)\s*\//g;
const match = regex.exec(str);
return match[1];
// File and directory paths.
const filePath =;
const UID = getUIDFromName(filePath);
console.log("generateThumbnail UID", UID);
const contentType = object.contentType; // This is the image MIME type
const fileDir = path.dirname(filePath);
const fileName = path.basename(filePath);
const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));
const tempLocalFile = path.join(os.tmpdir(), filePath);
const tempLocalDir = path.dirname(tempLocalFile);
const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);
// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith('image/')) {
console.log('This is not an image.');
return null;
// Exit if the image is already a thumbnail.
if (fileName.startsWith(THUMB_PREFIX)) {
console.log('Already a Thumbnail.');
return null;
// Cloud Storage files.
const bucket = gcs.bucket(object.bucket);
const file = bucket.file(filePath);
const thumbFile = bucket.file(thumbFilePath);
const metadata = {
contentType: contentType,
// To enable Client-side caching you can set the Cache-Control headers here. Uncomment below.
// 'Cache-Control': 'public,max-age=3600',
// Create the temp directory where the storage file will be downloaded.
return mkdirp(tempLocalDir).then(() => {
// Download file from bucket.
return{ destination: tempLocalFile });
}).then(() => {
console.log('The file has been downloaded to', tempLocalFile);
// Generate a thumbnail using ImageMagick.
return spawn('convert', [tempLocalFile, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile], { capture: ['stdout', 'stderr'] });
}).then(() => {
console.log('Thumbnail created at', tempLocalThumbFile);
// Uploading the Thumbnail.
return bucket.upload(tempLocalThumbFile, { destination: thumbFilePath, metadata: metadata });
}).then(() => {
console.log('Thumbnail uploaded to Storage at', thumbFilePath);
// Once the image has been uploaded delete the local files to free up disk space.
// Get the Signed URLs for the thumbnail and original image.
const config = {
action: 'read',
expires: '03-01-2500',
return Promise.all([
}).then((results) => {
console.log('Got Signed URLs.');
const thumbResult = results[0];
const originalResult = results[1];
const thumbFileUrl = thumbResult[0];
const fileUrl = originalResult[0];
// Add the URLs to the Database
return admin.database().ref('users/'+ UID).set({ photo: fileUrl, thumbnail: thumbFileUrl });
}).then(() => console.log('Thumbnail URLs saved to database.'));
const functions = require('firebase-functions');
const generateThumbnail = require('./generateThumb');
exports.generateThumbnail =;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.