[NEW] Accept GIFs and SVGs for Avatars converting them to PNG and keep transparency of PNGs (#11385)

pull/15622/head
Tasso Evangelista 6 years ago committed by Rodrigo Nascimento
parent 7b3bb7206d
commit 66f44ece9b
  1. 43
      app/file-upload/server/lib/FileUpload.js
  2. 7
      app/theme/client/imports/forms/select-avatar.css
  3. 2
      app/ui-account/client/accountProfile.html

@ -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();
}));
}));

@ -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 {

@ -41,7 +41,7 @@
<label class="rc-select-avatar__upload-label avatar" for="upload-avatar">
{{> icon block="rc-select-avatar__upload-icon" icon="upload"}}
</label>
<input type="file" name="" value="" id="upload-avatar" style="display:none;" accept="image/x-png,image/gif,image/jpeg">
<input type="file" name="" value="" id="upload-avatar" style="display:none;" accept="image/x-png,image/gif,image/jpeg,image/svg+xml">
</div>
<div class="rc-select-avatar__list-item rc-tooltip js-select-avatar-url {{selectUrl}}" aria-label="{{_ "Use_url_for_avatar" }}">
<label class="rc-select-avatar__upload-label avatar">

Loading…
Cancel
Save