diff --git a/functions/v2/imagemagick/index.js b/functions/v2/imagemagick/index.js index e6f32f0837..a8b26a290c 100644 --- a/functions/v2/imagemagick/index.js +++ b/functions/v2/imagemagick/index.js @@ -16,7 +16,7 @@ // [START functions_imagemagick_setup] const functions = require('@google-cloud/functions-framework'); -const gm = require('gm').subClass({imageMagick: true}); +const sharp = require('sharp'); const fs = require('fs').promises; const path = require('path'); const vision = require('@google-cloud/vision'); @@ -64,6 +64,7 @@ functions.cloudEvent('blurOffensiveImages', async cloudEvent => { // Blurs the given file using ImageMagick, 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 { @@ -74,19 +75,14 @@ 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); @@ -94,13 +90,14 @@ const blurImage = async (file, 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}`); } // Delete the temporary file. - return fs.unlink(tempLocalPath); + await fs.unlink(tempLocalPath); + return await fs.unlink(tempLocalBlurredPath); }; // [END functions_imagemagick_blur] diff --git a/functions/v2/imagemagick/package.json b/functions/v2/imagemagick/package.json index 43e1ac3d46..dc1396261b 100644 --- a/functions/v2/imagemagick/package.json +++ b/functions/v2/imagemagick/package.json @@ -18,7 +18,7 @@ "@google-cloud/functions-framework": "^3.1.0", "@google-cloud/storage": "^7.0.0", "@google-cloud/vision": "^4.0.0", - "gm": "^1.23.1" + "sharp": "^0.34.5" }, "devDependencies": { "c8": "^10.0.0", diff --git a/functions/v2/imagemagick/test/integration.test.js b/functions/v2/imagemagick/test/integration.test.js index 82f5b8a43e..e0a2ac56d2 100644 --- a/functions/v2/imagemagick/test/integration.test.js +++ b/functions/v2/imagemagick/test/integration.test.js @@ -15,7 +15,6 @@ 'use strict'; const assert = require('assert'); -const {execSync} = require('child_process'); const {Storage} = require('@google-cloud/storage'); const sinon = require('sinon'); const supertest = require('supertest'); @@ -34,11 +33,6 @@ const testFiles = { require('../index'); -// ImageMagick is available by default in Cloud Run Functions environments -// https://cloud.google.com/functions/1stgendocs/tutorials/imagemagick-1st-gen.md#importing_dependencies -// Manually install it for testing only. -execSync('sudo apt-get install imagemagick -y'); - describe('functions/imagemagick tests', () => { before(async () => { let exists; diff --git a/functions/v2/imagemagick/test/unit.test.js b/functions/v2/imagemagick/test/unit.test.js index acf453198d..979ff11711 100644 --- a/functions/v2/imagemagick/test/unit.test.js +++ b/functions/v2/imagemagick/test/unit.test.js @@ -38,31 +38,30 @@ const loadSample = (adultResult, fileName) => { return { bucket: sinon.stub().returnsThis(), file: sinon.stub().returnsThis(), - upload: sinon.stub().returnsThis(), - download: sinon.stub().returnsThis(), + upload: sinon.stub().resolves(), + download: sinon.stub().resolves(), name: fileName, }; }, }; - const gm = () => { - return { - blur: sinon.stub().returnsThis(), - write: sinon.stub().yields(), - }; + // 1. Reemplazamos la simulación de 'gm' por la de 'sharp' + const sharpInstance = { + blur: sinon.stub().returnsThis(), + toFile: sinon.stub().resolves(), }; - gm.subClass = sinon.stub().returnsThis(); + const sharpMock = sinon.stub().returns(sharpInstance); const fs = { promises: { - unlink: sinon.stub(), + unlink: sinon.stub().resolves(), }, }; return proxyquire('..', { '@google-cloud/vision': vision, '@google-cloud/storage': storage, - gm: gm, + sharp: sharpMock, fs: fs, }); };