wasm-image-optimization 1.2.1 → 1.2.3

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/README.md CHANGED
@@ -17,6 +17,31 @@
17
17
  - Web Worker (Browser) Multi process
18
18
  `import { optimizeImage } from 'wasm-image-optimization/web-worker';`
19
19
 
20
+ ## Samples
21
+
22
+ https://github.com/SoraKumo001/wasm-image-optimization-samples
23
+
24
+ ### cloudflare-ogp
25
+
26
+ Sample for generating OGP images on Cloudflare Workers.
27
+
28
+ ### deno-ogp
29
+
30
+ Sample for generating OGP images on Deno.
31
+
32
+ ### cloudflare-image-optimization
33
+
34
+ Sample for image optimization on Cloudflare Workers.
35
+
36
+ ### deno-image-optimization
37
+
38
+ Sample for image optimization on Deno.
39
+
40
+ ### node-image-convert
41
+
42
+ Sample for converting image formats on Node.js.
43
+ Single-threaded and multi-threaded operation can be selected.
44
+
20
45
  ## WebWorker on Vite
21
46
 
22
47
  - vite.config.ts
@@ -68,292 +93,3 @@ optimizeImageExt({
68
93
  - png
69
94
  - webp
70
95
  - avif(default)
71
-
72
- ## usage
73
-
74
- ### Node.js (CLI)
75
-
76
- ```ts
77
- import fs from "node:fs";
78
- import {
79
- optimizeImage,
80
- waitAll,
81
- close,
82
- } from "wasm-image-optimization/node-worker";
83
-
84
- const formats = ["webp", "jpeg", "png", "avif"] as const;
85
-
86
- const main = async () => {
87
- fs.mkdirSync("./image_output", { recursive: true });
88
- const files = fs.readdirSync("./images");
89
- for (const file of files) {
90
- const image = fs.readFileSync(`./images/${file}`);
91
- for (const format of formats) {
92
- optimizeImage({
93
- image,
94
- quality: 100,
95
- format,
96
- width: 1000,
97
- }).then((encoded) => {
98
- console.log(
99
- !!encoded,
100
- file,
101
- format,
102
- encoded && `${Math.floor(encoded.length / 1024)}KB`
103
- );
104
- if (encoded) {
105
- const fileName = file.split(".")[0];
106
- fs.promises.writeFile(`image_output/${fileName}.${format}`, encoded);
107
- }
108
- });
109
- }
110
- }
111
- await waitAll(); // Wait for all workers to finish before exiting the program.
112
- close(); // Close all workers
113
- console.log("exit");
114
- };
115
- main();
116
- ```
117
-
118
- ### Next.js image optimization with Cloudflare
119
-
120
- ```ts
121
- import { optimizeImage } from "wasm-image-optimization";
122
-
123
- const isValidUrl = (url: string) => {
124
- try {
125
- new URL(url);
126
- return true;
127
- } catch (err) {
128
- return false;
129
- }
130
- };
131
-
132
- const handleRequest = async (
133
- request: Request,
134
- _env: {},
135
- ctx: ExecutionContext
136
- ): Promise<Response> => {
137
- const accept = request.headers.get("accept");
138
- const isWebp =
139
- accept
140
- ?.split(",")
141
- .map((format) => format.trim())
142
- .some((format) => ["image/webp", "*/*", "image/*"].includes(format)) ??
143
- true;
144
- const isAvif =
145
- accept
146
- ?.split(",")
147
- .map((format) => format.trim())
148
- .some((format) => ["image/avif", "*/*", "image/*"].includes(format)) ??
149
- true;
150
-
151
- const url = new URL(request.url);
152
-
153
- const params = url.searchParams;
154
- const imageUrl = params.get("url");
155
- if (!imageUrl || !isValidUrl(imageUrl)) {
156
- return new Response("url is required", { status: 400 });
157
- }
158
-
159
- const cache = caches.default;
160
- url.searchParams.append("webp", isWebp.toString());
161
- const cacheKey = new Request(url.toString());
162
- const cachedResponse = await cache.match(cacheKey);
163
- if (cachedResponse) {
164
- return cachedResponse;
165
- }
166
-
167
- const width = params.get("w");
168
- const quality = params.get("q");
169
-
170
- const [srcImage, contentType] = await fetch(imageUrl, {
171
- cf: { cacheKey: imageUrl },
172
- })
173
- .then(async (res) =>
174
- res.ok
175
- ? ([await res.arrayBuffer(), res.headers.get("content-type")] as const)
176
- : []
177
- )
178
- .catch(() => []);
179
-
180
- if (!srcImage) {
181
- return new Response("image not found", { status: 404 });
182
- }
183
-
184
- if (contentType && ["image/svg+xml", "image/gif"].includes(contentType)) {
185
- const response = new Response(srcImage, {
186
- headers: {
187
- "Content-Type": contentType,
188
- "Cache-Control": "public, max-age=31536000, immutable",
189
- },
190
- });
191
- ctx.waitUntil(cache.put(cacheKey, response.clone()));
192
- return response;
193
- }
194
-
195
- const format = isAvif
196
- ? "avif"
197
- : isWebp
198
- ? "webp"
199
- : contentType === "image/jpeg"
200
- ? "jpeg"
201
- : "png";
202
- const image = await optimizeImage({
203
- image: srcImage,
204
- width: width ? parseInt(width) : undefined,
205
- quality: quality ? parseInt(quality) : undefined,
206
- format,
207
- });
208
- const response = new Response(image, {
209
- headers: {
210
- "Content-Type": `image/${format}`,
211
- "Cache-Control": "public, max-age=31536000, immutable",
212
- date: new Date().toUTCString(),
213
- },
214
- });
215
- ctx.waitUntil(cache.put(cacheKey, response.clone()));
216
- return response;
217
- };
218
-
219
- export default {
220
- fetch: handleRequest,
221
- };
222
- ```
223
-
224
- - next.config.js
225
-
226
- ```js
227
- /**
228
- * @type { import("next").NextConfig}
229
- */
230
- const config = {
231
- images: {
232
- path: "https://xxx.yyy.workers.dev/",
233
- },
234
- };
235
- export default config;
236
- ```
237
-
238
- ### Deno Deploy
239
-
240
- #### Parameters
241
-
242
- | Name | Type | Description |
243
- | ---- | ------ | ----------- |
244
- | url | string | Image URL |
245
- | q | number | Quality |
246
- | w | number | Width |
247
-
248
- https://xxxx.deno.dev/?url=https://xxx.png&q=80&w=200
249
-
250
- ```ts
251
- import { optimizeImage } from "npm:wasm-image-optimization/esm";
252
-
253
- const isValidUrl = (url: string) => {
254
- try {
255
- new URL(url);
256
- return true;
257
- } catch (_e) {
258
- return false;
259
- }
260
- };
261
-
262
- const isType = (accept: string | null, type: string) => {
263
- return (
264
- accept
265
- ?.split(",")
266
- .map((format) => format.trim())
267
- .some((format) => [`image/${type}`, "*/*", "image/*"].includes(format)) ??
268
- true
269
- );
270
- };
271
-
272
- Deno.serve(async (request) => {
273
- const url = new URL(request.url);
274
- const params = url.searchParams;
275
- const type = ["avif", "webp", "png", "jpeg"].find(
276
- (v) => v === params.get("type")
277
- ) as "avif" | "webp" | "png" | "jpeg" | undefined;
278
- const accept = request.headers.get("accept");
279
- const isAvif = isType(accept, "avif");
280
- const isWebp = isType(accept, "webp");
281
-
282
- const cache = await caches.open(
283
- `image-${isAvif ? "-avif" : ""}${isWebp ? "-webp" : ""}`
284
- );
285
-
286
- const cached = await cache.match(request);
287
- if (cached) {
288
- return cached;
289
- }
290
-
291
- const imageUrl = params.get("url");
292
- if (!imageUrl || !isValidUrl(imageUrl)) {
293
- return new Response("url is required", { status: 400 });
294
- }
295
-
296
- if (isAvif) {
297
- url.searchParams.append("avif", isAvif.toString());
298
- } else if (isWebp) {
299
- url.searchParams.append("webp", isWebp.toString());
300
- }
301
-
302
- const cacheKey = new Request(url.toString());
303
- const cachedResponse = await cache.match(cacheKey);
304
- if (cachedResponse) {
305
- return cachedResponse;
306
- }
307
-
308
- const width = params.get("w");
309
- const quality = params.get("q");
310
-
311
- const [srcImage, contentType] = await fetch(imageUrl)
312
- .then(async (res) =>
313
- res.ok
314
- ? ([await res.arrayBuffer(), res.headers.get("content-type")] as const)
315
- : []
316
- )
317
- .catch(() => []);
318
-
319
- if (!srcImage) {
320
- return new Response("image not found", { status: 404 });
321
- }
322
-
323
- if (contentType && ["image/svg+xml", "image/gif"].includes(contentType)) {
324
- const response = new Response(srcImage, {
325
- headers: {
326
- "Content-Type": contentType,
327
- "Cache-Control": "public, max-age=31536000, immutable",
328
- },
329
- });
330
- cache.put(request, response.clone());
331
- return response;
332
- }
333
-
334
- const format =
335
- type ??
336
- (isAvif
337
- ? "avif"
338
- : isWebp
339
- ? "webp"
340
- : contentType === "image/jpeg"
341
- ? "jpeg"
342
- : "png");
343
- const image = await optimizeImage({
344
- image: srcImage,
345
- width: width ? parseInt(width) : undefined,
346
- quality: quality ? parseInt(quality) : undefined,
347
- format,
348
- });
349
- const response = new Response(image, {
350
- headers: {
351
- "Content-Type": `image/${format}`,
352
- "Cache-Control": "public, max-age=31536000, immutable",
353
- date: new Date().toUTCString(),
354
- },
355
- });
356
- cache.put(request, response.clone());
357
- return response;
358
- });
359
- ```
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod) => function __require() {
4
4
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
5
5
  };
6
6
 
7
- // node_modules/.pnpm/worker-lib@1.0.4/node_modules/worker-lib/dist/cjs/node.js
7
+ // node_modules/.pnpm/worker-lib@2.0.0/node_modules/worker-lib/dist/cjs/node.js
8
8
  var require_node = __commonJS({
9
- "node_modules/.pnpm/worker-lib@1.0.4/node_modules/worker-lib/dist/cjs/node.js"(exports2) {
9
+ "node_modules/.pnpm/worker-lib@2.0.0/node_modules/worker-lib/dist/cjs/node.js"(exports2) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports2, "__esModule", { value: true });
12
12
  exports2.initWorker = exports2.createWorker = void 0;
@@ -3929,7 +3929,7 @@
3929
3929
  }
3930
3930
  });
