From e60efc3cc960e8dbc0a9eafe9c4581492a2dd9f8 Mon Sep 17 00:00:00 2001 From: Nicolas Garnier Date: Wed, 12 Oct 2016 16:57:29 +0200 Subject: [PATCH] Adding a convert image sample Change-Id: Id55a5a77180f4424242b2a02203fa45f6d5d7c3f --- README.md | 6 ++ convert-images/README.md | 32 +++++++++ convert-images/firebase.json | 1 + convert-images/functions/index.js | 99 +++++++++++++++++++++++++++ convert-images/functions/package.json | 12 ++++ 5 files changed, 150 insertions(+) create mode 100644 convert-images/README.md create mode 100644 convert-images/firebase.json create mode 100644 convert-images/functions/index.js create mode 100644 convert-images/functions/package.json diff --git a/README.md b/README.md index 14a9d96..2bd2544 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ Demonstrates how to authorize with a 3rd party sign-in mechanism (Instagram in t Uses an HTTP trigger. +### [Automatically Convert Images](/convert-images) + +Demonstrates how to automatically convert images that are uploaded to Firebase Storage to JPEG using ImageMagick. + +Uses a Firebase Storage trigger. + ### [Text Moderation](/text-moderation) How to moderate user input text for bad words. For example this can be used to moderate usernames, chat or forum messages. diff --git a/convert-images/README.md b/convert-images/README.md new file mode 100644 index 0000000..f1ea7b8 --- /dev/null +++ b/convert-images/README.md @@ -0,0 +1,32 @@ +# Automatically Convert Images + +This sample demonstrates how to automatically convert images that are uploaded to Firebase Storage to JPEG using ImageMagick. + + +## Functions Code + +See file [functions/index.js](functions/index.js) for the email sending code. + +The image conversion is performed using ImagMagick which is installed by default on all Firebase Functions. This is a CLI for which we use a NodeJS wrapper. The image is first downloaded locally from the Firebase Storage bucket to the `tmp` folder using the [google-cloud](https://github.com/GoogleCloudPlatform/google-cloud-node) SDK. + +The dependencies are listed in [functions/package.json](functions/package.json). + + +## Trigger rules + +The function triggers on upload of any file to the Firebase Functions bucket. + + +## Setting up the sample + +Create a Firebase project on the [Firebase Console](https://console.firebase.google.com) and visit the **Storage** tab. + +Replace the placeholder `FIREBASE_STORAGE_BUCKET_NAME` with the name of the Firebase Storage bucket which can be found in the **Storage** tab of your Firebase project's console. It is typically of the form `.appspot.com`. + + +## Deploy and test + +To test the sample: + + - Deploy your project using `firebase deploy` + - Go to the Firebase Console **Storage** tab and upload an image that is not a JEPG, for instance a PNG. After a short time an image with the same base name but the `.jpg` extension will be created in the same folder (make sure you refresh the UI to see the new file). diff --git a/convert-images/firebase.json b/convert-images/firebase.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/convert-images/firebase.json @@ -0,0 +1 @@ +{} diff --git a/convert-images/functions/index.js b/convert-images/functions/index.js new file mode 100644 index 0000000..8e42ae2 --- /dev/null +++ b/convert-images/functions/index.js @@ -0,0 +1,99 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for t`he specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +const functions = require('firebase-functions'); +const im = require('imagemagick'); +const mkdirp = require('mkdirp'); +const gcs = require('@google-cloud/storage')(); +const Q = require('q'); + +// File extension for the created JPEG files. +const JPEG_EXTENSION = 'jpg'; + +/** + * When an image is uploaded in the Storage bucket it is converted to JPEG automatically using + * ImageMagick. + */ +// TODO(DEVELOPER): Replace the placeholder below with the name of the Firebase Functions bucket. +exports.imagetojpg = functions.cloud.storage(FIREBASE_STORAGE_BUCKET_NAME).onChange(event => { + console.log(event); + const result = Q.defer(); + + const filePath = event.data.name; + const filePathSplit = filePath.split('/'); + const fileName = filePathSplit.pop(); + const fileNameSplit = fileName.split('.'); + const fileExtension = fileNameSplit.pop(); + const baseFileName = fileNameSplit.join('.'); + const fileDir = filePathSplit.join('/') + (filePathSplit.length > 0 ? '/' : ''); + const JPEGFilePath = `${fileDir}${baseFileName}.${JPEG_EXTENSION}`; + const tempLocalDir = `/tmp/${fileDir}`; + const tempLocalFile = `${tempLocalDir}${fileName}`; + const tempLocalJPEGFile = `/tmp/${JPEGFilePath}`; + + // Exit if this is triggered on a file that is not an image. + if (!event.data.contentType.startsWith('image/')) { + console.log('This is not an image.'); + return null; + } + + // Exit if this is triggered on a file that is not an image. + if (event.data.contentType.startsWith('image/jpeg')) { + console.log('Already a JPEG.'); + return null; + } + + // Exit if this is a move or deletion event. + if (event.data.resourceState === 'not_exists') { + console.log('This is a deletion event.'); + return null; + } + + // Create the temp directory where the storage file will be downloaded. + mkdirp(tempLocalDir, err => { + if (err) return result.reject(err); + + // Download file from bucket. + const bucket = gcs.bucket(event.data.bucket); + bucket.file(filePath).download({ + destination: tempLocalFile + }, err => { + if (err) return result.reject(err); + + console.log('The file has been downloaded to', tempLocalFile); + // Convert the image to JPEG using ImageMagick. + im.convert([ + tempLocalFile, + tempLocalJPEGFile + ], err => { + if (err) return result.reject(err); + + console.log('Created JPEG for', filePath); + // Uploading the JPEG. + bucket.upload(tempLocalJPEGFile, { + destination: JPEGFilePath + }, err => { + if (err) return result.reject(err); + + console.log('JPEG uploaded to Storage at', JPEGFilePath); + result.resolve(); + }); + }); + }); + }); + return result.promise; +}); diff --git a/convert-images/functions/package.json b/convert-images/functions/package.json new file mode 100644 index 0000000..f6e3f1a --- /dev/null +++ b/convert-images/functions/package.json @@ -0,0 +1,12 @@ +{ + "name": "functions", + "description": "Firebase Functions", + "dependencies": { + "@google-cloud/storage": "^0.2.0", + "firebase": "^3.4.1", + "firebase-functions": "https://storage.googleapis.com/firebase-preview-drop/node/firebase-functions/firebase-functions-preview.latest.tar.gz", + "imagemagick": "^0.1.3", + "mkdirp": "^0.5.1", + "q": "^1.4.1" + } +}