wasm-image-optimization 1.0.1 → 1.0.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 +161 -23
- package/dist/cjs/index.d.ts +4 -4
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +4 -4
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/libImage.js +5 -4
- package/dist/esm/libImage.wasm +0 -0
- package/dist/next/index.d.ts +4 -4
- package/dist/next/index.js +3 -3
- package/dist/next/index.js.map +1 -1
- package/dist/workers/index.d.ts +4 -4
- package/dist/workers/index.js +3 -3
- package/dist/workers/index.js.map +1 -1
- package/dist/workers/libImage.js +4 -3
- package/eslint.config.d.mts +2 -0
- package/eslint.config.mjs +45 -0
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# wasm-image-optimization
|
|
2
2
|
|
|
3
|
+
- The 'avif' version is available here
|
|
4
|
+
https://www.npmjs.com/package/wasm-image-optimization-avif
|
|
5
|
+
|
|
3
6
|
- Cloudflare workers
|
|
4
7
|
`import { optimizeImage } from 'wasm-image-optimization';`
|
|
5
8
|
- Next.js(Webpack)
|
|
@@ -29,10 +32,25 @@ optimizeImage({image: ArrayBuffer, width?: number, height?:number,quality?: numb
|
|
|
29
32
|
|
|
30
33
|
# usage
|
|
31
34
|
|
|
32
|
-
Next.js image optimization with Cloudflare
|
|
35
|
+
## Next.js image optimization with Cloudflare
|
|
36
|
+
|
|
37
|
+
### Parameters
|
|
38
|
+
|
|
39
|
+
| Name | Type | Description |
|
|
40
|
+
| ---- | ------ | -------------------------- |
|
|
41
|
+
| url | string | Image URL |
|
|
42
|
+
| q | number | Quality |
|
|
43
|
+
| w | number | Width |
|
|
44
|
+
| type | string | Output type(webp/png/jpeg) |
|
|
45
|
+
|
|
46
|
+
https://github.com/SoraKumo001/cloudflare-workers-image-optimization
|
|
47
|
+
|
|
48
|
+
https://xxx.yyy.workers.dev/?url=https://xxx.png&q=80&w=200
|
|
49
|
+
|
|
50
|
+
### Source code
|
|
33
51
|
|
|
34
52
|
```ts
|
|
35
|
-
import { optimizeImage } from
|
|
53
|
+
import { optimizeImage } from "wasm-image-optimization";
|
|
36
54
|
|
|
37
55
|
const isValidUrl = (url: string) => {
|
|
38
56
|
try {
|
|
@@ -48,54 +66,64 @@ const handleRequest = async (
|
|
|
48
66
|
_env: {},
|
|
49
67
|
ctx: ExecutionContext
|
|
50
68
|
): Promise<Response> => {
|
|
51
|
-
const
|
|
69
|
+
const url = new URL(request.url);
|
|
70
|
+
const params = url.searchParams;
|
|
71
|
+
const type = ["webp", "png", "jpeg"].find((v) => v === params.get("type")) as
|
|
72
|
+
| "webp"
|
|
73
|
+
| "png"
|
|
74
|
+
| "jpeg"
|
|
75
|
+
| undefined;
|
|
76
|
+
const accept = request.headers.get("accept");
|
|
52
77
|
const isWebp =
|
|
53
78
|
accept
|
|
54
|
-
?.split(
|
|
79
|
+
?.split(",")
|
|
55
80
|
.map((format) => format.trim())
|
|
56
|
-
.some((format) => [
|
|
57
|
-
|
|
58
|
-
const url = new URL(request.url);
|
|
81
|
+
.some((format) => ["image/webp", "*/*", "image/*"].includes(format)) ??
|
|
82
|
+
true;
|
|
59
83
|
|
|
60
|
-
const
|
|
61
|
-
const imageUrl = params.get('url');
|
|
84
|
+
const imageUrl = params.get("url");
|
|
62
85
|
if (!imageUrl || !isValidUrl(imageUrl)) {
|
|
63
|
-
return new Response(
|
|
86
|
+
return new Response("url is required", { status: 400 });
|
|
64
87
|
}
|
|
65
88
|
|
|
66
89
|
const cache = caches.default;
|
|
67
|
-
url.searchParams.append(
|
|
90
|
+
url.searchParams.append("webp", isWebp.toString());
|
|
68
91
|
const cacheKey = new Request(url.toString());
|
|
69
92
|
const cachedResponse = await cache.match(cacheKey);
|
|
70
93
|
if (cachedResponse) {
|
|
71
94
|
return cachedResponse;
|
|
72
95
|
}
|
|
73
96
|
|
|
74
|
-
const width = params.get(
|
|
75
|
-
const quality = params.get(
|
|
97
|
+
const width = params.get("w");
|
|
98
|
+
const quality = params.get("q");
|
|
76
99
|
|
|
77
|
-
const [srcImage, contentType] = await fetch(imageUrl, {
|
|
100
|
+
const [srcImage, contentType] = await fetch(imageUrl, {
|
|
101
|
+
cf: { cacheKey: imageUrl },
|
|
102
|
+
})
|
|
78
103
|
.then(async (res) =>
|
|
79
|
-
res.ok
|
|
104
|
+
res.ok
|
|
105
|
+
? ([await res.arrayBuffer(), res.headers.get("content-type")] as const)
|
|
106
|
+
: []
|
|
80
107
|
)
|
|
81
108
|
.catch(() => []);
|
|
82
109
|
|
|
83
110
|
if (!srcImage) {
|
|
84
|
-
return new Response(
|
|
111
|
+
return new Response("image not found", { status: 404 });
|
|
85
112
|
}
|
|
86
113
|
|
|
87
|
-
if (contentType && [
|
|
114
|
+
if (contentType && ["image/svg+xml", "image/gif"].includes(contentType)) {
|
|
88
115
|
const response = new Response(srcImage, {
|
|
89
116
|
headers: {
|
|
90
|
-
|
|
91
|
-
|
|
117
|
+
"Content-Type": contentType,
|
|
118
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
92
119
|
},
|
|
93
120
|
});
|
|
94
121
|
ctx.waitUntil(cache.put(cacheKey, response.clone()));
|
|
95
122
|
return response;
|
|
96
123
|
}
|
|
97
124
|
|
|
98
|
-
const format =
|
|
125
|
+
const format =
|
|
126
|
+
type ?? (isWebp ? "webp" : contentType === "image/jpeg" ? "jpeg" : "png");
|
|
99
127
|
const image = await optimizeImage({
|
|
100
128
|
image: srcImage,
|
|
101
129
|
width: width ? parseInt(width) : undefined,
|
|
@@ -104,8 +132,8 @@ const handleRequest = async (
|
|
|
104
132
|
});
|
|
105
133
|
const response = new Response(image, {
|
|
106
134
|
headers: {
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
"Content-Type": `image/${format}`,
|
|
136
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
109
137
|
date: new Date().toUTCString(),
|
|
110
138
|
},
|
|
111
139
|
});
|
|
@@ -126,8 +154,118 @@ export default {
|
|
|
126
154
|
*/
|
|
127
155
|
const config = {
|
|
128
156
|
images: {
|
|
129
|
-
path:
|
|
157
|
+
path: "https://xxx.yyy.workers.dev/",
|
|
130
158
|
},
|
|
131
159
|
};
|
|
132
160
|
export default config;
|
|
133
161
|
```
|
|
162
|
+
|
|
163
|
+
## Deno Deploy
|
|
164
|
+
|
|
165
|
+
### Parameters
|
|
166
|
+
|
|
167
|
+
| Name | Type | Description |
|
|
168
|
+
| ---- | ------ | -------------------------- |
|
|
169
|
+
| url | string | Image URL |
|
|
170
|
+
| q | number | Quality |
|
|
171
|
+
| w | number | Width |
|
|
172
|
+
| type | string | Output type(webp/png/jpeg) |
|
|
173
|
+
|
|
174
|
+
https://xxxx.deno.dev/?url=https://xxx.png&q=80&w=200
|
|
175
|
+
|
|
176
|
+
### Source code
|
|
177
|
+
|
|
178
|
+
https://github.com/SoraKumo001/deno-wasm-image-optimization
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { optimizeImage } from "npm:wasm-image-optimization/esm";
|
|
182
|
+
|
|
183
|
+
const isValidUrl = (url: string) => {
|
|
184
|
+
try {
|
|
185
|
+
new URL(url);
|
|
186
|
+
return true;
|
|
187
|
+
} catch (_e) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const cache = await caches.open("image-cache");
|
|
193
|
+
|
|
194
|
+
Deno.serve(async (request) => {
|
|
195
|
+
const cached = await cache.match(request);
|
|
196
|
+
if (cached) {
|
|
197
|
+
return cached;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const url = new URL(request.url);
|
|
201
|
+
const params = url.searchParams;
|
|
202
|
+
const type = ["webp", "png", "jpeg"].find((v) => v === params.get("type")) as
|
|
203
|
+
| "webp"
|
|
204
|
+
| "png"
|
|
205
|
+
| "jpeg"
|
|
206
|
+
| undefined;
|
|
207
|
+
const accept = request.headers.get("accept");
|
|
208
|
+
const isWebp =
|
|
209
|
+
accept
|
|
210
|
+
?.split(",")
|
|
211
|
+
.map((format) => format.trim())
|
|
212
|
+
.some((format) => ["image/webp", "*/*", "image/*"].includes(format)) ??
|
|
213
|
+
true;
|
|
214
|
+
|
|
215
|
+
const imageUrl = params.get("url");
|
|
216
|
+
if (!imageUrl || !isValidUrl(imageUrl)) {
|
|
217
|
+
return new Response("url is required", { status: 400 });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
url.searchParams.append("webp", isWebp.toString());
|
|
221
|
+
const cacheKey = new Request(url.toString());
|
|
222
|
+
const cachedResponse = await cache.match(cacheKey);
|
|
223
|
+
if (cachedResponse) {
|
|
224
|
+
return cachedResponse;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const width = params.get("w");
|
|
228
|
+
const quality = params.get("q");
|
|
229
|
+
|
|
230
|
+
const [srcImage, contentType] = await fetch(imageUrl)
|
|
231
|
+
.then(async (res) =>
|
|
232
|
+
res.ok
|
|
233
|
+
? ([await res.arrayBuffer(), res.headers.get("content-type")] as const)
|
|
234
|
+
: []
|
|
235
|
+
)
|
|
236
|
+
.catch(() => []);
|
|
237
|
+
|
|
238
|
+
if (!srcImage) {
|
|
239
|
+
return new Response("image not found", { status: 404 });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (contentType && ["image/svg+xml", "image/gif"].includes(contentType)) {
|
|
243
|
+
const response = new Response(srcImage, {
|
|
244
|
+
headers: {
|
|
245
|
+
"Content-Type": contentType,
|
|
246
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
cache.put(request, response.clone());
|
|
250
|
+
return response;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const format =
|
|
254
|
+
type ?? (isWebp ? "webp" : contentType === "image/jpeg" ? "jpeg" : "png");
|
|
255
|
+
const image = await optimizeImage({
|
|
256
|
+
image: srcImage,
|
|
257
|
+
width: width ? parseInt(width) : undefined,
|
|
258
|
+
quality: quality ? parseInt(quality) : undefined,
|
|
259
|
+
format,
|
|
260
|
+
});
|
|
261
|
+
const response = new Response(image, {
|
|
262
|
+
headers: {
|
|
263
|
+
"Content-Type": `image/${format}`,
|
|
264
|
+
"Cache-Control": "public, max-age=31536000, immutable",
|
|
265
|
+
date: new Date().toUTCString(),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
cache.put(request, response.clone());
|
|
269
|
+
return response;
|
|
270
|
+
});
|
|
271
|
+
```
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const optimizeImage: ({ image, width, height, quality, format, }: {
|
|
2
2
|
image: BufferSource;
|
|
3
|
-
width?: number
|
|
4
|
-
height?: number
|
|
5
|
-
quality?: number
|
|
6
|
-
format?: "jpeg" | "png" | "webp" |
|
|
3
|
+
width?: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
quality?: number;
|
|
6
|
+
format?: "jpeg" | "png" | "webp" | "avif";
|
|
7
7
|
}) => Promise<Uint8Array | null>;
|
package/dist/cjs/index.js
CHANGED
|
@@ -4,12 +4,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.optimizeImage = void 0;
|
|
7
|
-
const libImage_1 = __importDefault(require("../workers/libImage"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const libImage_1 = __importDefault(require("../workers/libImage"));
|
|
10
10
|
const libImage = (0, libImage_1.default)({
|
|
11
|
-
wasmBinary: fs_1.default.readFileSync(path_1.default.resolve(__dirname,
|
|
11
|
+
wasmBinary: fs_1.default.readFileSync(path_1.default.resolve(__dirname, "../esm/libImage.wasm")),
|
|
12
12
|
});
|
|
13
|
-
const optimizeImage = async ({ image, width = 0, height = 0, quality = 100, format =
|
|
13
|
+
const optimizeImage = async ({ image, width = 0, height = 0, quality = 100, format = "webp", }) => libImage.then(({ optimize }) => optimize(image, width, height, quality, format));
|
|
14
14
|
exports.optimizeImage = optimizeImage;
|
|
15
15
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cjs/index.ts"],"names":[],"mappings":";;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cjs/index.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,gDAAwB;AACxB,mEAA2C;AAE3C,MAAM,QAAQ,GAAG,IAAA,kBAAQ,EAAC;IACxB,UAAU,EAAE,YAAE,CAAC,YAAY,CAAC,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;CAC7E,CAAC,CAAC;AAEI,MAAM,aAAa,GAAG,KAAK,EAAE,EAClC,KAAK,EACL,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,CAAC,EACV,OAAO,GAAG,GAAG,EACb,MAAM,GAAG,MAAM,GAOhB,EAAE,EAAE,CACH,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAChD,CAAC;AAfS,QAAA,aAAa,iBAetB","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport LibImage from \"../workers/libImage\";\n\nconst libImage = LibImage({\n wasmBinary: fs.readFileSync(path.resolve(__dirname, \"../esm/libImage.wasm\")),\n});\n\nexport const optimizeImage = async ({\n image,\n width = 0,\n height = 0,\n quality = 100,\n format = \"webp\",\n}: {\n image: BufferSource;\n width?: number;\n height?: number;\n quality?: number;\n format?: \"jpeg\" | \"png\" | \"webp\" | \"avif\";\n}) =>\n libImage.then(({ optimize }) =>\n optimize(image, width, height, quality, format)\n );\n"]}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const optimizeImage: ({ image, width, height, quality, format, }: {
|
|
2
2
|
image: BufferSource;
|
|
3
|
-
width?: number
|
|
4
|
-
height?: number
|
|
5
|
-
quality?: number
|
|
6
|
-
format?: "jpeg" | "png" | "webp" |
|
|
3
|
+
width?: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
quality?: number;
|
|
6
|
+
format?: "jpeg" | "png" | "webp" | "avif";
|
|
7
7
|
}) => Promise<Uint8Array | null>;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import LibImage from
|
|
1
|
+
import LibImage from "./libImage.js";
|
|
2
2
|
const libImage = LibImage();
|
|
3
|
-
export const optimizeImage = async ({ image, width = 0, height = 0, quality = 100, format =
|
|
3
|
+
export const optimizeImage = async ({ image, width = 0, height = 0, quality = 100, format = "webp", }) => libImage.then(({ optimize }) => optimize(image, width, height, quality, format));
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/esm/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;AAE5B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,EAClC,KAAK,EACL,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,CAAC,EACV,OAAO,GAAG,GAAG,EACb,MAAM,GAAG,MAAM,GAOhB,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/esm/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,QAAQ,GAAG,QAAQ,EAAE,CAAC;AAE5B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,EAClC,KAAK,EACL,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,CAAC,EACV,OAAO,GAAG,GAAG,EACb,MAAM,GAAG,MAAM,GAOhB,EAAE,EAAE,CACH,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAChD,CAAC","sourcesContent":["import LibImage from \"./libImage.js\";\n\nconst libImage = LibImage();\n\nexport const optimizeImage = async ({\n image,\n width = 0,\n height = 0,\n quality = 100,\n format = \"webp\",\n}: {\n image: BufferSource;\n width?: number;\n height?: number;\n quality?: number;\n format?: \"jpeg\" | \"png\" | \"webp\" | \"avif\";\n}) =>\n libImage.then(({ optimize }) =>\n optimize(image, width, height, quality, format)\n );\n"]}
|