Skip to content

Instantly share code, notes, and snippets.

@max-barry
Last active April 29, 2021 16:47
Show Gist options
  • Save max-barry/ccd9541a3252f98c841af8197d441737 to your computer and use it in GitHub Desktop.
Save max-barry/ccd9541a3252f98c841af8197d441737 to your computer and use it in GitHub Desktop.
Dynamic Firestore Image Resizing Function > Simple #1
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