@skivuha/img-shrink 0.1.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 +21 -0
- package/README.md +125 -0
- package/dist/cjs/index.cjs +6 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/src/services/shrink-image.service.d.ts +125 -0
- package/dist/cjs/src/services/shrink-image.service.js +275 -0
- package/dist/cjs/src/types/index.d.ts +16 -0
- package/dist/cjs/src/types/index.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/src/services/shrink-image.service.d.ts +125 -0
- package/dist/src/services/shrink-image.service.js +271 -0
- package/dist/src/types/index.d.ts +16 -0
- package/dist/src/types/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +34 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 js-nerds
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# img-shrink
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@skivuha/img-shrink)
|
|
4
|
+
[](https://www.npmjs.com/package/@skivuha/img-shrink)
|
|
5
|
+
[](https://codecov.io/gh/js-nerds/img-shrink)
|
|
6
|
+
|
|
7
|
+
Tiny browser-first image resizer with sane defaults. Pass a `File`/`Blob`, get back a resized `Blob` with optional crop/contain behavior.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
- Works with `File` and `Blob`
|
|
11
|
+
- `cover` (crop) and `contain` (fit) modes
|
|
12
|
+
- Preserve aspect ratio when only width or height is provided
|
|
13
|
+
- Output format selection (`jpeg`, `png`, `webp`)
|
|
14
|
+
- Throws on upscale (target size must not exceed source)
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @skivuha/img-shrink
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pnpm add @skivuha/img-shrink
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yarn add @skivuha/img-shrink
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
### Basic (cover crop)
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { shrinkImage } from "@skivuha/img-shrink";
|
|
36
|
+
|
|
37
|
+
const file = input.files?.[0];
|
|
38
|
+
if (!file) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const resized = await shrinkImage(file, {
|
|
43
|
+
width: 100,
|
|
44
|
+
height: 100,
|
|
45
|
+
fit: "cover",
|
|
46
|
+
format: "image/webp",
|
|
47
|
+
quality: 0.9,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Fit into a box (contain)
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const resized = await shrinkImage(file, {
|
|
55
|
+
width: 360,
|
|
56
|
+
height: 440,
|
|
57
|
+
fit: "contain",
|
|
58
|
+
background: "#ffffff",
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Only width or height
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Height is computed using source aspect ratio
|
|
66
|
+
const resizedByWidth = await shrinkImage(file, { width: 800 });
|
|
67
|
+
|
|
68
|
+
// Width is computed using source aspect ratio
|
|
69
|
+
const resizedByHeight = await shrinkImage(file, { height: 600 });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
### `shrinkImage(input, options)`
|
|
75
|
+
|
|
76
|
+
Resizes and re-encodes the input image.
|
|
77
|
+
|
|
78
|
+
**Params**
|
|
79
|
+
- `input: Blob` — source image
|
|
80
|
+
- `options: ResizeOptions` — resize config
|
|
81
|
+
|
|
82
|
+
**Returns**
|
|
83
|
+
- `Promise<Blob>` — resized image
|
|
84
|
+
|
|
85
|
+
### `ResizeOptions`
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
type ResizeOptions =
|
|
89
|
+
| { width: number; height?: number }
|
|
90
|
+
| { width?: number; height: number };
|
|
91
|
+
|
|
92
|
+
type ResizeFit = "cover" | "contain";
|
|
93
|
+
type ResizeFormat = "image/jpeg" | "image/png" | "image/webp";
|
|
94
|
+
|
|
95
|
+
type ResizeOptions = ResizeSize & {
|
|
96
|
+
fit?: ResizeFit;
|
|
97
|
+
format?: ResizeFormat;
|
|
98
|
+
quality?: number;
|
|
99
|
+
background?: string;
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Notes**
|
|
104
|
+
- If both `width` and `height` are passed, exact size is used.
|
|
105
|
+
- If only one dimension is passed, the other is computed from the source aspect ratio.
|
|
106
|
+
- Upscale is not allowed. If target size exceeds source size, an error is thrown.
|
|
107
|
+
- Default `fit` is `"cover"`.
|
|
108
|
+
- Default `quality` is `0.92`.
|
|
109
|
+
- If `format` is not provided, the input type is used when possible, otherwise `image/jpeg`.
|
|
110
|
+
|
|
111
|
+
## Runtime requirements
|
|
112
|
+
|
|
113
|
+
`img-shrink` uses Canvas (`OffscreenCanvas` when available) and image decoding APIs. It is intended for browser environments. Node.js is not supported without a DOM/canvas polyfill.
|
|
114
|
+
|
|
115
|
+
## Coverage
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pnpm run test:coverage
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Generates a text summary in the terminal and an HTML report in `coverage/`.
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shrinkImage = void 0;
|
|
4
|
+
// Re-export all necessary entities for tree-shaking
|
|
5
|
+
var shrink_image_service_js_1 = require("./src/services/shrink-image.service.js");
|
|
6
|
+
Object.defineProperty(exports, "shrinkImage", { enumerable: true, get: function () { return shrink_image_service_js_1.shrinkImage; } });
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ResizeFormat, ResizeOptions } from "../types/index.js";
|
|
2
|
+
type Canvas2D = HTMLCanvasElement | OffscreenCanvas;
|
|
3
|
+
type SourceImage = ImageBitmap | HTMLImageElement;
|
|
4
|
+
type Canvas2DContext = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
|
|
5
|
+
/**
|
|
6
|
+
* Resize and encode an image Blob to a target size.
|
|
7
|
+
*
|
|
8
|
+
* @params {Blob} input: source image blob
|
|
9
|
+
* @params {ResizeOptions} options: resize configuration
|
|
10
|
+
* @returns {Promise<Blob>}
|
|
11
|
+
*/
|
|
12
|
+
export declare function shrinkImage(input: Blob, options: ResizeOptions): Promise<Blob>;
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a dimension value and round to an integer.
|
|
15
|
+
*
|
|
16
|
+
* @params {number} value: raw dimension value
|
|
17
|
+
* @params {string} name: dimension label for error messages
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
declare function normalizeDimension(value: number, name: string): number;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve target size based on inputs and source aspect ratio.
|
|
23
|
+
*
|
|
24
|
+
* @params {number | undefined} width: requested width
|
|
25
|
+
* @params {number | undefined} height: requested height
|
|
26
|
+
* @params {number} srcWidth: source image width
|
|
27
|
+
* @params {number} srcHeight: source image height
|
|
28
|
+
* @returns {{ width: number; height: number }}
|
|
29
|
+
*/
|
|
30
|
+
declare function resolveTargetSize(width: number | undefined, height: number | undefined, srcWidth: number, srcHeight: number): {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Normalize output quality when encoder supports it.
|
|
36
|
+
*
|
|
37
|
+
* @params {number | undefined} quality: requested quality value
|
|
38
|
+
* @returns {number | undefined}
|
|
39
|
+
*/
|
|
40
|
+
declare function normalizeQuality(quality?: number): number | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve output MIME type from options or input.
|
|
43
|
+
*
|
|
44
|
+
* @params {ResizeFormat | undefined} explicit: explicit output type
|
|
45
|
+
* @params {string} inputType: input blob type
|
|
46
|
+
* @returns {ResizeFormat}
|
|
47
|
+
*/
|
|
48
|
+
declare function resolveOutputType(explicit: ResizeFormat | undefined, inputType: string): ResizeFormat;
|
|
49
|
+
/**
|
|
50
|
+
* Compute source rectangle for "cover" crop.
|
|
51
|
+
*
|
|
52
|
+
* @params {number} srcWidth: source width
|
|
53
|
+
* @params {number} srcHeight: source height
|
|
54
|
+
* @params {number} targetWidth: target width
|
|
55
|
+
* @params {number} targetHeight: target height
|
|
56
|
+
* @returns {{ sx: number; sy: number; sWidth: number; sHeight: number }}
|
|
57
|
+
*/
|
|
58
|
+
declare function getCoverSourceRect(srcWidth: number, srcHeight: number, targetWidth: number, targetHeight: number): {
|
|
59
|
+
sx: number;
|
|
60
|
+
sy: number;
|
|
61
|
+
sWidth: number;
|
|
62
|
+
sHeight: number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Create a 2D canvas instance.
|
|
66
|
+
*
|
|
67
|
+
* @params {number} width: canvas width
|
|
68
|
+
* @params {number} height: canvas height
|
|
69
|
+
* @returns {Canvas2D}
|
|
70
|
+
*/
|
|
71
|
+
declare function createCanvas(width: number, height: number): Canvas2D;
|
|
72
|
+
/**
|
|
73
|
+
* Get a 2D rendering context from a canvas.
|
|
74
|
+
*
|
|
75
|
+
* @params {Canvas2D} canvas: target canvas
|
|
76
|
+
* @returns {Canvas2DContext | null}
|
|
77
|
+
*/
|
|
78
|
+
declare function get2dContext(canvas: Canvas2D): Canvas2DContext | null;
|
|
79
|
+
/**
|
|
80
|
+
* Decode a Blob into a drawable image source.
|
|
81
|
+
*
|
|
82
|
+
* @params {Blob} input: source image blob
|
|
83
|
+
* @returns {Promise<SourceImage>}
|
|
84
|
+
*/
|
|
85
|
+
declare function loadImage(input: Blob): Promise<SourceImage>;
|
|
86
|
+
/**
|
|
87
|
+
* Get the intrinsic size of an image source.
|
|
88
|
+
*
|
|
89
|
+
* @params {SourceImage} image: decoded image
|
|
90
|
+
* @returns {{ width: number; height: number }}
|
|
91
|
+
*/
|
|
92
|
+
declare function getImageSize(image: SourceImage): {
|
|
93
|
+
width: number;
|
|
94
|
+
height: number;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Release resources used by an image source.
|
|
98
|
+
*
|
|
99
|
+
* @params {SourceImage} image: decoded image
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
declare function cleanupImage(image: SourceImage): void;
|
|
103
|
+
/**
|
|
104
|
+
* Encode a canvas into a Blob.
|
|
105
|
+
*
|
|
106
|
+
* @params {Canvas2D} canvas: source canvas
|
|
107
|
+
* @params {ResizeFormat} type: output MIME type
|
|
108
|
+
* @params {number | undefined} quality: encoder quality
|
|
109
|
+
* @returns {Promise<Blob>}
|
|
110
|
+
*/
|
|
111
|
+
declare function canvasToBlob(canvas: Canvas2D, type: ResizeFormat, quality: number | undefined): Promise<Blob>;
|
|
112
|
+
export declare const __test__: {
|
|
113
|
+
normalizeDimension: typeof normalizeDimension;
|
|
114
|
+
resolveTargetSize: typeof resolveTargetSize;
|
|
115
|
+
normalizeQuality: typeof normalizeQuality;
|
|
116
|
+
resolveOutputType: typeof resolveOutputType;
|
|
117
|
+
getCoverSourceRect: typeof getCoverSourceRect;
|
|
118
|
+
createCanvas: typeof createCanvas;
|
|
119
|
+
get2dContext: typeof get2dContext;
|
|
120
|
+
loadImage: typeof loadImage;
|
|
121
|
+
getImageSize: typeof getImageSize;
|
|
122
|
+
cleanupImage: typeof cleanupImage;
|
|
123
|
+
canvasToBlob: typeof canvasToBlob;
|
|
124
|
+
};
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__test__ = void 0;
|
|
4
|
+
exports.shrinkImage = shrinkImage;
|
|
5
|
+
const DEFAULT_QUALITY = 0.92;
|
|
6
|
+
const SUPPORTED_FORMATS = [
|
|
7
|
+
"image/jpeg",
|
|
8
|
+
"image/png",
|
|
9
|
+
"image/webp",
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* Resize and encode an image Blob to a target size.
|
|
13
|
+
*
|
|
14
|
+
* @params {Blob} input: source image blob
|
|
15
|
+
* @params {ResizeOptions} options: resize configuration
|
|
16
|
+
* @returns {Promise<Blob>}
|
|
17
|
+
*/
|
|
18
|
+
async function shrinkImage(input, options) {
|
|
19
|
+
const fit = options.fit ?? "cover";
|
|
20
|
+
const outputType = resolveOutputType(options.format, input.type);
|
|
21
|
+
const quality = normalizeQuality(options.quality);
|
|
22
|
+
const image = await loadImage(input);
|
|
23
|
+
try {
|
|
24
|
+
const { width: srcWidth, height: srcHeight } = getImageSize(image);
|
|
25
|
+
const { width: targetWidth, height: targetHeight } = resolveTargetSize(options.width, options.height, srcWidth, srcHeight);
|
|
26
|
+
if (targetWidth > srcWidth || targetHeight > srcHeight) {
|
|
27
|
+
throw new Error(`Target size ${targetWidth}x${targetHeight} exceeds source ${srcWidth}x${srcHeight}.`);
|
|
28
|
+
}
|
|
29
|
+
const canvas = createCanvas(targetWidth, targetHeight);
|
|
30
|
+
const ctx = get2dContext(canvas);
|
|
31
|
+
if (!ctx) {
|
|
32
|
+
throw new Error("Canvas 2D context is not available.");
|
|
33
|
+
}
|
|
34
|
+
ctx.imageSmoothingEnabled = true;
|
|
35
|
+
if ("imageSmoothingQuality" in ctx) {
|
|
36
|
+
ctx.imageSmoothingQuality = "high";
|
|
37
|
+
}
|
|
38
|
+
if (fit === "contain") {
|
|
39
|
+
const bg = options.background ??
|
|
40
|
+
(outputType === "image/jpeg" ? "#ffffff" : "transparent");
|
|
41
|
+
ctx.fillStyle = bg;
|
|
42
|
+
ctx.fillRect(0, 0, targetWidth, targetHeight);
|
|
43
|
+
const scale = Math.min(targetWidth / srcWidth, targetHeight / srcHeight);
|
|
44
|
+
const destWidth = Math.round(srcWidth * scale);
|
|
45
|
+
const destHeight = Math.round(srcHeight * scale);
|
|
46
|
+
const dx = Math.round((targetWidth - destWidth) / 2);
|
|
47
|
+
const dy = Math.round((targetHeight - destHeight) / 2);
|
|
48
|
+
ctx.drawImage(image, 0, 0, srcWidth, srcHeight, dx, dy, destWidth, destHeight);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const { sx, sy, sWidth, sHeight } = getCoverSourceRect(srcWidth, srcHeight, targetWidth, targetHeight);
|
|
52
|
+
ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, targetWidth, targetHeight);
|
|
53
|
+
}
|
|
54
|
+
return await canvasToBlob(canvas, outputType, quality);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
cleanupImage(image);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Normalize a dimension value and round to an integer.
|
|
62
|
+
*
|
|
63
|
+
* @params {number} value: raw dimension value
|
|
64
|
+
* @params {string} name: dimension label for error messages
|
|
65
|
+
* @returns {number}
|
|
66
|
+
*/
|
|
67
|
+
function normalizeDimension(value, name) {
|
|
68
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
69
|
+
throw new Error(`${name} must be a positive number.`);
|
|
70
|
+
}
|
|
71
|
+
const normalized = Math.round(value);
|
|
72
|
+
if (normalized <= 0) {
|
|
73
|
+
throw new Error(`${name} must be a positive number.`);
|
|
74
|
+
}
|
|
75
|
+
return normalized;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolve target size based on inputs and source aspect ratio.
|
|
79
|
+
*
|
|
80
|
+
* @params {number | undefined} width: requested width
|
|
81
|
+
* @params {number | undefined} height: requested height
|
|
82
|
+
* @params {number} srcWidth: source image width
|
|
83
|
+
* @params {number} srcHeight: source image height
|
|
84
|
+
* @returns {{ width: number; height: number }}
|
|
85
|
+
*/
|
|
86
|
+
function resolveTargetSize(width, height, srcWidth, srcHeight) {
|
|
87
|
+
if (width === undefined && height === undefined) {
|
|
88
|
+
throw new Error("width or height must be provided.");
|
|
89
|
+
}
|
|
90
|
+
const normalizedWidth = width === undefined ? undefined : normalizeDimension(width, "width");
|
|
91
|
+
const normalizedHeight = height === undefined ? undefined : normalizeDimension(height, "height");
|
|
92
|
+
if (normalizedWidth !== undefined && normalizedHeight !== undefined) {
|
|
93
|
+
return { width: normalizedWidth, height: normalizedHeight };
|
|
94
|
+
}
|
|
95
|
+
const ratio = srcWidth / srcHeight;
|
|
96
|
+
if (normalizedWidth !== undefined) {
|
|
97
|
+
const computedHeight = Math.max(1, Math.round(normalizedWidth / ratio));
|
|
98
|
+
return { width: normalizedWidth, height: computedHeight };
|
|
99
|
+
}
|
|
100
|
+
const computedWidth = Math.max(1, Math.round(normalizedHeight * ratio));
|
|
101
|
+
return { width: computedWidth, height: normalizedHeight };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Normalize output quality when encoder supports it.
|
|
105
|
+
*
|
|
106
|
+
* @params {number | undefined} quality: requested quality value
|
|
107
|
+
* @returns {number | undefined}
|
|
108
|
+
*/
|
|
109
|
+
function normalizeQuality(quality) {
|
|
110
|
+
if (quality === undefined) {
|
|
111
|
+
return DEFAULT_QUALITY;
|
|
112
|
+
}
|
|
113
|
+
if (!Number.isFinite(quality) || quality < 0 || quality > 1) {
|
|
114
|
+
throw new Error("quality must be between 0 and 1.");
|
|
115
|
+
}
|
|
116
|
+
return quality;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Resolve output MIME type from options or input.
|
|
120
|
+
*
|
|
121
|
+
* @params {ResizeFormat | undefined} explicit: explicit output type
|
|
122
|
+
* @params {string} inputType: input blob type
|
|
123
|
+
* @returns {ResizeFormat}
|
|
124
|
+
*/
|
|
125
|
+
function resolveOutputType(explicit, inputType) {
|
|
126
|
+
if (explicit && SUPPORTED_FORMATS.indexOf(explicit) !== -1) {
|
|
127
|
+
return explicit;
|
|
128
|
+
}
|
|
129
|
+
const normalizedInput = inputType.toLowerCase();
|
|
130
|
+
if (SUPPORTED_FORMATS.indexOf(normalizedInput) !== -1) {
|
|
131
|
+
return normalizedInput;
|
|
132
|
+
}
|
|
133
|
+
return "image/jpeg";
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Compute source rectangle for "cover" crop.
|
|
137
|
+
*
|
|
138
|
+
* @params {number} srcWidth: source width
|
|
139
|
+
* @params {number} srcHeight: source height
|
|
140
|
+
* @params {number} targetWidth: target width
|
|
141
|
+
* @params {number} targetHeight: target height
|
|
142
|
+
* @returns {{ sx: number; sy: number; sWidth: number; sHeight: number }}
|
|
143
|
+
*/
|
|
144
|
+
function getCoverSourceRect(srcWidth, srcHeight, targetWidth, targetHeight) {
|
|
145
|
+
const srcRatio = srcWidth / srcHeight;
|
|
146
|
+
const targetRatio = targetWidth / targetHeight;
|
|
147
|
+
if (srcRatio > targetRatio) {
|
|
148
|
+
const sWidth = srcHeight * targetRatio;
|
|
149
|
+
const sx = (srcWidth - sWidth) / 2;
|
|
150
|
+
return { sx, sy: 0, sWidth, sHeight: srcHeight };
|
|
151
|
+
}
|
|
152
|
+
const sHeight = srcWidth / targetRatio;
|
|
153
|
+
const sy = (srcHeight - sHeight) / 2;
|
|
154
|
+
return { sx: 0, sy, sWidth: srcWidth, sHeight };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Create a 2D canvas instance.
|
|
158
|
+
*
|
|
159
|
+
* @params {number} width: canvas width
|
|
160
|
+
* @params {number} height: canvas height
|
|
161
|
+
* @returns {Canvas2D}
|
|
162
|
+
*/
|
|
163
|
+
function createCanvas(width, height) {
|
|
164
|
+
if (typeof OffscreenCanvas !== "undefined") {
|
|
165
|
+
return new OffscreenCanvas(width, height);
|
|
166
|
+
}
|
|
167
|
+
if (typeof document === "undefined") {
|
|
168
|
+
throw new Error("Canvas is not available in this environment.");
|
|
169
|
+
}
|
|
170
|
+
const canvas = document.createElement("canvas");
|
|
171
|
+
canvas.width = width;
|
|
172
|
+
canvas.height = height;
|
|
173
|
+
return canvas;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get a 2D rendering context from a canvas.
|
|
177
|
+
*
|
|
178
|
+
* @params {Canvas2D} canvas: target canvas
|
|
179
|
+
* @returns {Canvas2DContext | null}
|
|
180
|
+
*/
|
|
181
|
+
function get2dContext(canvas) {
|
|
182
|
+
return canvas.getContext("2d");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Decode a Blob into a drawable image source.
|
|
186
|
+
*
|
|
187
|
+
* @params {Blob} input: source image blob
|
|
188
|
+
* @returns {Promise<SourceImage>}
|
|
189
|
+
*/
|
|
190
|
+
async function loadImage(input) {
|
|
191
|
+
if (typeof createImageBitmap === "function") {
|
|
192
|
+
return createImageBitmap(input, { imageOrientation: "from-image" });
|
|
193
|
+
}
|
|
194
|
+
if (typeof Image === "undefined") {
|
|
195
|
+
throw new Error("Image decoding is not available in this environment.");
|
|
196
|
+
}
|
|
197
|
+
const url = URL.createObjectURL(input);
|
|
198
|
+
const image = new Image();
|
|
199
|
+
image.decoding = "async";
|
|
200
|
+
image.src = url;
|
|
201
|
+
try {
|
|
202
|
+
if (typeof image.decode === "function") {
|
|
203
|
+
await image.decode();
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
await new Promise((resolve, reject) => {
|
|
207
|
+
image.onload = () => resolve();
|
|
208
|
+
image.onerror = () => reject(new Error("Failed to load image."));
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
URL.revokeObjectURL(url);
|
|
214
|
+
}
|
|
215
|
+
return image;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get the intrinsic size of an image source.
|
|
219
|
+
*
|
|
220
|
+
* @params {SourceImage} image: decoded image
|
|
221
|
+
* @returns {{ width: number; height: number }}
|
|
222
|
+
*/
|
|
223
|
+
function getImageSize(image) {
|
|
224
|
+
if ("naturalWidth" in image) {
|
|
225
|
+
return { width: image.naturalWidth, height: image.naturalHeight };
|
|
226
|
+
}
|
|
227
|
+
return { width: image.width, height: image.height };
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Release resources used by an image source.
|
|
231
|
+
*
|
|
232
|
+
* @params {SourceImage} image: decoded image
|
|
233
|
+
* @returns {void}
|
|
234
|
+
*/
|
|
235
|
+
function cleanupImage(image) {
|
|
236
|
+
if ("close" in image) {
|
|
237
|
+
image.close();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Encode a canvas into a Blob.
|
|
242
|
+
*
|
|
243
|
+
* @params {Canvas2D} canvas: source canvas
|
|
244
|
+
* @params {ResizeFormat} type: output MIME type
|
|
245
|
+
* @params {number | undefined} quality: encoder quality
|
|
246
|
+
* @returns {Promise<Blob>}
|
|
247
|
+
*/
|
|
248
|
+
async function canvasToBlob(canvas, type, quality) {
|
|
249
|
+
if ("convertToBlob" in canvas) {
|
|
250
|
+
return canvas.convertToBlob({ type, quality });
|
|
251
|
+
}
|
|
252
|
+
return new Promise((resolve, reject) => {
|
|
253
|
+
canvas.toBlob((blob) => {
|
|
254
|
+
if (blob) {
|
|
255
|
+
resolve(blob);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
reject(new Error("Failed to create image blob."));
|
|
259
|
+
}
|
|
260
|
+
}, type, quality);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
exports.__test__ = {
|
|
264
|
+
normalizeDimension,
|
|
265
|
+
resolveTargetSize,
|
|
266
|
+
normalizeQuality,
|
|
267
|
+
resolveOutputType,
|
|
268
|
+
getCoverSourceRect,
|
|
269
|
+
createCanvas,
|
|
270
|
+
get2dContext,
|
|
271
|
+
loadImage,
|
|
272
|
+
getImageSize,
|
|
273
|
+
cleanupImage,
|
|
274
|
+
canvasToBlob,
|
|
275
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ResizeFit = "cover" | "contain";
|
|
2
|
+
export type ResizeFormat = "image/jpeg" | "image/png" | "image/webp";
|
|
3
|
+
type ResizeSize = {
|
|
4
|
+
width: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
} | {
|
|
7
|
+
width?: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
export type ResizeOptions = ResizeSize & {
|
|
11
|
+
fit?: ResizeFit;
|
|
12
|
+
format?: ResizeFormat;
|
|
13
|
+
quality?: number;
|
|
14
|
+
background?: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ResizeFormat, ResizeOptions } from "../types/index.js";
|
|
2
|
+
type Canvas2D = HTMLCanvasElement | OffscreenCanvas;
|
|
3
|
+
type SourceImage = ImageBitmap | HTMLImageElement;
|
|
4
|
+
type Canvas2DContext = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
|
|
5
|
+
/**
|
|
6
|
+
* Resize and encode an image Blob to a target size.
|
|
7
|
+
*
|
|
8
|
+
* @params {Blob} input: source image blob
|
|
9
|
+
* @params {ResizeOptions} options: resize configuration
|
|
10
|
+
* @returns {Promise<Blob>}
|
|
11
|
+
*/
|
|
12
|
+
export declare function shrinkImage(input: Blob, options: ResizeOptions): Promise<Blob>;
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a dimension value and round to an integer.
|
|
15
|
+
*
|
|
16
|
+
* @params {number} value: raw dimension value
|
|
17
|
+
* @params {string} name: dimension label for error messages
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
declare function normalizeDimension(value: number, name: string): number;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve target size based on inputs and source aspect ratio.
|
|
23
|
+
*
|
|
24
|
+
* @params {number | undefined} width: requested width
|
|
25
|
+
* @params {number | undefined} height: requested height
|
|
26
|
+
* @params {number} srcWidth: source image width
|
|
27
|
+
* @params {number} srcHeight: source image height
|
|
28
|
+
* @returns {{ width: number; height: number }}
|
|
29
|
+
*/
|
|
30
|
+
declare function resolveTargetSize(width: number | undefined, height: number | undefined, srcWidth: number, srcHeight: number): {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Normalize output quality when encoder supports it.
|
|
36
|
+
*
|
|
37
|
+
* @params {number | undefined} quality: requested quality value
|
|
38
|
+
* @returns {number | undefined}
|
|
39
|
+
*/
|
|
40
|
+
declare function normalizeQuality(quality?: number): number | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve output MIME type from options or input.
|
|
43
|
+
*
|
|
44
|
+
* @params {ResizeFormat | undefined} explicit: explicit output type
|
|
45
|
+
* @params {string} inputType: input blob type
|
|
46
|
+
* @returns {ResizeFormat}
|
|
47
|
+
*/
|
|
48
|
+
declare function resolveOutputType(explicit: ResizeFormat | undefined, inputType: string): ResizeFormat;
|
|
49
|
+
/**
|
|
50
|
+
* Compute source rectangle for "cover" crop.
|
|
51
|
+
*
|
|
52
|
+
* @params {number} srcWidth: source width
|
|
53
|
+
* @params {number} srcHeight: source height
|
|
54
|
+
* @params {number} targetWidth: target width
|
|
55
|
+
* @params {number} targetHeight: target height
|
|
56
|
+
* @returns {{ sx: number; sy: number; sWidth: number; sHeight: number }}
|
|
57
|
+
*/
|
|
58
|
+
declare function getCoverSourceRect(srcWidth: number, srcHeight: number, targetWidth: number, targetHeight: number): {
|
|
59
|
+
sx: number;
|
|
60
|
+
sy: number;
|
|
61
|
+
sWidth: number;
|
|
62
|
+
sHeight: number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Create a 2D canvas instance.
|
|
66
|
+
*
|
|
67
|
+
* @params {number} width: canvas width
|
|
68
|
+
* @params {number} height: canvas height
|
|
69
|
+
* @returns {Canvas2D}
|
|
70
|
+
*/
|
|
71
|
+
declare function createCanvas(width: number, height: number): Canvas2D;
|
|
72
|
+
/**
|
|
73
|
+
* Get a 2D rendering context from a canvas.
|
|
74
|
+
*
|
|
75
|
+
* @params {Canvas2D} canvas: target canvas
|
|
76
|
+
* @returns {Canvas2DContext | null}
|
|
77
|
+
*/
|
|
78
|
+
declare function get2dContext(canvas: Canvas2D): Canvas2DContext | null;
|
|
79
|
+
/**
|
|
80
|
+
* Decode a Blob into a drawable image source.
|
|
81
|
+
*
|
|
82
|
+
* @params {Blob} input: source image blob
|
|
83
|
+
* @returns {Promise<SourceImage>}
|
|
84
|
+
*/
|
|
85
|
+
declare function loadImage(input: Blob): Promise<SourceImage>;
|
|
86
|
+
/**
|
|
87
|
+
* Get the intrinsic size of an image source.
|
|
88
|
+
*
|
|
89
|
+
* @params {SourceImage} image: decoded image
|
|
90
|
+
* @returns {{ width: number; height: number }}
|
|
91
|
+
*/
|
|
92
|
+
declare function getImageSize(image: SourceImage): {
|
|
93
|
+
width: number;
|
|
94
|
+
height: number;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Release resources used by an image source.
|
|
98
|
+
*
|
|
99
|
+
* @params {SourceImage} image: decoded image
|
|
100
|
+
* @returns {void}
|
|
101
|
+
*/
|
|
102
|
+
declare function cleanupImage(image: SourceImage): void;
|
|
103
|
+
/**
|
|
104
|
+
* Encode a canvas into a Blob.
|
|
105
|
+
*
|
|
106
|
+
* @params {Canvas2D} canvas: source canvas
|
|
107
|
+
* @params {ResizeFormat} type: output MIME type
|
|
108
|
+
* @params {number | undefined} quality: encoder quality
|
|
109
|
+
* @returns {Promise<Blob>}
|
|
110
|
+
*/
|
|
111
|
+
declare function canvasToBlob(canvas: Canvas2D, type: ResizeFormat, quality: number | undefined): Promise<Blob>;
|
|
112
|
+
export declare const __test__: {
|
|
113
|
+
normalizeDimension: typeof normalizeDimension;
|
|
114
|
+
resolveTargetSize: typeof resolveTargetSize;
|
|
115
|
+
normalizeQuality: typeof normalizeQuality;
|
|
116
|
+
resolveOutputType: typeof resolveOutputType;
|
|
117
|
+
getCoverSourceRect: typeof getCoverSourceRect;
|
|
118
|
+
createCanvas: typeof createCanvas;
|
|
119
|
+
get2dContext: typeof get2dContext;
|
|
120
|
+
loadImage: typeof loadImage;
|
|
121
|
+
getImageSize: typeof getImageSize;
|
|
122
|
+
cleanupImage: typeof cleanupImage;
|
|
123
|
+
canvasToBlob: typeof canvasToBlob;
|
|
124
|
+
};
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
const DEFAULT_QUALITY = 0.92;
|
|
2
|
+
const SUPPORTED_FORMATS = [
|
|
3
|
+
"image/jpeg",
|
|
4
|
+
"image/png",
|
|
5
|
+
"image/webp",
|
|
6
|
+
];
|
|
7
|
+
/**
|
|
8
|
+
* Resize and encode an image Blob to a target size.
|
|
9
|
+
*
|
|
10
|
+
* @params {Blob} input: source image blob
|
|
11
|
+
* @params {ResizeOptions} options: resize configuration
|
|
12
|
+
* @returns {Promise<Blob>}
|
|
13
|
+
*/
|
|
14
|
+
export async function shrinkImage(input, options) {
|
|
15
|
+
const fit = options.fit ?? "cover";
|
|
16
|
+
const outputType = resolveOutputType(options.format, input.type);
|
|
17
|
+
const quality = normalizeQuality(options.quality);
|
|
18
|
+
const image = await loadImage(input);
|
|
19
|
+
try {
|
|
20
|
+
const { width: srcWidth, height: srcHeight } = getImageSize(image);
|
|
21
|
+
const { width: targetWidth, height: targetHeight } = resolveTargetSize(options.width, options.height, srcWidth, srcHeight);
|
|
22
|
+
if (targetWidth > srcWidth || targetHeight > srcHeight) {
|
|
23
|
+
throw new Error(`Target size ${targetWidth}x${targetHeight} exceeds source ${srcWidth}x${srcHeight}.`);
|
|
24
|
+
}
|
|
25
|
+
const canvas = createCanvas(targetWidth, targetHeight);
|
|
26
|
+
const ctx = get2dContext(canvas);
|
|
27
|
+
if (!ctx) {
|
|
28
|
+
throw new Error("Canvas 2D context is not available.");
|
|
29
|
+
}
|
|
30
|
+
ctx.imageSmoothingEnabled = true;
|
|
31
|
+
if ("imageSmoothingQuality" in ctx) {
|
|
32
|
+
ctx.imageSmoothingQuality = "high";
|
|
33
|
+
}
|
|
34
|
+
if (fit === "contain") {
|
|
35
|
+
const bg = options.background ??
|
|
36
|
+
(outputType === "image/jpeg" ? "#ffffff" : "transparent");
|
|
37
|
+
ctx.fillStyle = bg;
|
|
38
|
+
ctx.fillRect(0, 0, targetWidth, targetHeight);
|
|
39
|
+
const scale = Math.min(targetWidth / srcWidth, targetHeight / srcHeight);
|
|
40
|
+
const destWidth = Math.round(srcWidth * scale);
|
|
41
|
+
const destHeight = Math.round(srcHeight * scale);
|
|
42
|
+
const dx = Math.round((targetWidth - destWidth) / 2);
|
|
43
|
+
const dy = Math.round((targetHeight - destHeight) / 2);
|
|
44
|
+
ctx.drawImage(image, 0, 0, srcWidth, srcHeight, dx, dy, destWidth, destHeight);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const { sx, sy, sWidth, sHeight } = getCoverSourceRect(srcWidth, srcHeight, targetWidth, targetHeight);
|
|
48
|
+
ctx.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, targetWidth, targetHeight);
|
|
49
|
+
}
|
|
50
|
+
return await canvasToBlob(canvas, outputType, quality);
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
cleanupImage(image);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Normalize a dimension value and round to an integer.
|
|
58
|
+
*
|
|
59
|
+
* @params {number} value: raw dimension value
|
|
60
|
+
* @params {string} name: dimension label for error messages
|
|
61
|
+
* @returns {number}
|
|
62
|
+
*/
|
|
63
|
+
function normalizeDimension(value, name) {
|
|
64
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
65
|
+
throw new Error(`${name} must be a positive number.`);
|
|
66
|
+
}
|
|
67
|
+
const normalized = Math.round(value);
|
|
68
|
+
if (normalized <= 0) {
|
|
69
|
+
throw new Error(`${name} must be a positive number.`);
|
|
70
|
+
}
|
|
71
|
+
return normalized;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Resolve target size based on inputs and source aspect ratio.
|
|
75
|
+
*
|
|
76
|
+
* @params {number | undefined} width: requested width
|
|
77
|
+
* @params {number | undefined} height: requested height
|
|
78
|
+
* @params {number} srcWidth: source image width
|
|
79
|
+
* @params {number} srcHeight: source image height
|
|
80
|
+
* @returns {{ width: number; height: number }}
|
|
81
|
+
*/
|
|
82
|
+
function resolveTargetSize(width, height, srcWidth, srcHeight) {
|
|
83
|
+
if (width === undefined && height === undefined) {
|
|
84
|
+
throw new Error("width or height must be provided.");
|
|
85
|
+
}
|
|
86
|
+
const normalizedWidth = width === undefined ? undefined : normalizeDimension(width, "width");
|
|
87
|
+
const normalizedHeight = height === undefined ? undefined : normalizeDimension(height, "height");
|
|
88
|
+
if (normalizedWidth !== undefined && normalizedHeight !== undefined) {
|
|
89
|
+
return { width: normalizedWidth, height: normalizedHeight };
|
|
90
|
+
}
|
|
91
|
+
const ratio = srcWidth / srcHeight;
|
|
92
|
+
if (normalizedWidth !== undefined) {
|
|
93
|
+
const computedHeight = Math.max(1, Math.round(normalizedWidth / ratio));
|
|
94
|
+
return { width: normalizedWidth, height: computedHeight };
|
|
95
|
+
}
|
|
96
|
+
const computedWidth = Math.max(1, Math.round(normalizedHeight * ratio));
|
|
97
|
+
return { width: computedWidth, height: normalizedHeight };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Normalize output quality when encoder supports it.
|
|
101
|
+
*
|
|
102
|
+
* @params {number | undefined} quality: requested quality value
|
|
103
|
+
* @returns {number | undefined}
|
|
104
|
+
*/
|
|
105
|
+
function normalizeQuality(quality) {
|
|
106
|
+
if (quality === undefined) {
|
|
107
|
+
return DEFAULT_QUALITY;
|
|
108
|
+
}
|
|
109
|
+
if (!Number.isFinite(quality) || quality < 0 || quality > 1) {
|
|
110
|
+
throw new Error("quality must be between 0 and 1.");
|
|
111
|
+
}
|
|
112
|
+
return quality;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolve output MIME type from options or input.
|
|
116
|
+
*
|
|
117
|
+
* @params {ResizeFormat | undefined} explicit: explicit output type
|
|
118
|
+
* @params {string} inputType: input blob type
|
|
119
|
+
* @returns {ResizeFormat}
|
|
120
|
+
*/
|
|
121
|
+
function resolveOutputType(explicit, inputType) {
|
|
122
|
+
if (explicit && SUPPORTED_FORMATS.indexOf(explicit) !== -1) {
|
|
123
|
+
return explicit;
|
|
124
|
+
}
|
|
125
|
+
const normalizedInput = inputType.toLowerCase();
|
|
126
|
+
if (SUPPORTED_FORMATS.indexOf(normalizedInput) !== -1) {
|
|
127
|
+
return normalizedInput;
|
|
128
|
+
}
|
|
129
|
+
return "image/jpeg";
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Compute source rectangle for "cover" crop.
|
|
133
|
+
*
|
|
134
|
+
* @params {number} srcWidth: source width
|
|
135
|
+
* @params {number} srcHeight: source height
|
|
136
|
+
* @params {number} targetWidth: target width
|
|
137
|
+
* @params {number} targetHeight: target height
|
|
138
|
+
* @returns {{ sx: number; sy: number; sWidth: number; sHeight: number }}
|
|
139
|
+
*/
|
|
140
|
+
function getCoverSourceRect(srcWidth, srcHeight, targetWidth, targetHeight) {
|
|
141
|
+
const srcRatio = srcWidth / srcHeight;
|
|
142
|
+
const targetRatio = targetWidth / targetHeight;
|
|
143
|
+
if (srcRatio > targetRatio) {
|
|
144
|
+
const sWidth = srcHeight * targetRatio;
|
|
145
|
+
const sx = (srcWidth - sWidth) / 2;
|
|
146
|
+
return { sx, sy: 0, sWidth, sHeight: srcHeight };
|
|
147
|
+
}
|
|
148
|
+
const sHeight = srcWidth / targetRatio;
|
|
149
|
+
const sy = (srcHeight - sHeight) / 2;
|
|
150
|
+
return { sx: 0, sy, sWidth: srcWidth, sHeight };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Create a 2D canvas instance.
|
|
154
|
+
*
|
|
155
|
+
* @params {number} width: canvas width
|
|
156
|
+
* @params {number} height: canvas height
|
|
157
|
+
* @returns {Canvas2D}
|
|
158
|
+
*/
|
|
159
|
+
function createCanvas(width, height) {
|
|
160
|
+
if (typeof OffscreenCanvas !== "undefined") {
|
|
161
|
+
return new OffscreenCanvas(width, height);
|
|
162
|
+
}
|
|
163
|
+
if (typeof document === "undefined") {
|
|
164
|
+
throw new Error("Canvas is not available in this environment.");
|
|
165
|
+
}
|
|
166
|
+
const canvas = document.createElement("canvas");
|
|
167
|
+
canvas.width = width;
|
|
168
|
+
canvas.height = height;
|
|
169
|
+
return canvas;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Get a 2D rendering context from a canvas.
|
|
173
|
+
*
|
|
174
|
+
* @params {Canvas2D} canvas: target canvas
|
|
175
|
+
* @returns {Canvas2DContext | null}
|
|
176
|
+
*/
|
|
177
|
+
function get2dContext(canvas) {
|
|
178
|
+
return canvas.getContext("2d");
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Decode a Blob into a drawable image source.
|
|
182
|
+
*
|
|
183
|
+
* @params {Blob} input: source image blob
|
|
184
|
+
* @returns {Promise<SourceImage>}
|
|
185
|
+
*/
|
|
186
|
+
async function loadImage(input) {
|
|
187
|
+
if (typeof createImageBitmap === "function") {
|
|
188
|
+
return createImageBitmap(input, { imageOrientation: "from-image" });
|
|
189
|
+
}
|
|
190
|
+
if (typeof Image === "undefined") {
|
|
191
|
+
throw new Error("Image decoding is not available in this environment.");
|
|
192
|
+
}
|
|
193
|
+
const url = URL.createObjectURL(input);
|
|
194
|
+
const image = new Image();
|
|
195
|
+
image.decoding = "async";
|
|
196
|
+
image.src = url;
|
|
197
|
+
try {
|
|
198
|
+
if (typeof image.decode === "function") {
|
|
199
|
+
await image.decode();
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
await new Promise((resolve, reject) => {
|
|
203
|
+
image.onload = () => resolve();
|
|
204
|
+
image.onerror = () => reject(new Error("Failed to load image."));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
URL.revokeObjectURL(url);
|
|
210
|
+
}
|
|
211
|
+
return image;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Get the intrinsic size of an image source.
|
|
215
|
+
*
|
|
216
|
+
* @params {SourceImage} image: decoded image
|
|
217
|
+
* @returns {{ width: number; height: number }}
|
|
218
|
+
*/
|
|
219
|
+
function getImageSize(image) {
|
|
220
|
+
if ("naturalWidth" in image) {
|
|
221
|
+
return { width: image.naturalWidth, height: image.naturalHeight };
|
|
222
|
+
}
|
|
223
|
+
return { width: image.width, height: image.height };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Release resources used by an image source.
|
|
227
|
+
*
|
|
228
|
+
* @params {SourceImage} image: decoded image
|
|
229
|
+
* @returns {void}
|
|
230
|
+
*/
|
|
231
|
+
function cleanupImage(image) {
|
|
232
|
+
if ("close" in image) {
|
|
233
|
+
image.close();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Encode a canvas into a Blob.
|
|
238
|
+
*
|
|
239
|
+
* @params {Canvas2D} canvas: source canvas
|
|
240
|
+
* @params {ResizeFormat} type: output MIME type
|
|
241
|
+
* @params {number | undefined} quality: encoder quality
|
|
242
|
+
* @returns {Promise<Blob>}
|
|
243
|
+
*/
|
|
244
|
+
async function canvasToBlob(canvas, type, quality) {
|
|
245
|
+
if ("convertToBlob" in canvas) {
|
|
246
|
+
return canvas.convertToBlob({ type, quality });
|
|
247
|
+
}
|
|
248
|
+
return new Promise((resolve, reject) => {
|
|
249
|
+
canvas.toBlob((blob) => {
|
|
250
|
+
if (blob) {
|
|
251
|
+
resolve(blob);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
reject(new Error("Failed to create image blob."));
|
|
255
|
+
}
|
|
256
|
+
}, type, quality);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
export const __test__ = {
|
|
260
|
+
normalizeDimension,
|
|
261
|
+
resolveTargetSize,
|
|
262
|
+
normalizeQuality,
|
|
263
|
+
resolveOutputType,
|
|
264
|
+
getCoverSourceRect,
|
|
265
|
+
createCanvas,
|
|
266
|
+
get2dContext,
|
|
267
|
+
loadImage,
|
|
268
|
+
getImageSize,
|
|
269
|
+
cleanupImage,
|
|
270
|
+
canvasToBlob,
|
|
271
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ResizeFit = "cover" | "contain";
|
|
2
|
+
export type ResizeFormat = "image/jpeg" | "image/png" | "image/webp";
|
|
3
|
+
type ResizeSize = {
|
|
4
|
+
width: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
} | {
|
|
7
|
+
width?: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
export type ResizeOptions = ResizeSize & {
|
|
11
|
+
fit?: ResizeFit;
|
|
12
|
+
format?: ResizeFormat;
|
|
13
|
+
quality?: number;
|
|
14
|
+
background?: string;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/types/index.ts","../src/services/shrink-image.service.ts","../index.ts","../node_modules/.pnpm/@vitest+spy@3.2.4/node_modules/@vitest/spy/dist/index.d.ts","../node_modules/.pnpm/@vitest+pretty-format@3.2.4/node_modules/@vitest/pretty-format/dist/index.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/types.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/helpers.d.ts","../node_modules/.pnpm/tinyrainbow@2.0.0/node_modules/tinyrainbow/dist/index-8b61d5bc.d.ts","../node_modules/.pnpm/tinyrainbow@2.0.0/node_modules/tinyrainbow/dist/node.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/index.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/diff.d.ts","../node_modules/.pnpm/@vitest+expect@3.2.4/node_modules/@vitest/expect/dist/index.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/compatibility/index.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/globals.typedarray.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/buffer.buffer.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/globals.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/abortcontroller.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/domexception.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/events.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/header.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/readable.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/file.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/fetch.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/formdata.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/connector.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/client.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/errors.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-origin.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool-stats.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/handlers.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/balanced-pool.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/agent.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-interceptor.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-agent.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-client.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-pool.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-errors.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-handler.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-agent.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/api.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/interceptors.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/util.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cookies.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/patch.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/websocket.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/eventsource.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/filereader.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/content-type.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cache.d.ts","../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/index.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/fetch.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/navigator.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/web-globals/storage.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/assert.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/assert/strict.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/async_hooks.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/buffer.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/child_process.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/cluster.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/console.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/constants.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/crypto.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/dgram.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/dns.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/dns/promises.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/domain.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/events.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/fs.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/fs/promises.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/http.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/http2.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/https.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/inspector.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/inspector.generated.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/module.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/net.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/os.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/path.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/perf_hooks.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/process.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/punycode.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/querystring.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/readline.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/readline/promises.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/repl.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/sea.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/sqlite.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/stream.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/stream/promises.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/stream/consumers.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/stream/web.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/string_decoder.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/test.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/timers.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/timers/promises.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/tls.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/trace_events.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/tty.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/url.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/util.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/v8.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/vm.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/wasi.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/worker_threads.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/zlib.d.ts","../node_modules/.pnpm/@types+node@22.19.7/node_modules/@types/node/index.d.ts","../node_modules/.pnpm/@types+estree@1.0.8/node_modules/@types/estree/index.d.ts","../node_modules/.pnpm/rollup@4.55.3/node_modules/rollup/dist/rollup.d.ts","../node_modules/.pnpm/rollup@4.55.3/node_modules/rollup/dist/parseAst.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/hmrPayload.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/customEvent.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/hot.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/dist/node/moduleRunnerTransport.d-DJ_mE5sf.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/dist/node/module-runner.d.ts","../node_modules/.pnpm/esbuild@0.25.12/node_modules/esbuild/lib/main.d.ts","../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/previous-map.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/input.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/css-syntax-error.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/declaration.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/root.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/warning.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/lazy-result.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/no-work-result.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/processor.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/result.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/document.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/rule.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/node.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/comment.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/container.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/at-rule.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/list.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/postcss.d.ts","../node_modules/.pnpm/postcss@8.5.6/node_modules/postcss/lib/postcss.d.mts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/internal/lightningcssOptions.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/internal/cssPreprocessorOptions.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/importGlob.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/types/metadata.d.ts","../node_modules/.pnpm/vite@6.4.1_@types+node@22.19.7/node_modules/vite/dist/node/index.d.ts","../node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/tasks.d-CkscK4of.d.ts","../node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/types.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/error.d.ts","../node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/index.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/optional-types.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/environment.d.cL3nLXbE.d.ts","../node_modules/.pnpm/@vitest+mocker@3.2.4_vite@6.4.1_@types+node@22.19.7_/node_modules/@vitest/mocker/dist/registry.d-D765pazg.d.ts","../node_modules/.pnpm/@vitest+mocker@3.2.4_vite@6.4.1_@types+node@22.19.7_/node_modules/@vitest/mocker/dist/types.d-D_aRZRdy.d.ts","../node_modules/.pnpm/@vitest+mocker@3.2.4_vite@6.4.1_@types+node@22.19.7_/node_modules/@vitest/mocker/dist/index.d.ts","../node_modules/.pnpm/@vitest+utils@3.2.4/node_modules/@vitest/utils/dist/source-map.d.ts","../node_modules/.pnpm/vite-node@3.2.4_@types+node@22.19.7/node_modules/vite-node/dist/trace-mapping.d-DLVdEqOp.d.ts","../node_modules/.pnpm/vite-node@3.2.4_@types+node@22.19.7/node_modules/vite-node/dist/index.d-DGmxD2U7.d.ts","../node_modules/.pnpm/vite-node@3.2.4_@types+node@22.19.7/node_modules/vite-node/dist/index.d.ts","../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/environment.d-DHdQ1Csl.d.ts","../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/rawSnapshot.d-lFsMJFUd.d.ts","../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/index.d.ts","../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/environment.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/config.d.D2ROskhv.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/worker.d.1GmBbd7G.d.ts","../node_modules/.pnpm/@types+deep-eql@4.0.2/node_modules/@types/deep-eql/index.d.ts","../node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error/index.d.ts","../node_modules/.pnpm/@types+chai@5.2.3/node_modules/@types/chai/index.d.ts","../node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/utils.d.ts","../node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/benchmark.d.BwvBVTda.d.ts","../node_modules/.pnpm/vite-node@3.2.4_@types+node@22.19.7/node_modules/vite-node/dist/client.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/coverage.d.S9RMNXIe.d.ts","../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/manager.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/reporters.d.BFLkQcL6.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/vite.d.CMLlLIFP.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/config.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/config.d.ts","../vitest.config.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/worker.d.CKwWzBSj.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/global.d.MAmajcmJ.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/mocker.d.BE_2ls6u.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/chunks/suite.d.FvehnV49.d.ts","../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.d.ts","../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.d.ts","../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.d.ts","../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.d.ts","../node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/dist/index.d.ts","../node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.7_@vitest+ui@3.2.4/node_modules/vitest/globals.d.ts"],"fileIdsList":[[52,53,70,118,135,136],[70,118,135,136,222,223],[70,118,135,136],[70,115,116,118,135,136],[70,117,118,135,136],[118,135,136],[70,118,123,135,136,153],[70,118,119,124,129,135,136,138,150,161],[70,118,119,120,129,135,136,138],[65,66,67,70,118,135,136],[70,118,121,135,136,162],[70,118,122,123,130,135,136,139],[70,118,123,135,136,150,158],[70,118,124,126,129,135,136,138],[70,117,118,125,135,136],[70,118,126,127,135,136],[70,118,128,129,135,136],[70,117,118,129,135,136],[70,118,129,130,131,135,136,150,161],[70,118,129,130,131,135,136,145,150,153],[70,111,118,126,129,132,135,136,138,150,161],[70,118,129,130,132,133,135,136,138,150,158,161],[70,118,132,134,135,136,150,158,161],[68,69,70,71,72,73,74,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167],[70,118,129,135,136],[70,118,135,136,137,161],[70,118,126,129,135,136,138,150],[70,118,135,136,139],[70,118,135,136,140],[70,117,118,135,136,141],[70,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167],[70,118,135,136,143],[70,118,135,136,144],[70,118,129,135,136,145,146],[70,118,135,136,145,147,162,164],[70,118,130,135,136],[70,118,129,135,136,150,151,153],[70,118,135,136,152,153],[70,118,135,136,150,151],[70,118,135,136,153],[70,118,135,136,154],[70,115,118,135,136,150,155],[70,118,129,135,136,156,157],[70,118,135,136,156,157],[70,118,123,135,136,138,150,158],[70,118,135,136,159],[70,118,135,136,138,160],[70,118,132,135,136,144,161],[70,118,123,135,136,162],[70,118,135,136,150,163],[70,118,135,136,137,164],[70,118,135,136,165],[70,111,118,135,136],[70,111,118,129,131,135,136,141,150,153,161,163,164,166],[70,118,135,136,150,167],[55,60,61,63,70,118,135,136],[70,118,135,136,209,210],[61,63,70,118,135,136,203,204,205],[61,70,118,135,136],[61,63,70,118,135,136,203],[61,70,118,135,136,203],[70,118,135,136,216],[56,70,118,135,136,216,217],[56,70,118,135,136,216],[56,62,70,118,135,136],[57,70,118,135,136],[56,57,58,60,70,118,135,136],[56,70,118,135,136],[70,118,135,136,240,241],[70,118,135,136,240,241,242,243],[70,118,135,136,240,242],[70,118,135,136,240],[70,118,135,136,193],[70,118,135,136,191,193],[70,118,135,136,182,190,191,192,194,196],[70,118,135,136,180],[70,118,135,136,183,188,193,196],[70,118,135,136,179,196],[70,118,135,136,183,184,187,188,189,196],[70,118,135,136,183,184,185,187,188,196],[70,118,135,136,180,181,182,183,184,188,189,190,192,193,194,196],[70,118,135,136,196],[70,118,135,136,178,180,181,182,183,184,185,187,188,189,190,191,192,193,194,195],[70,118,135,136,178,196],[70,118,135,136,183,185,186,188,189,196],[70,118,135,136,187,196],[70,118,135,136,188,189,193,196],[70,118,135,136,181,191],[70,118,135,136,170,201,202],[70,118,135,136,169,170],[59,70,118,135,136],[70,83,87,118,135,136,161],[70,83,118,135,136,150,161],[70,78,118,135,136],[70,80,83,118,135,136,158,161],[70,118,135,136,138,158],[70,118,135,136,168],[70,78,118,135,136,168],[70,80,83,118,135,136,138,161],[70,75,76,79,82,118,129,135,136,150,161],[70,83,90,118,135,136],[70,75,81,118,135,136],[70,83,104,105,118,135,136],[70,79,83,118,135,136,153,161,168],[70,104,118,135,136,168],[70,77,78,118,135,136,168],[70,83,118,135,136],[70,77,78,79,80,81,82,83,84,85,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,105,106,107,108,109,110,118,135,136],[70,83,98,118,135,136],[70,83,90,91,118,135,136],[70,81,83,91,92,118,135,136],[70,82,118,135,136],[70,75,78,83,118,135,136],[70,83,87,91,92,118,135,136],[70,87,118,135,136],[70,81,83,86,118,135,136,161],[70,75,80,83,90,118,135,136],[70,118,135,136,150],[70,78,83,104,118,135,136,166,168],[70,118,135,136,213,214],[70,118,135,136,213],[70,118,129,130,132,133,134,135,136,138,150,158,161,167,168,170,171,172,173,175,176,177,197,198,199,200,201,202],[70,118,135,136,172,173,174,175],[70,118,135,136,172],[70,118,135,136,173],[70,118,135,136,170,202],[64,70,118,135,136,233,237],[70,118,135,136,206,225,226,237],[56,63,70,118,135,136,206,218,219,237],[70,118,135,136,228],[70,118,135,136,207],[56,64,70,118,135,136,206,208,218,227,237],[70,118,135,136,211],[56,61,63,70,118,121,130,135,136,150,202,206,208,211,212,215,218,220,221,224,227,229,230,232,237],[70,118,135,136,206,225,226,227,237],[70,118,135,136,202,231,232],[70,118,135,136,206,208,215,218,220,237],[70,118,135,136,166,221],[56,61,63,70,118,121,130,135,136,150,202,206,207,208,211,212,215,218,219,220,221,224,225,226,227,228,229,230,231,232,237],[55,56,61,63,64,70,118,121,130,135,136,150,166,202,206,207,208,211,212,215,218,219,220,221,224,225,226,227,228,229,230,231,232,236,237,238,239,244],[70,118,135,136,245],[52,70,118,135,136],[70,118,135,136,140,234]],"fileInfos":[{"version":"e41c290ef7dd7dab3493e6cbe5909e0148edf4a8dad0271be08edec368a0f7b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"4fd3f3422b2d2a3dfd5cdd0f387b3a8ec45f006c6ea896a4cb41264c2100bb2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"62bb211266ee48b2d0edf0d8d1b191f0c24fc379a82bd4c1692a082c540bc6b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"936e80ad36a2ee83fc3caf008e7c4c5afe45b3cf3d5c24408f039c1d47bdc1df","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"fef8cfad2e2dc5f5b3d97a6f4f2e92848eb1b88e897bb7318cef0e2820bceaab","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f1e2a172204962276504466a6393426d2ca9c54894b1ad0a6c9dad867a65f876","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"cecbac77473a402e83c3abc28129fc0f0877e6595b4cdf831d7570cb677cfce4","signature":"7bddb2a5f9621edfa6d8bdfb4b2020d152a2dea7977ffbf014db417730de28df","impliedFormat":99},{"version":"cf14b0cfce93ee98341f88873b01e8387a63257d3312056af8b05171322645b0","signature":"3bea5bb001c317046a4f8b2c73357c1c63eb0ef3e66702128658303a92ff6e86","impliedFormat":99},{"version":"8dc364b70826c578afa38589cdb40668886c3b960ac155a90cbb749788c9ccb9","signature":"9d8b24ac26b7e2b332b26cbb8610eb6efc8926e75dd5bbd42f8cfaca52b9d8eb","impliedFormat":99},{"version":"04471dc55f802c29791cc75edda8c4dd2a121f71c2401059da61eff83099e8ab","impliedFormat":99},{"version":"5c54a34e3d91727f7ae840bfe4d5d1c9a2f93c54cb7b6063d06ee4a6c3322656","impliedFormat":99},{"version":"db4da53b03596668cf6cc9484834e5de3833b9e7e64620cf08399fe069cd398d","impliedFormat":99},{"version":"ac7c28f153820c10850457994db1462d8c8e462f253b828ad942a979f726f2f9","impliedFormat":99},{"version":"f9b028d3c3891dd817e24d53102132b8f696269309605e6ed4f0db2c113bbd82","impliedFormat":99},{"version":"fb7c8d90e52e2884509166f96f3d591020c7b7977ab473b746954b0c8d100960","impliedFormat":99},{"version":"0bff51d6ed0c9093f6955b9d8258ce152ddb273359d50a897d8baabcb34de2c4","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"13918e2b81c4288695f9b1f3dcc2468caf0f848d5c1f3dc00071c619d34ff63a","impliedFormat":99},{"version":"120a80aa556732f684db3ed61aeff1d6671e1655bd6cba0aa88b22b88ac9a6b1","affectsGlobalScope":true,"impliedFormat":99},{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"bb45cd435da536500f1d9692a9b49d0c570b763ccbf00473248b777f5c1f353b","impliedFormat":1},{"version":"6b4e081d55ac24fc8a4631d5dd77fe249fa25900abd7d046abb87d90e3b45645","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"83e63d6ccf8ec004a3bb6d58b9bb0104f60e002754b1e968024b320730cc5311","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2bc7425ef40526650d6db7e072c1ff4a51101c3ac2cc4b666623b19496a6e27","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"f27524f4bef4b6519c604bdb23bf4465bddcccbf3f003abb901acbd0d7404d99","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"dba28a419aec76ed864ef43e5f577a5c99a010c32e5949fe4e17a4d57c58dd11","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c959a391a75be9789b43c8468f71e3fa06488b4d691d5729dde1416dcd38225b","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"0dba70b3fb0dcd713fda33c2df64fa6751fff6460e536971cee917260fb17882","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"9f663c2f91127ef7024e8ca4b3b4383ff2770e5f826696005de382282794b127","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"4e741b9c88e80c9e4cedf07b5a698e8e3a3bd73cf649f664d6dd3f868c05c2f3","affectsGlobalScope":true,"impliedFormat":1},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"11443a1dcfaaa404c68d53368b5b818712b95dd19f188cab1669c39bee8b84b3","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"035d0934d304483f07148427a5bd5b98ac265dae914a6b49749fe23fbd893ec7","impliedFormat":99},{"version":"e2ed5b81cbed3a511b21a18ab2539e79ac1f4bc1d1d28f8d35d8104caa3b429f","impliedFormat":99},{"version":"161c8e0690c46021506e32fda85956d785b70f309ae97011fd27374c065cac9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","impliedFormat":1},{"version":"333caa2bfff7f06017f114de738050dd99a765c7eb16571c6d25a38c0d5365dc","impliedFormat":1},{"version":"e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","impliedFormat":1},{"version":"459920181700cec8cbdf2a5faca127f3f17fd8dd9d9e577ed3f5f3af5d12a2e4","impliedFormat":1},{"version":"4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","impliedFormat":1},{"version":"7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","impliedFormat":1},{"version":"70790a7f0040993ca66ab8a07a059a0f8256e7bb57d968ae945f696cbff4ac7a","impliedFormat":1},{"version":"d1b9a81e99a0050ca7f2d98d7eedc6cda768f0eb9fa90b602e7107433e64c04c","impliedFormat":1},{"version":"a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","impliedFormat":1},{"version":"b215c4f0096f108020f666ffcc1f072c81e9f2f95464e894a5d5f34c5ea2a8b1","impliedFormat":1},{"version":"644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","impliedFormat":1},{"version":"dfe54dab1fa4961a6bcfba68c4ca955f8b5bbeb5f2ab3c915aa7adaa2eabc03a","impliedFormat":1},{"version":"1251d53755b03cde02466064260bb88fd83c30006a46395b7d9167340bc59b73","impliedFormat":1},{"version":"47865c5e695a382a916b1eedda1b6523145426e48a2eae4647e96b3b5e52024f","impliedFormat":1},{"version":"4cdf27e29feae6c7826cdd5c91751cc35559125e8304f9e7aed8faef97dcf572","impliedFormat":1},{"version":"331b8f71bfae1df25d564f5ea9ee65a0d847c4a94baa45925b6f38c55c7039bf","impliedFormat":1},{"version":"2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","impliedFormat":1},{"version":"0146fd6262c3fd3da51cb0254bb6b9a4e42931eb2f56329edd4c199cb9aaf804","impliedFormat":1},{"version":"183f480885db5caa5a8acb833c2be04f98056bdcc5fb29e969ff86e07efe57ab","impliedFormat":99},{"version":"4ec16d7a4e366c06a4573d299e15fe6207fc080f41beac5da06f4af33ea9761e","impliedFormat":1},{"version":"7870becb94cbc11d2d01b77c4422589adcba4d8e59f726246d40cd0d129784d8","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","impliedFormat":1},{"version":"f70b8328a15ca1d10b1436b691e134a49bc30dcf3183a69bfaa7ba77e1b78ecd","impliedFormat":1},{"version":"683b035f752e318d02e303894e767a1ac16ac4493baa2b593195d7976e6b7310","impliedFormat":99},{"version":"45cec9a1ba6549060552eead8959d47226048e0b71c7d0702ae58b7e16a28912","impliedFormat":99},{"version":"6907b09850f86610e7a528348c15484c1e1c09a18a9c1e98861399dfe4b18b46","impliedFormat":99},{"version":"12deea8eaa7a4fc1a2908e67da99831e5c5a6b46ad4f4f948fd4759314ea2b80","impliedFormat":99},{"version":"f0a8b376568a18f9a4976ecb0855187672b16b96c4df1c183a7e52dc1b5d98e8","impliedFormat":99},{"version":"8124828a11be7db984fcdab052fd4ff756b18edcfa8d71118b55388176210923","impliedFormat":99},{"version":"092944a8c05f9b96579161e88c6f211d5304a76bd2c47f8d4c30053269146bc8","impliedFormat":99},{"version":"b34b5f6b506abb206b1ea73c6a332b9ee9c8c98be0f6d17cdbda9430ecc1efab","impliedFormat":99},{"version":"75d4c746c3d16af0df61e7b0afe9606475a23335d9f34fcc525d388c21e9058b","impliedFormat":99},{"version":"fa959bf357232201c32566f45d97e70538c75a093c940af594865d12f31d4912","impliedFormat":99},{"version":"d2c52abd76259fc39a30dfae70a2e5ce77fd23144457a7ff1b64b03de6e3aec7","impliedFormat":99},{"version":"e6233e1c976265e85aa8ad76c3881febe6264cb06ae3136f0257e1eab4a6cc5a","impliedFormat":99},{"version":"f73e2335e568014e279927321770da6fe26facd4ac96cdc22a56687f1ecbb58e","impliedFormat":99},{"version":"317878f156f976d487e21fd1d58ad0461ee0a09185d5b0a43eedf2a56eb7e4ea","impliedFormat":99},{"version":"324ac98294dab54fbd580c7d0e707d94506d7b2c3d5efe981a8495f02cf9ad96","impliedFormat":99},{"version":"9ec72eb493ff209b470467e24264116b6a8616484bca438091433a545dfba17e","impliedFormat":99},{"version":"d6ee22aba183d5fc0c7b8617f77ee82ecadc2c14359cc51271c135e23f6ed51f","impliedFormat":99},{"version":"49747416f08b3ba50500a215e7a55d75268b84e31e896a40313c8053e8dec908","impliedFormat":99},{"version":"81e634f1c5e1ca309e7e3dc69e2732eea932ef07b8b34517d452e5a3e9a36fa3","impliedFormat":99},{"version":"34f39f75f2b5aa9c84a9f8157abbf8322e6831430e402badeaf58dd284f9b9a6","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"891694d3694abd66f0b8872997b85fd8e52bc51632ce0f8128c96962b443189f","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"971a2c327ff166c770c5fb35699575ba2d13bba1f6d2757309c9be4b30036c8e","impliedFormat":99},{"version":"4f45e8effab83434a78d17123b01124259fbd1e335732135c213955d85222234","impliedFormat":99},{"version":"7bd51996fb7717941cbe094b05adc0d80b9503b350a77b789bbb0fc786f28053","impliedFormat":99},{"version":"b62006bbc815fe8190c7aee262aad6bff993e3f9ade70d7057dfceab6de79d2f","impliedFormat":99},{"version":"13497c0d73306e27f70634c424cd2f3b472187164f36140b504b3756b0ff476d","impliedFormat":99},{"version":"a23a08b626aa4d4a1924957bd8c4d38a7ffc032e21407bbd2c97413e1d8c3dbd","impliedFormat":99},{"version":"c320fe76361c53cad266b46986aac4e68d644acda1629f64be29c95534463d28","impliedFormat":99},{"version":"7bbff6783e96c691a41a7cf12dd5486b8166a01b0c57d071dbcfca55c9525ec4","impliedFormat":99},{"version":"62551fca1c326304f190970a15aacc6c2196caae0088903ad061f1d4354df0f1","signature":"4b96dd19fd2949d28ce80e913412b0026dc421e5bf6c31d87c7b5eb11b5753b4","impliedFormat":99},{"version":"bf7a2d0f6d9e72d59044079d61000c38da50328ccdff28c47528a1a139c610ec","impliedFormat":99},{"version":"e58c0b5226aff07b63be6ac6e1bec9d55bc3d2bda3b11b9b68cccea8c24ae839","affectsGlobalScope":true,"impliedFormat":99},{"version":"5a88655bf852c8cc007d6bc874ab61d1d63fba97063020458177173c454e9b4a","impliedFormat":99},{"version":"7e4dfae2da12ec71ffd9f55f4641a6e05610ce0d6784838659490e259e4eb13c","impliedFormat":99},{"version":"c30a41267fc04c6518b17e55dcb2b810f267af4314b0b6d7df1c33a76ce1b330","impliedFormat":1},{"version":"72422d0bac4076912385d0c10911b82e4694fc106e2d70added091f88f0824ba","impliedFormat":1},{"version":"da251b82c25bee1d93f9fd80c5a61d945da4f708ca21285541d7aff83ecb8200","impliedFormat":1},{"version":"64db14db2bf37ac089766fdb3c7e1160fabc10e9929bc2deeede7237e4419fc8","impliedFormat":1},{"version":"98b94085c9f78eba36d3d2314affe973e8994f99864b8708122750788825c771","impliedFormat":1},{"version":"13573a613314e40482386fe9c7934f9d86f3e06f19b840466c75391fb833b99b","impliedFormat":99},{"version":"ed09d42b14a604190e8c9fc972d18ea47d5c03c6c4a0003c9620dca915a1973d","affectsGlobalScope":true,"impliedFormat":99}],"root":[[52,54],235],"options":{"composite":true,"declaration":true,"declarationMap":false,"emitDeclarationOnly":false,"module":199,"outDir":"./","target":8},"referencedMap":[[54,1],[224,2],[222,3],[169,3],[115,4],[116,4],[117,5],[70,6],[118,7],[119,8],[120,9],[65,3],[68,10],[66,3],[67,3],[121,11],[122,12],[123,13],[124,14],[125,15],[126,16],[127,16],[128,17],[129,18],[130,19],[131,20],[71,3],[69,3],[132,21],[133,22],[134,23],[168,24],[135,25],[136,3],[137,26],[138,27],[139,28],[140,29],[141,30],[142,31],[143,32],[144,33],[145,34],[146,34],[147,35],[148,3],[149,36],[150,37],[152,38],[151,39],[153,40],[154,41],[155,42],[156,43],[157,44],[158,45],[159,46],[160,47],[161,48],[162,49],[163,50],[164,51],[165,52],[72,3],[73,3],[74,3],[112,53],[113,3],[114,3],[166,54],[167,55],[64,56],[211,57],[209,3],[210,3],[56,3],[206,58],[203,59],[204,60],[225,61],[216,3],[219,62],[218,63],[230,63],[217,64],[55,3],[63,65],[205,65],[58,66],[61,67],[212,66],[62,68],[57,3],[223,3],[177,3],[242,69],[244,70],[243,71],[241,72],[240,3],[194,73],[192,74],[193,75],[181,76],[182,74],[189,77],[180,78],[185,79],[195,3],[186,80],[191,81],[197,82],[196,83],[179,84],[187,85],[188,86],[183,87],[190,73],[184,88],[171,89],[170,90],[178,3],[226,3],[59,3],[60,91],[50,3],[51,3],[9,3],[11,3],[10,3],[2,3],[12,3],[13,3],[14,3],[15,3],[16,3],[17,3],[18,3],[19,3],[3,3],[20,3],[21,3],[4,3],[22,3],[26,3],[23,3],[24,3],[25,3],[27,3],[28,3],[29,3],[5,3],[30,3],[31,3],[32,3],[33,3],[6,3],[37,3],[34,3],[35,3],[36,3],[38,3],[7,3],[39,3],[44,3],[45,3],[40,3],[41,3],[42,3],[43,3],[8,3],[49,3],[46,3],[47,3],[48,3],[1,3],[90,92],[100,93],[89,92],[110,94],[81,95],[80,96],[109,97],[103,98],[108,99],[83,100],[97,101],[82,102],[106,103],[78,104],[77,97],[107,105],[79,106],[84,107],[85,3],[88,107],[75,3],[111,108],[101,109],[92,110],[93,111],[95,112],[91,113],[94,114],[104,97],[86,115],[87,116],[96,117],[76,118],[99,109],[98,107],[102,3],[105,119],[228,120],[214,121],[215,120],[213,3],[202,122],[176,123],[175,124],[173,124],[172,3],[174,125],[200,3],[199,3],[198,3],[201,126],[234,127],[227,128],[220,129],[229,130],[208,131],[237,132],[238,133],[231,134],[239,135],[232,136],[221,137],[236,138],[233,139],[245,140],[246,141],[207,3],[53,142],[52,3],[235,143]],"latestChangedDtsFile":"./vitest.config.d.ts","version":"5.7.3"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: "node",
|
|
7
|
+
include: ["src/**/*.test.ts", "tests/**/*.test.ts"],
|
|
8
|
+
pool: "threads",
|
|
9
|
+
poolOptions: {
|
|
10
|
+
threads: {
|
|
11
|
+
minThreads: 1,
|
|
12
|
+
maxThreads: 1,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
coverage: {
|
|
16
|
+
provider: "v8",
|
|
17
|
+
reporter: ["text", "json", "html", "lcov"],
|
|
18
|
+
reportsDirectory: "coverage",
|
|
19
|
+
exclude: [
|
|
20
|
+
"index.ts",
|
|
21
|
+
"src/types/**",
|
|
22
|
+
"dist/**",
|
|
23
|
+
"**/*.d.ts",
|
|
24
|
+
"vite.config.ts",
|
|
25
|
+
"vitest.config.ts",
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
resolve: {
|
|
30
|
+
alias: {
|
|
31
|
+
"@": resolve(__dirname),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skivuha/img-shrink",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tiny browser-first image resizer with crop/contain and compression.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Igor Danylov <skivuha@hotmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/js-nerds/img-shrink.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/js-nerds/img-shrink/issues",
|
|
13
|
+
"homepage": "https://github.com/js-nerds/img-shrink#readme",
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18.0.0"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"image",
|
|
22
|
+
"resize",
|
|
23
|
+
"compress",
|
|
24
|
+
"shrink",
|
|
25
|
+
"crop",
|
|
26
|
+
"canvas",
|
|
27
|
+
"browser",
|
|
28
|
+
"file",
|
|
29
|
+
"blob",
|
|
30
|
+
"webp",
|
|
31
|
+
"jpeg",
|
|
32
|
+
"png"
|
|
33
|
+
],
|
|
34
|
+
"main": "./dist/cjs/index.cjs",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js",
|
|
41
|
+
"require": "./dist/cjs/index.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist"
|
|
46
|
+
],
|
|
47
|
+
"sideEffects": false,
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"@vitest/coverage-v8": "^3.2.3",
|
|
51
|
+
"@vitest/ui": "^3.2.3",
|
|
52
|
+
"typescript": "~5.7.2",
|
|
53
|
+
"vite": "^6.3.5",
|
|
54
|
+
"vitest": "^3.2.3"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc --project tsconfig.json && tsc --project tsconfig.cjs.json && mv dist/cjs/index.js dist/cjs/index.cjs",
|
|
58
|
+
"build:esm": "tsc --project tsconfig.json",
|
|
59
|
+
"build:cjs": "tsc --project tsconfig.cjs.json && mv dist/cjs/index.js dist/cjs/index.cjs",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:ui": "vitest --ui",
|
|
62
|
+
"test:coverage": "vitest run --coverage",
|
|
63
|
+
"build:vite": "vite build && tsc --emitDeclarationOnly"
|
|
64
|
+
}
|
|
65
|
+
}
|