baize-compress 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +165 -0
- package/README.md +82 -2
- package/dist/assets/compress-BQao8LZ4.js +501 -0
- package/dist/assets/compress-CRhfuN3_.js +4 -0
- package/dist/assets/compress-Di96HUYT.js +1 -0
- package/dist/assets/compress-I5veHSQ1.js +110 -0
- package/dist/assets/compress-XlJOQ9AQ.js +1 -0
- package/dist/assets/pool.worker-BZcE0nvO.js +4 -0
- package/dist/index.js +150 -0
- package/dist/plugins/gif.js +16 -0
- package/dist/plugins/jpeg-webp.js +12 -0
- package/dist/plugins/media.js +32 -0
- package/dist/plugins/png.js +12 -0
- package/dist/plugins/svg.js +14 -0
- package/dist/types/config.d.ts +1 -0
- package/dist/types/main.d.ts +14 -0
- package/dist/types/plugins/gif/compress.d.ts +2 -0
- package/dist/types/plugins/gif/index.d.ts +6 -0
- package/dist/types/plugins/jpeg-webp/compress.d.ts +2 -0
- package/dist/types/plugins/jpeg-webp/index.d.ts +2 -0
- package/dist/types/plugins/media/compress.d.ts +2 -0
- package/dist/types/plugins/media/index.d.ts +23 -0
- package/dist/types/plugins/png/compress.d.ts +2 -0
- package/dist/types/plugins/png/index.d.ts +2 -0
- package/dist/types/plugins/svg/compress.d.ts +2 -0
- package/dist/types/plugins/svg/index.d.ts +6 -0
- package/dist/types/pool.worker.d.ts +1 -0
- package/dist/types/types.d.ts +45 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types/workerManage.d.ts +15 -0
- package/dist/types/workerTask.d.ts +16 -0
- package/dist/utils-DHI2QTd1.js +8 -0
- package/index.d.ts +2 -0
- package/package.json +100 -4
- package/plugins/gif.d.ts +2 -0
- package/plugins/jpeg-webp.d.ts +2 -0
- package/plugins/media.d.ts +2 -0
- package/plugins/png.d.ts +2 -0
- package/plugins/svg.d.ts +2 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e({arrayBuffer:e,fileName:t,fileType:n},r){return{success:!0,data:r.byteLength<e.byteLength?r:e,fileName:t,fileType:n}}async function t({arrayBuffer:t,fileName:n,fileType:r,quality:i}){let a=new Blob([t],{type:r}),o=await createImageBitmap(a);try{let a=new OffscreenCanvas(o.width,o.height),s=a.getContext(`2d`);if(!s)throw Error(`当前浏览器不支持离屏画布绘图`);s.drawImage(o,0,0);let c=await a.convertToBlob({type:r,quality:i}),l=c.type===r&&c.size<t.byteLength?await c.arrayBuffer():t;return e({arrayBuffer:t,fileName:n,fileType:r},l)}finally{o.close()}}export{t as compress};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const e=/* @__PURE__ */ new Map;function t(t){let n=e.get(t);if(n)return n;let r=import(
|
|
2
|
+
/* @vite-ignore */
|
|
3
|
+
/* webpackIgnore: true */
|
|
4
|
+
t).then(e=>{if(typeof e.compress!=`function`)throw Error(`压缩模块缺少 compress 导出`);return e.compress}).catch(n=>{throw e.delete(t),n});return e.set(t,r),r}self.addEventListener(`message`,async e=>{let{type:n,moduleUrl:r,...i}=e.data??{};if(n===`compress`)try{if(typeof r!=`string`||!r)throw Error(`插件缺少压缩模块入口`);let e=await(await t(r))(i);if(e.success&&!(e.data instanceof ArrayBuffer))throw Error(`压缩模块未返回有效的 ArrayBuffer`);self.postMessage(e,e.success?[e.data]:[])}catch(e){self.postMessage({success:!1,error:e instanceof Error?e.message:`压缩失败`})}});
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { n as e, t } from "./utils-DHI2QTd1.js";
|
|
2
|
+
// lib/pool.worker.ts?worker&url
|
|
3
|
+
var n = new URL("./assets/pool.worker-BZcE0nvO.js?no-inline", import.meta.url).href;
|
|
4
|
+
// lib/workerTask.ts
|
|
5
|
+
async function r(e, t) {
|
|
6
|
+
if (t.aborted) throw Error("Worker manager terminated");
|
|
7
|
+
let n, r = new Promise((e, r) => {
|
|
8
|
+
n = () => r(/* @__PURE__ */ Error("Worker manager terminated")), t.addEventListener("abort", n, { once: !0 });
|
|
9
|
+
});
|
|
10
|
+
try {
|
|
11
|
+
return await Promise.race([r, e.arrayBuffer()]);
|
|
12
|
+
} finally {
|
|
13
|
+
t.removeEventListener("abort", n);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function i(e, t, n, r) {
|
|
17
|
+
return new Promise((i, a) => {
|
|
18
|
+
let o = Date.now(), s = !1, c = (t, c, p = !1) => {
|
|
19
|
+
s || (s = !0, clearTimeout(f), e.removeEventListener("message", l), e.removeEventListener("error", u), n.removeEventListener("abort", d), p && r(), c ? i({
|
|
20
|
+
...c,
|
|
21
|
+
startTime: o,
|
|
22
|
+
endTime: Date.now()
|
|
23
|
+
}) : a(t));
|
|
24
|
+
}, l = (e) => {
|
|
25
|
+
let t = e.data;
|
|
26
|
+
t.success && !(t.data instanceof ArrayBuffer) ? c(/* @__PURE__ */ Error("压缩模块未返回有效的 ArrayBuffer")) : t.success ? c(void 0, t) : c(Error(t.error || "压缩失败"));
|
|
27
|
+
}, u = (e) => {
|
|
28
|
+
c(/* @__PURE__ */ Error(`Worker error: ${e.message}`), void 0, !0);
|
|
29
|
+
}, d = () => c(/* @__PURE__ */ Error("Worker manager terminated")), f = setTimeout(() => {
|
|
30
|
+
c(/* @__PURE__ */ Error("Worker timeout"), void 0, !0);
|
|
31
|
+
}, t.timeoutMs);
|
|
32
|
+
if (e.addEventListener("message", l), e.addEventListener("error", u), n.addEventListener("abort", d, { once: !0 }), n.aborted) d();
|
|
33
|
+
else try {
|
|
34
|
+
e.postMessage({
|
|
35
|
+
...t.config,
|
|
36
|
+
type: "compress",
|
|
37
|
+
moduleUrl: t.moduleUrl,
|
|
38
|
+
arrayBuffer: t.arrayBuffer,
|
|
39
|
+
fileName: t.fileName,
|
|
40
|
+
fileType: t.fileType
|
|
41
|
+
}, [t.arrayBuffer]);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
c(e);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// lib/workerManage.ts
|
|
48
|
+
var a = class {
|
|
49
|
+
plugins;
|
|
50
|
+
workers = /* @__PURE__ */ new Set();
|
|
51
|
+
active = /* @__PURE__ */ new Map();
|
|
52
|
+
taskQueue = [];
|
|
53
|
+
maxWorkers;
|
|
54
|
+
constructor(e, t = 4) {
|
|
55
|
+
if (!Number.isSafeInteger(t) || t <= 0) throw Error("workerNum 必须是有效的正整数");
|
|
56
|
+
this.plugins = e, this.maxWorkers = t;
|
|
57
|
+
}
|
|
58
|
+
findPlugin(e) {
|
|
59
|
+
return this.plugins.find((t) => t.matches(e)) ?? null;
|
|
60
|
+
}
|
|
61
|
+
processNextTask() {
|
|
62
|
+
for (; this.taskQueue.length > 0;) {
|
|
63
|
+
let e = this.taskQueue[0], t = [...this.workers].find((e) => !this.active.has(e));
|
|
64
|
+
if (!t) {
|
|
65
|
+
if (this.workers.size >= this.maxWorkers) return;
|
|
66
|
+
try {
|
|
67
|
+
t = new Worker(new URL(n, globalThis.location.href), { type: "module" }), this.workers.add(t);
|
|
68
|
+
} catch (t) {
|
|
69
|
+
this.taskQueue.shift(), e.reject(t);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
this.taskQueue.shift(), this.executeTaskWithWorker(t, e);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async executeTaskWithWorker(e, t) {
|
|
77
|
+
let n = new AbortController();
|
|
78
|
+
this.active.set(e, n);
|
|
79
|
+
let a = () => {
|
|
80
|
+
e.terminate(), this.workers.delete(e);
|
|
81
|
+
};
|
|
82
|
+
try {
|
|
83
|
+
let o = await r(t.file, n.signal);
|
|
84
|
+
t.resolve(await i(e, {
|
|
85
|
+
...t,
|
|
86
|
+
arrayBuffer: o
|
|
87
|
+
}, n.signal, a));
|
|
88
|
+
} catch (e) {
|
|
89
|
+
t.reject(e);
|
|
90
|
+
} finally {
|
|
91
|
+
this.active.delete(e), this.processNextTask();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async executeTask(t) {
|
|
95
|
+
let { name: n, type: r } = t, i = this.findPlugin(r);
|
|
96
|
+
if (!i) throw Error(`Unsupported file type: ${r}`);
|
|
97
|
+
if (typeof i.moduleUrl != "string" || !i.moduleUrl) throw Error(`插件 ${i.name} 缺少压缩模块入口`);
|
|
98
|
+
let a = new URL(i.moduleUrl, globalThis.location.href).href, o = i.timeoutMs ?? 3e4;
|
|
99
|
+
return e(o, `插件 ${i.name}`), new Promise((e, s) => {
|
|
100
|
+
this.taskQueue.push({
|
|
101
|
+
file: t,
|
|
102
|
+
fileName: n,
|
|
103
|
+
fileType: r,
|
|
104
|
+
moduleUrl: a,
|
|
105
|
+
config: i.defaultConfig,
|
|
106
|
+
timeoutMs: o,
|
|
107
|
+
resolve: e,
|
|
108
|
+
reject: s
|
|
109
|
+
}), this.processNextTask();
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
terminate() {
|
|
113
|
+
this.taskQueue.forEach((e) => e.reject(/* @__PURE__ */ Error("Worker manager terminated"))), this.taskQueue = [], this.active.forEach((e) => e.abort()), this.workers.forEach((e) => e.terminate()), this.workers.clear(), this.active.clear();
|
|
114
|
+
}
|
|
115
|
+
}, o = class {
|
|
116
|
+
workerManager;
|
|
117
|
+
constructor(e) {
|
|
118
|
+
this.workerManager = new a(e.plugins, e.workerNum ?? 4);
|
|
119
|
+
}
|
|
120
|
+
compressFile = async (e) => {
|
|
121
|
+
e.type.startsWith("image/") && t(e);
|
|
122
|
+
let n = e.size, r = await this.workerManager.executeTask(e), i = r.data.byteLength, a = n > 0 ? (n - i) / n * 100 : 0, o = new File([r.data], r.fileName || e.name, { type: r.fileType || e.type });
|
|
123
|
+
return {
|
|
124
|
+
compressInfo: {
|
|
125
|
+
rate: Math.round(a * 100) / 100,
|
|
126
|
+
time: r.endTime - r.startTime,
|
|
127
|
+
originalSize: n,
|
|
128
|
+
compressedSize: i
|
|
129
|
+
},
|
|
130
|
+
file: o
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
compressFilesWorker = async (e) => {
|
|
134
|
+
let t = e.map((e) => this.compressFile(e));
|
|
135
|
+
if (Promise.allSettled) return Promise.allSettled(t);
|
|
136
|
+
let n = (e) => ({
|
|
137
|
+
status: "fulfilled",
|
|
138
|
+
value: e
|
|
139
|
+
}), r = (e) => ({
|
|
140
|
+
status: "rejected",
|
|
141
|
+
reason: e
|
|
142
|
+
});
|
|
143
|
+
return Promise.all(t.map((e) => e.then(n, r)));
|
|
144
|
+
};
|
|
145
|
+
compressImagesWorker = (e) => this.compressFilesWorker(e);
|
|
146
|
+
cancelAll() {
|
|
147
|
+
this.workerManager.terminate();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
export { o as ImageCompressor };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// lib/plugins/gif/compress.ts?worker&url
|
|
2
|
+
var e = new URL("./../assets/compress-CRhfuN3_.js?no-inline", import.meta.url).href;
|
|
3
|
+
// lib/plugins/gif/index.ts
|
|
4
|
+
function t(t) {
|
|
5
|
+
return {
|
|
6
|
+
name: "gif",
|
|
7
|
+
matches: (e) => e === "image/gif",
|
|
8
|
+
moduleUrl: e,
|
|
9
|
+
defaultConfig: {
|
|
10
|
+
quality: t?.quality ?? .75,
|
|
11
|
+
optimize: t?.optimize ?? 1,
|
|
12
|
+
...t?.lossy === void 0 ? {} : { lossy: t.lossy }
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export { t as gif };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// lib/plugins/jpeg-webp/compress.ts?worker&url
|
|
2
|
+
var e = new URL("./../assets/compress-XlJOQ9AQ.js?no-inline", import.meta.url).href;
|
|
3
|
+
// lib/plugins/jpeg-webp/index.ts
|
|
4
|
+
function t(t) {
|
|
5
|
+
return {
|
|
6
|
+
name: "jpeg-webp",
|
|
7
|
+
matches: (e) => e === "image/jpeg" || e === "image/webp",
|
|
8
|
+
moduleUrl: e,
|
|
9
|
+
defaultConfig: { quality: t?.quality ?? .75 }
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export { t as jpegWebp };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { n as e } from "../utils-DHI2QTd1.js";
|
|
2
|
+
// lib/plugins/media/compress.ts?worker&url
|
|
3
|
+
var t = new URL("./../assets/compress-BQao8LZ4.js?no-inline", import.meta.url).href;
|
|
4
|
+
// lib/plugins/media/index.ts
|
|
5
|
+
function n(n = {}) {
|
|
6
|
+
let { timeoutMs: r = 6e5, ...i } = n;
|
|
7
|
+
if (i.quality !== void 0 && (!Number.isFinite(i.quality) || i.quality < 0 || i.quality > 1)) throw Error("media quality 必须是 0-1 之间的数值");
|
|
8
|
+
for (let e of [
|
|
9
|
+
"videoBitrate",
|
|
10
|
+
"audioBitrate",
|
|
11
|
+
"maxWidth",
|
|
12
|
+
"maxHeight",
|
|
13
|
+
"sampleRate",
|
|
14
|
+
"numberOfChannels"
|
|
15
|
+
]) {
|
|
16
|
+
let t = i[e];
|
|
17
|
+
if (t !== void 0 && (!Number.isInteger(t) || t < (e === "maxWidth" || e === "maxHeight" ? 2 : 1))) throw Error(`media ${e} 必须是有效的正整数(视频尺寸至少为 2)`);
|
|
18
|
+
}
|
|
19
|
+
if (i.frameRate !== void 0 && (!Number.isFinite(i.frameRate) || i.frameRate <= 0)) throw Error("media frameRate 必须是正数");
|
|
20
|
+
return e(r, "media"), {
|
|
21
|
+
name: "media",
|
|
22
|
+
matches: (e) => /^(audio|video)\//i.test(e) || e === "application/ogg",
|
|
23
|
+
moduleUrl: t,
|
|
24
|
+
timeoutMs: r,
|
|
25
|
+
defaultConfig: {
|
|
26
|
+
quality: .5,
|
|
27
|
+
keepOriginalIfLarger: !0,
|
|
28
|
+
...i
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export { n as media };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// lib/plugins/png/compress.ts?worker&url
|
|
2
|
+
var e = new URL("./../assets/compress-Di96HUYT.js?no-inline", import.meta.url).href;
|
|
3
|
+
// lib/plugins/png/index.ts
|
|
4
|
+
function t(t) {
|
|
5
|
+
return {
|
|
6
|
+
name: "png",
|
|
7
|
+
matches: (e) => e === "image/png",
|
|
8
|
+
moduleUrl: e,
|
|
9
|
+
defaultConfig: { quality: t?.quality ?? .8 }
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export { t as png };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// lib/plugins/svg/compress.ts?worker&url
|
|
2
|
+
var e = new URL("./../assets/compress-I5veHSQ1.js?no-inline", import.meta.url).href, t = ["preset-default", "removeDimensions"];
|
|
3
|
+
function n(n) {
|
|
4
|
+
return {
|
|
5
|
+
name: "svg",
|
|
6
|
+
matches: (e) => e === "image/svg+xml",
|
|
7
|
+
moduleUrl: e,
|
|
8
|
+
defaultConfig: {
|
|
9
|
+
floatPrecision: n?.floatPrecision ?? 8,
|
|
10
|
+
svgoPlugins: n?.svgoPlugins ?? t
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export { n as svg };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MAX_IMG_SIZE: number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CompressPlugin, CompressBackInfo } from "./types.js";
|
|
2
|
+
export type { CompressPlugin, CompressBackInfo, CompressPluginConfig, CompressPayload, CompressResult, CompressFunc, } from "./types.js";
|
|
3
|
+
export interface ImageCompressorOptions {
|
|
4
|
+
workerNum?: number;
|
|
5
|
+
plugins: CompressPlugin[];
|
|
6
|
+
}
|
|
7
|
+
export declare class ImageCompressor {
|
|
8
|
+
private workerManager;
|
|
9
|
+
constructor(params: ImageCompressorOptions);
|
|
10
|
+
private compressFile;
|
|
11
|
+
compressFilesWorker: (files: File[]) => Promise<PromiseSettledResult<CompressBackInfo>[]>;
|
|
12
|
+
compressImagesWorker: (files: File[]) => Promise<PromiseSettledResult<CompressBackInfo>[]>;
|
|
13
|
+
cancelAll(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CompressPlugin } from "../../types.js";
|
|
2
|
+
export interface MediaConfig {
|
|
3
|
+
/** 0-1,默认 0.5;对应轨道设置 bitrate 时忽略 quality */
|
|
4
|
+
quality?: number;
|
|
5
|
+
/** 默认保留 WebM / Ogg 容器,其他输入输出为 MP4(纯音频为 M4A) */
|
|
6
|
+
format?: "mp4" | "webm" | "ogg";
|
|
7
|
+
videoCodec?: "avc" | "hevc" | "vp8" | "vp9" | "av1";
|
|
8
|
+
audioCodec?: "aac" | "opus" | "mp3" | "vorbis" | "flac";
|
|
9
|
+
/** 比特率,单位 bit/s */
|
|
10
|
+
videoBitrate?: number;
|
|
11
|
+
audioBitrate?: number;
|
|
12
|
+
/** 等比缩小,不放大;编码尺寸对齐为偶数 */
|
|
13
|
+
maxWidth?: number;
|
|
14
|
+
maxHeight?: number;
|
|
15
|
+
frameRate?: number;
|
|
16
|
+
sampleRate?: number;
|
|
17
|
+
numberOfChannels?: number;
|
|
18
|
+
/** 默认 true;结果没有变小时返回原文件,包括原文件名和 MIME */
|
|
19
|
+
keepOriginalIfLarger?: boolean;
|
|
20
|
+
/** 单个任务的超时时间(毫秒),默认 10 分钟 */
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export declare function media(config?: MediaConfig): CompressPlugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type CompressResult = {
|
|
2
|
+
success: true;
|
|
3
|
+
data: ArrayBuffer;
|
|
4
|
+
fileName?: string;
|
|
5
|
+
fileType?: string;
|
|
6
|
+
} | {
|
|
7
|
+
success: false;
|
|
8
|
+
error: string;
|
|
9
|
+
};
|
|
10
|
+
export interface CompressPluginConfig {
|
|
11
|
+
quality?: number;
|
|
12
|
+
floatPrecision?: number;
|
|
13
|
+
svgoPlugins?: any[];
|
|
14
|
+
/** gif:gifsicle -O 等级,1 | 2 | 3 */
|
|
15
|
+
optimize?: 1 | 2 | 3;
|
|
16
|
+
/** gif:gifsicle --lossy,0-200。设置后不再按 quality 换算 */
|
|
17
|
+
lossy?: number;
|
|
18
|
+
/** 自定义插件可附带自己的参数,会原样发给 worker */
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
export interface CompressPayload {
|
|
22
|
+
arrayBuffer: ArrayBuffer;
|
|
23
|
+
fileName: string;
|
|
24
|
+
fileType: string;
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}
|
|
27
|
+
export type CompressFunc = (payload: CompressPayload) => Promise<CompressResult>;
|
|
28
|
+
export interface CompressPlugin {
|
|
29
|
+
name: string;
|
|
30
|
+
matches: (fileType: string) => boolean;
|
|
31
|
+
/** 插件内部的压缩模块入口,模块必须导出 compress;使用者无需配置 */
|
|
32
|
+
moduleUrl: string;
|
|
33
|
+
/** 单个任务的超时时间(毫秒),默认 30000 */
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
defaultConfig: CompressPluginConfig;
|
|
36
|
+
}
|
|
37
|
+
export interface CompressBackInfo {
|
|
38
|
+
compressInfo: {
|
|
39
|
+
rate: number;
|
|
40
|
+
time: number;
|
|
41
|
+
originalSize: number;
|
|
42
|
+
compressedSize: number;
|
|
43
|
+
};
|
|
44
|
+
file: File;
|
|
45
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CompressPayload, CompressResult } from "./types";
|
|
2
|
+
export declare const checkImageSize: (file: File) => void;
|
|
3
|
+
export declare function createCompressResult({ arrayBuffer, fileName, fileType }: Pick<CompressPayload, "arrayBuffer" | "fileName" | "fileType">, data: ArrayBuffer): CompressResult;
|
|
4
|
+
export declare function validateTimeout(timeoutMs: number, name: string): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CompressPlugin } from "./types";
|
|
2
|
+
import { type WorkerTaskResult } from "./workerTask";
|
|
3
|
+
export declare class WorkerManager {
|
|
4
|
+
private plugins;
|
|
5
|
+
private workers;
|
|
6
|
+
private active;
|
|
7
|
+
private taskQueue;
|
|
8
|
+
private maxWorkers;
|
|
9
|
+
constructor(plugins: CompressPlugin[], maxWorkers?: number);
|
|
10
|
+
private findPlugin;
|
|
11
|
+
private processNextTask;
|
|
12
|
+
private executeTaskWithWorker;
|
|
13
|
+
executeTask(file: File): Promise<WorkerTaskResult>;
|
|
14
|
+
terminate(): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CompressPayload, CompressResult, CompressPluginConfig } from "./types";
|
|
2
|
+
export interface WorkerTaskOptions extends Pick<CompressPayload, "arrayBuffer" | "fileName" | "fileType"> {
|
|
3
|
+
moduleUrl: string;
|
|
4
|
+
config: CompressPluginConfig;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
}
|
|
7
|
+
type SuccessfulResult = Extract<CompressResult, {
|
|
8
|
+
success: true;
|
|
9
|
+
}>;
|
|
10
|
+
export interface WorkerTaskResult extends SuccessfulResult {
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function readTaskFile(file: File, signal: AbortSignal): Promise<ArrayBuffer>;
|
|
15
|
+
export declare function runWorkerTask(worker: Worker, task: WorkerTaskOptions, signal: AbortSignal, discardWorker: () => void): Promise<WorkerTaskResult>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// lib/utils.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (e.size > 52428800) throw Error("Image size is too large");
|
|
4
|
+
};
|
|
5
|
+
function t(e, t) {
|
|
6
|
+
if (!Number.isInteger(e) || e <= 0 || e > 2147483647) throw Error(`${t} 的 timeoutMs 必须是 1-2147483647 之间的整数`);
|
|
7
|
+
}
|
|
8
|
+
export { t as n, e as t };
|
package/index.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,102 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baize-compress",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"compress",
|
|
7
|
+
"image",
|
|
8
|
+
"audio",
|
|
9
|
+
"video",
|
|
10
|
+
"mediabunny",
|
|
11
|
+
"webcodecs",
|
|
12
|
+
"web-worker",
|
|
13
|
+
"image-compression",
|
|
14
|
+
"video-compression",
|
|
15
|
+
"audio-compression",
|
|
16
|
+
"mp3",
|
|
17
|
+
"mp4",
|
|
18
|
+
"webm",
|
|
19
|
+
"jpeg",
|
|
20
|
+
"png",
|
|
21
|
+
"webp",
|
|
22
|
+
"svg",
|
|
23
|
+
"gif",
|
|
24
|
+
"svgo",
|
|
25
|
+
"gifsicle",
|
|
26
|
+
"OffscreenCanvas",
|
|
27
|
+
"upng-js"
|
|
28
|
+
],
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"index.d.ts",
|
|
32
|
+
"plugins"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/baizeteam/baize-compress"
|
|
37
|
+
},
|
|
38
|
+
"module": "./dist/index.js",
|
|
39
|
+
"types": "./index.d.ts",
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./index.d.ts",
|
|
43
|
+
"import": "./dist/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./plugins/jpeg-webp": {
|
|
46
|
+
"types": "./plugins/jpeg-webp.d.ts",
|
|
47
|
+
"import": "./dist/plugins/jpeg-webp.js"
|
|
48
|
+
},
|
|
49
|
+
"./plugins/png": {
|
|
50
|
+
"types": "./plugins/png.d.ts",
|
|
51
|
+
"import": "./dist/plugins/png.js"
|
|
52
|
+
},
|
|
53
|
+
"./plugins/svg": {
|
|
54
|
+
"types": "./plugins/svg.d.ts",
|
|
55
|
+
"import": "./dist/plugins/svg.js"
|
|
56
|
+
},
|
|
57
|
+
"./plugins/gif": {
|
|
58
|
+
"types": "./plugins/gif.d.ts",
|
|
59
|
+
"import": "./dist/plugins/gif.js"
|
|
60
|
+
},
|
|
61
|
+
"./plugins/media": {
|
|
62
|
+
"types": "./plugins/media.d.ts",
|
|
63
|
+
"import": "./dist/plugins/media.js"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"format": "oxfmt --write .",
|
|
68
|
+
"format:check": "oxfmt --check .",
|
|
69
|
+
"typecheck": "tsc --noEmit",
|
|
70
|
+
"test": "pnpm build && tsc -p tests/tsconfig.json && node --test tests/*.test.mjs",
|
|
71
|
+
"dev": "vite",
|
|
72
|
+
"build:page": "tsc && cross-env BUILD_MODE=page vite build",
|
|
73
|
+
"build": "tsc && cross-env BUILD_MODE=lib vite build && tsc -p tsconfig.declarations.json",
|
|
74
|
+
"prepack": "pnpm build"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/node": "^24.19.2",
|
|
78
|
+
"@types/react": "^18.3.3",
|
|
79
|
+
"@types/react-dom": "^18.3.0",
|
|
80
|
+
"@types/upng-js": "^2.1.5",
|
|
81
|
+
"@vitejs/plugin-react": "^6.3.0",
|
|
82
|
+
"cross-env": "^7.0.3",
|
|
83
|
+
"gifsicle-wasm-browser": "1.5.19",
|
|
84
|
+
"mediabunny": "^1.66.0",
|
|
85
|
+
"oxfmt": "^0.78.0",
|
|
86
|
+
"react": "^18.3.1",
|
|
87
|
+
"react-dom": "^18.3.1",
|
|
88
|
+
"svgo": "^4.0.1",
|
|
89
|
+
"typescript": "^7.0.2",
|
|
90
|
+
"upng-js": "^2.1.0",
|
|
91
|
+
"vite": "^8.3.8"
|
|
92
|
+
},
|
|
93
|
+
"description": "基于插件和共用 Web Worker 池的图片、音频及视频压缩库。",
|
|
94
|
+
"engines": {
|
|
95
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
96
|
+
},
|
|
97
|
+
"packageManager": "pnpm@10.33.4",
|
|
98
|
+
"publishConfig": {
|
|
99
|
+
"registry": "https://registry.npmjs.org/"
|
|
100
|
+
},
|
|
101
|
+
"license": "LGPL-3.0-only"
|
|
102
|
+
}
|
package/plugins/gif.d.ts
ADDED
package/plugins/png.d.ts
ADDED
package/plugins/svg.d.ts
ADDED