Przeglądaj źródła

Merge pull request #5455 from taye/fix-webgl-filters

fix(compose-modal): avoid WebGL if it's not needed
daniel 5 miesięcy temu
rodzic
commit
6ef4af29fe
3 zmienionych plików z 91 dodań i 27 usunięć
  1. 32 5
      package-lock.json
  2. 1 1
      package.json
  3. 58 21
      resources/assets/js/components/ComposeModal.vue

+ 32 - 5
package-lock.json

@@ -44,7 +44,7 @@
 				"vue-loading-overlay": "^3.3.3",
 				"vue-timeago": "^5.1.2",
 				"vue-tribute": "^1.0.7",
-				"webgl-media-editor": "^0.0.1",
+				"webgl-media-editor": "^0.0.6",
 				"zuck.js": "^1.6.0"
 			},
 			"devDependencies": {
@@ -2323,6 +2323,12 @@
 				"m3u8-parser": "~4.7.1"
 			}
 		},
+		"node_modules/@reactively/core": {
+			"version": "0.0.8",
+			"resolved": "https://registry.npmjs.org/@reactively/core/-/core-0.0.8.tgz",
+			"integrity": "sha512-5uAnNf2gQSm3gM7z6Lx079H1/MuDQQI+5aYfwyDFGR9nHZj8yblLY/6aOJVWp+NcBwXVBKuWQ28qWHD9F1qN1w==",
+			"license": "ISC"
+		},
 		"node_modules/@thaunknown/simple-peer": {
 			"version": "10.0.11",
 			"resolved": "https://registry.npmjs.org/@thaunknown/simple-peer/-/simple-peer-10.0.11.tgz",
@@ -5645,6 +5651,15 @@
 				"node": ">=8"
 			}
 		},
+		"node_modules/fine-jsx": {
+			"version": "0.0.5",
+			"resolved": "https://registry.npmjs.org/fine-jsx/-/fine-jsx-0.0.5.tgz",
+			"integrity": "sha512-UKQ0ymyZnA605yf7np/wAv3iTs6i9oRKgyYmz+dX+F3VanYEBr60zRQ+WPcYzXMtl9NghNxT736qHfDBjoXVDg==",
+			"license": "AGPL-3.0-only",
+			"dependencies": {
+				"@reactively/core": "^0.0.8"
+			}
+		},
 		"node_modules/fizzy-ui-utils": {
 			"version": "2.0.7",
 			"resolved": "https://registry.npmjs.org/fizzy-ui-utils/-/fizzy-ui-utils-2.0.7.tgz",
@@ -10749,16 +10764,28 @@
 				"node": ">= 8"
 			}
 		},
+		"node_modules/webgl-effects": {
+			"version": "0.0.3",
+			"resolved": "https://registry.npmjs.org/webgl-effects/-/webgl-effects-0.0.3.tgz",
+			"integrity": "sha512-P+qxcO0QyydUnHHwnsge2ckou85Pnsdgn0BKAjrhD9LiPFz5i2hq8rT8AdS7wNdXrXyqlM1Y0id+AB0gKTDtpQ==",
+			"license": "AGPL-3.0-only",
+			"dependencies": {
+				"gl-matrix": "^3.4.3",
+				"twgl.js": "^5.5.4"
+			}
+		},
 		"node_modules/webgl-media-editor": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/webgl-media-editor/-/webgl-media-editor-0.0.1.tgz",
