From e8afc7c3e87978ca995f37094c8503a606cf1dda Mon Sep 17 00:00:00 2001 From: Cyperghost Date: Fri, 20 Dec 2024 12:35:50 +0100 Subject: [PATCH] Do not use `precise` anymore so that we only calculate with integers --- .../Core/Component/Image/Cropper.ts | 54 ++++++++++--------- .../Core/Component/Image/Cropper.js | 36 ++++++++----- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/ts/WoltLabSuite/Core/Component/Image/Cropper.ts b/ts/WoltLabSuite/Core/Component/Image/Cropper.ts index 4c1048249d..4504e558d8 100644 --- a/ts/WoltLabSuite/Core/Component/Image/Cropper.ts +++ b/ts/WoltLabSuite/Core/Component/Image/Cropper.ts @@ -178,8 +178,8 @@ abstract class ImageCropper { const height = width / this.configuration.aspectRatio; return this.cropperSelection!.$toCanvas({ - width: Math.max(Math.min(Math.floor(width), this.maxSize.width), this.minSize.width), - height: Math.max(Math.min(Math.ceil(height), this.maxSize.height), this.minSize.height), + width: Math.max(Math.min(Math.round(width), this.maxSize.width), this.minSize.width), + height: Math.max(Math.min(Math.round(height), this.maxSize.height), this.minSize.height), }); } @@ -212,13 +212,15 @@ abstract class ImageCropper { // Round all values to integers to avoid dealing with the wonderful world // of IEEE 754 numbers. - const minWidth = Math.round(this.minSize.width * selectionRatio); + const minWidth = Math.ceil(this.minSize.width * selectionRatio); const maxWidth = Math.round(this.cropperCanvasRect.width); - const minHeight = Math.round(minWidth / this.configuration.aspectRatio); + const minHeight = Math.ceil(minWidth / this.configuration.aspectRatio); const maxHeight = Math.round(maxWidth / this.configuration.aspectRatio); const width = Math.round(selection.width); const height = Math.round(selection.height); + const x = Math.round(selection.x); + const y = Math.round(selection.y); if (width < minWidth || height < minHeight || width > maxWidth || height > maxHeight) { event.preventDefault(); @@ -234,20 +236,19 @@ abstract class ImageCropper { const maxSelection: Selection = { x: 0, y: 0, - width: this.cropperCanvasRect.width, - height: this.cropperCanvasRect.height, + width: maxWidth, + height: Math.round(this.cropperCanvasRect.height), }; if (!inSelection(selection, maxSelection)) { event.preventDefault(); - // Clamp the position to the boundaries of the canvas. void this.cropperSelection!.$nextTick().then(() => { this.cropperSelection!.$change( - clampValue(selection.x, selection.width, maxSelection.width), - clampValue(selection.y, selection.height, maxSelection.height), - selection.width, - selection.height, + clampValue(x, width, maxSelection.width), + clampValue(y, height, maxSelection.height), + width, + height, ); }); } @@ -255,8 +256,6 @@ abstract class ImageCropper { } protected setCropperStyle() { - this.cropperCanvas!.style.aspectRatio = `${this.width}/${this.height}`; - this.cropperSelection!.aspectRatio = this.configuration.aspectRatio; } @@ -267,11 +266,15 @@ abstract class ImageCropper { const dimension = DomUtil.innerDimensions(this.cropperCanvas!.parentElement!); const ratio = Math.min(dimension.width / this.width, dimension.height / this.height); + const imageRatio = this.width / this.height; - this.cropperCanvas!.style.height = `${this.height * ratio}px`; - this.cropperCanvas!.style.width = `${this.width * ratio}px`; + const canvasHeight = Math.round(this.height * ratio); + const canvasWidth = Math.round(canvasHeight * imageRatio); - this.cropperImage!.$center("contain"); + this.cropperCanvas!.style.height = `${canvasHeight}px`; + this.cropperCanvas!.style.width = `${canvasWidth}px`; + + this.cropperImage!.$center("cover"); this.cropperCanvasRect = this.cropperImage!.getBoundingClientRect(); const selectionRatio = Math.min( @@ -279,14 +282,15 @@ abstract class ImageCropper { this.cropperCanvasRect.height / this.maxSize.height, ); - this.cropperSelection!.$change( - 0, - 0, - Math.min(this.cropperCanvasRect.width, this.maxSize.width * selectionRatio), - Math.min(this.cropperCanvasRect.height, this.maxSize.height * selectionRatio), - this.configuration.aspectRatio, - true, - ); + let selectionHeight = Math.min(this.cropperCanvasRect.height, Math.floor(this.maxSize.height * selectionRatio)); + let selectionWidth = Math.floor(selectionHeight * this.configuration.aspectRatio); + + if (selectionWidth > this.cropperCanvasRect.width) { + selectionWidth = Math.floor(this.cropperCanvasRect.width); + selectionHeight = Math.floor(selectionWidth / this.configuration.aspectRatio); + } + + this.cropperSelection!.$change(0, 0, selectionWidth, selectionHeight, this.configuration.aspectRatio, true); this.cropperSelection!.$center(); this.cropperSelection!.scrollIntoView({ block: "center", inline: "center" }); @@ -297,7 +301,7 @@ abstract class ImageCropper { - + diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Image/Cropper.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Image/Cropper.js index 4d8597286f..dc54f6c8b2 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Image/Cropper.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Component/Image/Cropper.js @@ -134,8 +134,8 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL const width = this.cropperSelection.width / selectionRatio; const height = width / this.configuration.aspectRatio; return this.cropperSelection.$toCanvas({ - width: Math.max(Math.min(Math.floor(width), this.maxSize.width), this.minSize.width), - height: Math.max(Math.min(Math.ceil(height), this.maxSize.height), this.minSize.height), + width: Math.max(Math.min(Math.round(width), this.maxSize.width), this.minSize.width), + height: Math.max(Math.min(Math.round(height), this.maxSize.height), this.minSize.height), }); } createCropper() { @@ -157,12 +157,14 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL const selectionRatio = Math.min(this.cropperCanvasRect.width / this.width, this.cropperCanvasRect.height / this.height); // Round all values to integers to avoid dealing with the wonderful world // of IEEE 754 numbers. - const minWidth = Math.round(this.minSize.width * selectionRatio); + const minWidth = Math.ceil(this.minSize.width * selectionRatio); const maxWidth = Math.round(this.cropperCanvasRect.width); - const minHeight = Math.round(minWidth / this.configuration.aspectRatio); + const minHeight = Math.ceil(minWidth / this.configuration.aspectRatio); const maxHeight = Math.round(maxWidth / this.configuration.aspectRatio); const width = Math.round(selection.width); const height = Math.round(selection.height); + const x = Math.round(selection.x); + const y = Math.round(selection.y); if (width < minWidth || height < minHeight || width > maxWidth || height > maxHeight) { event.preventDefault(); // Stop the event handling here otherwise the following code would try @@ -175,20 +177,19 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL const maxSelection = { x: 0, y: 0, - width: this.cropperCanvasRect.width, - height: this.cropperCanvasRect.height, + width: maxWidth, + height: Math.round(this.cropperCanvasRect.height), }; if (!inSelection(selection, maxSelection)) { event.preventDefault(); // Clamp the position to the boundaries of the canvas. void this.cropperSelection.$nextTick().then(() => { - this.cropperSelection.$change(clampValue(selection.x, selection.width, maxSelection.width), clampValue(selection.y, selection.height, maxSelection.height), selection.width, selection.height); + this.cropperSelection.$change(clampValue(x, width, maxSelection.width), clampValue(y, height, maxSelection.height), width, height); }); } }); } setCropperStyle() { - this.cropperCanvas.style.aspectRatio = `${this.width}/${this.height}`; this.cropperSelection.aspectRatio = this.configuration.aspectRatio; } centerSelection() { @@ -197,12 +198,21 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL this.cropperCanvas.style.height = `${this.height}px`; const dimension = Util_1.default.innerDimensions(this.cropperCanvas.parentElement); const ratio = Math.min(dimension.width / this.width, dimension.height / this.height); - this.cropperCanvas.style.height = `${this.height * ratio}px`; - this.cropperCanvas.style.width = `${this.width * ratio}px`; - this.cropperImage.$center("contain"); + const imageRatio = this.width / this.height; + const canvasHeight = Math.round(this.height * ratio); + const canvasWidth = Math.round(canvasHeight * imageRatio); + this.cropperCanvas.style.height = `${canvasHeight}px`; + this.cropperCanvas.style.width = `${canvasWidth}px`; + this.cropperImage.$center("cover"); this.cropperCanvasRect = this.cropperImage.getBoundingClientRect(); const selectionRatio = Math.min(this.cropperCanvasRect.width / this.maxSize.width, this.cropperCanvasRect.height / this.maxSize.height); - this.cropperSelection.$change(0, 0, Math.min(this.cropperCanvasRect.width, this.maxSize.width * selectionRatio), Math.min(this.cropperCanvasRect.height, this.maxSize.height * selectionRatio), this.configuration.aspectRatio, true); + let selectionHeight = Math.min(this.cropperCanvasRect.height, Math.floor(this.maxSize.height * selectionRatio)); + let selectionWidth = Math.floor(selectionHeight * this.configuration.aspectRatio); + if (selectionWidth > this.cropperCanvasRect.width) { + selectionWidth = Math.floor(this.cropperCanvasRect.width); + selectionHeight = Math.floor(selectionWidth / this.configuration.aspectRatio); + } + this.cropperSelection.$change(0, 0, selectionWidth, selectionHeight, this.configuration.aspectRatio, true); this.cropperSelection.$center(); this.cropperSelection.scrollIntoView({ block: "center", inline: "center" }); } @@ -211,7 +221,7 @@ define(["require", "exports", "tslib", "WoltLabSuite/Core/Image/Resizer", "WoltL - + -- 2.20.1