Skip to content

Commit

Permalink
Merge pull request #33 from baizeteam/feature/baize-compress-image_dog
Browse files Browse the repository at this point in the history
adpater png and webp
  • Loading branch information
sulgweb authored Aug 4, 2024
2 parents ec5df36 + 100011b commit e4113d1
Show file tree
Hide file tree
Showing 9 changed files with 1,027 additions and 27 deletions.
7 changes: 7 additions & 0 deletions packages/baize-compress-image/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# baize-compress-image

## 0.0.4

### Patch Changes

- 添加 png 和 webp 图片的压缩适配
915 changes: 915 additions & 0 deletions packages/baize-compress-image/lib/UPNG.min.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/baize-compress-image/lib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const store = localforage.createInstance(DEFAUTL_FORAGE_CONFIG);

const worker = new Worker();

export const compressImageWorker = async (file: File, quality = DEFAULT_QUALITY) => {
export const compressImageWorker = async (file: File, quality = DEFAULT_QUALITY): Promise<File> => {
return new Promise(async (resolve, reject) => {
const id = nanoid(8);
const taskData = {
Expand All @@ -21,7 +21,7 @@ export const compressImageWorker = async (file: File, quality = DEFAULT_QUALITY)
worker.onmessage = async (event) => {
const message = JSON.parse(event.data);
if (message.type === "compressImageSuccess") {
const result = await store.getItem(taskId);
const result = (await store.getItem(taskId)) as File;
await store.removeItem(taskId);
resolve(result);
} else {
Expand Down
2 changes: 2 additions & 0 deletions packages/baize-compress-image/lib/pako.min.js

Large diffs are not rendered by default.

52 changes: 38 additions & 14 deletions packages/baize-compress-image/lib/worker.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// worker.ts
import "./localforage.min.js";
import "./pako.min.js";
import "./UPNG.min.js";
import "localforage";
import { DEFAUTL_FORAGE_CONFIG, DEFAULT_QUALITY } from "./config.js";

declare const localforage: LocalForage;
declare const UPNG: any;
interface TaskType {
file: File;
taskId: string;
Expand All @@ -12,23 +15,39 @@ interface TaskType {

const store = localforage.createInstance(DEFAUTL_FORAGE_CONFIG);

const compressJpegImage = async ({ img, quality }) => {
// 利用OffscreenCanvas压缩jpeg图片
const compressJpegImage = async ({ file, quality }) => {
const img = file.slice(0, file.size, file.type);
const offscreen = new OffscreenCanvas(100, 100);
const ctx = offscreen.getContext("2d") as OffscreenCanvasRenderingContext2D;
const imgData = await createImageBitmap(img);
offscreen.width = imgData.width;
offscreen.height = imgData.height;
ctx.drawImage(imgData, 0, 0, offscreen.width, offscreen.height);
const res = await offscreen.convertToBlob({ type: "image/jpeg", quality }).then((blob) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
return new Promise((resolve) => {
reader.onloadend = () => {
resolve(reader.result);
};
});
});
return res;
const blob = await offscreen.convertToBlob({ type: file.type, quality });
const newFile = new File([blob], file.name, { type: file.type, lastModified: Date.now() });
return newFile;
};

// 利用UPNG压缩png图片
const compressPngImage = async ({ file, quality }) => {
const arrayBuffer = await file.arrayBuffer();
const decoded = UPNG.decode(arrayBuffer);
const rgba8 = UPNG.toRGBA8(decoded);
const compressImg = UPNG.encode(rgba8, decoded.width, decoded.height, 256 * quality);
const compressFile = new File([compressImg], file.name, { type: file.type });
return compressFile;
};

const compressImage = async ({ file, quality }) => {
const type = file.type.split("/")[1];
if (type === "jpeg" || type === "jpg" || type === "webp") {
return await compressJpegImage({ file, quality });
} else if (type === "png") {
return await compressPngImage({ file, quality });
} else {
throw new Error("Unsupported image type");
}
};

self.onmessage = async (event) => {
Expand All @@ -37,11 +56,16 @@ self.onmessage = async (event) => {
const taskData = (await store.getItem(params.taskId)) as TaskType;
await store.removeItem(params.taskId);
const file = taskData.file;
const compressRes = await compressJpegImage({
img: file.slice(0, file.size, file.type),
const compressRes = await compressImage({
file: file,
quality: taskData.quality || DEFAULT_QUALITY,
});
store.setItem(params.taskId, compressRes);
if (compressRes.size < file.size) {
// 压缩后大小小于原文件大小,则替换原文件
store.setItem(params.taskId, compressRes);
} else {
store.setItem(params.taskId, file);
}
self.postMessage(
JSON.stringify({
type: "compressImageSuccess",
Expand Down
6 changes: 4 additions & 2 deletions packages/baize-compress-image/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "baize-compress-image",
"version": "0.0.3",
"version": "0.0.4",
"type": "module",
"files": [
"dist",
Expand All @@ -24,6 +24,7 @@
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/upng-js": "^2.1.5",
"@vitejs/plugin-react": "^4.3.0",
"cross-env": "^7.0.3",
"react": "^18.3.1",
Expand All @@ -33,7 +34,8 @@
"vite": "^5.2.10"
},
"dependencies": {
"nanoid": "^5.0.7"
"nanoid": "^5.0.7",
"upng-js": "^2.1.0"
},
"peerDependencies": {
"localforage": ">=1.10.0"
Expand Down
43 changes: 35 additions & 8 deletions packages/baize-compress-image/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,51 @@
// import React from "react";
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom/client";
import { compressImageWorker } from "../lib/main";
// import { compressImageWorker } from "../dist/index.js";
import { useEffect } from "react";

function App() {
useEffect(() => {}, []);

const handleFileChange = async (e: any) => {
const file = e.target.files[0];
const [originalImageUrl, setOriginalImageUrl] = useState("");
const [compressedImageUrl, setCompressedImageUrl] = useState("");

const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (!files || files.length === 0) {
return;
}

const file = files[0];
console.time("compressImageWorker");
const res = await compressImageWorker(file);
console.log("%c [ res ]-12", "font-size:13px; background:pink; color:#bf2c9f;", res);
console.timeEnd("compressImageWorker");
try {
const compressedFile = await compressImageWorker(file);
console.log("%c [ res ]-12", "font-size:13px; background:pink; color:#bf2c9f;", compressedFile);

const originalUrl = URL.createObjectURL(file);
setOriginalImageUrl(originalUrl);

const compressedUrl = URL.createObjectURL(compressedFile);
setCompressedImageUrl(compressedUrl);

console.timeEnd("compressImageWorker");
} catch (error) {
console.error("Compression failed:", error);
}
};

return (
<div>
Hello localforage-worker!
<div>
<input type="file" onChange={handleFileChange} />
<input type="file" multiple onChange={handleFileChange} />
</div>
<div style={{ display: originalImageUrl ? "block" : "none" }}>
<h2>原图</h2>
<img src={originalImageUrl} style={{ maxHeight: "200px" }} alt="Original Image" />
</div>
<div style={{ display: originalImageUrl ? "block" : "none" }}>
<h2>压缩图</h2>
<img src={compressedImageUrl} style={{ maxHeight: "200px" }} alt="Compressed Image" />
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/baize-compress-image/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const libConfig = {
inlineDynamicImports: true,
},
},
external: ["localforage"],
external: ["localforage", "upng-js"],
},
},
};
Expand Down
23 changes: 23 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e4113d1

Please sign in to comment.