Last active
April 29, 2021 16:47
-
-
Save max-barry/ccd9541a3252f98c841af8197d441737 to your computer and use it in GitHub Desktop.
Dynamic Firestore Image Resizing Function > Simple #1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as functions from "firebase-functions"; | |
import * as admin from "firebase-admin"; | |
import * as sharp from "sharp"; | |
// Just a list of all of the formats supported by Sharp | |
const SHARP_FORMATS = Object.values(sharp.format); | |
export const dynamicImages = functions.https.onRequest(async (request, response) => { | |
// From the URL we want to get our passed parameters | |
const { query, params } = request; | |
// The URL param (/path/to/image) | |
const { 0: urlparam = "" } = params; | |
// Parse these params to integers | |
let width = query.w && parseInt(query.w); | |
let height = query.h && parseInt(query.h); | |
const quality = query.q && parseInt(query.q); | |
// We need to strip the leading "/" in he URL parameter | |
const filepath = urlparam.replace(/^\/+/, ""); | |
// If you don't have a filepath then return a 404 | |
if (!filepath || !filepath.length) { | |
response.sendStatus(400); | |
return; | |
} | |
// todo: you might want to check that width / height / quality | |
// are actually numbers and 400 if you received non-numerical inputs. | |
// Get a reference to the file on our storage using the filepath passed in the URL | |
// n.b. You will need to authenticate and initializeApp the Firebase Admin elsewhere | |
// We might be reading from the local filesystem or Amazon S3, but just do whatever you can to get a file readstream | |
const bucket = admin.storage().bucket(); | |
const ref = bucket.file(filepath); | |
// We need to check if the file exists before continuing and 404 if it doesn't | |
// UPDATE: ref.exists() appears to return an array of bools in the latest version of the storage SDK: | |
// https://googleapis.dev/nodejs/storage/latest/File.html#exists | |
// That feels like a change from previous implementations, so buyer beware for this line! | |
const [isExists] = await ref.exists(); | |
if (!isExists) { | |
response.sendStatus(404); | |
return; | |
} | |
// Get the contentType from the file's metadata | |
const { contentType } = ref.metadata | |
// We're going to use Sharp.js to resize our image. | |
// Use the URL parameters to build options for Sharp | |
const resizeOpts = { width, height, fit: "inside" }; | |
const formatOpts = { quality }; | |
const format = SHARP_FORMATS.find( | |
f => f.id === contentType.replace("image/", "") | |
); | |
// Write our content type response header | |
response.contentType(contentType); | |
// We're going to use streams to do the following: | |
// read from our source image > pipe to Sharp > pipe to the HTTP response | |
// Let's create a Sharp pipeline | |
const pipeline = sharp(); | |
// Read the remote file into that pipeline | |
ref.createReadStream().pipe(pipeline); | |
// Now run the Sharp pipeline and pipe the output to the response | |
pipeline.resize(resizeOpts).toFormat(format, formatOpts).pipe(response); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment