diff --git a/resources/assets/js/components/ComposeModal.vue b/resources/assets/js/components/ComposeModal.vue
index e4ae59c8..94f6f5e1 100644
--- a/resources/assets/js/components/ComposeModal.vue
+++ b/resources/assets/js/components/ComposeModal.vue
@@ -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() {