@flighthq/image-codec 0.5.1-next.1556.ff9e615 → 0.5.1-next.1584.db3c393
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/contract.d.ts +0 -4
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +0 -4
- package/dist/contract.js.map +1 -1
- package/dist/decodeImage.d.ts +3 -3
- package/dist/decodeImage.d.ts.map +1 -1
- package/dist/decodeImage.js +28 -16
- package/dist/decodeImage.js.map +1 -1
- package/dist/encodeImage.d.ts +2 -2
- package/dist/encodeImage.d.ts.map +1 -1
- package/dist/encodeImage.js +16 -7
- package/dist/encodeImage.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/decodeImage.test.ts +36 -35
- package/src/encodeImage.test.ts +20 -17
- package/dist/explainImageDecodeFailure.d.ts +0 -3
- package/dist/explainImageDecodeFailure.d.ts.map +0 -1
- package/dist/explainImageDecodeFailure.js +0 -13
- package/dist/explainImageDecodeFailure.js.map +0 -1
- package/dist/explainImageEncodeFailure.d.ts +0 -3
- package/dist/explainImageEncodeFailure.d.ts.map +0 -1
- package/dist/explainImageEncodeFailure.js +0 -9
- package/dist/explainImageEncodeFailure.js.map +0 -1
- package/dist/imageDecoderRegistry.d.ts +0 -8
- package/dist/imageDecoderRegistry.d.ts.map +0 -1
- package/dist/imageDecoderRegistry.js +0 -25
- package/dist/imageDecoderRegistry.js.map +0 -1
- package/dist/imageEncoderRegistry.d.ts +0 -8
- package/dist/imageEncoderRegistry.d.ts.map +0 -1
- package/dist/imageEncoderRegistry.js +0 -25
- package/dist/imageEncoderRegistry.js.map +0 -1
- package/src/explainImageDecodeFailure.test.ts +0 -37
- package/src/explainImageEncodeFailure.test.ts +0 -24
- package/src/imageDecoderRegistry.test.ts +0 -84
- package/src/imageEncoderRegistry.test.ts +0 -80
package/README.md
CHANGED
|
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/image-codec`. The `@
|
|
|
13
13
|
This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
|
|
14
14
|
|
|
15
15
|
- [Flight project](https://github.com/flighthq/flight)
|
|
16
|
-
- [Source for @flighthq/image-codec@0.5.1-next.
|
|
17
|
-
- [License](https://github.com/flighthq/flight/blob/
|
|
16
|
+
- [Source for @flighthq/image-codec@0.5.1-next.1584.db3c393](https://github.com/flighthq/flight/tree/db3c393cc51ac6ab80c0fa7e6af97ef7b354298c/packages/image-codec)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/db3c393cc51ac6ab80c0fa7e6af97ef7b354298c/LICENSE.md)
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export * from './decodeImage';
|
|
2
2
|
export * from './detectImageMimeType';
|
|
3
3
|
export * from './encodeImage';
|
|
4
|
-
export * from './explainImageDecodeFailure';
|
|
5
|
-
export * from './explainImageEncodeFailure';
|
|
6
|
-
export * from './imageDecoderRegistry';
|
|
7
|
-
export * from './imageEncoderRegistry';
|
|
8
4
|
//# sourceMappingURL=contract.d.ts.map
|
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC"}
|
package/dist/contract.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export * from './decodeImage';
|
|
2
2
|
export * from './detectImageMimeType';
|
|
3
3
|
export * from './encodeImage';
|
|
4
|
-
export * from './explainImageDecodeFailure';
|
|
5
|
-
export * from './explainImageEncodeFailure';
|
|
6
|
-
export * from './imageDecoderRegistry';
|
|
7
|
-
export * from './imageEncoderRegistry';
|
|
8
4
|
//# sourceMappingURL=contract.js.map
|
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC"}
|
package/dist/decodeImage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DecodedImage } from '@flighthq/types/contract';
|
|
2
|
-
export declare function decodeImage(bytes: Readonly<Uint8Array>, mimeType?: string): Promise<DecodedImage | null>;
|
|
3
|
-
export declare function decodeImagePremultiplied(bytes: Readonly<Uint8Array>, mimeType?: string): Promise<DecodedImage | null>;
|
|
1
|
+
import type { DecodedImage, HostImageDecodeCapabilities } from '@flighthq/types/contract';
|
|
2
|
+
export declare function decodeImage(imageDecode: Readonly<HostImageDecodeCapabilities>, bytes: Readonly<Uint8Array>, mimeType?: string): Promise<DecodedImage | null>;
|
|
3
|
+
export declare function decodeImagePremultiplied(imageDecode: Readonly<HostImageDecodeCapabilities>, bytes: Readonly<Uint8Array>, mimeType?: string): Promise<DecodedImage | null>;
|
|
4
4
|
//# sourceMappingURL=decodeImage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decodeImage.d.ts","sourceRoot":"","sources":["../src/decodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"decodeImage.d.ts","sourceRoot":"","sources":["../src/decodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,2BAA2B,EAE5B,MAAM,0BAA0B,CAAC;AAIlC,wBAAsB,WAAW,CAC/B,WAAW,EAAE,QAAQ,CAAC,2BAA2B,CAAC,EAClD,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAI9B;AAED,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,QAAQ,CAAC,2BAA2B,CAAC,EAClD,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAI9B"}
|
package/dist/decodeImage.js
CHANGED
|
@@ -1,26 +1,38 @@
|
|
|
1
1
|
import { detectImageMimeType } from './detectImageMimeType';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// when the type cannot be determined or no decoder is registered for it.
|
|
6
|
-
export async function decodeImage(bytes, mimeType) {
|
|
7
|
-
const decoder = resolveImageDecoder(bytes, mimeType);
|
|
8
|
-
if (decoder === null)
|
|
2
|
+
export async function decodeImage(imageDecode, bytes, mimeType) {
|
|
3
|
+
const slot = resolveDecodeSlot(imageDecode, bytes, mimeType);
|
|
4
|
+
if (slot === null)
|
|
9
5
|
return null;
|
|
10
|
-
return
|
|
6
|
+
return slot.decode(bytes);
|
|
11
7
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const decoder = resolveImageDecoder(bytes, mimeType);
|
|
16
|
-
if (decoder === null)
|
|
8
|
+
export async function decodeImagePremultiplied(imageDecode, bytes, mimeType) {
|
|
9
|
+
const slot = resolveDecodeSlot(imageDecode, bytes, mimeType);
|
|
10
|
+
if (slot === null)
|
|
17
11
|
return null;
|
|
18
|
-
return
|
|
12
|
+
return slot.decode(bytes, { premultiplyAlpha: true });
|
|
19
13
|
}
|
|
20
|
-
function
|
|
14
|
+
function resolveDecodeSlot(imageDecode, bytes, mimeType) {
|
|
21
15
|
const type = mimeType ?? detectImageMimeType(bytes);
|
|
22
16
|
if (type === null)
|
|
23
17
|
return null;
|
|
24
|
-
return
|
|
18
|
+
return getImageDecodeSlot(imageDecode, type);
|
|
19
|
+
}
|
|
20
|
+
function getImageDecodeSlot(imageDecode, mimeType) {
|
|
21
|
+
switch (mimeType) {
|
|
22
|
+
case 'image/avif':
|
|
23
|
+
return imageDecode.avif ?? null;
|
|
24
|
+
case 'image/bmp':
|
|
25
|
+
return imageDecode.bmp ?? null;
|
|
26
|
+
case 'image/gif':
|
|
27
|
+
return imageDecode.gif ?? null;
|
|
28
|
+
case 'image/jpeg':
|
|
29
|
+
return imageDecode.jpeg ?? null;
|
|
30
|
+
case 'image/png':
|
|
31
|
+
return imageDecode.png ?? null;
|
|
32
|
+
case 'image/webp':
|
|
33
|
+
return imageDecode.webp ?? null;
|
|
34
|
+
default:
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
25
37
|
}
|
|
26
38
|
//# sourceMappingURL=decodeImage.js.map
|
package/dist/decodeImage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decodeImage.js","sourceRoot":"","sources":["../src/decodeImage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decodeImage.js","sourceRoot":"","sources":["../src/decodeImage.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAkD,EAClD,KAA2B,EAC3B,QAAiB;IAEjB,MAAM,IAAI,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC7D,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,WAAkD,EAClD,KAA2B,EAC3B,QAAiB;IAEjB,MAAM,IAAI,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC7D,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,iBAAiB,CACxB,WAAkD,EAClD,KAA2B,EAC3B,QAAiB;IAEjB,MAAM,IAAI,GAAG,QAAQ,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,kBAAkB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,kBAAkB,CACzB,WAAkD,EAClD,QAAgB;IAEhB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,YAAY;YACf,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC,KAAK,WAAW;YACd,OAAO,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC;QACjC,KAAK,WAAW;YACd,OAAO,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC,KAAK,WAAW;YACd,OAAO,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/dist/encodeImage.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { DecodedImage, ImageEncodeOptions } from '@flighthq/types/contract';
|
|
2
|
-
export declare function encodeImage(image: Readonly<DecodedImage>, mimeType: string, options?: Readonly<ImageEncodeOptions>): Promise<Uint8Array | null>;
|
|
1
|
+
import type { DecodedImage, HostImageEncodeCapabilities, ImageEncodeOptions } from '@flighthq/types/contract';
|
|
2
|
+
export declare function encodeImage(imageEncode: Readonly<HostImageEncodeCapabilities>, image: Readonly<DecodedImage>, mimeType: string, options?: Readonly<ImageEncodeOptions>): Promise<Uint8Array | null>;
|
|
3
3
|
//# sourceMappingURL=encodeImage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encodeImage.d.ts","sourceRoot":"","sources":["../src/encodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"encodeImage.d.ts","sourceRoot":"","sources":["../src/encodeImage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,2BAA2B,EAE3B,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAElC,wBAAsB,WAAW,CAC/B,WAAW,EAAE,QAAQ,CAAC,2BAA2B,CAAC,EAClD,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,EAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GACrC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAI5B"}
|
package/dist/encodeImage.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export async function encodeImage(image, mimeType, options) {
|
|
5
|
-
const encoder = getImageEncoder(mimeType);
|
|
6
|
-
if (encoder === null)
|
|
1
|
+
export async function encodeImage(imageEncode, image, mimeType, options) {
|
|
2
|
+
const slot = getImageEncodeSlot(imageEncode, mimeType);
|
|
3
|
+
if (slot === null)
|
|
7
4
|
return null;
|
|
8
|
-
return
|
|
5
|
+
return slot.encode(image, options);
|
|
6
|
+
}
|
|
7
|
+
function getImageEncodeSlot(imageEncode, mimeType) {
|
|
8
|
+
switch (mimeType) {
|
|
9
|
+
case 'image/jpeg':
|
|
10
|
+
return imageEncode.jpeg ?? null;
|
|
11
|
+
case 'image/png':
|
|
12
|
+
return imageEncode.png ?? null;
|
|
13
|
+
case 'image/webp':
|
|
14
|
+
return imageEncode.webp ?? null;
|
|
15
|
+
default:
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
9
18
|
}
|
|
10
19
|
//# sourceMappingURL=encodeImage.js.map
|
package/dist/encodeImage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encodeImage.js","sourceRoot":"","sources":["../src/encodeImage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"encodeImage.js","sourceRoot":"","sources":["../src/encodeImage.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAkD,EAClD,KAA6B,EAC7B,QAAgB,EAChB,OAAsC;IAEtC,MAAM,IAAI,GAAG,kBAAkB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,kBAAkB,CACzB,WAAkD,EAClD,QAAgB;IAEhB,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,YAAY;YACf,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC,KAAK,WAAW;YACd,OAAO,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC;QACjC,KAAK,YAAY;YACf,OAAO,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC;QAClC;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/image-codec",
|
|
3
|
-
"version": "0.5.1-next.
|
|
3
|
+
"version": "0.5.1-next.1584.db3c393",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/types": "0.5.1-next.
|
|
41
|
+
"@flighthq/types": "0.5.1-next.1584.db3c393"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"typescript": "^5.3.0"
|
package/src/decodeImage.test.ts
CHANGED
|
@@ -1,70 +1,71 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
DecodedImage,
|
|
3
|
+
HostImageDecodeCapabilities,
|
|
4
|
+
HostImageDecodeFormatCapability,
|
|
5
|
+
} from '@flighthq/types/contract';
|
|
2
6
|
import { vi } from 'vitest';
|
|
3
7
|
|
|
4
8
|
import { decodeImage, decodeImagePremultiplied } from './decodeImage';
|
|
5
|
-
import { clearImageDecoders, registerImageDecoder } from './imageDecoderRegistry';
|
|
6
9
|
|
|
7
|
-
// PNG magic bytes so the omitted-mimeType path resolves through detectImageMimeType.
|
|
8
10
|
const pngBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
9
11
|
|
|
10
12
|
function fakeDecoded(): DecodedImage {
|
|
11
13
|
return { data: new Uint8ClampedArray([1, 2, 3, 4]), width: 1, height: 1 };
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
16
|
+
function fakeSlot(): HostImageDecodeFormatCapability {
|
|
17
|
+
return { decode: vi.fn(async () => fakeDecoded()) };
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
describe('decodeImage', () => {
|
|
19
|
-
it('auto-detects the MIME type when omitted and dispatches to the
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const result = await decodeImage(pngBytes);
|
|
21
|
+
it('auto-detects the MIME type when omitted and dispatches to the capability slot', async () => {
|
|
22
|
+
const slot = fakeSlot();
|
|
23
|
+
const caps: HostImageDecodeCapabilities = { png: slot };
|
|
24
|
+
const result = await decodeImage(caps, pngBytes);
|
|
23
25
|
expect(result).toEqual(fakeDecoded());
|
|
24
|
-
expect(
|
|
26
|
+
expect(slot.decode).toHaveBeenCalledWith(pngBytes);
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
it('uses an explicit MIME type over detection', async () => {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
await decodeImage(pngBytes, 'image/jpeg');
|
|
31
|
-
expect(
|
|
30
|
+
const slot = fakeSlot();
|
|
31
|
+
const caps: HostImageDecodeCapabilities = { jpeg: slot };
|
|
32
|
+
await decodeImage(caps, pngBytes, 'image/jpeg');
|
|
33
|
+
expect(slot.decode).toHaveBeenCalledOnce();
|
|
32
34
|
});
|
|
33
35
|
|
|
34
|
-
it('returns null when no
|
|
35
|
-
expect(await decodeImage(pngBytes)).toBeNull();
|
|
36
|
+
it('returns null when no slot is present for the detected type', async () => {
|
|
37
|
+
expect(await decodeImage({}, pngBytes)).toBeNull();
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
it('returns null when the MIME type cannot be determined', async () => {
|
|
39
|
-
|
|
41
|
+
const caps: HostImageDecodeCapabilities = { png: fakeSlot() };
|
|
42
|
+
expect(await decodeImage(caps, new Uint8Array([0, 1, 2, 3]))).toBeNull();
|
|
40
43
|
});
|
|
41
44
|
|
|
42
45
|
it('does not request premultiplied output', async () => {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
await decodeImage(pngBytes);
|
|
46
|
-
expect(
|
|
46
|
+
const slot = fakeSlot();
|
|
47
|
+
const caps: HostImageDecodeCapabilities = { png: slot };
|
|
48
|
+
await decodeImage(caps, pngBytes);
|
|
49
|
+
expect(slot.decode).toHaveBeenCalledWith(pngBytes);
|
|
47
50
|
});
|
|
48
51
|
});
|
|
49
52
|
|
|
50
53
|
describe('decodeImagePremultiplied', () => {
|
|
51
|
-
it('passes premultiplyAlpha true to the
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
await decodeImagePremultiplied(pngBytes, 'image/png');
|
|
57
|
-
expect(decoder).toHaveBeenCalledWith(pngBytes, { premultiplyAlpha: true });
|
|
54
|
+
it('passes premultiplyAlpha true to the slot', async () => {
|
|
55
|
+
const slot = fakeSlot();
|
|
56
|
+
const caps: HostImageDecodeCapabilities = { png: slot };
|
|
57
|
+
await decodeImagePremultiplied(caps, pngBytes, 'image/png');
|
|
58
|
+
expect(slot.decode).toHaveBeenCalledWith(pngBytes, { premultiplyAlpha: true });
|
|
58
59
|
});
|
|
59
60
|
|
|
60
61
|
it('auto-detects the MIME type when omitted', async () => {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
expect(await decodeImagePremultiplied(pngBytes)).toEqual(fakeDecoded());
|
|
64
|
-
expect(
|
|
62
|
+
const slot = fakeSlot();
|
|
63
|
+
const caps: HostImageDecodeCapabilities = { png: slot };
|
|
64
|
+
expect(await decodeImagePremultiplied(caps, pngBytes)).toEqual(fakeDecoded());
|
|
65
|
+
expect(slot.decode).toHaveBeenCalledWith(pngBytes, { premultiplyAlpha: true });
|
|
65
66
|
});
|
|
66
67
|
|
|
67
|
-
it('returns null when no
|
|
68
|
-
expect(await decodeImagePremultiplied(pngBytes)).toBeNull();
|
|
68
|
+
it('returns null when no slot is present for the detected type', async () => {
|
|
69
|
+
expect(await decodeImagePremultiplied({}, pngBytes)).toBeNull();
|
|
69
70
|
});
|
|
70
71
|
});
|
package/src/encodeImage.test.ts
CHANGED
|
@@ -1,37 +1,40 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
DecodedImage,
|
|
3
|
+
HostImageEncodeCapabilities,
|
|
4
|
+
HostImageEncodeFormatCapability,
|
|
5
|
+
} from '@flighthq/types/contract';
|
|
2
6
|
import { vi } from 'vitest';
|
|
3
7
|
|
|
4
8
|
import { encodeImage } from './encodeImage';
|
|
5
|
-
import { clearImageEncoders, registerImageEncoder } from './imageEncoderRegistry';
|
|
6
9
|
|
|
7
10
|
function fakeImage(): DecodedImage {
|
|
8
11
|
return { data: new Uint8ClampedArray([1, 2, 3, 4]), width: 1, height: 1 };
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
+
function fakeSlot(result: Uint8Array = new Uint8Array(0)): HostImageEncodeFormatCapability {
|
|
15
|
+
return { encode: vi.fn(async () => result) };
|
|
16
|
+
}
|
|
14
17
|
|
|
15
18
|
describe('encodeImage', () => {
|
|
16
|
-
it('dispatches to the
|
|
19
|
+
it('dispatches to the capability slot and returns its bytes', async () => {
|
|
17
20
|
const bytes = new Uint8Array([9, 8, 7]);
|
|
18
|
-
const
|
|
19
|
-
|
|
21
|
+
const slot = fakeSlot(bytes);
|
|
22
|
+
const caps: HostImageEncodeCapabilities = { png: slot };
|
|
20
23
|
const image = fakeImage();
|
|
21
|
-
const result = await encodeImage(image, 'image/png');
|
|
24
|
+
const result = await encodeImage(caps, image, 'image/png');
|
|
22
25
|
expect(result).toBe(bytes);
|
|
23
|
-
expect(
|
|
26
|
+
expect(slot.encode).toHaveBeenCalledWith(image, undefined);
|
|
24
27
|
});
|
|
25
28
|
|
|
26
|
-
it('forwards encode options to the
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
+
it('forwards encode options to the slot', async () => {
|
|
30
|
+
const slot = fakeSlot();
|
|
31
|
+
const caps: HostImageEncodeCapabilities = { jpeg: slot };
|
|
29
32
|
const image = fakeImage();
|
|
30
|
-
await encodeImage(image, 'image/jpeg', { quality: 0.5 });
|
|
31
|
-
expect(
|
|
33
|
+
await encodeImage(caps, image, 'image/jpeg', { quality: 0.5 });
|
|
34
|
+
expect(slot.encode).toHaveBeenCalledWith(image, { quality: 0.5 });
|
|
32
35
|
});
|
|
33
36
|
|
|
34
|
-
it('returns null when no
|
|
35
|
-
expect(await encodeImage(fakeImage(), 'image/png')).toBeNull();
|
|
37
|
+
it('returns null when no slot is present for the MIME type', async () => {
|
|
38
|
+
expect(await encodeImage({}, fakeImage(), 'image/png')).toBeNull();
|
|
36
39
|
});
|
|
37
40
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"explainImageDecodeFailure.d.ts","sourceRoot":"","sources":["../src/explainImageDecodeFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAO9E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,6BAA6B,GAAG,IAAI,CAKtC"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { detectImageMimeType } from './detectImageMimeType';
|
|
2
|
-
import { getImageDecoder } from './imageDecoderRegistry';
|
|
3
|
-
// Explains the two dispatcher failures that decodeImage represents with null. Returns null when the
|
|
4
|
-
// same request can reach a registered decoder. This is a read-only query and never invokes the codec.
|
|
5
|
-
export function explainImageDecodeFailure(bytes, mimeType) {
|
|
6
|
-
const type = mimeType ?? detectImageMimeType(bytes);
|
|
7
|
-
if (type === null)
|
|
8
|
-
return { mimeType: null, reason: 'mime-type-undetected' };
|
|
9
|
-
if (getImageDecoder(type) === null)
|
|
10
|
-
return { mimeType: type, reason: 'decoder-not-registered' };
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=explainImageDecodeFailure.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"explainImageDecodeFailure.js","sourceRoot":"","sources":["../src/explainImageDecodeFailure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,oGAAoG;AACpG,sGAAsG;AACtG,MAAM,UAAU,yBAAyB,CACvC,KAA2B,EAC3B,QAAiB;IAEjB,MAAM,IAAI,GAAG,QAAQ,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACpD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC7E,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAChG,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"explainImageEncodeFailure.d.ts","sourceRoot":"","sources":["../src/explainImageEncodeFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAM9E,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,6BAA6B,GAAG,IAAI,CAGhG"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { getImageEncoder } from './imageEncoderRegistry';
|
|
2
|
-
// Explains the dispatcher failure that encodeImage represents with null. Returns null when an encoder
|
|
3
|
-
// is registered for the requested MIME type. This is a read-only query and never invokes the codec.
|
|
4
|
-
export function explainImageEncodeFailure(mimeType) {
|
|
5
|
-
if (getImageEncoder(mimeType) !== null)
|
|
6
|
-
return null;
|
|
7
|
-
return { mimeType, reason: 'encoder-not-registered' };
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=explainImageEncodeFailure.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"explainImageEncodeFailure.js","sourceRoot":"","sources":["../src/explainImageEncodeFailure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,sGAAsG;AACtG,oGAAoG;AACpG,MAAM,UAAU,yBAAyB,CAAC,QAAgB;IACxD,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;AACxD,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ImageDecoder } from '@flighthq/types/contract';
|
|
2
|
-
export declare function clearImageDecoders(): void;
|
|
3
|
-
export declare function getImageDecoder(mimeType: string): ImageDecoder | null;
|
|
4
|
-
export declare function getImageDecoderMimeTypes(): readonly string[];
|
|
5
|
-
export declare function hasImageDecoder(mimeType: string): boolean;
|
|
6
|
-
export declare function registerImageDecoder(mimeType: string, decoder: ImageDecoder): void;
|
|
7
|
-
export declare function unregisterImageDecoder(mimeType: string): void;
|
|
8
|
-
//# sourceMappingURL=imageDecoderRegistry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageDecoderRegistry.d.ts","sourceRoot":"","sources":["../src/imageDecoderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAErE;AAID,wBAAgB,wBAAwB,IAAI,SAAS,MAAM,EAAE,CAE5D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAElF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE7D"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export function clearImageDecoders() {
|
|
2
|
-
decoders.clear();
|
|
3
|
-
}
|
|
4
|
-
export function getImageDecoder(mimeType) {
|
|
5
|
-
return decoders.get(mimeType) ?? null;
|
|
6
|
-
}
|
|
7
|
-
// Returns an insertion-ordered snapshot of the MIME types with registered decoders. Mutating the
|
|
8
|
-
// returned array cannot change registry state.
|
|
9
|
-
export function getImageDecoderMimeTypes() {
|
|
10
|
-
return Array.from(decoders.keys());
|
|
11
|
-
}
|
|
12
|
-
export function hasImageDecoder(mimeType) {
|
|
13
|
-
return decoders.has(mimeType);
|
|
14
|
-
}
|
|
15
|
-
export function registerImageDecoder(mimeType, decoder) {
|
|
16
|
-
decoders.set(mimeType, decoder);
|
|
17
|
-
}
|
|
18
|
-
export function unregisterImageDecoder(mimeType) {
|
|
19
|
-
decoders.delete(mimeType);
|
|
20
|
-
}
|
|
21
|
-
// Global MIME-keyed decoder registry. Empty at import — only register* populates it, so importing this
|
|
22
|
-
// package has no side effects. Last-write-wins: a native host can override the web decoder for a MIME
|
|
23
|
-
// type by registering after registerWebImageDecoders.
|
|
24
|
-
const decoders = new Map();
|
|
25
|
-
//# sourceMappingURL=imageDecoderRegistry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageDecoderRegistry.js","sourceRoot":"","sources":["../src/imageDecoderRegistry.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAED,iGAAiG;AACjG,+CAA+C;AAC/C,MAAM,UAAU,wBAAwB;IACtC,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,OAAqB;IAC1E,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,uGAAuG;AACvG,sGAAsG;AACtG,sDAAsD;AACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ImageEncoder } from '@flighthq/types/contract';
|
|
2
|
-
export declare function clearImageEncoders(): void;
|
|
3
|
-
export declare function getImageEncoder(mimeType: string): ImageEncoder | null;
|
|
4
|
-
export declare function getImageEncoderMimeTypes(): readonly string[];
|
|
5
|
-
export declare function hasImageEncoder(mimeType: string): boolean;
|
|
6
|
-
export declare function registerImageEncoder(mimeType: string, encoder: ImageEncoder): void;
|
|
7
|
-
export declare function unregisterImageEncoder(mimeType: string): void;
|
|
8
|
-
//# sourceMappingURL=imageEncoderRegistry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageEncoderRegistry.d.ts","sourceRoot":"","sources":["../src/imageEncoderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAErE;AAID,wBAAgB,wBAAwB,IAAI,SAAS,MAAM,EAAE,CAE5D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAElF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE7D"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export function clearImageEncoders() {
|
|
2
|
-
encoders.clear();
|
|
3
|
-
}
|
|
4
|
-
export function getImageEncoder(mimeType) {
|
|
5
|
-
return encoders.get(mimeType) ?? null;
|
|
6
|
-
}
|
|
7
|
-
// Returns an insertion-ordered snapshot of the MIME types with registered encoders. Mutating the
|
|
8
|
-
// returned array cannot change registry state.
|
|
9
|
-
export function getImageEncoderMimeTypes() {
|
|
10
|
-
return Array.from(encoders.keys());
|
|
11
|
-
}
|
|
12
|
-
export function hasImageEncoder(mimeType) {
|
|
13
|
-
return encoders.has(mimeType);
|
|
14
|
-
}
|
|
15
|
-
export function registerImageEncoder(mimeType, encoder) {
|
|
16
|
-
encoders.set(mimeType, encoder);
|
|
17
|
-
}
|
|
18
|
-
export function unregisterImageEncoder(mimeType) {
|
|
19
|
-
encoders.delete(mimeType);
|
|
20
|
-
}
|
|
21
|
-
// Global MIME-keyed encoder registry. Empty at import — only register* populates it, so importing this
|
|
22
|
-
// package has no side effects. Last-write-wins: a native host can override the web encoder for a MIME
|
|
23
|
-
// type by registering after registerWebImageEncoders.
|
|
24
|
-
const encoders = new Map();
|
|
25
|
-
//# sourceMappingURL=imageEncoderRegistry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageEncoderRegistry.js","sourceRoot":"","sources":["../src/imageEncoderRegistry.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB;IAChC,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAED,iGAAiG;AACjG,+CAA+C;AAC/C,MAAM,UAAU,wBAAwB;IACtC,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,OAAqB;IAC1E,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,uGAAuG;AACvG,sGAAsG;AACtG,sDAAsD;AACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { explainImageDecodeFailure } from './explainImageDecodeFailure';
|
|
4
|
-
import { clearImageDecoders, registerImageDecoder } from './imageDecoderRegistry';
|
|
5
|
-
|
|
6
|
-
const pngBytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
7
|
-
|
|
8
|
-
afterEach(() => {
|
|
9
|
-
clearImageDecoders();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe('explainImageDecodeFailure', () => {
|
|
13
|
-
it('distinguishes an undetected MIME type from a missing decoder', () => {
|
|
14
|
-
expect(explainImageDecodeFailure(new Uint8Array([0, 1, 2, 3]))).toEqual({
|
|
15
|
-
mimeType: null,
|
|
16
|
-
reason: 'mime-type-undetected',
|
|
17
|
-
});
|
|
18
|
-
expect(explainImageDecodeFailure(pngBytes)).toEqual({
|
|
19
|
-
mimeType: 'image/png',
|
|
20
|
-
reason: 'decoder-not-registered',
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('reports the explicit MIME type when its decoder is missing', () => {
|
|
25
|
-
expect(explainImageDecodeFailure(pngBytes, 'image/custom')).toEqual({
|
|
26
|
-
mimeType: 'image/custom',
|
|
27
|
-
reason: 'decoder-not-registered',
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('returns null without invoking a registered decoder', () => {
|
|
32
|
-
const decoder = vi.fn();
|
|
33
|
-
registerImageDecoder('image/png', decoder);
|
|
34
|
-
expect(explainImageDecodeFailure(pngBytes)).toBeNull();
|
|
35
|
-
expect(decoder).not.toHaveBeenCalled();
|
|
36
|
-
});
|
|
37
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { explainImageEncodeFailure } from './explainImageEncodeFailure';
|
|
4
|
-
import { clearImageEncoders, registerImageEncoder } from './imageEncoderRegistry';
|
|
5
|
-
|
|
6
|
-
afterEach(() => {
|
|
7
|
-
clearImageEncoders();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
describe('explainImageEncodeFailure', () => {
|
|
11
|
-
it('reports a missing encoder and its requested MIME type', () => {
|
|
12
|
-
expect(explainImageEncodeFailure('image/custom')).toEqual({
|
|
13
|
-
mimeType: 'image/custom',
|
|
14
|
-
reason: 'encoder-not-registered',
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('returns null without invoking a registered encoder', () => {
|
|
19
|
-
const encoder = vi.fn();
|
|
20
|
-
registerImageEncoder('image/png', encoder);
|
|
21
|
-
expect(explainImageEncodeFailure('image/png')).toBeNull();
|
|
22
|
-
expect(encoder).not.toHaveBeenCalled();
|
|
23
|
-
});
|
|
24
|
-
});
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import type { DecodedImage, ImageDecoder } from '@flighthq/types/contract';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
clearImageDecoders,
|
|
5
|
-
getImageDecoder,
|
|
6
|
-
getImageDecoderMimeTypes,
|
|
7
|
-
hasImageDecoder,
|
|
8
|
-
registerImageDecoder,
|
|
9
|
-
unregisterImageDecoder,
|
|
10
|
-
} from './imageDecoderRegistry';
|
|
11
|
-
|
|
12
|
-
const fakeDecoder: ImageDecoder = async (): Promise<DecodedImage> => ({
|
|
13
|
-
data: new Uint8ClampedArray(4),
|
|
14
|
-
width: 1,
|
|
15
|
-
height: 1,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
clearImageDecoders();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
describe('clearImageDecoders', () => {
|
|
23
|
-
it('removes every registered decoder', () => {
|
|
24
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
25
|
-
registerImageDecoder('image/jpeg', fakeDecoder);
|
|
26
|
-
clearImageDecoders();
|
|
27
|
-
expect(hasImageDecoder('image/png')).toBe(false);
|
|
28
|
-
expect(hasImageDecoder('image/jpeg')).toBe(false);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe('getImageDecoder', () => {
|
|
33
|
-
it('returns the registered decoder', () => {
|
|
34
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
35
|
-
expect(getImageDecoder('image/png')).toBe(fakeDecoder);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('returns null when no decoder is registered', () => {
|
|
39
|
-
expect(getImageDecoder('image/png')).toBeNull();
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
describe('getImageDecoderMimeTypes', () => {
|
|
44
|
-
it('returns an empty snapshot before registration', () => {
|
|
45
|
-
expect(getImageDecoderMimeTypes()).toEqual([]);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('returns an insertion-ordered snapshot isolated from the registry', () => {
|
|
49
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
50
|
-
registerImageDecoder('image/jpeg', fakeDecoder);
|
|
51
|
-
const mimeTypes = getImageDecoderMimeTypes() as string[];
|
|
52
|
-
mimeTypes.push('image/webp');
|
|
53
|
-
expect(getImageDecoderMimeTypes()).toEqual(['image/png', 'image/jpeg']);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe('hasImageDecoder', () => {
|
|
58
|
-
it('reflects registration state', () => {
|
|
59
|
-
expect(hasImageDecoder('image/png')).toBe(false);
|
|
60
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
61
|
-
expect(hasImageDecoder('image/png')).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('registerImageDecoder', () => {
|
|
66
|
-
it('is empty until called', () => {
|
|
67
|
-
expect(hasImageDecoder('image/png')).toBe(false);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('overwrites an existing decoder (last-write-wins)', () => {
|
|
71
|
-
const other: ImageDecoder = async () => ({ data: new Uint8ClampedArray(4), width: 1, height: 1 });
|
|
72
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
73
|
-
registerImageDecoder('image/png', other);
|
|
74
|
-
expect(getImageDecoder('image/png')).toBe(other);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('unregisterImageDecoder', () => {
|
|
79
|
-
it('removes a single decoder', () => {
|
|
80
|
-
registerImageDecoder('image/png', fakeDecoder);
|
|
81
|
-
unregisterImageDecoder('image/png');
|
|
82
|
-
expect(hasImageDecoder('image/png')).toBe(false);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type { ImageEncoder } from '@flighthq/types/contract';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
clearImageEncoders,
|
|
5
|
-
getImageEncoder,
|
|
6
|
-
getImageEncoderMimeTypes,
|
|
7
|
-
hasImageEncoder,
|
|
8
|
-
registerImageEncoder,
|
|
9
|
-
unregisterImageEncoder,
|
|
10
|
-
} from './imageEncoderRegistry';
|
|
11
|
-
|
|
12
|
-
const fakeEncoder: ImageEncoder = async (): Promise<Uint8Array> => new Uint8Array(0);
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
clearImageEncoders();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
describe('clearImageEncoders', () => {
|
|
19
|
-
it('removes every registered encoder', () => {
|
|
20
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
21
|
-
registerImageEncoder('image/jpeg', fakeEncoder);
|
|
22
|
-
clearImageEncoders();
|
|
23
|
-
expect(hasImageEncoder('image/png')).toBe(false);
|
|
24
|
-
expect(hasImageEncoder('image/jpeg')).toBe(false);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('getImageEncoder', () => {
|
|
29
|
-
it('returns the registered encoder', () => {
|
|
30
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
31
|
-
expect(getImageEncoder('image/png')).toBe(fakeEncoder);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('returns null when no encoder is registered', () => {
|
|
35
|
-
expect(getImageEncoder('image/png')).toBeNull();
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('getImageEncoderMimeTypes', () => {
|
|
40
|
-
it('returns an empty snapshot before registration', () => {
|
|
41
|
-
expect(getImageEncoderMimeTypes()).toEqual([]);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('returns an insertion-ordered snapshot isolated from the registry', () => {
|
|
45
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
46
|
-
registerImageEncoder('image/jpeg', fakeEncoder);
|
|
47
|
-
const mimeTypes = getImageEncoderMimeTypes() as string[];
|
|
48
|
-
mimeTypes.push('image/webp');
|
|
49
|
-
expect(getImageEncoderMimeTypes()).toEqual(['image/png', 'image/jpeg']);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('hasImageEncoder', () => {
|
|
54
|
-
it('reflects registration state', () => {
|
|
55
|
-
expect(hasImageEncoder('image/png')).toBe(false);
|
|
56
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
57
|
-
expect(hasImageEncoder('image/png')).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('registerImageEncoder', () => {
|
|
62
|
-
it('is empty until called', () => {
|
|
63
|
-
expect(hasImageEncoder('image/png')).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('overwrites an existing encoder (last-write-wins)', () => {
|
|
67
|
-
const other: ImageEncoder = async () => new Uint8Array(1);
|
|
68
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
69
|
-
registerImageEncoder('image/png', other);
|
|
70
|
-
expect(getImageEncoder('image/png')).toBe(other);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe('unregisterImageEncoder', () => {
|
|
75
|
-
it('removes a single encoder', () => {
|
|
76
|
-
registerImageEncoder('image/png', fakeEncoder);
|
|
77
|
-
unregisterImageEncoder('image/png');
|
|
78
|
-
expect(hasImageEncoder('image/png')).toBe(false);
|
|
79
|
-
});
|
|
80
|
-
});
|