Skip to content

Instantly share code, notes, and snippets.

@androidovshchik
Last active July 13, 2021 16:00
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save androidovshchik/9e9c8299d393a28f74e17cf09d06d466 to your computer and use it in GitHub Desktop.
Save androidovshchik/9e9c8299d393a28f74e17cf09d06d466 to your computer and use it in GitHub Desktop.
Firebase image optimizing in typescript
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import mkdirpPromise from 'mkdirp-promise';
import {spawn} from 'promisify-child-process';
import {ObjectMetadata} from "firebase-functions/lib/providers/storage";
admin.initializeApp();
const storage = admin.storage();
export const optimizeImage = functions.storage.object().onFinalize((object: ObjectMetadata) => {
if (!object.name) {
console.warn(`'${object.id}' has invalid name`);
return null;
}
if (!object.contentType || !object.contentType.startsWith('image/')) {
console.info(`'${object.name}' is not an image`);
return null;
}
const bucket = storage.bucket(object.bucket);
const originalFile = bucket.file(object.name);
const tempFilePath = path.join(os.tmpdir(), object.name);
const tempFolderPath = path.dirname(tempFilePath);
let metadata: any = null;
return originalFile.getMetadata()
.then((data: any) => {
if (Array.isArray(data) && data.length > 0 && data[0].metadata) {
metadata = data[0].metadata;
if (!metadata.optimized) {
return Promise.resolve();
} else {
return Promise.reject('Image has been already optimized');
}
} else {
return Promise.reject('Invalid metadata response');
}
})
.then(() => mkdirpPromise(tempFolderPath))
.then(() => originalFile.download({
destination: tempFilePath
}))
.then(() => {
console.log(`Original file downloaded to ${tempFilePath}`);
return spawn('convert', [
tempFilePath,
'-strip',
'-sampling-factor', '4:2:0',
'-interlace', 'Plane',
'-quality', '85',
tempFilePath
]);
})
.then(() => {
console.log(`Optimized image converted at ${tempFilePath}`);
return bucket.upload(tempFilePath, {
destination: originalFile,
metadata: {
metadata: {
...metadata,
optimized: true
}
}
});
})
.then(() => {
console.log(`Optimized image uploaded at ${originalFile.name}`);
fs.unlinkSync(tempFilePath);
})
.catch(error => {
console.error(error)
});
});
{
"name": "functions",
"scripts": {
"lint": "tslint --project tsconfig.json",
"build": "tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"@types/mkdirp-promise": "^5.0.0",
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.2.0",
"mkdirp-promise": "^5.0.1",
"promisify-child-process": "^3.1.0"
},
"devDependencies": {
"tslint": "^5.12.0",
"typescript": "^3.2.2"
},
"private": true
}
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2015",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
},
"compileOnSave": true,
"include": [
"src"
]
}
@nikpl7777
Copy link

Good job!

@nightroadcosplay
Copy link

Awesome job! But how do i use it with"engines": { "node": "10" } ? It keeps getting timeout.

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