From 15cdd115942a1534b2d2847e23029675c8c065d9 Mon Sep 17 00:00:00 2001 From: zhaoyao91 Date: Mon, 21 Oct 2019 14:10:30 +0800 Subject: [PATCH] support input props --- README.md | 5 +++++ package.json | 2 +- src/CropImageModal.js | 49 ++++++++++++++++++++++++++++++++++++------- src/HiddenCropper.js | 2 ++ src/ImageCropper.js | 4 ++++ src/utils.js | 31 ++++++++++++++++++++++++++- 6 files changed, 84 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 803fa27..91c896c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ Options with `*` prefix are recommended to set. ### Common Options +- `inputOptions` ? : object + - \* `maxWidth` = Infinity + - \* `maxHeight` = Infinity + - `mimeType` = 'image/jpeg' + - `quality` ? : number - `cropOptions` ? : object - \* `aspect` ? : number - `maxZoom` ? : number diff --git a/package.json b/package.json index 89d6d92..c134e26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-bootstrap-image-cropper", - "version": "0.2.4", + "version": "0.3.0", "description": "Select, crop, preview, edit, all in one!", "keywords": [ "react-bootstrap", diff --git a/src/CropImageModal.js b/src/CropImageModal.js index 41370bf..02bbc4b 100644 --- a/src/CropImageModal.js +++ b/src/CropImageModal.js @@ -1,9 +1,9 @@ -import React, { useRef } from "react"; -import { Button, Modal } from "react-bootstrap"; +import React, { useEffect, useRef, useState } from "react"; +import { Button, Modal, Spinner } from "react-bootstrap"; import useObjectURL from "use-object-url"; import CropImagePanel from "./CropImagePanel"; -import { getCroppedFile } from "./utils"; +import { getCroppedFile, limitImageSize } from "./utils"; export default function CropImageModal({ show, @@ -13,10 +13,18 @@ export default function CropImageModal({ onConfirm, // (croppedFile) => void onCancel, // void => void onRemove, // void => void + inputOptions = {}, // {maxWidth, maxHeight, mimeType, quality} cropOptions = {}, // {aspect, maxZoom} outputOptions = {}, // {maxWidth, maxHeight, mimeType, quality} displayOptions = {} // {title, removeButtonText, confirmButtonText, showRemoveButton, showConfirmButton} }) { + const { + maxWidth: inputMaxWidth = Infinity, + maxHeight: inputMaxHeight = Infinity, + mimeType: inputMimeType = "image/jpeg", + quality: inputQuality + } = inputOptions; + const { aspect, maxZoom } = cropOptions; const { @@ -35,6 +43,28 @@ export default function CropImageModal({ } = displayOptions; const imageUrl = useObjectURL(imageFile); + + const [resizedUrl, setResizedUrl] = useState(); + const [resizing, setResizing] = useState(false); + + useEffect(() => { + if (imageUrl) { + setResizing(true); + limitImageSize({ + imageUrl, + maxWidth: inputMaxWidth, + maxHeight: inputMaxHeight, + mimeType: inputMimeType, + quality: inputQuality + }) + .then(url => setResizedUrl(url)) + .catch(err => console.error(err)) + .finally(() => setResizing(false)); + } else { + setResizedUrl(); + } + }, [imageUrl]); + const cropResultRef = useRef(); function handleCropComplete(croppedArea, croppedAreaPixels) { @@ -43,7 +73,7 @@ export default function CropImageModal({ function handleConfirm() { getCroppedFile( - imageUrl, + resizedUrl, cropResultRef.current.croppedAreaPixels, maxWidth, maxHeight, @@ -57,10 +87,15 @@ export default function CropImageModal({ {title} - - {imageUrl && ( + + {resizing && ( +
+ +
+ )} + {resizedUrl && ( void + inputOptions = {}, cropOptions = {}, outputOptions = {}, displayOptions = {} @@ -59,6 +60,7 @@ export default function HiddenCropper({ onChange={setCropState} onConfirm={handleConfirm} onCancel={handleCancel} + inputOptions={inputOptions} cropOptions={cropOptions} outputOptions={outputOptions} displayOptions={{ ...displayOptions, showRemoveButton: false }} diff --git a/src/ImageCropper.js b/src/ImageCropper.js index 486428c..9000c66 100644 --- a/src/ImageCropper.js +++ b/src/ImageCropper.js @@ -6,6 +6,7 @@ import CropImageModal from "./CropImageModal"; export default function ImageCropper({ fileRef, onChange, + inputOptions, cropOptions, outputOptions, displayOptions, @@ -85,6 +86,7 @@ export default function ImageCropper({ onConfirm={handleConfirm} onCancel={handleCancel} onRemove={handleRemove} + inputOptions={inputOptions} cropOptions={cropOptions} outputOptions={outputOptions} displayOptions={displayOptions} @@ -102,6 +104,7 @@ export function ControlledImageCropper({ onConfirm, onCancel, onRemove, + inputOptions = {}, cropOptions = {}, outputOptions = {}, displayOptions = {}, @@ -143,6 +146,7 @@ export function ControlledImageCropper({ onConfirm={onConfirm} onCancel={onCancel} onRemove={onRemove} + inputOptions={inputOptions} cropOptions={cropOptions} outputOptions={outputOptions} displayOptions={displayOptions} diff --git a/src/utils.js b/src/utils.js index 593365a..5d8dd1d 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,4 @@ -// 以下工具复制自 https://codesandbox.io/s/q8q1mnr01w +// 以下工具部分复制自 https://codesandbox.io/s/q8q1mnr01w // 略有修改 export async function createImageDomFromUrl(url) { @@ -10,6 +10,35 @@ export async function createImageDomFromUrl(url) { }); } +export async function limitImageSize({ + imageUrl, + maxWidth, + maxHeight, + mimeType, + quality +}) { + const image = await createImageDomFromUrl(imageUrl); + + if (image.width <= maxWidth && image.height <= maxHeight) { + return imageUrl; + } + + const { width, height } = limitSize( + image.width, + image.height, + maxWidth, + maxHeight + ); + + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, 0, 0, width, height); + + return canvas.toDataURL(mimeType, quality); +} + /** * This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop * @param {string} imageUrl - Image File url