@flighthq/image 0.1.0 → 0.2.1-next.410.a23f189

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.
@@ -1,9 +1,11 @@
1
- import type { ImageResource } from '@flighthq/types';
1
+ import type { ImageResource, ImageResourceCompressed } from '@flighthq/types';
2
2
  export declare function cloneImageResource(resource: Readonly<ImageResource>): ImageResource;
3
+ export declare function createCompressedImageResource(compressed: Readonly<ImageResourceCompressed>): ImageResource;
3
4
  export declare function createImageResource(image?: CanvasImageSource): ImageResource;
4
5
  export declare function disposeImageResource(resource: ImageResource): void;
5
6
  export declare function getImageResourceByteSize(resource: Readonly<ImageResource>): number;
6
7
  export declare function hasImageResourceData(resource: Readonly<ImageResource>): boolean;
8
+ export declare function hasImageResourcePixels(resource: Readonly<ImageResource>): boolean;
7
9
  export declare function hasImageResourceSource(resource: Readonly<ImageResource>): boolean;
8
10
  export declare function invalidateImageResource(resource: ImageResource): void;
9
11
  export declare function isImageResourceEmpty(resource: Readonly<ImageResource>): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"imageResource.d.ts","sourceRoot":"","sources":["../src/imageResource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMrD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,aAAa,CAUnF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAY5E;AAMD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAIlE;AAMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAElF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAE/E;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAEjF;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAErE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAE/E;AAID,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAIvG"}
