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) { defineErrorMessage(errObject) {
let msg;
if (errObject.response) { 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 { else {
let msg = errObject.message; msg = errObject.message;
} }
return swal('Oops, something went wrong!', msg, 'error'); return swal('Oops, something went wrong!', msg, 'error');
}, },
@ -1765,57 +1766,91 @@ export default {
applyFilterToMedia() { applyFilterToMedia() {
// this is where the magic happens // 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; let count = this.media.filter(m => m.filter_class).length;
if(count) { if(count) {
this.page = 'filteringMedia'; this.page = 'filteringMedia';
this.filteringRemainingCount = count; this.filteringRemainingCount = count;
this.$nextTick(() => { this.$nextTick(() => {
this.isFilteringMedia = true; 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 { } else {
this.page = 3; this.page = 3;
} }
}, },
applyFilterToMediaSave(media, idx) { async applyFilterToMediaSave(media) {
if(!media.filter_class) { if(!media.filter_class) {
return; return;
} }
let self = this; // Load image
let data = null; const image = document.createElement('img');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let image = document.createElement('img');
image.src = media.url; 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.width = image.width;
canvas.height = image.height; canvas.height = image.height;
}
// 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.filter = App.util.filterCss[media.filter_class];
ctx.drawImage(image, 0, 0, image.width, image.height); ctx.drawImage(image, 0, 0, image.width, image.height);
ctx.save(); ctx.save();
canvas.toBlob(function(blob) {
data = new FormData(); // Convert canvas to blob
let blob;
if(usingOffscreenCanvas) {
blob = await canvas.convertToBlob({
type: media.mime,
quality: 1,
});
} 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('file', blob);
data.append('id', media.id); data.append('id', media.id);
axios.post('/api/compose/v0/media/update', data) await axios.post('/api/compose/v0/media/update', data);
.then(res => { media.is_filtered = true;
self.media[idx].is_filtered = true; this.updateFilteringMedia();
self.updateFilteringMedia();
}).catch(err => {
});
});
}, media.mime, 0.9);
ctx.clearRect(0, 0, image.width, image.height);
}, },
updateFilteringMedia() { updateFilteringMedia() {