Skip to content

Instantly share code, notes, and snippets.

@swistaczek
Created September 5, 2023 12:38
Show Gist options
  • Save swistaczek/7cf44d43639e6fadb06f6a2156972f98 to your computer and use it in GitHub Desktop.
Save swistaczek/7cf44d43639e6fadb06f6a2156972f98 to your computer and use it in GitHub Desktop.
Google Cloud Functions: Strip exif from image files when added to Google Cloud Storage
const functions = require('@google-cloud/functions-framework');
const { Storage } = require('@google-cloud/storage');
const ExifTransformer = require('exif-be-gone');
const stream = require('stream');
const util = require('util');
const storage = new Storage();
const pipeline = util.promisify(stream.pipeline);
// Register a CloudEvent callback with the Functions Framework that will
// be triggered by Cloud Storage.
functions.cloudEvent('helloGCS', async cloudEvent => {
console.info(`Event ID: ${cloudEvent.id}`);
console.info(`Event Type: ${cloudEvent.type}`);
const file = cloudEvent.data;
console.info(`Bucket: ${file.bucket}`);
console.info(`File: ${file.name}`);
console.info(`Metageneration: ${file.metageneration}`);
console.info(`Created: ${file.timeCreated}`);
console.info(`Updated: ${file.updated}`);
const bucket = storage.bucket(file.bucket);
const remoteFile = bucket.file(file.name);
const contentType = file.contentType;
// Fetch the metadata of the file
const [metadata] = await remoteFile.getMetadata();
console.info(`Metadata: ${JSON.stringify(metadata.metadata)}`);
// Check if metadata contains "strip-exif"
if (metadata.metadata && metadata.metadata['strip-exif'] === 'false') {
console.info('Metadata has strip-exif flag set to false. Skipping exif removal.');
return;
}
// Check if the file has already been processed
if (metadata.metadata && metadata.metadata.processed) {
console.info('File has already been processed');
return;
}
// Check if the file is an image
if (!contentType.startsWith('image/')) {
console.info('Uploaded file is not an image');
return;
}
remoteFile.download((err, buffer) => {
if (err) {
console.error('Error downloading file:', err);
return;
}
const reader = stream.Readable.from(buffer);
const writer = new stream.PassThrough();
reader.pipe(new ExifTransformer()).pipe(writer);
writer.on('data', async modifiedBuffer => {
await remoteFile.save(modifiedBuffer);
// Update the metadata of the file
await remoteFile.setMetadata({
metadata: {
processed: 'true',
'processed-by': 'functions/us-central1/strip-exif'
}
});
console.info('EXIF data stripped and image saved back to bucket');
});
writer.on('error', error => {
console.error('Error processing image:', error);
});
});
});
{
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0",
"@google-cloud/storage": "^7.0.1",
"exif-be-gone": "^1.3.2"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment