WIP
parent
30244c1598
commit
25476835e3
@ -0,0 +1,30 @@
|
|||||||
|
.crop-image {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100vw;
|
||||||
|
z-index: 99;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-image .crop-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-image .crop-close-btn,
|
||||||
|
.crop-image .crop-ok-btn {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40px;
|
||||||
|
color: var(--primary-color);
|
||||||
|
z-index: 1;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-image .crop-close-btn {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-image .crop-ok-btn {
|
||||||
|
right: 20px;
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { PlusOutlined } from "@ant-design/icons";
|
||||||
|
import { message, Upload } from "antd";
|
||||||
|
import ImgCrop from "antd-img-crop";
|
||||||
|
import { RcFile, UploadChangeParam, UploadFile } from "antd/es/upload";
|
||||||
|
|
||||||
|
type ImageBase64UploadProps = {
|
||||||
|
value?: string;
|
||||||
|
onChange?: (info: UploadChangeParam<UploadFile<any>>) => void;
|
||||||
|
};
|
||||||
|
export default ((props) => {
|
||||||
|
return (
|
||||||
|
<ImgCrop rotationSlider>
|
||||||
|
<Upload
|
||||||
|
name="file"
|
||||||
|
accept="image/*"
|
||||||
|
listType="picture-card"
|
||||||
|
headers={{
|
||||||
|
authorization: localStorage.getItem('token') ?? '',
|
||||||
|
}}
|
||||||
|
maxCount={1}
|
||||||
|
action={process.env.BASE_URL + '/oss/imgUpload'}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
beforeUpload={(file: RcFile) => {
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 10;
|
||||||
|
if (!isLt2M) {
|
||||||
|
message.error('图片大小不能超过10MB!');
|
||||||
|
}
|
||||||
|
return isLt2M || Upload.LIST_IGNORE;
|
||||||
|
}}
|
||||||
|
onPreview={async (file) => {
|
||||||
|
console.log(file)
|
||||||
|
if (file.uid === '-1') {
|
||||||
|
window.open(file.url);
|
||||||
|
}
|
||||||
|
if (file.response && file.response.retcode) {
|
||||||
|
window.open(file.response.data);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onChange={props.onChange}
|
||||||
|
>
|
||||||
|
{!props.value && (
|
||||||
|
<div>
|
||||||
|
{<PlusOutlined />}
|
||||||
|
<div style={{ marginTop: 8 }}>点击上传图片</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Upload>
|
||||||
|
</ImgCrop>
|
||||||
|
);
|
||||||
|
}) as React.FC<ImageBase64UploadProps>;
|
@ -0,0 +1,3 @@
|
|||||||
|
.ant-upload-list .ant-upload-list-item-container > div {
|
||||||
|
height: 100%;
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
export const createImage = (url: string) =>
|
||||||
|
new Promise<HTMLImageElement>((resolve, reject) => {
|
||||||
|
const image = new Image()
|
||||||
|
image.addEventListener('load', () => resolve(image))
|
||||||
|
image.addEventListener('error', (error) => reject(error))
|
||||||
|
image.setAttribute('crossOrigin', 'anonymous') // needed to avoid cross-origin issues on CodeSandbox
|
||||||
|
image.src = url
|
||||||
|
})
|
||||||
|
|
||||||
|
export function getRadianAngle(degreeValue: number) {
|
||||||
|
return (degreeValue * Math.PI) / 180
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the new bounding area of a rotated rectangle.
|
||||||
|
*/
|
||||||
|
export function rotateSize(width: number, height: number, rotation: number) {
|
||||||
|
const rotRad = getRadianAngle(rotation)
|
||||||
|
|
||||||
|
return {
|
||||||
|
width:
|
||||||
|
Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
|
||||||
|
height:
|
||||||
|
Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function was adapted from the one in the ReadMe of https://github.com/DominicTobias/react-image-crop
|
||||||
|
*/
|
||||||
|
export default async function getCroppedImg(
|
||||||
|
imageSrc: string,
|
||||||
|
pixelCrop: any,
|
||||||
|
rotation = 0,
|
||||||
|
flip = { horizontal: false, vertical: false }
|
||||||
|
) {
|
||||||
|
const image = await createImage(imageSrc)
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotRad = getRadianAngle(rotation)
|
||||||
|
|
||||||
|
// calculate bounding box of the rotated image
|
||||||
|
const { width: bBoxWidth, height: bBoxHeight } = rotateSize(
|
||||||
|
image.width,
|
||||||
|
image.height,
|
||||||
|
rotation
|
||||||
|
)
|
||||||
|
|
||||||
|
// set canvas size to match the bounding box
|
||||||
|
canvas.width = bBoxWidth
|
||||||
|
canvas.height = bBoxHeight
|
||||||
|
|
||||||
|
// translate canvas context to a central location to allow rotating and flipping around the center
|
||||||
|
ctx.translate(bBoxWidth / 2, bBoxHeight / 2)
|
||||||
|
ctx.rotate(rotRad)
|
||||||
|
ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1)
|
||||||
|
ctx.translate(-image.width / 2, -image.height / 2)
|
||||||
|
|
||||||
|
// draw rotated image
|
||||||
|
ctx.drawImage(image, 0, 0)
|
||||||
|
|
||||||
|
const croppedCanvas = document.createElement('canvas')
|
||||||
|
|
||||||
|
const croppedCtx = croppedCanvas.getContext('2d')
|
||||||
|
|
||||||
|
if (!croppedCtx) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the size of the cropped canvas
|
||||||
|
croppedCanvas.width = pixelCrop.width
|
||||||
|
croppedCanvas.height = pixelCrop.height
|
||||||
|
|
||||||
|
// Draw the cropped image onto the new canvas
|
||||||
|
croppedCtx.drawImage(
|
||||||
|
canvas,
|
||||||
|
pixelCrop.x,
|
||||||
|
pixelCrop.y,
|
||||||
|
pixelCrop.width,
|
||||||
|
pixelCrop.height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
pixelCrop.width,
|
||||||
|
pixelCrop.height
|
||||||
|
)
|
||||||
|
|
||||||
|
// As Base64 string
|
||||||
|
// return croppedCanvas.toDataURL('image/jpeg');
|
||||||
|
|
||||||
|
// As a blob
|
||||||
|
return new Promise<Blob>((resolve) => {
|
||||||
|
croppedCanvas.toBlob((file: any) => {
|
||||||
|
resolve(file)
|
||||||
|
}, 'image/jpeg')
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue