From 27704cd5f7971df176dbcc2cf043c7a4e676cf7d Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Thu, 11 Jan 2024 10:16:04 +0800 Subject: [PATCH 1/7] =?UTF-8?q?refactor=EF=BC=9A=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E8=AE=A1=E7=AE=97=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E6=9C=80=E5=A4=A7=E5=B0=BA=E5=AF=B8=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E9=81=BF=E5=85=8D=E5=A4=B4=E5=83=8F=E8=A3=81?= =?UTF-8?q?=E5=89=AA=E5=87=BA=E6=9D=A5=E5=A4=AA=E5=A4=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/modals/ImageCropper.tsx | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index dcea4e53dfd..14fcb97c2c6 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -85,36 +85,28 @@ function getCroppedImg( const ctx = canvas.getContext('2d'); if (!_isNil(ctx)) { - const maxSize = Math.max(image.width, image.height); - const safeArea = 2 * ((maxSize / 2) * Math.sqrt(2)); + // 设置头像大小 + const size = 256; - // set each dimensions to double largest dimension to allow for a safe area for the - // image to rotate in without being clipped by canvas context - canvas.width = safeArea; - canvas.height = safeArea; + canvas.width = size; + canvas.height = size; // translate canvas context to a central location on image to allow rotating around the center. - ctx.translate(safeArea / 2, safeArea / 2); + ctx.translate(size / 2, size / 2); ctx.rotate(getRadianAngle(rotation)); - ctx.translate(-safeArea / 2, -safeArea / 2); + ctx.translate(-size / 2, -size / 2); // draw rotated image and store data. ctx.drawImage( image, - safeArea / 2 - image.width * 0.5, - safeArea / 2 - image.height * 0.5 - ); - const data = ctx.getImageData(0, 0, safeArea, safeArea); - - // set canvas width to final desired crop size - this will clear existing context - canvas.width = crop.width; - canvas.height = crop.height; - - // paste generated rotate image with correct offsets for x,y crop values. - ctx.putImageData( - data, - Math.round(0 - safeArea / 2 + image.width * 0.5 - crop.x), - Math.round(0 - safeArea / 2 + image.height * 0.5 - crop.y) + crop.x, + crop.y, + crop.width, + crop.height, + 0, + 0, + size, + size ); } From 87bb0e3b79bea436a3284ee0ce78916903df4ad6 Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Thu, 11 Jan 2024 17:04:32 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix:=20=E6=94=B9=E4=B8=BA=E9=80=9A=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/modals/ImageCropper.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index 14fcb97c2c6..28b98486ba6 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -85,16 +85,22 @@ function getCroppedImg( const ctx = canvas.getContext('2d'); if (!_isNil(ctx)) { - // 设置头像大小 - const size = 256; + // 设定最大尺寸,可以提出来作为参数传入 + const maxSize = 256; - canvas.width = size; - canvas.height = size; + // 计算最大尺寸 + const size = Math.min(crop.width, crop.height, maxSize); + + // 计算缩放比例 + const scale = size / Math.max(crop.width, crop.height); + + canvas.width = scale * crop.width; + canvas.height = scale * crop.height; // translate canvas context to a central location on image to allow rotating around the center. - ctx.translate(size / 2, size / 2); + ctx.translate(canvas.width / 2, canvas.width / 2); ctx.rotate(getRadianAngle(rotation)); - ctx.translate(-size / 2, -size / 2); + ctx.translate(-canvas.width / 2, -canvas.width / 2); // draw rotated image and store data. ctx.drawImage( @@ -105,8 +111,8 @@ function getCroppedImg( crop.height, 0, 0, - size, - size + canvas.width, + canvas.height ); } From 4d9aa7248f2eba48956bf492e70ced621c011d5a Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Thu, 11 Jan 2024 17:33:07 +0800 Subject: [PATCH 3/7] =?UTF-8?q?fix:=20maxSize=20=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/web/src/components/modals/ImageCropper.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index 28b98486ba6..09f1db6ed9a 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -73,21 +73,20 @@ let fileUrlTemp: string | null = null; // 缓存裁剪后的图片url * @param crop 裁剪信息 * @param rotation 旋转角度 * @param fileName 文件名 + * @param maxSize 最大尺寸 * @returns 裁剪后的图片blob url */ function getCroppedImg( image: HTMLImageElement, crop: Area, rotation = 0, - fileName = 'newFile.jpeg' + fileName = 'newFile.jpeg', + maxSize = Infinity ): Promise { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!_isNil(ctx)) { - // 设定最大尺寸,可以提出来作为参数传入 - const maxSize = 256; - // 计算最大尺寸 const size = Math.min(crop.width, crop.height, maxSize); From 0e732d33031da9c26cb56c8a80dfec733f387d5d Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Thu, 11 Jan 2024 18:18:09 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix:=20=E5=8F=AF=E4=BB=A5=E6=AD=A3=E7=A1=AE?= =?UTF-8?q?=E6=97=8B=E8=BD=AC=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/web/src/components/modals/ImageCropper.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index 09f1db6ed9a..e66b66c377c 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -104,14 +104,14 @@ function getCroppedImg( // draw rotated image and store data. ctx.drawImage( image, - crop.x, - crop.y, - crop.width, - crop.height, 0, 0, - canvas.width, - canvas.height + image.width, + image.height, + -crop.x * scale, + -crop.y * scale, + image.width * scale, + image.height * scale ); } From 854d52ed3253b45bfaa557b2df5fb14f9db0b6e3 Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Thu, 11 Jan 2024 18:26:53 +0800 Subject: [PATCH 5/7] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=97=8B=E8=BD=AC?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/web/src/components/modals/ImageCropper.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index e66b66c377c..e5fa1b53974 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -97,9 +97,9 @@ function getCroppedImg( canvas.height = scale * crop.height; // translate canvas context to a central location on image to allow rotating around the center. - ctx.translate(canvas.width / 2, canvas.width / 2); + ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(getRadianAngle(rotation)); - ctx.translate(-canvas.width / 2, -canvas.width / 2); + ctx.translate(-canvas.width / 2, -canvas.height / 2); // draw rotated image and store data. ctx.drawImage( From 163f79ebb840ac830b0209dec299619f9f8853ae Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Fri, 12 Jan 2024 09:42:49 +0800 Subject: [PATCH 6/7] fix: maxSize --- client/web/src/components/modals/ImageCropper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index e5fa1b53974..d7c83df0dbf 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -88,7 +88,7 @@ function getCroppedImg( if (!_isNil(ctx)) { // 计算最大尺寸 - const size = Math.min(crop.width, crop.height, maxSize); + const size = Math.min(Math.max(crop.width, crop.height), maxSize); // 计算缩放比例 const scale = size / Math.max(crop.width, crop.height); From c8e5102092491ed996af87bf372b419ca3b6f765 Mon Sep 17 00:00:00 2001 From: youxia <243802688@qq.com> Date: Fri, 12 Jan 2024 10:09:05 +0800 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=E5=A4=B4=E5=83=8F=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=B0=BA=E5=AF=B8=E8=AE=BE=E5=AE=9A=E4=B8=BA256?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/web/src/components/ImagePicker.tsx | 2 ++ client/web/src/components/ImageUploader.tsx | 11 ++++++++++- client/web/src/components/modals/ImageCropper.tsx | 7 ++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/client/web/src/components/ImagePicker.tsx b/client/web/src/components/ImagePicker.tsx index 8a7f02964b3..bb42dec29da 100644 --- a/client/web/src/components/ImagePicker.tsx +++ b/client/web/src/components/ImagePicker.tsx @@ -10,6 +10,7 @@ interface ImagePickerProps extends PropsWithChildren { className?: string; imageUrl?: string; // 初始image url, 仅children为空时生效 aspect?: number; + maxSize?: number; onChange?: (blobUrl: string) => void; disabled?: boolean; // 禁用选择 } @@ -43,6 +44,7 @@ export const ImagePicker: React.FC = React.memo((props) => { { closeModal(key); updateAvatar(croppedImageBlobUrl); diff --git a/client/web/src/components/ImageUploader.tsx b/client/web/src/components/ImageUploader.tsx index a0c2effce9b..21390afe4c2 100644 --- a/client/web/src/components/ImageUploader.tsx +++ b/client/web/src/components/ImageUploader.tsx @@ -7,6 +7,7 @@ import { ImagePicker } from './ImagePicker'; interface ImageUploaderProps extends PropsWithChildren { circle?: boolean; aspect?: number; + maxSize?: number; className?: string; onUploadSuccess: (fileInfo: UploadFileResult) => void; } @@ -39,6 +40,7 @@ export const ImageUploader: React.FC = React.memo( 'rounded-full': props.circle, })} aspect={aspect} + maxSize={props.maxSize} disabled={loading} onChange={handlePickImage} > @@ -58,7 +60,14 @@ ImageUploader.displayName = 'ImageUploader'; export const AvatarUploader: React.FC = React.memo( (props) => { - return ; + return ( + + ); } ); AvatarUploader.displayName = 'AvatarUploader'; diff --git a/client/web/src/components/modals/ImageCropper.tsx b/client/web/src/components/modals/ImageCropper.tsx index d7c83df0dbf..a6630127979 100644 --- a/client/web/src/components/modals/ImageCropper.tsx +++ b/client/web/src/components/modals/ImageCropper.tsx @@ -11,9 +11,11 @@ import { ModalWrapper } from '../Modal'; export const ImageCropperModal: React.FC<{ imageUrl: string; aspect?: number; + maxSize?: number; onConfirm: (croppedImageBlobUrl: string) => void; }> = React.memo((props) => { const aspect = props.aspect ?? 1; + const maxSize = props.maxSize ?? Infinity; const [crop, setCrop] = useState({ x: 0, y: 0 }); const [zoom, setZoom] = useState(1); const [area, setArea] = useState({ width: 0, height: 0, x: 0, y: 0 }); @@ -21,7 +23,10 @@ export const ImageCropperModal: React.FC<{ const handleConfirm = async () => { const blobUrl = await getCroppedImg( await createImage(props.imageUrl), - area + area, + 0, + 'newFile.jpeg', + maxSize ); props.onConfirm(blobUrl); };