1
+ {"version":3,"file":"imageResource.d.ts","sourceRoot":"","sources":["../src/imageResource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAM9E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,aAAa,CAWnF;AAMD,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GAAG,aAAa,CAW1G;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAa5E;AAMD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAKlE;AAMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAElF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAE/E;AAQD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAEjF;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAEjF;AAKD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAErE;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,OAAO,CAE/E;AAID,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAIvG"}
@@ -1,11 +1,12 @@
1
1
  import { createEntity } from '@flighthq/entity';
2
- // Allocates a new resource identity over the SAME underlying pixels. The element and the `data` array
3
- // are shared by reference, not duplicated — clone gives you an independent version counter and entity
4
- // identity over the same pixels, e.g. to upload one image into two render states with separate
5
- // invalidation. Use a Surface copy when you need the pixels themselves duplicated.
2
+ // Allocates a new resource identity over the SAME underlying pixels. The element, the `data` array, and
3
+ // the `compressed` payload are shared by reference, not duplicated — clone gives you an independent
4
+ // version counter and entity identity over the same pixels, e.g. to upload one image into two render
5
+ // states with separate invalidation. Use a Surface copy when you need the pixels themselves duplicated.
6
6
  export function cloneImageResource(resource) {
7
7
  return createEntity({
8
8
  alphaType: resource.alphaType,
9
+ compressed: resource.compressed,
9
10
  data: resource.data,
10
11
  format: resource.format,
11
12
  height: resource.height,
@@ -14,9 +15,26 @@ export function cloneImageResource(resource) {
14
15
  width: resource.width,
15
16
  });
16
17
  }
18
+ // Wraps a parsed block-compressed (KTX2/DDS/Basis) payload as an ImageResource. `width`/`height` mirror
19
+ // the container's base-mip dimensions so the same 2D draw path sizes the quad; `source`/`data` stay null
20
+ // (a GPU backend uploads the `compressed` payload instead, and a Canvas/DOM backend ignores it). The
21
+ // caller owns the payload bytes the container's level ranges index into.
22
+ export function createCompressedImageResource(compressed) {
23
+ return createEntity({
24
+ alphaType: 'straight',
25
+ compressed,
26
+ data: null,
27
+ format: 'rgba8unorm',
28
+ height: compressed.container.height,
29
+ source: null,
30
+ version: 0,
31
+ width: compressed.container.width,
32
+ });
33
+ }
17
34
  export function createImageResource(image) {
18
35
  const resource = createEntity({
19
36
  alphaType: 'straight',
37
+ compressed: null,
20
38
  data: null,
21
39
  format: 'rgba8unorm',
22
40
  height: 0,
@@ -33,6 +51,7 @@ export function createImageResource(image) {
33
51
  // backend's destroy*Texture) and does NOT close an owned ImageBitmap (ownership is ambiguous; close it
34
52
  // explicitly if you own it). Dimensions are left intact; setImageResourceSource repopulates the resource.
35
53
  export function disposeImageResource(resource) {
54
+ resource.compressed = null;
36
55
  resource.data = null;
37
56
  resource.source = null;
38
57
  invalidateImageResource(resource);
@@ -47,6 +66,15 @@ export function getImageResourceByteSize(resource) {
47
66
  export function hasImageResourceData(resource) {
48
67
  return resource.data !== null;
49
68
  }
69
+ // True when the resource carries pixels in any representation — a decoded `source` element, raw CPU
70
+ // `data`, or a block-`compressed` payload. The upload-readiness predicate for backends that can consume
71
+ // any of them: an element-only load, a data-only generated Surface, a compressed-only parsed container,
72
+ // or a resource holding several are all uploadable. Prefer this over hasImageResourceSource at any gate
73
+ // that feeds a source-or-data uploader (bindGlTexture, bindWgpuTexture), so a memory-generated Surface
74
+ // or a compressed container is not rejected for lacking an element.
75
+ export function hasImageResourcePixels(resource) {
76
+ return resource.source !== null || resource.data !== null || resource.compressed !== null;
77
+ }
50
78
  export function hasImageResourceSource(resource) {
51
79
  return resource.source !== null;
52
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"imageResource.js","sourceRoot":"","sources":["../src/imageResource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imageResource.js","sourceRoot":"","sources":["../src/imageResource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,wGAAwG;AACxG,oGAAoG;AACpG,qGAAqG;AACrG,wGAAwG;AACxG,MAAM,UAAU,kBAAkB,CAAC,QAAiC;IAClE,OAAO,YAAY,CAAC;QAClB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,KAAK,EAAE,QAAQ,CAAC,KAAK;KACtB,CAAC,CAAC;AACL,CAAC;AAED,wGAAwG;AACxG,yGAAyG;AACzG,qGAAqG;AACrG,yEAAyE;AACzE,MAAM,UAAU,6BAA6B,CAAC,UAA6C;IACzF,OAAO,YAAY,CAAC;QAClB,SAAS,EAAE,UAAU;QACrB,UAAU;QACV,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,MAAM;QACnC,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK;KAClC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,MAAM,QAAQ,GAAkB,YAAY,CAAC;QAC3C,SAAS,EAAE,UAAU;QACrB,UAAU,EAAE,IAAI;QAChB,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,CAAC;QACT,MAAM,EAAE,KAAK,IAAI,IAAI;QACrB,OAAO,EAAE,CAAC;QACV,KAAK,EAAE,CAAC;KACT,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI;QAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAChE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,sGAAsG;AACtG,iGAAiG;AACjG,uGAAuG;AACvG,0GAA0G;AAC1G,MAAM,UAAU,oBAAoB,CAAC,QAAuB;IAC1D,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,uBAAuB,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC;AAED,iGAAiG;AACjG,qGAAqG;AACrG,iGAAiG;AACjG,8FAA8F;AAC9F,MAAM,UAAU,wBAAwB,CAAC,QAAiC;IACxE,OAAO,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAiC;IACpE,OAAO,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC;AAChC,CAAC;AAED,oGAAoG;AACpG,wGAAwG;AACxG,wGAAwG;AACxG,wGAAwG;AACxG,uGAAuG;AACvG,oEAAoE;AACpE,MAAM,UAAU,sBAAsB,CAAC,QAAiC;IACtE,OAAO,QAAQ,CAAC,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,KAAK,IAAI,CAAC;AAC5F,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAiC;IACtE,OAAO,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC;AAClC,CAAC;AAED,oGAAoG;AACpG,kGAAkG;AAClG,yGAAyG;AACzG,MAAM,UAAU,uBAAuB,CAAC,QAAuB;IAC7D,QAAQ,CAAC,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAiC;IACpE,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,kGAAkG;AAClG,sGAAsG;AACtG,MAAM,UAAU,sBAAsB,CAAC,QAAuB,EAAE,OAAiC;IAC/F,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC;IAC1B,IAAI,OAAO,KAAK,IAAI;QAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACxD,uBAAuB,CAAC,QAAQ,CAAC,CAAC;AACpC,CAAC;AAED,gGAAgG;AAChG,uFAAuF;AACvF,SAAS,uBAAuB,CAAC,QAAuB;IACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAO,CAAC;IACjC,IAAI,OAAO,YAAY,gBAAgB,EAAE,CAAC;QACxC,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;QACpC,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IACxC,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,OAA6D,CAAC;QAC5E,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC7B,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IACjC,CAAC;AACH,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import type { ImageResource } from '@flighthq/types';
2
+ export declare function createCanvasFromImageResource(image: Readonly<ImageResource>): HTMLCanvasElement | null;
2
3
  export declare function createImageResourceFromCanvas(canvas: HTMLCanvasElement): ImageResource;
3
4
  export declare function createImageResourceFromImageBitmap(bitmap: ImageBitmap): ImageResource;
4
5
  export declare function createImageResourceFromImageElement(img: HTMLImageElement): ImageResource;
5
- export declare function detectImageMimeType(data: ArrayBuffer | Uint8Array): string | null;
6
6
  export declare function isImageResourceSameOrigin(url: string): boolean;
7
7
  export declare function loadImageResourceFromBase64(base64: string, mimeType: string, signal?: AbortSignal): Promise<ImageResource>;
8
8
  export declare function loadImageResourceFromBlob(blob: Blob, signal?: AbortSignal): Promise<ImageResource>;
@@ -1 +1 @@
1
- {"version":3,"file":"imageResourceFrom.d.ts","sourceRoot":"","sources":["../src/imageResourceFrom.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,iBAAiB,GAAG,aAAa,CAUtF;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAUrF;AAED,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,gBAAgB,GAAG,aAAa,CAUxF;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,CA+BjF;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO9D;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAExB;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAOxG;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,UAAU,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAexB"}
1
+ {"version":3,"file":"imageResourceFrom.d.ts","sourceRoot":"","sources":["../src/imageResourceFrom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAQrD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,iBAAiB,GAAG,IAAI,CAStG;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,iBAAiB,GAAG,aAAa,CAWtF;AAED,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,WAAW,GAAG,aAAa,CAWrF;AAED,wBAAgB,mCAAmC,CAAC,GAAG,EAAE,gBAAgB,GAAG,aAAa,CAWxF;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO9D;AAED,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAExB;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAOxG;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,UAAU,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAOxB;AAED,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,aAAa,CAAC,CAexB"}
@@ -1,7 +1,26 @@
1
1
  import { createEntity } from '@flighthq/entity';
2
+ import { detectImageMimeType } from '@flighthq/image-codec';
3
+ // Materializes a data-backed ImageResource's raw pixels into a detached, drawable HTMLCanvasElement
4
+ // via putImageData. The inverse of createImageResourceFromCanvas: it turns the portable `data`
5
+ // representation of a generated Surface into the host element that Canvas/DOM `drawImage` needs.
6
+ // Returns null for an element-only resource (no `data` to transcode). Straight-alpha in, straight-alpha
7
+ // out — the drawn canvas matches the source's `alphaType`. Callers that draw data-only resources cache
8
+ // the result keyed on `version`; this primitive allocates a fresh canvas on every call.
9
+ export function createCanvasFromImageResource(image) {
10
+ if (image.data === null)
11
+ return null;
12
+ const canvas = document.createElement('canvas');
13
+ canvas.width = image.width;
14
+ canvas.height = image.height;
15
+ const imageData = new globalThis.ImageData(image.width, image.height);
16
+ imageData.data.set(image.data);
17
+ canvas.getContext('2d').putImageData(imageData, 0, 0);
18
+ return canvas;
19
+ }
2
20
  export function createImageResourceFromCanvas(canvas) {
3
21
  return createEntity({
4
22
  alphaType: 'straight',
23
+ compressed: null,
5
24
  data: null,
6
25
  format: 'rgba8unorm',
7
26
  height: canvas.height,
@@ -13,6 +32,7 @@ export function createImageResourceFromCanvas(canvas) {
13
32
  export function createImageResourceFromImageBitmap(bitmap) {
14
33
  return createEntity({
15
34
  alphaType: 'straight',
35
+ compressed: null,
16
36
  data: null,
17
37
  format: 'rgba8unorm',
18
38
  height: bitmap.height,
@@ -24,6 +44,7 @@ export function createImageResourceFromImageBitmap(bitmap) {
24
44
  export function createImageResourceFromImageElement(img) {
25
45
  return createEntity({
26
46
  alphaType: 'straight',
47
+ compressed: null,
27
48
  data: null,
28
49
  format: 'rgba8unorm',
29
50
  height: img.height,
@@ -32,35 +53,6 @@ export function createImageResourceFromImageElement(img) {
32
53
  width: img.width,
33
54
  });
34
55
  }
35
- export function detectImageMimeType(data) {
36
- const b = data instanceof Uint8Array ? data : new Uint8Array(data);
37
- if (b.byteLength < 4)
38
- return null;
39
- // PNG: 89 50 4E 47 0D 0A 1A 0A
40
- if (b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47)
41
- return 'image/png';
42
- // JPEG: FF D8 FF
43
- if (b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff)
44
- return 'image/jpeg';
45
- // GIF87a / GIF89a: 47 49 46 38
46
- if (b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x38)
47
- return 'image/gif';
48
- // WebP: RIFF....WEBP (bytes 0-3 and 8-11)
49
- if (b.byteLength >= 12 &&
50
- b[0] === 0x52 &&
51
- b[1] === 0x49 &&
52
- b[2] === 0x46 &&
53
- b[3] === 0x46 &&
54
- b[8] === 0x57 &&
55
- b[9] === 0x45 &&
56
- b[10] === 0x42 &&
57
- b[11] === 0x50)
58
- return 'image/webp';
59
- // BMP: 42 4D
60
- if (b[0] === 0x42 && b[1] === 0x4d)
61
- return 'image/bmp';
62
- return null;
63
- }
64
56
  export function isImageResourceSameOrigin(url) {
65
57
  if (url.startsWith('data:') || url.startsWith('blob:'))
66
58
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"imageResourceFrom.js","sourceRoot":"","sources":["../src/imageResourceFrom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imageResourceFrom.js","sourceRoot":"","sources":["../src/imageResourceFrom.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@flighthq/image",
3
- "version": "0.1.0",
3
+ "version": "0.2.1-next.410.a23f189",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/flighthq/flight.git",
7
+ "directory": "packages/image"
8
+ },
4
9
  "type": "module",
5
10
  "main": "dist/index.js",
6
11
  "types": "dist/index.d.ts",
@@ -27,8 +32,9 @@
27
32
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
28
33
  },
29
34
  "dependencies": {
30
- "@flighthq/entity": "0.1.0",
31
- "@flighthq/types": "0.1.0"
35
+ "@flighthq/entity": "0.2.1-next.410.a23f189",
36
+ "@flighthq/image-codec": "0.2.1-next.410.a23f189",
37
+ "@flighthq/types": "0.2.1-next.410.a23f189"
32
38
  },
33
39
  "devDependencies": {
34
40
  "typescript": "^5.3.0"
@@ -1,15 +1,37 @@
1
+ import type { ImageResourceCompressed } from '@flighthq/types';
2
+
1
3
  import {
2
4
  cloneImageResource,
5
+ createCompressedImageResource,
3
6
  createImageResource,
4
7
  disposeImageResource,
5
8
  getImageResourceByteSize,
6
9
  hasImageResourceData,
10
+ hasImageResourcePixels,
7
11
  hasImageResourceSource,
8
12
  invalidateImageResource,
9
13
  isImageResourceEmpty,
10
14
  setImageResourceSource,
11
15
  } from './imageResource';
12
16
 
17
+ // A minimal single-mip bc3 4x4 compressed payload stand-in for the resource wrapper tests.
18
+ function makeCompressed(): ImageResourceCompressed {
19
+ return {
20
+ container: {
21
+ format: 'bc3',
22
+ width: 4,
23
+ height: 4,
24
+ depth: 1,
25
+ mipLevels: 1,
26
+ layers: 1,
27
+ faces: 1,
28
+ supercompression: 'None',
29
+ levels: [{ byteOffset: 0, byteLength: 16, width: 4, height: 4 }],
30
+ },
31
+ payload: new Uint8Array(16),
32
+ };
33
+ }
34
+
13
35
  describe('cloneImageResource', () => {
14
36
  it('copies fields, shares the element, and gives an independent identity', () => {
15
37
  const element = { width: 4, height: 5 } as HTMLImageElement;
@@ -40,6 +62,25 @@ describe('cloneImageResource', () => {
40
62
  expect(copy.format).toStrictEqual('bgra8unorm');
41
63
  expect(copy.alphaType).toStrictEqual('premultiplied');
42
64
  });
65
+
66
+ it('shares the compressed payload by reference', () => {
67
+ const resource = createCompressedImageResource(makeCompressed());
68
+ const copy = cloneImageResource(resource);
69
+ expect(copy.compressed).toBe(resource.compressed);
70
+ });
71
+ });
72
+
73
+ describe('createCompressedImageResource', () => {
74
+ it('wraps the container, mirrors its base dimensions, and leaves source/data null', () => {
75
+ const compressed = makeCompressed();
76
+ const resource = createCompressedImageResource(compressed);
77
+ expect(resource.compressed).toBe(compressed);
78
+ expect(resource.width).toStrictEqual(4);
79
+ expect(resource.height).toStrictEqual(4);
80
+ expect(resource.source).toBeNull();
81
+ expect(resource.data).toBeNull();
82
+ expect(resource.version).toStrictEqual(0);
83
+ });
43
84
  });
44
85
 
45
86
  describe('createImageResource', () => {
@@ -69,15 +110,17 @@ describe('createImageResource', () => {
69
110
  });
70
111
 
71
112
  describe('disposeImageResource', () => {
72
- it('releases the element and data and marks the resource changed', () => {
113
+ it('releases the element, data, and compressed payload and marks the resource changed', () => {
73
114
  const resource = createImageResource({ width: 4, height: 5 } as HTMLImageElement);
74
115
  resource.data = new Uint8ClampedArray(4 * 5 * 4);
116
+ resource.compressed = makeCompressed();
75
117
  const before = resource.version;
76
118
 
77
119
  disposeImageResource(resource);
78
120
 
79
121
  expect(resource.source).toBeNull();
80
122
  expect(resource.data).toBeNull();
123
+ expect(resource.compressed).toBeNull();
81
124
  expect(resource.version).toStrictEqual(before + 1);
82
125
  });
83
126
  });
@@ -112,6 +155,28 @@ describe('hasImageResourceData', () => {
112
155
  });
113
156
  });
114
157
 
158
+ describe('hasImageResourcePixels', () => {
159
+ it('is false when neither representation is present', () => {
160
+ expect(hasImageResourcePixels(createImageResource())).toStrictEqual(false);
161
+ });
162
+
163
+ it('is true for a data-only resource (a generated Surface)', () => {
164
+ const resource = createImageResource();
165
+ resource.data = new Uint8ClampedArray(4);
166
+ expect(hasImageResourcePixels(resource)).toStrictEqual(true);
167
+ });
168
+
169
+ it('is true for an element-only resource', () => {
170
+ expect(hasImageResourcePixels(createImageResource({ width: 1, height: 1 } as HTMLImageElement))).toStrictEqual(
171
+ true,
172
+ );
173
+ });
174
+
175
+ it('is true for a compressed-only resource (a parsed container)', () => {
176
+ expect(hasImageResourcePixels(createCompressedImageResource(makeCompressed()))).toStrictEqual(true);
177
+ });
178
+ });
179
+
115
180
  describe('hasImageResourceSource', () => {
116
181
  it('is false without an element and true with one', () => {
117
182
  expect(hasImageResourceSource(createImageResource())).toStrictEqual(false);
@@ -1,8 +1,9 @@
1
+ import { createImageResource } from './imageResource';
1
2
  import {
3
+ createCanvasFromImageResource,
2
4
  createImageResourceFromCanvas,
3
5
  createImageResourceFromImageBitmap,
4
6
  createImageResourceFromImageElement,
5
- detectImageMimeType,
6
7
  isImageResourceSameOrigin,
7
8
  loadImageResourceFromBase64,
8
9
  loadImageResourceFromBlob,
@@ -20,6 +21,32 @@ afterEach(() => {
20
21
  delete (HTMLImageElement.prototype as Partial<HTMLImageElement>).decode;
21
22
  });
22
23
 
24
+ describe('createCanvasFromImageResource', () => {
25
+ function makeDataResource(width: number, height: number) {
26
+ const resource = createImageResource();
27
+ resource.width = width;
28
+ resource.height = height;
29
+ resource.data = new Uint8ClampedArray(width * height * 4).fill(255);
30
+ return resource;
31
+ }
32
+
33
+ it('materializes a canvas sized to the resource', () => {
34
+ const canvas = createCanvasFromImageResource(makeDataResource(6, 5));
35
+ expect(canvas).toBeInstanceOf(HTMLCanvasElement);
36
+ expect(canvas!.width).toBe(6);
37
+ expect(canvas!.height).toBe(5);
38
+ });
39
+
40
+ it('returns a new canvas each call', () => {
41
+ const resource = makeDataResource(4, 4);
42
+ expect(createCanvasFromImageResource(resource)).not.toBe(createCanvasFromImageResource(resource));
43
+ });
44
+
45
+ it('returns null for an element-only resource with no data', () => {
46
+ expect(createCanvasFromImageResource(createImageResource(document.createElement('img')))).toBeNull();
47
+ });
48
+ });
49
+
23
50
  describe('createImageResourceFromCanvas', () => {
24
51
  it('wraps a canvas with correct dimensions', () => {
25
52
  const canvas = document.createElement('canvas');
@@ -88,61 +115,6 @@ describe('createImageResourceFromImageElement', () => {
88
115
  });
89
116
  });
90
117
 
91
- describe('detectImageMimeType', () => {
92
- it('returns null for a buffer that is too small', () => {
93
- expect(detectImageMimeType(new ArrayBuffer(2))).toBeNull();
94
- });
95
-
96
- it('returns null for an unrecognised header', () => {
97
- const buf = new ArrayBuffer(16);
98
- new Uint8Array(buf).set([0x00, 0x01, 0x02, 0x03]);
99
- expect(detectImageMimeType(buf)).toBeNull();
100
- });
101
-
102
- it('detects PNG', () => {
103
- const buf = new ArrayBuffer(16);
104
- new Uint8Array(buf).set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
105
- expect(detectImageMimeType(buf)).toBe('image/png');
106
- });
107
-
108
- it('detects JPEG', () => {
109
- const buf = new ArrayBuffer(16);
110
- new Uint8Array(buf).set([0xff, 0xd8, 0xff, 0xe0]);
111
- expect(detectImageMimeType(buf)).toBe('image/jpeg');
112
- });
113
-
114
- it('detects GIF', () => {
115
- const buf = new ArrayBuffer(16);
116
- new Uint8Array(buf).set([0x47, 0x49, 0x46, 0x38, 0x39, 0x61]);
117
- expect(detectImageMimeType(buf)).toBe('image/gif');
118
- });
119
-
120
- it('detects WebP', () => {
121
- const buf = new ArrayBuffer(16);
122
- new Uint8Array(buf).set([
123
- 0x52,
124
- 0x49,
125
- 0x46,
126
- 0x46, // RIFF
127
- 0x00,
128
- 0x00,
129
- 0x00,
130
- 0x00, // size (ignored)
131
- 0x57,
132
- 0x45,
133
- 0x42,
134
- 0x50, // WEBP
135
- ]);
136
- expect(detectImageMimeType(buf)).toBe('image/webp');
137
- });
138
-
139
- it('detects BMP', () => {
140
- const buf = new ArrayBuffer(16);
141
- new Uint8Array(buf).set([0x42, 0x4d]);
142
- expect(detectImageMimeType(buf)).toBe('image/bmp');
143
- });
144
- });
145
-
146
118
  describe('isImageResourceSameOrigin', () => {
147
119
  it('returns true for data: URLs', () => {
148
120
  expect(isImageResourceSameOrigin('data:image/png;base64,abc')).toBe(true);