@flighthq/image-codec 0.5.1-next.1069.554a2ac → 0.5.1-next.1201.9b49dee
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 -3
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +0 -3
- package/dist/contract.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/dist/imageBitmapComposerRegistry.d.ts +0 -8
- package/dist/imageBitmapComposerRegistry.d.ts.map +0 -1
- package/dist/imageBitmapComposerRegistry.js +0 -23
- package/dist/imageBitmapComposerRegistry.js.map +0 -1
- package/dist/registerWebImageDecoders.d.ts +0 -2
- package/dist/registerWebImageDecoders.d.ts.map +0 -1
- package/dist/registerWebImageDecoders.js +0 -48
- package/dist/registerWebImageDecoders.js.map +0 -1
- package/dist/registerWebImageEncoders.d.ts +0 -2
- package/dist/registerWebImageEncoders.d.ts.map +0 -1
- package/dist/registerWebImageEncoders.js +0 -23
- package/dist/registerWebImageEncoders.js.map +0 -1
- package/src/imageBitmapComposerRegistry.test.ts +0 -72
- package/src/registerWebImageDecoders.test.ts +0 -80
- package/src/registerWebImageEncoders.test.ts +0 -78
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.1201.9b49dee](https://github.com/flighthq/flight/tree/9b49dee3f22f6b2838c3d237edcc77bca65734f2/packages/image-codec)
|
|
17
|
+
- [License](https://github.com/flighthq/flight/blob/9b49dee3f22f6b2838c3d237edcc77bca65734f2/LICENSE.md)
|
package/dist/contract.d.ts
CHANGED
|
@@ -4,8 +4,5 @@ export * from './encodeImage';
|
|
|
4
4
|
export * from './explainImageDecodeFailure';
|
|
5
5
|
export * from './explainImageEncodeFailure';
|
|
6
6
|
export * from './imageDecoderRegistry';
|
|
7
|
-
export * from './imageBitmapComposerRegistry';
|
|
8
7
|
export * from './imageEncoderRegistry';
|
|
9
|
-
export * from './registerWebImageDecoders';
|
|
10
|
-
export * from './registerWebImageEncoders';
|
|
11
8
|
//# 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;AAC9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,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;AAC9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
|
package/dist/contract.js
CHANGED
|
@@ -4,8 +4,5 @@ export * from './encodeImage';
|
|
|
4
4
|
export * from './explainImageDecodeFailure';
|
|
5
5
|
export * from './explainImageEncodeFailure';
|
|
6
6
|
export * from './imageDecoderRegistry';
|
|
7
|
-
export * from './imageBitmapComposerRegistry';
|
|
8
7
|
export * from './imageEncoderRegistry';
|
|
9
|
-
export * from './registerWebImageDecoders';
|
|
10
|
-
export * from './registerWebImageEncoders';
|
|
11
8
|
//# 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;AAC9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,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;AAC9B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { clearImageDecoders, clearImageEncoders, decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage, explainImageDecodeFailure, explainImageEncodeFailure, getImageDecoder, getImageDecoderMimeTypes, getImageEncoder, getImageEncoderMimeTypes, hasImageDecoder, hasImageEncoder, registerImageDecoder, registerImageEncoder,
|
|
1
|
+
export { clearImageDecoders, clearImageEncoders, decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage, explainImageDecodeFailure, explainImageEncodeFailure, getImageDecoder, getImageDecoderMimeTypes, getImageEncoder, getImageEncoderMimeTypes, hasImageDecoder, hasImageEncoder, registerImageDecoder, registerImageEncoder, unregisterImageDecoder, unregisterImageEncoder, } 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,EACL,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { clearImageDecoders, clearImageEncoders, decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage, explainImageDecodeFailure, explainImageEncodeFailure, getImageDecoder, getImageDecoderMimeTypes, getImageEncoder, getImageEncoderMimeTypes, hasImageDecoder, hasImageEncoder, registerImageDecoder, registerImageEncoder,
|
|
1
|
+
export { clearImageDecoders, clearImageEncoders, decodeImage, decodeImagePremultiplied, detectImageMimeType, encodeImage, explainImageDecodeFailure, explainImageEncodeFailure, getImageDecoder, getImageDecoderMimeTypes, getImageEncoder, getImageEncoderMimeTypes, hasImageDecoder, hasImageEncoder, registerImageDecoder, registerImageEncoder, unregisterImageDecoder, unregisterImageEncoder, } 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,EACL,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,wBAAwB,EACxB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,yBAAyB,EACzB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GACvB,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.1201.9b49dee",
|
|
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.1201.9b49dee"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"typescript": "^5.3.0"
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ImageBitmapComposer } from '@flighthq/types/contract';
|
|
2
|
-
export declare function clearImageBitmapComposers(): void;
|
|
3
|
-
export declare function getImageBitmapComposer(kind: string): ImageBitmapComposer | null;
|
|
4
|
-
export declare function getImageBitmapComposerKinds(): readonly string[];
|
|
5
|
-
export declare function hasImageBitmapComposer(kind: string): boolean;
|
|
6
|
-
export declare function registerImageBitmapComposer(kind: string, composer: ImageBitmapComposer): void;
|
|
7
|
-
export declare function unregisterImageBitmapComposer(kind: string): void;
|
|
8
|
-
//# sourceMappingURL=imageBitmapComposerRegistry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageBitmapComposerRegistry.d.ts","sourceRoot":"","sources":["../src/imageBitmapComposerRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAE/E;AAED,wBAAgB,2BAA2B,IAAI,SAAS,MAAM,EAAE,CAE/D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAE7F;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhE"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export function clearImageBitmapComposers() {
|
|
2
|
-
composers.clear();
|
|
3
|
-
}
|
|
4
|
-
export function getImageBitmapComposer(kind) {
|
|
5
|
-
return composers.get(kind) ?? null;
|
|
6
|
-
}
|
|
7
|
-
export function getImageBitmapComposerKinds() {
|
|
8
|
-
return Array.from(composers.keys());
|
|
9
|
-
}
|
|
10
|
-
export function hasImageBitmapComposer(kind) {
|
|
11
|
-
return composers.has(kind);
|
|
12
|
-
}
|
|
13
|
-
export function registerImageBitmapComposer(kind, composer) {
|
|
14
|
-
composers.set(kind, composer);
|
|
15
|
-
}
|
|
16
|
-
export function unregisterImageBitmapComposer(kind) {
|
|
17
|
-
composers.delete(kind);
|
|
18
|
-
}
|
|
19
|
-
// Open, format-neutral composer registry. A container puts only the stable key and payload bytes on a
|
|
20
|
-
// reference; its package owns the callback that understands those bytes. Last registration wins so an
|
|
21
|
-
// application can replace a built-in producer deliberately without embedding executable state in a scene.
|
|
22
|
-
const composers = new Map();
|
|
23
|
-
//# sourceMappingURL=imageBitmapComposerRegistry.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imageBitmapComposerRegistry.js","sourceRoot":"","sources":["../src/imageBitmapComposerRegistry.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB;IACvC,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAY,EAAE,QAA6B;IACrF,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,IAAY;IACxD,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,sGAAsG;AACtG,sGAAsG;AACtG,0GAA0G;AAC1G,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerWebImageDecoders.d.ts","sourceRoot":"","sources":["../src/registerWebImageDecoders.ts"],"names":[],"mappings":"AAOA,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C"}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { registerImageDecoder } from './imageDecoderRegistry';
|
|
2
|
-
// Registers the browser's createImageBitmap + OffscreenCanvas decoder under every MIME type the platform
|
|
3
|
-
// can decode. Opt-in — nothing runs until the caller invokes this. A native host registers wasm codecs
|
|
4
|
-
// instead and never calls this.
|
|
5
|
-
export function registerWebImageDecoders() {
|
|
6
|
-
for (const mimeType of webDecodableMimeTypes) {
|
|
7
|
-
registerImageDecoder(mimeType, decodeImageWithCanvas);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
// One decoder shared across every browser-decodable MIME type: createImageBitmap sniffs the format from
|
|
11
|
-
// the bytes, so the registration key does not need to reach the Blob. getImageData is always straight
|
|
12
|
-
// (non-premultiplied) RGBA, so premultiplied output cannot come from a single canvas pass — when
|
|
13
|
-
// premultiplyAlpha is requested we decode straight, then premultiply the pixels in JS.
|
|
14
|
-
const decodeImageWithCanvas = async (bytes, options) => {
|
|
15
|
-
// slice() yields a fresh, non-readonly Uint8Array for Blob and detaches from any pooled input buffer.
|
|
16
|
-
const bitmap = await createImageBitmap(new Blob([bytes.slice()]));
|
|
17
|
-
const width = bitmap.width;
|
|
18
|
-
const height = bitmap.height;
|
|
19
|
-
const canvas = new OffscreenCanvas(width, height);
|
|
20
|
-
const context = canvas.getContext('2d');
|
|
21
|
-
context.drawImage(bitmap, 0, 0);
|
|
22
|
-
bitmap.close();
|
|
23
|
-
const data = context.getImageData(0, 0, width, height).data;
|
|
24
|
-
if (options?.premultiplyAlpha === true)
|
|
25
|
-
premultiplyRgbaInPlace(data);
|
|
26
|
-
return { data, width, height };
|
|
27
|
-
};
|
|
28
|
-
// In-place straight → premultiplied RGBA: scale each color channel by alpha/255. Only the premultiplied
|
|
29
|
-
// decode path calls this, since canvas getImageData always yields straight alpha.
|
|
30
|
-
function premultiplyRgbaInPlace(data) {
|
|
31
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
32
|
-
const alpha = data[i + 3];
|
|
33
|
-
if (alpha === 255)
|
|
34
|
-
continue;
|
|
35
|
-
data[i] = (data[i] * alpha) / 255;
|
|
36
|
-
data[i + 1] = (data[i + 1] * alpha) / 255;
|
|
37
|
-
data[i + 2] = (data[i + 2] * alpha) / 255;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const webDecodableMimeTypes = [
|
|
41
|
-
'image/png',
|
|
42
|
-
'image/jpeg',
|
|
43
|
-
'image/webp',
|
|
44
|
-
'image/gif',
|
|
45
|
-
'image/avif',
|
|
46
|
-
'image/bmp',
|
|
47
|
-
];
|
|
48
|
-
//# sourceMappingURL=registerWebImageDecoders.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerWebImageDecoders.js","sourceRoot":"","sources":["../src/registerWebImageDecoders.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,yGAAyG;AACzG,uGAAuG;AACvG,gCAAgC;AAChC,MAAM,UAAU,wBAAwB;IACtC,KAAK,MAAM,QAAQ,IAAI,qBAAqB,EAAE,CAAC;QAC7C,oBAAoB,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,sGAAsG;AACtG,iGAAiG;AACjG,uFAAuF;AACvF,MAAM,qBAAqB,GAAiB,KAAK,EAC/C,KAA2B,EAC3B,OAAsC,EACf,EAAE;IACzB,sGAAsG;IACtG,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAsC,CAAC;IAC7E,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC;IAC5D,IAAI,OAAO,EAAE,gBAAgB,KAAK,IAAI;QAAE,sBAAsB,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACjC,CAAC,CAAC;AAEF,wGAAwG;AACxG,kFAAkF;AAClF,SAAS,sBAAsB,CAAC,IAAuB;IACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,IAAI,KAAK,KAAK,GAAG;YAAE,SAAS;QAC5B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;QAClC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;QAC1C,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,MAAM,qBAAqB,GAAsB;IAC/C,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,WAAW;CACZ,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerWebImageEncoders.d.ts","sourceRoot":"","sources":["../src/registerWebImageEncoders.ts"],"names":[],"mappings":"AAMA,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { registerImageEncoder } from './imageEncoderRegistry';
|
|
2
|
-
// Registers the OffscreenCanvas + convertToBlob encoder under every MIME type the platform can encode.
|
|
3
|
-
// Opt-in — nothing runs until the caller invokes this. A native host registers wasm encoders instead.
|
|
4
|
-
export function registerWebImageEncoders() {
|
|
5
|
-
for (const mimeType of webEncodableMimeTypes) {
|
|
6
|
-
registerImageEncoder(mimeType, createCanvasImageEncoder(mimeType));
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
// Each encoder closes over its MIME type so convertToBlob emits that format (unlike decode, encode must
|
|
10
|
-
// name the target format). quality is forwarded as the lossy-format hint; lossless PNG ignores it.
|
|
11
|
-
function createCanvasImageEncoder(mimeType) {
|
|
12
|
-
return async (image, options) => {
|
|
13
|
-
const canvas = new OffscreenCanvas(image.width, image.height);
|
|
14
|
-
const context = canvas.getContext('2d');
|
|
15
|
-
// ImageData needs a mutable Uint8ClampedArray; copy so a Readonly input is honored and not aliased.
|
|
16
|
-
const pixels = new Uint8ClampedArray(image.data);
|
|
17
|
-
context.putImageData(new ImageData(pixels, image.width, image.height), 0, 0);
|
|
18
|
-
const blob = await canvas.convertToBlob({ type: mimeType, quality: options?.quality });
|
|
19
|
-
return new Uint8Array(await blob.arrayBuffer());
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
const webEncodableMimeTypes = ['image/png', 'image/jpeg', 'image/webp'];
|
|
23
|
-
//# sourceMappingURL=registerWebImageEncoders.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerWebImageEncoders.js","sourceRoot":"","sources":["../src/registerWebImageEncoders.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,uGAAuG;AACvG,sGAAsG;AACtG,MAAM,UAAU,wBAAwB;IACtC,KAAK,MAAM,QAAQ,IAAI,qBAAqB,EAAE,CAAC;QAC7C,oBAAoB,CAAC,QAAQ,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrE,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,mGAAmG;AACnG,SAAS,wBAAwB,CAAC,QAAgB;IAChD,OAAO,KAAK,EAAE,KAA6B,EAAE,OAAsC,EAAuB,EAAE;QAC1G,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAsC,CAAC;QAC7E,oGAAoG;QACpG,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO,CAAC,YAAY,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACvF,OAAO,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,qBAAqB,GAAsB,CAAC,WAAW,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC"}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { ImageBitmapComposer } from '@flighthq/types/contract';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
clearImageBitmapComposers,
|
|
5
|
-
getImageBitmapComposer,
|
|
6
|
-
getImageBitmapComposerKinds,
|
|
7
|
-
hasImageBitmapComposer,
|
|
8
|
-
registerImageBitmapComposer,
|
|
9
|
-
unregisterImageBitmapComposer,
|
|
10
|
-
} from './imageBitmapComposerRegistry';
|
|
11
|
-
|
|
12
|
-
const composer: ImageBitmapComposer = () => null;
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
clearImageBitmapComposers();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
describe('clearImageBitmapComposers', () => {
|
|
19
|
-
it('removes every registered composer', () => {
|
|
20
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
21
|
-
clearImageBitmapComposers();
|
|
22
|
-
|
|
23
|
-
expect(hasImageBitmapComposer('acme/raw-raster')).toBe(false);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('getImageBitmapComposer', () => {
|
|
28
|
-
it('returns the registered composer or null for a missing kind', () => {
|
|
29
|
-
expect(getImageBitmapComposer('acme/raw-raster')).toBeNull();
|
|
30
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
31
|
-
|
|
32
|
-
expect(getImageBitmapComposer('acme/raw-raster')).toBe(composer);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('getImageBitmapComposerKinds', () => {
|
|
37
|
-
it('returns an insertion-ordered enumeration detached from registry state', () => {
|
|
38
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
39
|
-
expect(getImageBitmapComposerKinds()).toEqual(['acme/raw-raster']);
|
|
40
|
-
(getImageBitmapComposerKinds() as string[]).length = 0;
|
|
41
|
-
|
|
42
|
-
expect(getImageBitmapComposerKinds()).toEqual(['acme/raw-raster']);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('hasImageBitmapComposer', () => {
|
|
47
|
-
it('reports whether a kind is registered', () => {
|
|
48
|
-
expect(hasImageBitmapComposer('acme/raw-raster')).toBe(false);
|
|
49
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
50
|
-
|
|
51
|
-
expect(hasImageBitmapComposer('acme/raw-raster')).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe('registerImageBitmapComposer', () => {
|
|
56
|
-
it('uses the final registration for a kind', () => {
|
|
57
|
-
const replacement: ImageBitmapComposer = () => null;
|
|
58
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
59
|
-
registerImageBitmapComposer('acme/raw-raster', replacement);
|
|
60
|
-
|
|
61
|
-
expect(getImageBitmapComposer('acme/raw-raster')).toBe(replacement);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe('unregisterImageBitmapComposer', () => {
|
|
66
|
-
it('removes one registered kind', () => {
|
|
67
|
-
registerImageBitmapComposer('acme/raw-raster', composer);
|
|
68
|
-
unregisterImageBitmapComposer('acme/raw-raster');
|
|
69
|
-
|
|
70
|
-
expect(getImageBitmapComposer('acme/raw-raster')).toBeNull();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { clearImageDecoders, getImageDecoder, hasImageDecoder } from './imageDecoderRegistry';
|
|
4
|
-
import { registerWebImageDecoders } from './registerWebImageDecoders';
|
|
5
|
-
|
|
6
|
-
// jsdom / node lack createImageBitmap + OffscreenCanvas + Blob; these minimal stand-ins let the
|
|
7
|
-
// canvas decoder run. getImageData always returns straight (non-premultiplied) RGBA, matching the browser.
|
|
8
|
-
const straightPixels = [200, 100, 50, 128];
|
|
9
|
-
let bitmapCloseMock: ReturnType<typeof vi.fn>;
|
|
10
|
-
let createImageBitmapMock: ReturnType<typeof vi.fn>;
|
|
11
|
-
|
|
12
|
-
class MockBlob {
|
|
13
|
-
constructor(readonly parts: readonly unknown[]) {}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
class MockOffscreenCanvas {
|
|
17
|
-
constructor(
|
|
18
|
-
readonly width: number,
|
|
19
|
-
readonly height: number,
|
|
20
|
-
) {}
|
|
21
|
-
|
|
22
|
-
getContext(contextId: string): unknown {
|
|
23
|
-
if (contextId !== '2d') return null;
|
|
24
|
-
return {
|
|
25
|
-
drawImage: vi.fn(),
|
|
26
|
-
getImageData: () => ({ data: new Uint8ClampedArray(straightPixels) }),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
bitmapCloseMock = vi.fn();
|
|
33
|
-
createImageBitmapMock = vi.fn(async () => ({ width: 1, height: 1, close: bitmapCloseMock }));
|
|
34
|
-
vi.stubGlobal('createImageBitmap', createImageBitmapMock);
|
|
35
|
-
vi.stubGlobal('OffscreenCanvas', MockOffscreenCanvas);
|
|
36
|
-
vi.stubGlobal('Blob', MockBlob);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
afterEach(() => {
|
|
40
|
-
vi.unstubAllGlobals();
|
|
41
|
-
clearImageDecoders();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('registerWebImageDecoders', () => {
|
|
45
|
-
it('registers a decoder under every browser-decodable MIME type', () => {
|
|
46
|
-
registerWebImageDecoders();
|
|
47
|
-
for (const mimeType of ['image/png', 'image/jpeg', 'image/webp', 'image/gif', 'image/avif', 'image/bmp']) {
|
|
48
|
-
expect(hasImageDecoder(mimeType)).toBe(true);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('decodes to straight (non-premultiplied) RGBA', async () => {
|
|
53
|
-
registerWebImageDecoders();
|
|
54
|
-
const decoder = getImageDecoder('image/png');
|
|
55
|
-
const result = await decoder!(new Uint8Array([0x89, 0x50, 0x4e, 0x47]));
|
|
56
|
-
expect(result.width).toBe(1);
|
|
57
|
-
expect(result.height).toBe(1);
|
|
58
|
-
expect(Array.from(result.data)).toEqual(straightPixels);
|
|
59
|
-
expect(bitmapCloseMock).toHaveBeenCalledOnce();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('forwards only the bytes inside the supplied view to createImageBitmap', async () => {
|
|
63
|
-
registerWebImageDecoders();
|
|
64
|
-
const decoder = getImageDecoder('image/png');
|
|
65
|
-
const backing = new Uint8Array([1, 2, 3, 4, 5, 6]);
|
|
66
|
-
|
|
67
|
-
await decoder!(backing.subarray(1, 5));
|
|
68
|
-
|
|
69
|
-
const blob = createImageBitmapMock.mock.calls[0][0] as MockBlob;
|
|
70
|
-
expect(Array.from(blob.parts[0] as Uint8Array)).toEqual([2, 3, 4, 5]);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('premultiplies the straight result when premultiplyAlpha is requested', async () => {
|
|
74
|
-
registerWebImageDecoders();
|
|
75
|
-
const decoder = getImageDecoder('image/png');
|
|
76
|
-
const result = await decoder!(new Uint8Array([0x89, 0x50, 0x4e, 0x47]), { premultiplyAlpha: true });
|
|
77
|
-
// 200*128/255 -> 100, 100*128/255 -> 50, 50*128/255 -> 25, alpha unchanged.
|
|
78
|
-
expect(Array.from(result.data)).toEqual([100, 50, 25, 128]);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import type { DecodedImage } from '@flighthq/types/contract';
|
|
2
|
-
import { vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import { clearImageEncoders, getImageEncoder, hasImageEncoder } from './imageEncoderRegistry';
|
|
5
|
-
import { registerWebImageEncoders } from './registerWebImageEncoders';
|
|
6
|
-
|
|
7
|
-
// node lacks OffscreenCanvas + ImageData; these stand-ins record the convertToBlob call and hand back
|
|
8
|
-
// fixed bytes so the encoder's byte extraction can be verified.
|
|
9
|
-
const convertToBlobMock = vi.fn(async (_options: { type: string; quality?: number }) => ({
|
|
10
|
-
arrayBuffer: async () => new Uint8Array([1, 2, 3]).buffer,
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
class MockOffscreenCanvas {
|
|
14
|
-
constructor(
|
|
15
|
-
readonly width: number,
|
|
16
|
-
readonly height: number,
|
|
17
|
-
) {}
|
|
18
|
-
|
|
19
|
-
getContext(contextId: string): unknown {
|
|
20
|
-
if (contextId !== '2d') return null;
|
|
21
|
-
return { putImageData: vi.fn() };
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
convertToBlob(options: { type: string; quality?: number }): Promise<{ arrayBuffer: () => Promise<ArrayBuffer> }> {
|
|
25
|
-
return convertToBlobMock(options);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class MockImageData {
|
|
30
|
-
constructor(
|
|
31
|
-
readonly data: Uint8ClampedArray,
|
|
32
|
-
readonly width: number,
|
|
33
|
-
readonly height: number,
|
|
34
|
-
) {
|
|
35
|
-
if (data.length !== width * height * 4) {
|
|
36
|
-
throw new DOMException('ImageData data length must equal width * height * 4', 'IndexSizeError');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function fakeImage(): DecodedImage {
|
|
42
|
-
return { data: new Uint8ClampedArray([10, 20, 30, 255]), width: 1, height: 1 };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
beforeEach(() => {
|
|
46
|
-
vi.stubGlobal('OffscreenCanvas', MockOffscreenCanvas);
|
|
47
|
-
vi.stubGlobal('ImageData', MockImageData);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
afterEach(() => {
|
|
51
|
-
vi.unstubAllGlobals();
|
|
52
|
-
convertToBlobMock.mockClear();
|
|
53
|
-
clearImageEncoders();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('registerWebImageEncoders', () => {
|
|
57
|
-
it('registers an encoder under every browser-encodable MIME type', () => {
|
|
58
|
-
registerWebImageEncoders();
|
|
59
|
-
for (const mimeType of ['image/png', 'image/jpeg', 'image/webp']) {
|
|
60
|
-
expect(hasImageEncoder(mimeType)).toBe(true);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('encodes to bytes via convertToBlob under the registered MIME type', async () => {
|
|
65
|
-
registerWebImageEncoders();
|
|
66
|
-
const encoder = getImageEncoder('image/png');
|
|
67
|
-
const bytes = await encoder!(fakeImage());
|
|
68
|
-
expect(Array.from(bytes)).toEqual([1, 2, 3]);
|
|
69
|
-
expect(convertToBlobMock).toHaveBeenCalledWith({ type: 'image/png', quality: undefined });
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('forwards the quality option to convertToBlob', async () => {
|
|
73
|
-
registerWebImageEncoders();
|
|
74
|
-
const encoder = getImageEncoder('image/jpeg');
|
|
75
|
-
await encoder!(fakeImage(), { quality: 0.7 });
|
|
76
|
-
expect(convertToBlobMock).toHaveBeenCalledWith({ type: 'image/jpeg', quality: 0.7 });
|
|
77
|
-
});
|
|
78
|
-
});
|