Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions run/image-processing/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Cloud Run Image Processing Sample

This sample service applies [Cloud Storage](https://cloud.google.com/storage/docs)-triggered image processing with [Cloud Vision API](https://cloud.google.com/vision/docs) analysis and ImageMagick transformation.
This sample service applies [Cloud Storage](https://cloud.google.com/storage/docs)-triggered image processing with [Cloud Vision API](https://cloud.google.com/vision/docs) analysis and sharp transformation.

Use it with the [Image Processing with Cloud Run tutorial](http://cloud.google.com/run/docs/tutorials/image-processing).

Expand All @@ -9,7 +9,7 @@ For more details on how to work with this sample read the [Google Cloud Run Node
## Dependencies

* **express**: Web server framework
* **[gm](https://github.com/aheckmann/gm#readme)**: ImageMagick integration library.
* **[sharp](https://sharp.pixelplumbing.com/)**: High-performance Node.js image processing library.
* **@google-cloud/storage**: Google Cloud Storage client library.
* **@google-cloud/vision**: Cloud Vision API client library.

Expand Down
46 changes: 25 additions & 21 deletions run/image-processing/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
'use strict';

// [START cloudrun_imageproc_handler_setup]
const gm = require('gm').subClass({imageMagick: true});
const fs = require('fs');
const {promisify} = require('util');
const sharp = require('sharp');
const path = require('path');
const vision = require('@google-cloud/vision');

Expand All @@ -34,6 +33,13 @@ exports.blurOffensiveImages = async event => {
// This event represents the triggering Cloud Storage object.
const object = event;

if (object.bucket === BLURRED_BUCKET_NAME) {
console.log(
'Event triggered by the blurred bucket; skip to avoid recursion'
);
return;
}

const file = storage.bucket(object.bucket).file(object.name);
const filePath = `gs://${object.bucket}/${object.name}`;

Expand Down Expand Up @@ -61,9 +67,10 @@ exports.blurOffensiveImages = async event => {
// [END cloudrun_imageproc_handler_analyze]

// [START cloudrun_imageproc_handler_blur]
// Blurs the given file using ImageMagick, and uploads it to another bucket.
// Blurs the given file using sharp, and uploads it to another bucket.
const blurImage = async (file, blurredBucketName) => {
const tempLocalPath = `/tmp/${path.parse(file.name).base}`;
const tempLocalBlurredPath = `/tmp/blurred-${path.parse(file.name).base}`;

// Download file from bucket.
try {
Expand All @@ -74,34 +81,31 @@ const blurImage = async (file, blurredBucketName) => {
throw new Error(`File download failed: ${err}`);
}

await new Promise((resolve, reject) => {
gm(tempLocalPath)
.blur(0, 16)
.write(tempLocalPath, (err, stdout) => {
if (err) {
console.error('Failed to blur image.', err);
reject(err);
} else {
console.log(`Blurred image: ${file.name}`);
resolve(stdout);
}
});
});
try {
await sharp(tempLocalPath).blur(16).toFile(tempLocalBlurredPath);

console.log(`Blurred image: ${file.name}`);
} catch (err) {
console.error('Failed to blur image.', err);
throw err;
}

// Upload result to a different bucket, to avoid re-triggering this function.
const blurredBucket = storage.bucket(blurredBucketName);

// Upload the Blurred image back into the bucket.
const gcsPath = `gs://${blurredBucketName}/${file.name}`;
try {
await blurredBucket.upload(tempLocalPath, {destination: file.name});
await blurredBucket.upload(tempLocalBlurredPath, {destination: file.name});
console.log(`Uploaded blurred image to: ${gcsPath}`);
} catch (err) {
throw new Error(`Unable to upload blurred image to ${gcsPath}: ${err}`);
} finally {
// Delete the temporary file.
await Promise.allSettled([
fs.unlink(tempLocalPath),
fs.unlink(tempLocalBlurredPath),
]);
}
Comment thread
angelcaamal marked this conversation as resolved.

// Delete the temporary file.
const unlink = promisify(fs.unlink);
return unlink(tempLocalPath);
};
// [END cloudrun_imageproc_handler_blur]
2 changes: 1 addition & 1 deletion run/image-processing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@google-cloud/storage": "^7.0.0",
"@google-cloud/vision": "^4.0.0",
"express": "^4.16.4",
"gm": "^1.23.1"
"sharp": "^0.34.5"
},
"devDependencies": {
"c8": "^10.0.0",
Expand Down
Loading