-			"integrity": "sha512-TxnuRl3rpWa1Cia/pn+vh+0iz3yDNwzsrnRGJ61YkdZAYuimu2afBivSHv0RK73hKza6Y/YoRCkuEcsFmtxPNw==",
+			"version": "0.0.6",
+			"resolved": "https://registry.npmjs.org/webgl-media-editor/-/webgl-media-editor-0.0.6.tgz",
+			"integrity": "sha512-hqpIY+a+ay3QzXKECC4pFSHS0dVogV3GlBWzuSwBzEeGZcs7MeEYxLhFdqUa1D2xFtNnXb0pAo+1lCndYDKP2A==",
 			"license": "AGPL-3.0-only",
 			"dependencies": {
 				"cropperjs": "^1.6.2",
+				"fine-jsx": "^0.0.5",
 				"gl-matrix": "^3.4.3",
 				"throttle-debounce": "^5.0.2",
-				"twgl.js": "^5.5.4"
+				"twgl.js": "^5.5.4",
+				"webgl-effects": "^0.0.3"
 			}
 		},
 		"node_modules/webidl-conversions": {

+ 1 - 1
package.json

@@ -71,7 +71,7 @@
 		"vue-loading-overlay": "^3.3.3",
 		"vue-timeago": "^5.1.2",
 		"vue-tribute": "^1.0.7",
-		"webgl-media-editor": "^0.0.1",
+		"webgl-media-editor": "^0.0.6",
 		"zuck.js": "^1.6.0"
 	},
 	"collective": {

+ 58 - 21
resources/assets/js/components/ComposeModal.vue

@@ -1015,19 +1015,29 @@ export default {
 	},
 
     created() {
-        this.editor = new MediaEditor({
-            effects: filterEffects,
-		    onEdit: (index, {effect, intensity, crop}) => {
-			    if (index >= this.files.length) return
-			    const file = this.files[index]
-
-			    this.$set(file, 'editState', { effect, intensity, crop })
-		    },
-		    onRenderPreview: (sourceIndex, previewUrl) => {
-				const media = this.media[sourceIndex]
-				if (media) media.preview_url = previewUrl
-		    },
-        })
+        try {
+            this.editor = new MediaEditor({
+                effects: filterEffects,
+                onEdit: (sourceIndex, {effect, intensity, crop}) => {
+                    if (sourceIndex >= this.files.length) return
+                    const file = this.files[sourceIndex]
+
+                    this.$set(file, 'editState', { effect, intensity, crop })
+                },
+                onRenderPreview: (sourceIndex, previewUrl) => {
+                    if (sourceIndex >= this.files.length) return
+                    const file = this.files[sourceIndex]
+                    const { editState } = file
+                    const media = this.media[sourceIndex]
+
+                    // If the image was edited, use the preview image from the editor.
+                    if (editState && (editState.crop || editState.effect !== -1)) media.preview_url = previewUrl
+                    // When no edits are applied, use the original media URL.
+                    // This limits broken previews with firefox's resistFingerprinting setting.
+                    else media.preview_url = media.url
+                },
+            })
+        } catch {}
     },
 
 	computed: {
@@ -1054,8 +1064,9 @@ export default {
 	},
 
 	destroyed() {
-		this.files.forEach(fileInfo => {
-            URL.revokeObjectURL(fileInfo.url);
+		this.media.forEach(media => {
+            URL.revokeObjectURL(media.url);
+            URL.revokeObjectURL(media.preview_url);
         })
 		this.files.length = this.media.length = 0
 		this.editor = undefined
@@ -1161,7 +1172,7 @@ export default {
 
                 const type = file.type.replace(/\/.*/, '')
 				const url = URL.createObjectURL(file)
-                const preview_url = type === 'image' ? url : '/storage/no-preview.png'
+                const preview_url = type === 'image' ? URL.createObjectURL(file) : '/storage/no-preview.png'
 
 				this.files.push({ file, editState: undefined })
 				this.media.push({ url, preview_url, type })
@@ -1182,7 +1193,16 @@ export default {
 				const media = this.media[i]
 
 				if (media.type === 'image' && fileInfo.editState) {
-					file = await this.editor.toBlob(i)
+                    const { editState, cropperBlob } = fileInfo
+
+                    // If the WebGL editor is supported by the browser, apply the edits and use the resulting blob
+                    if (this.editor && (editState.effect !== -1 || !!editState.crop)) {
+					    file = await this.editor.toBlob(i)
+                    }
+                    // Otherwise, only the cropped result from cropper.js may be used
+                    else if (cropperBlob) {
+                        file = cropperBlob
+                    }
 				}
 
 				let form = new FormData();
@@ -1555,12 +1575,29 @@ export default {
 				break;
 
 				case 'cropPhoto':
-                    const { editState } = this.files[this.carouselCursor]
+                    const file = this.files[this.carouselCursor]
+                    const { cropper } = this.$refs
+
+                    // update the file state in this vue component
                     const croppedState = {
-                        ...editState,
-                        crop: this.$refs.cropper.getData()
+                        ...file.editState,
+                        crop: cropper.getData()
+                    }
+
+                    if (this.editor) {
+                        // also update the file state in the WebGL editor
+                        this.editor.setEditState(this.carouselCursor, croppedState)
+                    } else {
+                        // if the browser can't run the WebGL editor, get the cropped image from cropper.js
+                         cropper.getCroppedCanvas().toBlob((blob) => {
+                            const { media } = this.media[this.carouselCursor]
+
+                            file.croppedBlob = blob
+                            URL.revokeObjectURL(media.preview_url)
+                            media.preview_url = URL.createObjectURL(blob)
+                        })
                     }
-                    this.editor.setEditState(this.carouselCursor, croppedState)
+
 					this.page = 2;
 				break;