Merge pull request #5333 from jonasgeiler/staging

Improve media filtering by using OffscreenCanvas, if supported
This commit is contained in:
daniel 2024-11-08 21:52:03 -07:00 committed by GitHub
commit aea5392044
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1095,11 +1095,12 @@ export default {
},
defineErrorMessage(errObject) {
let msg;
if (errObject.response) {
let msg = errObject.response.data.message ? errObject.response.data.message : 'An unexpected error occured.';
msg = errObject.response.data.message ? errObject.response.data.message : 'An unexpected error occured.';
}
else {
let msg = errObject.message;
msg = errObject.message;
}
return swal('Oops, something went wrong!', msg, 'error');
},
@ -1765,57 +1766,91 @@ export default {
applyFilterToMedia() {
// this is where the magic happens
var ua = navigator.userAgent.toLowerCase();
if(ua.indexOf('firefox') == -1 && ua.indexOf('chrome') == -1) {
this.isPosting = false;
swal('Oops!', 'Your browser does not support the filter feature.', 'error');
this.page = 3;
return;
}
let count = this.media.filter(m => m.filter_class).length;
if(count) {
this.page = 'filteringMedia';
this.filteringRemainingCount = count;
this.$nextTick(() => {
this.isFilteringMedia = true;
this.media.forEach((media, idx) => this.applyFilterToMediaSave(media, idx));
Promise.all(this.media.map(media => {
return this.applyFilterToMediaSave(media);
})).catch(err => {
console.error(err);
swal('Oops!', 'An error occurred while applying filters to your media. Please refresh the page and try again. If the problem persist, please try a different web browser.', 'error');
});
})
} else {
this.page = 3;
}
},
applyFilterToMediaSave(media, idx) {
async applyFilterToMediaSave(media) {
if(!media.filter_class) {
return;
}
let self = this;
let data = null;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let image = document.createElement('img');
// Load image
const image = document.createElement('img');
image.src = media.url;
image.addEventListener('load', e => {
await new Promise((resolve, reject) => {
image.addEventListener('load', () => resolve());
image.addEventListener('error', () => {
reject(new Error('Failed to load image'));
});
});
// Create canvas
let canvas;
let usingOffscreenCanvas = false;
if('OffscreenCanvas' in window) {
canvas = new OffscreenCanvas(image.width, image.height);
usingOffscreenCanvas = true;
} else {
canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
ctx.filter = App.util.filterCss[media.filter_class];
ctx.drawImage(image, 0, 0, image.width, image.height);
ctx.save();
canvas.toBlob(function(blob) {
data = new FormData();
data.append('file', blob);
data.append('id', media.id);
axios.post('/api/compose/v0/media/update', data)
.then(res => {
self.media[idx].is_filtered = true;
self.updateFilteringMedia();
}).catch(err => {
});
}
// Draw image with filter to canvas
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error('Failed to get canvas context');
}
if (!('filter' in ctx)) {
throw new Error('Canvas filter not supported');
}
ctx.filter = App.util.filterCss[media.filter_class];
ctx.drawImage(image, 0, 0, image.width, image.height);
ctx.save();
// Convert canvas to blob
let blob;
if(usingOffscreenCanvas) {
blob = await canvas.convertToBlob({
type: media.mime,
quality: 1,
});
}, media.mime, 0.9);
ctx.clearRect(0, 0, image.width, image.height);
} else {
blob = await new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if(blob) {
resolve(blob);
} else {
reject(
new Error('Failed to convert canvas to blob'),
);
}
}, media.mime, 1);
});
}
// Upload blob / Update media
const data = new FormData();
data.append('file', blob);
data.append('id', media.id);
await axios.post('/api/compose/v0/media/update', data);
media.is_filtered = true;
this.updateFilteringMedia();
},
updateFilteringMedia() {