Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
48 changes: 26 additions & 22 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 fs = require('fs').promises;
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