Skip to content

Commit c230750

Browse files
committed
refactor(functions/v2/imagemagick): migrate image processing from gm to sharp
1 parent cf020ea commit c230750

4 files changed

Lines changed: 23 additions & 33 deletions

File tree

functions/v2/imagemagick/index.js

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// [START functions_imagemagick_setup]
1818
const functions = require('@google-cloud/functions-framework');
19-
const gm = require('gm').subClass({imageMagick: true});
19+
const sharp = require('sharp');
2020
const fs = require('fs').promises;
2121
const path = require('path');
2222
const vision = require('@google-cloud/vision');
@@ -64,6 +64,7 @@ functions.cloudEvent('blurOffensiveImages', async cloudEvent => {
6464
// Blurs the given file using ImageMagick, and uploads it to another bucket.
6565
const blurImage = async (file, blurredBucketName) => {
6666
const tempLocalPath = `/tmp/${path.parse(file.name).base}`;
67+
const tempLocalBlurredPath = `/tmp/blurred-${path.parse(file.name).base}`;
6768

6869
// Download file from bucket.
6970
try {
@@ -74,33 +75,29 @@ const blurImage = async (file, blurredBucketName) => {
7475
throw new Error(`File download failed: ${err}`);
7576
}
7677

77-
await new Promise((resolve, reject) => {
78-
gm(tempLocalPath)
79-
.blur(0, 16)
80-
.write(tempLocalPath, (err, stdout) => {
81-
if (err) {
82-
console.error('Failed to blur image.', err);
83-
reject(err);
84-
} else {
85-
console.log(`Blurred image: ${file.name}`);
86-
resolve(stdout);
87-
}
88-
});
89-
});
78+
try {
79+
await sharp(tempLocalPath).blur(16).toFile(tempLocalBlurredPath);
80+
81+
console.log(`Blurred image: ${file.name}`);
82+
} catch (err) {
83+
console.error('Failed to blur image.', err);
84+
throw err;
85+
}
9086

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

9490
// Upload the Blurred image back into the bucket.
9591
const gcsPath = `gs://${blurredBucketName}/${file.name}`;
9692
try {
97-
await blurredBucket.upload(tempLocalPath, {destination: file.name});
93+
await blurredBucket.upload(tempLocalBlurredPath, {destination: file.name});
9894
console.log(`Uploaded blurred image to: ${gcsPath}`);
9995
} catch (err) {
10096
throw new Error(`Unable to upload blurred image to ${gcsPath}: ${err}`);
10197
}
10298

10399
// Delete the temporary file.
104-
return fs.unlink(tempLocalPath);
100+
await fs.unlink(tempLocalPath);
101+
return await fs.unlink(tempLocalBlurredPath);
105102
};
106103
// [END functions_imagemagick_blur]

functions/v2/imagemagick/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"@google-cloud/functions-framework": "^3.1.0",
1919
"@google-cloud/storage": "^7.0.0",
2020
"@google-cloud/vision": "^4.0.0",
21-
"gm": "^1.23.1"
21+
"sharp": "^0.34.5"
2222
},
2323
"devDependencies": {
2424
"c8": "^10.0.0",

functions/v2/imagemagick/test/integration.test.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
'use strict';
1616

1717
const assert = require('assert');
18-
const {execSync} = require('child_process');
1918
const {Storage} = require('@google-cloud/storage');
2019
const sinon = require('sinon');
2120
const supertest = require('supertest');
@@ -34,11 +33,6 @@ const testFiles = {
3433

3534
require('../index');
3635

37-
// ImageMagick is available by default in Cloud Run Functions environments
38-
// https://cloud.google.com/functions/1stgendocs/tutorials/imagemagick-1st-gen.md#importing_dependencies
39-
// Manually install it for testing only.
40-
execSync('sudo apt-get install imagemagick -y');
41-
4236
describe('functions/imagemagick tests', () => {
4337
before(async () => {
4438
let exists;

functions/v2/imagemagick/test/unit.test.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,30 @@ const loadSample = (adultResult, fileName) => {
3838
return {
3939
bucket: sinon.stub().returnsThis(),
4040
file: sinon.stub().returnsThis(),
41-
upload: sinon.stub().returnsThis(),
42-
download: sinon.stub().returnsThis(),
41+
upload: sinon.stub().resolves(),
42+
download: sinon.stub().resolves(),
4343
name: fileName,
4444
};
4545
},
4646
};
4747

48-
const gm = () => {
49-
return {
50-
blur: sinon.stub().returnsThis(),
51-
write: sinon.stub().yields(),
52-
};
48+
// 1. Reemplazamos la simulación de 'gm' por la de 'sharp'
49+
const sharpInstance = {
50+
blur: sinon.stub().returnsThis(),
51+
toFile: sinon.stub().resolves(),
5352
};
54-
gm.subClass = sinon.stub().returnsThis();
53+
const sharpMock = sinon.stub().returns(sharpInstance);
5554

5655
const fs = {
5756
promises: {
58-
unlink: sinon.stub(),
57+
unlink: sinon.stub().resolves(),
5958
},
6059
};
6160

6261
return proxyquire('..', {
6362
'@google-cloud/vision': vision,
6463
'@google-cloud/storage': storage,
65-
gm: gm,
64+
sharp: sharpMock,
6665
fs: fs,
6766
});
6867
};

0 commit comments

Comments
 (0)