Skip to content

Commit

Permalink
batchImageCompress
Browse files Browse the repository at this point in the history
  • Loading branch information
Xutaotaotao committed May 8, 2024
1 parent ad9b6c3 commit 9db93d2
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 47 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
},
"devDependencies": {
"@douyinfe/semi-icons-lab": "^2.56.3",
"@douyinfe/semi-ui": "^2.56.3",
"@douyinfe/semi-ui": "^2.57.0",
"@types/react": "^18.0.33",
"@types/react-dom": "^18.0.11",
"antd": "^5.16.4",
Expand Down
6 changes: 4 additions & 2 deletions src/.umi/core/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ if (process.env.NODE_ENV === 'development') {
import React from 'react';

export async function getRoutes() {
const routes = {"jsonFormatting":{"path":"jsonFormatting","id":"jsonFormatting","parentId":"@@/global-layout"},"imageCompress":{"path":"imageCompress","id":"imageCompress","parentId":"@@/global-layout"},"imageSlicing":{"path":"imageSlicing","id":"imageSlicing","parentId":"@@/global-layout"},"index":{"path":"/","id":"index","parentId":"@@/global-layout"},"docs":{"path":"docs","id":"docs","parentId":"@@/global-layout"},"home":{"path":"home","id":"home","parentId":"@@/global-layout"},"@@/global-layout":{"id":"@@/global-layout","path":"/","isLayout":true}} as const;
const routes = {"imageCompress/singleImageCompress":{"path":"imageCompress/singleImageCompress","id":"imageCompress/singleImageCompress","parentId":"@@/global-layout"},"imageCompress/batchImageCompress":{"path":"imageCompress/batchImageCompress","id":"imageCompress/batchImageCompress","parentId":"@@/global-layout"},"imageCompress/index":{"path":"imageCompress","id":"imageCompress/index","parentId":"@@/global-layout"},"jsonFormatting":{"path":"jsonFormatting","id":"jsonFormatting","parentId":"@@/global-layout"},"imageSlicing":{"path":"imageSlicing","id":"imageSlicing","parentId":"@@/global-layout"},"index":{"path":"/","id":"index","parentId":"@@/global-layout"},"docs":{"path":"docs","id":"docs","parentId":"@@/global-layout"},"home":{"path":"home","id":"home","parentId":"@@/global-layout"},"@@/global-layout":{"id":"@@/global-layout","path":"/","isLayout":true}} as const;
return {
routes,
routeComponents: {
'imageCompress/singleImageCompress': React.lazy(() => import(/* webpackChunkName: "src__pages__imageCompress__singleImageCompress" */'../../../src/pages/imageCompress/singleImageCompress.tsx')),
'imageCompress/batchImageCompress': React.lazy(() => import(/* webpackChunkName: "src__pages__imageCompress__batchImageCompress" */'../../../src/pages/imageCompress/batchImageCompress.tsx')),
'imageCompress/index': React.lazy(() => import(/* webpackChunkName: "src__pages__imageCompress__index" */'../../../src/pages/imageCompress/index.tsx')),
'jsonFormatting': React.lazy(() => import(/* webpackChunkName: "src__pages__jsonFormatting" */'../../../src/pages/jsonFormatting.tsx')),
'imageCompress': React.lazy(() => import(/* webpackChunkName: "src__pages__imageCompress" */'../../../src/pages/imageCompress.tsx')),
'imageSlicing': React.lazy(() => import(/* webpackChunkName: "src__pages__imageSlicing" */'../../../src/pages/imageSlicing.tsx')),
'index': React.lazy(() => import(/* webpackChunkName: "src__pages__index" */'../../../src/pages/index.tsx')),
'docs': React.lazy(() => import(/* webpackChunkName: "src__pages__docs" */'../../../src/pages/docs.tsx')),
Expand Down
235 changes: 235 additions & 0 deletions src/pages/imageCompress/batchImageCompress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
import { InboxOutlined } from "@ant-design/icons";
import { IconAlignBottom } from "@douyinfe/semi-icons";
import { Button, Form, Image, Table } from "@douyinfe/semi-ui";
import { Col, Row, Space, Upload,Spin, message } from "antd";
import Compressor from "compressorjs";
import { useRef, useState } from "react";

const { Dragger } = Upload;

export default function BatchImageCompress() {
const api = useRef<any>();
const [fileList, setFileList] = useState<Array<any>>([]);
const [selectedRows, setSelectedRows] = useState([]);

const [spinningStatus, setSpinningStatus] = useState({
spinning: false,
tip: "",
})

const filesChange = (info: any) => {
const { fileList } = info;
setSpinningStatus({
spinning: true,
tip: "选取图片中,请稍后..."
})
const updatedFileList = fileList.map((file: any) => {
const reader = new FileReader();
return new Promise((resolve) => {
reader.onload = () => {
const fileUrl = reader.result;
file.url = fileUrl;
resolve(file);
};
reader.readAsDataURL(file.originFileObj);
});
});
Promise.all(updatedFileList).then((files) => {
setFileList(files);
}).finally(() => {
setSpinningStatus({
spinning: false,
tip: "",
})
})
};

const downLoad = (record: any) => {
const a = document.createElement("a");
a.href = URL.createObjectURL(record.compressedFile); // 创建对象超链接
a.download = `${record.name}.jpg`; // 下载后文件名
a.click();
};

const columns = [
{
title: "标题",
dataIndex: "name",
render: (text: string, record: any, index: number) => {
return (
<div>
<Image
height={80}
width={80}
src={record.url}
style={{ marginRight: 12 }}
imgStyle={{ objectFit: "cover" }}
></Image>
{text}
</div>
);
},
},
{
title: "原始大小",
dataIndex: "size",
render: (text: number) => {
return `${(text / 1024).toFixed(2)}KB`;
},
},
{
title: "压缩后大小",
dataIndex: "compressedSize",
render: (text: number) => {
return text ? `${(text / 1024).toFixed(2)}KB` : "-";
},
},
{
title: "压缩率",
dataIndex: "compressRate",
render: (text: number, record: any) => {
const compressRate = (record.compressedSize / record.size) * 100;
return record.compressedSize ? `${compressRate.toFixed(2)}%` : "-";
},
},
{
title: "压缩后图片",
dataIndex: "compressRate",
render: (text: string, record: any, index: number) => {
return (
<div>
<Image
height={80}
width={80}
src={record.compressedUrl}
style={{ marginRight: 12 }}
imgStyle={{ objectFit: "cover" }}
></Image>
</div>
);
},
},
{
title: "操作",
dataIndex: "operation",
render: (_text: any, record: any) => {
return (
<Button
disabled={!record.compressedSize}
icon={<IconAlignBottom />}
theme="borderless"
onClick={() => downLoad(record)}
/>
);
},
},
];

const rowSelection = {
onChange: (selectedRowKeys: any, selectedRows: any) => {
setSelectedRows(selectedRows);
},
};

const startCompress = () => {
setSpinningStatus({
spinning: true,
tip: "压缩中,请稍后..."
})
const compressingPromise = fileList.map((file: any) => {
return new Promise((resolve) => {
new Compressor(file.originFileObj, {
quality: api.current.getValue("quality") || 0.6,
success: (result) => {
file.compressedFile = result;
file.compressedSize = result.size;
let reader = new FileReader();
reader.readAsDataURL(result);
reader.onload = function (e: any) {
resolve({ ...file, compressedUrl: e.target.result });
};
},
error: (err) => {
console.log(err.message);
},
});
});
});
Promise.all(compressingPromise).then((result) => {
setFileList(result);
message.success("压缩成功");
}).finally(() => {
setSpinningStatus({
spinning: false,
tip: "",
})
})
};

return (
<div style={{ height: "calc(100vh - 170px)" }}>
<Spin spinning={spinningStatus.spinning} tip={spinningStatus.tip} style={{ width: "100%",height: "100%" }}>
<Row gutter={[16, 16]} style={{ height: "100%" }}>
{fileList.length > 0 ? (
<div style={{ height: "100%", width: "100%", padding: "16px" }}>
<Row gutter={[16, 16]} justify={"space-between"} align={"middle"}>
<Col span={12}>
<Form
getFormApi={(formApi) => (api.current = formApi)}
labelPosition="left"
initValues={{ quality: 0.6 }}
>
<Form.InputNumber
min={0}
max={1}
field="quality"
label="压缩质量"
defaultValue={0.6}
></Form.InputNumber>
</Form>
</Col>
<Col span={12} style={{ textAlign: "right" }}>
<Space>
<Button onClick={() => setFileList([])}>重新上传图片</Button>
<Button
theme="solid"
type="primary"
onClick={startCompress}
>
开始压缩
</Button>
</Space>
</Col>
</Row>
<Table
rowKey={"name"}
style={{ marginTop: 16 }}
columns={columns}
dataSource={fileList}
pagination={false}
// rowSelection={rowSelection}
/>
</div>
) : (
<Col span={24} style={{ height: "40vh" }}>
<Dragger
name="file"
multiple
onChange={filesChange}
fileList={fileList}
customRequest={() => {}}
showUploadList={false}
>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">点击或拖拽上传图片</p>
</Dragger>
</Col>
)}

</Row>
</Spin>
</div>
);
}
16 changes: 16 additions & 0 deletions src/pages/imageCompress/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Tabs, TabPane } from '@douyinfe/semi-ui';
import SingleImageCompress from './singleImageCompress';
import BatchImageCompress from './batchImageCompress';

export default function ImageCompress() {
return <div>
<Tabs type="line">
<TabPane tab="单个图片压缩" itemKey="1">
<SingleImageCompress/>
</TabPane>
<TabPane tab="JPG批量压缩" itemKey="2">
<BatchImageCompress />
</TabPane>
</Tabs>
</div>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function ImageCompress() {
<Col lg={6} xs={24}>
<Card
title="设置"
styles={{ body: { height: "calc(100vh - 150px", overflow: "auto" } }}
styles={{ body: { height: "calc(100vh - 200px", overflow: "auto" } }}
>
<Form
getFormApi={(formApi) => (api.current = formApi)}
Expand Down Expand Up @@ -128,7 +128,7 @@ export default function ImageCompress() {
</Col>
<Col lg={18} xs={24}>
{currentImg ? (
<div style={{ height: "calc(100vh - 100px)", overflow: "auto" }}>
<div style={{ height: "calc(100vh - 170px)", overflow: "auto" }}>
<Card
title={`原图 【大小】:${file.size / 1024}KB`}
styles={{ body: { textAlign: "center" } }}
Expand Down Expand Up @@ -156,7 +156,6 @@ export default function ImageCompress() {
) : (
<Dragger
name="file"
multiple
onChange={filesChange}
fileList={fileList}
customRequest={() => {}}
Expand Down
Loading

0 comments on commit 9db93d2

Please sign in to comment.