3931
3931
 
3932
- // node_modules/.pnpm/worker-lib@1.0.4/node_modules/worker-lib/dist/esm/index.js
3932
+ // node_modules/.pnpm/worker-lib@2.0.0/node_modules/worker-lib/dist/esm/index.js
3933
3933
  var initWorker = (WorkerProc) => {
3934
3934
  const worker = self;
3935
3935
  worker.addEventListener("message", async (e) => {
@@ -1,4 +1,5 @@
1
1
  import { type OptimizeParams } from "../lib/optimizeImage.js";
2
+ declare const setLimit: (limit: number) => void, close: () => void;
2
3
  export declare const optimizeImage: (params: OptimizeParams) => Promise<Uint8Array<ArrayBuffer> | undefined>;
3
4
  export declare const optimizeImageExt: (params: OptimizeParams) => Promise<{
4
5
  data: Uint8Array<ArrayBuffer>;
@@ -7,3 +8,4 @@ export declare const optimizeImageExt: (params: OptimizeParams) => Promise<{
7
8
  width: number;
8
9
  height: number;
9
10
  } | undefined>;
11
+ export { setLimit, close };
@@ -1,5 +1,6 @@
1
1
  import { createWorker } from "worker-lib";
2
- const execute = createWorker(() => new Worker(new URL("../esm/web-worker.js", import.meta.url)), 5);
2
+ const { execute, setLimit, close } = createWorker(() => new Worker(new URL("../esm/web-worker.js", import.meta.url)), 5);
3
3
  export const optimizeImage = async (params) => execute("optimizeImage", params);
4
4
  export const optimizeImageExt = async (params) => execute("optimizeImageExt", params);
5
+ export { setLimit, close };
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web-worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ1C,MAAM,OAAO,GAAG,YAAY,CAC1B,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAClE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,MAAsB,EAAE,EAAE,CAC5D,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AAEnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAsB,EAAE,EAAE,CAC/D,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC","sourcesContent":["import { createWorker } from \"worker-lib\";\nimport {\n _optimizeImage,\n _optimizeImageExt,\n type OptimizeParams,\n} from \"../lib/optimizeImage.js\";\nimport type { WorkerType } from \"../esm/_web-worker.js\";\n\nconst execute = createWorker<WorkerType>(\n () => new Worker(new URL(\"../esm/web-worker.js\", import.meta.url)),\n 5\n);\n\nexport const optimizeImage = async (params: OptimizeParams) =>\n execute(\"optimizeImage\", params);\n\nexport const optimizeImageExt = async (params: OptimizeParams) =>\n execute(\"optimizeImageExt\", params);\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web-worker/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ1C,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,YAAY,CAC/C,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAClE,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,MAAsB,EAAE,EAAE,CAC5D,OAAO,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AAEnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAsB,EAAE,EAAE,CAC/D,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import { createWorker } from \"worker-lib\";\nimport {\n _optimizeImage,\n _optimizeImageExt,\n type OptimizeParams,\n} from \"../lib/optimizeImage.js\";\nimport type { WorkerType } from \"../esm/_web-worker.js\";\n\nconst { execute, setLimit, close } = createWorker<WorkerType>(\n () => new Worker(new URL(\"../esm/web-worker.js\", import.meta.url)),\n 5\n);\n\nexport const optimizeImage = async (params: OptimizeParams) =>\n execute(\"optimizeImage\", params);\n\nexport const optimizeImageExt = async (params: OptimizeParams) =>\n execute(\"optimizeImageExt\", params);\n\nexport { setLimit, close };\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "wasm-image-optimization",
3
3
  "description": "Optimize images with wasm on edge runtime",
4
- "version": "1.2.1",
4
+ "version": "1.2.3",
5
5
  "scripts": {
6
6
  "test": "yarn ts-node test",
7
7
  "lint:fix": "eslint --fix src/ && prettier -w src",
@@ -92,7 +92,7 @@
92
92
  },
93
93
  "license": "MIT",
94
94
  "dependencies": {
95
- "worker-lib": "1.0.4"
95
+ "worker-lib": "2.0.2"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@eslint/js": "9.21.0",