From 66f44ece9b67efecc0f14bf1848438e49ee38a10 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Sun, 20 Oct 2019 18:12:18 -0300 Subject: [PATCH] [NEW] Accept GIFs and SVGs for Avatars converting them to PNG and keep transparency of PNGs (#11385) --- app/file-upload/server/lib/FileUpload.js | 43 +++++++++---------- .../client/imports/forms/select-avatar.css | 7 +++ app/ui-account/client/accountProfile.html | 2 +- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/app/file-upload/server/lib/FileUpload.js b/app/file-upload/server/lib/FileUpload.js index 8fb538c5b64..46f670fb6ad 100644 --- a/app/file-upload/server/lib/FileUpload.js +++ b/app/file-upload/server/lib/FileUpload.js @@ -162,43 +162,42 @@ export const FileUpload = { const tempFilePath = UploadFS.getTempFilePath(file._id); const height = settings.get('Accounts_AvatarSize'); + const width = height; const future = new Future(); const s = sharp(tempFilePath); s.rotate(); - // Get metadata to resize the image the first time to keep "inside" the dimensions - // then resize again to create the canvas around s.metadata(Meteor.bindEnvironment((err, metadata) => { if (!metadata) { metadata = {}; } - s.flatten({ background: '#FFFFFF' }) - .jpeg() - .resize({ - width: Math.min(height || 0, metadata.width || Infinity), - height: Math.min(height || 0, metadata.height || Infinity), - fit: sharp.fit.cover, - }) - .pipe(sharp() - .resize({ - height, - width: height, - fit: sharp.fit.contain, - background: '#FFFFFF', - }) - ) + s.resize({ + width, + height, + fit: metadata.hasAlpha ? sharp.fit.contain : sharp.fit.cover, + background: { r: 255, g: 255, b: 255, alpha: metadata.hasAlpha ? 0 : 1 }, + }) // Use buffer to get the result in memory then replace the existing file // There is no option to override a file using this library - .toBuffer() - .then(Meteor.bindEnvironment((outputBuffer) => { - fs.writeFile(tempFilePath, outputBuffer, Meteor.bindEnvironment((err) => { + // + // BY THE SHARP DOCUMENTATION: + // toBuffer: Write output to a Buffer. JPEG, PNG, WebP, TIFF and RAW output are supported. + // By default, the format will match the input image, except GIF and SVG input which become PNG output. + .toBuffer({ resolveWithObject: true }) + .then(Meteor.bindEnvironment(({ data, info }) => { + fs.writeFile(tempFilePath, data, Meteor.bindEnvironment((err) => { if (err != null) { console.error(err); } - const { size } = fs.lstatSync(tempFilePath); - this.getCollection().direct.update({ _id: file._id }, { $set: { size } }); + + this.getCollection().direct.update({ _id: file._id }, { + $set: { + size: info.size, + ...['gif', 'svg'].includes(metadata.format) ? { type: 'image/png' } : {}, + }, + }); future.return(); })); })); diff --git a/app/theme/client/imports/forms/select-avatar.css b/app/theme/client/imports/forms/select-avatar.css index bb61ffdfb20..41510385bf3 100644 --- a/app/theme/client/imports/forms/select-avatar.css +++ b/app/theme/client/imports/forms/select-avatar.css @@ -8,6 +8,13 @@ width: var(--select-avatar-preview-size); height: var(--select-avatar-preview-size); margin-right: 1rem; + + background-color: transparent; + background-image: + linear-gradient(45deg, var(--color-gray) 25%, transparent 25%, transparent 75%, var(--color-gray) 75%, var(--color-gray)), + linear-gradient(45deg, var(--color-gray) 25%, transparent 25%, transparent 75%, var(--color-gray) 75%, var(--color-gray)); + background-position: 0 0, 5px 5px; + background-size: 10px 10px; } &__loading::after { diff --git a/app/ui-account/client/accountProfile.html b/app/ui-account/client/accountProfile.html index 59435c30f2f..e0b7483d067 100644 --- a/app/ui-account/client/accountProfile.html +++ b/app/ui-account/client/accountProfile.html @@ -41,7 +41,7 @@ - +