image-js 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/image-js.esm.js +1041 -245
  2. package/dist/image-js.esm.js.map +1 -1
  3. package/dist/image-js.esm.min.js +2 -2
  4. package/dist/image-js.esm.min.js.map +1 -1
  5. package/dist/image-js.umd.js +1009 -211
  6. package/dist/image-js.umd.js.map +1 -1
  7. package/dist/image-js.umd.min.js +2 -2
  8. package/dist/image-js.umd.min.js.map +1 -1
  9. package/dist-types/image-js.d.ts +4 -5
  10. package/lib/Mask.d.ts +1 -1
  11. package/lib/Mask.js +1 -1
  12. package/lib/draw/drawLineOnImage.d.ts.map +1 -1
  13. package/lib/draw/drawLineOnImage.js.map +1 -1
  14. package/lib/extra/draw/draw_text.d.ts +47 -0
  15. package/lib/extra/draw/draw_text.d.ts.map +1 -0
  16. package/lib/extra/draw/draw_text.js +108 -0
  17. package/lib/extra/draw/draw_text.js.map +1 -0
  18. package/lib/extra/draw/index.d.ts +3 -0
  19. package/lib/extra/draw/index.d.ts.map +1 -0
  20. package/lib/extra/draw/index.js +3 -0
  21. package/lib/extra/draw/index.js.map +1 -0
  22. package/lib/{ssim → extra/ssim}/compute_dssim.d.ts +2 -2
  23. package/lib/extra/ssim/compute_dssim.d.ts.map +1 -0
  24. package/lib/{ssim → extra/ssim}/compute_dssim.js +1 -1
  25. package/lib/extra/ssim/compute_dssim.js.map +1 -0
  26. package/lib/{ssim → extra/ssim}/compute_ssim.d.ts +1 -1
  27. package/lib/extra/ssim/compute_ssim.d.ts.map +1 -0
  28. package/lib/{ssim → extra/ssim}/compute_ssim.js +2 -2
  29. package/lib/extra/ssim/compute_ssim.js.map +1 -0
  30. package/lib/extra/ssim/index.d.ts +3 -0
  31. package/lib/extra/ssim/index.d.ts.map +1 -0
  32. package/lib/extra/ssim/index.js +3 -0
  33. package/lib/extra/ssim/index.js.map +1 -0
  34. package/lib/featureMatching/matching/filterEuclideanDistance.d.ts.map +1 -1
  35. package/lib/featureMatching/matching/filterEuclideanDistance.js +6 -7
  36. package/lib/featureMatching/matching/filterEuclideanDistance.js.map +1 -1
  37. package/lib/featureMatching/matching/filterSmallestDistanceMatches.d.ts.map +1 -1
  38. package/lib/featureMatching/matching/filterSmallestDistanceMatches.js +6 -3
  39. package/lib/featureMatching/matching/filterSmallestDistanceMatches.js.map +1 -1
  40. package/lib/featureMatching/utils/sortByDistance.d.ts.map +1 -1
  41. package/lib/featureMatching/utils/sortByDistance.js +3 -1
  42. package/lib/featureMatching/utils/sortByDistance.js.map +1 -1
  43. package/lib/featureMatching/utils/sortBySourceDest.d.ts.map +1 -1
  44. package/lib/featureMatching/utils/sortBySourceDest.js +6 -2
  45. package/lib/featureMatching/utils/sortBySourceDest.js.map +1 -1
  46. package/lib/index_browser.d.ts +3 -0
  47. package/lib/index_browser.d.ts.map +1 -0
  48. package/lib/index_browser.js +5 -0
  49. package/lib/index_browser.js.map +1 -0
  50. package/lib/index_full.d.ts +4 -0
  51. package/lib/index_full.d.ts.map +1 -0
  52. package/lib/index_full.js +5 -0
  53. package/lib/index_full.js.map +1 -0
  54. package/lib/load/decode.d.ts.map +1 -1
  55. package/lib/load/decode.js +2 -0
  56. package/lib/load/decode.js.map +1 -1
  57. package/lib/load/decodeBmp.d.ts +8 -0
  58. package/lib/load/decodeBmp.d.ts.map +1 -0
  59. package/lib/load/decodeBmp.js +36 -0
  60. package/lib/load/decodeBmp.js.map +1 -0
  61. package/lib/load/decodePng.d.ts.map +1 -1
  62. package/lib/load/decodePng.js +29 -5
  63. package/lib/load/decodePng.js.map +1 -1
  64. package/lib/load/decodeTiff.d.ts.map +1 -1
  65. package/lib/load/decodeTiff.js +44 -21
  66. package/lib/load/decodeTiff.js.map +1 -1
  67. package/lib/load/read.d.ts +1 -1
  68. package/lib/load/read.js +1 -1
  69. package/lib/maskAnalysis/utils/getMbrAngle.d.ts.map +1 -1
  70. package/lib/maskAnalysis/utils/getMbrAngle.js +2 -1
  71. package/lib/maskAnalysis/utils/getMbrAngle.js.map +1 -1
  72. package/lib/maskAnalysis/utils/monotoneChainConvexHull.d.ts.map +1 -1
  73. package/lib/maskAnalysis/utils/monotoneChainConvexHull.js +2 -1
  74. package/lib/maskAnalysis/utils/monotoneChainConvexHull.js.map +1 -1
  75. package/lib/save/encodeBmp.d.ts +4 -4
  76. package/lib/save/encodeBmp.d.ts.map +1 -1
  77. package/lib/save/encodeBmp.js +22 -14
  78. package/lib/save/encodeBmp.js.map +1 -1
  79. package/lib/save/write.d.ts +1 -1
  80. package/lib/save/write.js +1 -1
  81. package/lib/stack/load/decodeApng.d.ts +8 -0
  82. package/lib/stack/load/decodeApng.d.ts.map +1 -0
  83. package/lib/stack/load/decodeApng.js +60 -0
  84. package/lib/stack/load/decodeApng.js.map +1 -0
  85. package/lib/stack/load/decodeStack.d.ts.map +1 -1
  86. package/lib/stack/load/decodeStack.js +2 -0
  87. package/lib/stack/load/decodeStack.js.map +1 -1
  88. package/lib/utils/cross_platform.d.ts +8 -0
  89. package/lib/utils/cross_platform.d.ts.map +1 -1
  90. package/lib/utils/cross_platform.js +34 -2
  91. package/lib/utils/cross_platform.js.map +1 -1
  92. package/lib/utils/geometry/points.d.ts.map +1 -1
  93. package/lib/utils/geometry/points.js +3 -1
  94. package/lib/utils/geometry/points.js.map +1 -1
  95. package/lib/utils/geometry/removeClosePoints.d.ts.map +1 -1
  96. package/lib/utils/geometry/removeClosePoints.js +2 -1
  97. package/lib/utils/geometry/removeClosePoints.js.map +1 -1
  98. package/lib/utils/setBlendedPixel.d.ts +1 -1
  99. package/lib/utils/setBlendedPixel.js +1 -1
  100. package/lib/utils/setBlendedVisiblePixel.d.ts +1 -1
  101. package/lib/utils/setBlendedVisiblePixel.js +1 -1
  102. package/package.json +43 -29
  103. package/src/Mask.ts +1 -1
  104. package/src/draw/drawLineOnImage.ts +0 -1
  105. package/src/extra/draw/draw_text.ts +194 -0
  106. package/src/extra/draw/index.ts +2 -0
  107. package/src/{ssim → extra/ssim}/compute_dssim.ts +3 -3
  108. package/src/{ssim → extra/ssim}/compute_ssim.ts +3 -3
  109. package/src/extra/ssim/index.ts +2 -0
  110. package/src/featureMatching/matching/filterEuclideanDistance.ts +6 -13
  111. package/src/featureMatching/matching/filterSmallestDistanceMatches.ts +6 -9
  112. package/src/featureMatching/utils/sortByDistance.ts +3 -1
  113. package/src/featureMatching/utils/sortBySourceDest.ts +6 -2
  114. package/src/index_browser.ts +4 -0
  115. package/src/index_full.ts +4 -0
  116. package/src/load/decode.ts +2 -1
  117. package/src/load/decodeBmp.ts +37 -0
  118. package/src/load/decodePng.ts +39 -7
  119. package/src/load/decodeTiff.ts +53 -22
  120. package/src/load/read.ts +1 -1
  121. package/src/maskAnalysis/utils/getMbrAngle.ts +2 -1
  122. package/src/maskAnalysis/utils/monotoneChainConvexHull.ts +2 -1
  123. package/src/save/encodeBmp.ts +22 -15
  124. package/src/save/write.ts +1 -1
  125. package/src/stack/load/decodeApng.ts +71 -0
  126. package/src/stack/load/decodeStack.ts +2 -0
  127. package/src/utils/cross_platform.ts +47 -4
  128. package/src/utils/geometry/points.ts +3 -1
  129. package/src/utils/geometry/removeClosePoints.ts +2 -1
  130. package/src/utils/setBlendedPixel.ts +1 -1
  131. package/src/utils/setBlendedVisiblePixel.ts +1 -1
  132. package/lib/ssim/compute_dssim.d.ts.map +0 -1
  133. package/lib/ssim/compute_dssim.js.map +0 -1
  134. package/lib/ssim/compute_ssim.d.ts.map +0 -1
  135. package/lib/ssim/compute_ssim.js.map +0 -1
  136. package/lib/ssim/index.d.ts +0 -3
  137. package/lib/ssim/index.d.ts.map +0 -1
  138. package/lib/ssim/index.js +0 -3
  139. package/lib/ssim/index.js.map +0 -1
  140. package/src/ssim/index.ts +0 -2
@@ -15,12 +15,16 @@ export function decodePng(buffer: Uint8Array): Image {
15
15
  const png = decode(buffer);
16
16
 
17
17
  let colorModel: ImageColorModel;
18
- const bitDepth: BitDepth = png.depth === 16 ? 16 : 8;
19
-
18
+ const bitDepth: BitDepth = png.depth as BitDepth;
20
19
  if (png.palette) {
21
20
  return loadPalettePng(png);
22
21
  }
23
-
22
+ if (bitDepth === 1) {
23
+ return new Image(png.width, png.height, {
24
+ data: decodeBinary(png),
25
+ colorModel: 'GREY',
26
+ });
27
+ }
24
28
  switch (png.channels) {
25
29
  case 1:
26
30
  colorModel = 'GREY';
@@ -37,6 +41,7 @@ export function decodePng(buffer: Uint8Array): Image {
37
41
  default:
38
42
  throw new RangeError(`invalid number of channels: ${png.channels}`);
39
43
  }
44
+
40
45
  return new Image(png.width, png.height, {
41
46
  colorModel,
42
47
  bitDepth,
@@ -52,7 +57,7 @@ export function decodePng(buffer: Uint8Array): Image {
52
57
  function loadPalettePng(png: DecodedPng): Image {
53
58
  assert(png.palette);
54
59
  const pixels = png.width * png.height;
55
- const data = new Uint8Array(pixels * 3);
60
+ const data = new Uint8Array(pixels * png.palette[0].length);
56
61
  const pixelsPerByte = 8 / png.depth;
57
62
  const factor = png.depth < 8 ? pixelsPerByte : 1;
58
63
  const mask = Number.parseInt('1'.repeat(png.depth), 2);
@@ -67,12 +72,39 @@ function loadPalettePng(png: DecodedPng): Image {
67
72
  mask;
68
73
  }
69
74
  const paletteValue = png.palette[value];
70
- data[dataIndex++] = paletteValue[0];
71
- data[dataIndex++] = paletteValue[1];
72
- data[dataIndex++] = paletteValue[2];
75
+ for (const paletteChannel of paletteValue) {
76
+ data[dataIndex++] = paletteChannel;
77
+ }
73
78
  }
74
79
 
75
80
  return new Image(png.width, png.height, {
76
81
  data,
82
+ colorModel: png.palette[0].length === 4 ? 'RGBA' : 'RGB',
77
83
  });
78
84
  }
85
+
86
+ function decodeBinary(png: DecodedPng): Uint8Array {
87
+ const totalPixels = png.width * png.height;
88
+ const result = new Uint8Array(totalPixels);
89
+ const pngData = png.data;
90
+ const padding = png.width % 8;
91
+ const bytesPerLine = Math.ceil(png.width / 8);
92
+ let pixelIndex = 0;
93
+ for (
94
+ let byteIndex = 0;
95
+ byteIndex < pngData.length && pixelIndex < totalPixels;
96
+ byteIndex++
97
+ ) {
98
+ const byte = pngData[byteIndex];
99
+ const limit = byteIndex % bytesPerLine === 0 ? 8 - padding : 0;
100
+ for (
101
+ let bitIndex = 7;
102
+ bitIndex >= limit && pixelIndex < totalPixels;
103
+ bitIndex--
104
+ ) {
105
+ const bit = (byte >> bitIndex) & 1;
106
+ result[pixelIndex++] = bit * 255;
107
+ }
108
+ }
109
+ return result;
110
+ }
@@ -13,9 +13,8 @@ type TiffIfd = ReturnType<typeof decode>[number];
13
13
  * @returns The decoded image.
14
14
  */
15
15
  export function decodeTiff(buffer: Uint8Array): Image {
16
- const result = decode(buffer);
16
+ const result = decode(buffer, { pages: [0] });
17
17
  return getImageFromIFD(result[0]);
18
- // TODO: optimize not to decode whole file
19
18
  }
20
19
 
21
20
  /**
@@ -24,39 +23,71 @@ export function decodeTiff(buffer: Uint8Array): Image {
24
23
  * @returns The decoded image.
25
24
  */
26
25
  export function getImageFromIFD(ifd: TiffIfd): Image {
26
+ if (ifd.data instanceof Float32Array || ifd.data instanceof Float64Array) {
27
+ throw new Error('Float TIFF data is not supported.');
28
+ }
29
+
27
30
  if (ifd.type === 3) {
28
- // Palette
29
- const data = new Uint16Array(3 * ifd.width * ifd.height);
31
+ const hasAlpha = ifd.samplesPerPixel === 2;
32
+ const pixelLength = hasAlpha ? 4 : 3;
33
+ const data = new Uint16Array(pixelLength * ifd.width * ifd.height);
30
34
  const palette = ifd.palette as Array<[number, number, number]>;
31
35
  let ptr = 0;
32
- for (const index of ifd.data) {
33
- const color = palette[index];
34
- data[ptr++] = color[0];
35
- data[ptr++] = color[1];
36
- data[ptr++] = color[2];
36
+ if (hasAlpha) {
37
+ for (
38
+ let index = 0;
39
+ index < ifd.data.length;
40
+ index += ifd.samplesPerPixel
41
+ ) {
42
+ const color = palette[ifd.data[index]];
43
+ data[ptr++] = color[0];
44
+ data[ptr++] = color[1];
45
+ data[ptr++] = color[2];
46
+ // To ensure that the value is 16 bits.
47
+ data[ptr++] = Math.round(
48
+ (ifd.data[index + 1] / 2 ** ifd.bitsPerSample) * 65535,
49
+ );
50
+ }
51
+ } else {
52
+ for (
53
+ let index = 0;
54
+ index < ifd.data.length;
55
+ index += ifd.samplesPerPixel
56
+ ) {
57
+ const color = palette[ifd.data[index]];
58
+ data[ptr++] = color[0];
59
+ data[ptr++] = color[1];
60
+ data[ptr++] = color[2];
61
+ }
37
62
  }
63
+
38
64
  return new Image(ifd.width, ifd.height, {
39
65
  data,
40
- // TODO: handle alpha properly
41
- colorModel: ifd.alpha ? 'RGBA' : 'RGB',
42
- // TODO: handle other bit depths
66
+ colorModel: hasAlpha ? 'RGBA' : 'RGB',
43
67
  bitDepth: 16,
44
68
  meta: getMetadata(ifd),
45
69
  });
70
+ } else if (ifd.type === 1 || ifd.type === 0) {
71
+ if (ifd.bitsPerSample !== 1) {
72
+ return new Image(ifd.width, ifd.height, {
73
+ data: ifd.data,
74
+ bitDepth: ifd.bitsPerSample as BitDepth,
75
+ colorModel: ifd.alpha ? 'GREYA' : 'GREY',
76
+ meta: getMetadata(ifd),
77
+ });
78
+ } else {
79
+ return new Image(ifd.width, ifd.height, {
80
+ data: ifd.data.map((pixel) => pixel * 255),
81
+ bitDepth: 8 as BitDepth,
82
+ colorModel: 'GREY',
83
+ meta: getMetadata(ifd),
84
+ });
85
+ }
46
86
  } else {
47
87
  return new Image(ifd.width, ifd.height, {
48
- // TODO: handle float data
49
- // @ts-expect-error float data not handled yet
50
88
  data: ifd.data,
51
89
  bitDepth: ifd.bitsPerSample as BitDepth,
52
- colorModel:
53
- ifd.type === 2
54
- ? ifd.alpha
55
- ? 'RGBA'
56
- : 'RGB'
57
- : ifd.alpha
58
- ? 'GREYA'
59
- : 'GREY',
90
+ colorModel: ifd.alpha ? 'RGBA' : 'RGB',
60
91
  meta: getMetadata(ifd),
61
92
  });
62
93
  }
package/src/load/read.ts CHANGED
@@ -17,7 +17,7 @@ export async function read(path: string | URL): Promise<Image> {
17
17
  }
18
18
 
19
19
  /**
20
- * Synchronous version of @see {@link read}.
20
+ * Synchronous version of {@link read}.
21
21
  * This method is only implemented for Node.js.
22
22
  * @param path - The path to the image.
23
23
  * @returns Image instance.
@@ -14,7 +14,8 @@ const topFirst = (mbrPoint1: Point, mbrPoint2: Point) =>
14
14
  * @returns The angle in degrees.
15
15
  */
16
16
  export function getMbrAngle(mbr: readonly Point[]): number {
17
- const sorted = mbr.slice().sort(leftFirst);
17
+ const sorted = mbr.slice();
18
+ sorted.sort(leftFirst);
18
19
  const left = sorted.slice(0, 2);
19
20
  const right = sorted.slice(2, 4);
20
21
  left.sort(topFirst);
@@ -21,7 +21,8 @@ export function monotoneChainConvexHull(
21
21
  ): Point[] {
22
22
  const { sorted = false } = options;
23
23
  if (!sorted) {
24
- points = points.slice().sort(byXThenY);
24
+ points = points.slice();
25
+ points.sort(byXThenY);
25
26
  }
26
27
 
27
28
  const n = points.length;
@@ -1,24 +1,31 @@
1
1
  import * as bmp from 'fast-bmp';
2
2
 
3
- import type { Image } from '../Image.js';
4
- import { Mask } from '../Mask.js';
3
+ import { Image } from '../Image.js';
4
+ import type { Mask } from '../Mask.js';
5
5
 
6
6
  /**
7
7
  * Creates a BMP buffer from a mask.
8
- * @param mask - The mask instance.
8
+ * @param image - The mask instance.
9
9
  * @returns The buffer.
10
10
  */
11
- export function encodeBmp(mask: Image | Mask) {
12
- if (!(mask instanceof Mask)) {
13
- throw new TypeError('Image bmp encoding is not implemented.');
11
+ export function encodeBmp(image: Image | Mask) {
12
+ if (image instanceof Image) {
13
+ return bmp.encode({
14
+ width: image.width,
15
+ height: image.height,
16
+ components: image.components,
17
+ bitsPerPixel: image.channels * image.bitDepth,
18
+ channels: image.channels,
19
+ data: image.getRawImage().data,
20
+ });
21
+ } else {
22
+ return bmp.encode({
23
+ width: image.width,
24
+ height: image.height,
25
+ components: 1,
26
+ bitsPerPixel: 1,
27
+ channels: 1,
28
+ data: image.getRawImage().data,
29
+ });
14
30
  }
15
- const imageData = mask.getRawImage();
16
- return bmp.encode({
17
- width: imageData.width,
18
- height: imageData.height,
19
- components: 1,
20
- bitsPerPixel: 1,
21
- channels: 1,
22
- data: imageData.data,
23
- });
24
31
  }
package/src/save/write.ts CHANGED
@@ -106,7 +106,7 @@ export async function write(
106
106
  }
107
107
 
108
108
  /**
109
- * Synchronous version of @see {@link write}.
109
+ * Synchronous version of {@link write}.
110
110
  * This method is only implemented for Node.js.
111
111
  * @param path - Path where the image should be written.
112
112
  * @param image - Image to save.
@@ -0,0 +1,71 @@
1
+ import type { IndexedColors } from 'fast-png';
2
+ import { decodeApng } from 'fast-png';
3
+
4
+ import { Image } from '../../Image.ts';
5
+ import { Stack } from '../../Stack.ts';
6
+ import type { ImageColorModel } from '../../utils/constants/colorModels.ts';
7
+
8
+ /**
9
+ * Decodes APNG image into a Stack
10
+ * @param data - APNG data.
11
+ * @returns stack of frames.
12
+ */
13
+ export function decodeStackFromApng(data: Uint8Array) {
14
+ const decodedApng = decodeApng(data);
15
+ const images: Image[] = [];
16
+ let colorModel: ImageColorModel;
17
+ switch (decodedApng.channels) {
18
+ case 1:
19
+ if (decodedApng.palette) {
20
+ colorModel = decodedApng.palette[0].length === 3 ? 'RGB' : 'RGBA';
21
+ } else {
22
+ colorModel = 'GREY';
23
+ }
24
+ break;
25
+ case 2:
26
+ colorModel = 'GREYA';
27
+ break;
28
+ case 3:
29
+ colorModel = 'RGB';
30
+ break;
31
+ default:
32
+ colorModel = 'RGBA';
33
+ break;
34
+ }
35
+ if (decodedApng.palette) {
36
+ for (const image of decodedApng.frames) {
37
+ images.push(
38
+ new Image(decodedApng.width, decodedApng.height, {
39
+ data: convertIndexedData(
40
+ image.data as Uint8Array,
41
+ decodedApng.palette,
42
+ ),
43
+ colorModel,
44
+ }),
45
+ );
46
+ }
47
+ } else {
48
+ for (const image of decodedApng.frames) {
49
+ images.push(
50
+ new Image(decodedApng.width, decodedApng.height, {
51
+ data: image.data,
52
+ colorModel,
53
+ }),
54
+ );
55
+ }
56
+ }
57
+
58
+ const stack = new Stack(images);
59
+
60
+ return stack;
61
+ }
62
+
63
+ function convertIndexedData(data: Uint8Array, palette: IndexedColors) {
64
+ const result = new Uint8Array(data.length * palette[0].length);
65
+ for (let i = 0; i < data.length; i++) {
66
+ for (let channel = 0; channel < palette[0].length; channel++) {
67
+ result[i * palette[0].length + channel] = palette[data[i]][channel];
68
+ }
69
+ }
70
+ return result;
71
+ }
@@ -3,6 +3,7 @@ import { match } from 'ts-pattern';
3
3
 
4
4
  import type { Stack } from '../../Stack.js';
5
5
 
6
+ import { decodeStackFromApng } from './decodeApng.ts';
6
7
  import { decodeStackFromTiff } from './decodeTiff.js';
7
8
 
8
9
  /**
@@ -20,6 +21,7 @@ export function decodeStack(data: ArrayBufferView): Stack {
20
21
  const type = imageType(typedArray);
21
22
  return match(type)
22
23
  .with({ mime: 'image/tiff' }, () => decodeStackFromTiff(typedArray))
24
+ .with({ mime: 'image/png' }, () => decodeStackFromApng(typedArray))
23
25
  .otherwise(() => {
24
26
  throw new RangeError(`invalid data format: ${type?.mime}`);
25
27
  });
@@ -1,13 +1,15 @@
1
+ import type {
2
+ Canvas as SkiaCanvas,
3
+ CanvasRenderingContext2D as SkiaCanvasRenderingContext2D,
4
+ } from 'skia-canvas';
5
+
1
6
  /**
2
7
  * Returns builtin Node.js modules or throws an error saying that the method is only implemented in Node.js.
3
8
  * @param methodName - Name of the method that calls this function
4
9
  * @returns - The `fs`, `path` and `url` Node.js modules.
5
10
  */
6
11
  export function getNodeApiOrThrow(methodName: string) {
7
- if (
8
- typeof process === 'undefined' ||
9
- typeof process.getBuiltinModule !== 'function'
10
- ) {
12
+ if (!isNode()) {
11
13
  throw new Error(`${methodName} is only implemented for Node.js`);
12
14
  }
13
15
  return {
@@ -16,3 +18,44 @@ export function getNodeApiOrThrow(methodName: string) {
16
18
  url: process.getBuiltinModule('node:url'),
17
19
  };
18
20
  }
21
+
22
+ let CanvasCtorBrowser: typeof OffscreenCanvas;
23
+ let CanvasCtorNode: typeof SkiaCanvas;
24
+
25
+ /**
26
+ * Returns a 2D canvas context for rendering on the browser or Node.js.
27
+ * @param width - Width of the canvas.
28
+ * @param height - Height of the canvas.
29
+ * @returns The initialised canvas context.
30
+ */
31
+ export function getCanvasContext(
32
+ width: number,
33
+ height: number,
34
+ ): OffscreenCanvasRenderingContext2D | SkiaCanvasRenderingContext2D {
35
+ if (isNode()) {
36
+ CanvasCtorNode ??= getRequireFn()('skia-canvas').Canvas;
37
+ return new CanvasCtorNode(width, height).getContext('2d');
38
+ } else {
39
+ CanvasCtorBrowser ??= globalThis.OffscreenCanvas;
40
+ const context = new CanvasCtorBrowser(width, height).getContext('2d');
41
+ if (!context) {
42
+ throw new Error('Failed to create canvas context');
43
+ }
44
+ return context;
45
+ }
46
+ }
47
+
48
+ function isNode() {
49
+ return (
50
+ typeof process !== 'undefined' &&
51
+ typeof process.getBuiltinModule === 'function'
52
+ );
53
+ }
54
+
55
+ let requireFn: NodeJS.Require;
56
+ function getRequireFn() {
57
+ requireFn ??= process
58
+ .getBuiltinModule('node:module')
59
+ .createRequire(import.meta.url);
60
+ return requireFn;
61
+ }
@@ -94,9 +94,11 @@ export function round(point: Point): Point {
94
94
  * @returns Sorted points.
95
95
  */
96
96
  export function sortByColumnRow(points: Point[]): Point[] {
97
- return points.slice().sort((point1, point2) => {
97
+ const sortedPoints = points.slice();
98
+ sortedPoints.sort((point1, point2) => {
98
99
  if (point1.column < point2.column) return -1;
99
100
  if (point1.column > point2.column) return 1;
100
101
  return point1.row - point2.row;
101
102
  });
103
+ return sortedPoints;
102
104
  }
@@ -42,7 +42,8 @@ export function removeClosePoints(
42
42
  const channel = options?.channel || 0;
43
43
  const isMax = kind === 'maximum';
44
44
 
45
- const sortedPoints = points.slice().sort(getSort(image, channel, isMax));
45
+ const sortedPoints = points.slice();
46
+ sortedPoints.sort(getSort(image, channel, isMax));
46
47
 
47
48
  if (distance > 0) {
48
49
  for (let i = 0; i < sortedPoints.length; i++) {
@@ -9,7 +9,7 @@ import { assert } from './validators/assert.js';
9
9
  * @param image - The image with which to blend.
10
10
  * @param column - Column of the target pixel.
11
11
  * @param row - Row of the target pixel.
12
- * @param color - Color with which to blend the image pixel. @default `'Opaque black'`.
12
+ * @param color - Color with which to blend the image pixel. Default: `Opaque black`.
13
13
  */
14
14
 
15
15
  export function setBlendedPixel(
@@ -8,7 +8,7 @@ import { setBlendedPixel } from './setBlendedPixel.js';
8
8
  * @param image - The image with which to blend.
9
9
  * @param column - Column of the target pixel.
10
10
  * @param row - Row of the target pixel.
11
- * @param color - Color with which to blend the image pixel. @default `'Opaque black'`.
11
+ * @param color - Color with which to blend the image pixel. Default: `Opaque black`.
12
12
  */
13
13
  export function setBlendedVisiblePixel(
14
14
  image: Image | Mask,
@@ -1 +0,0 @@
1
- {"version":3,"file":"compute_dssim.d.ts","sourceRoot":"","sources":["../../src/ssim/compute_dssim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,KAAK,EACjB,OAAO,GAAE,WAAgB,GACxB,MAAM,CAGR"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compute_dssim.js","sourceRoot":"","sources":["../../src/ssim/compute_dssim.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAY,EACZ,UAAiB,EACjB,UAAuB,EAAE;IAEzB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IAC3D,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;AACxB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compute_ssim.d.ts","sourceRoot":"","sources":["../../src/ssim/compute_ssim.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIzC,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,CAAC;CACzD;AAED,MAAM,WAAW,IAAI;IACnB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,KAAK,EACjB,OAAO,GAAE,WAAgB,GACxB,IAAI,CA8CN"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"compute_ssim.js","sourceRoot":"","sources":["../../src/ssim/compute_ssim.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAG7C,OAAO,gBAAgB,MAAM,yCAAyC,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAC;AA4B1E;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,KAAY,EACZ,UAAiB,EACjB,UAAuB,EAAE;IAEzB,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,EAAE,SAAS,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC;IAE3C,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,UAAU,GAAG,KAAK,CAAC,KAAK,IAAI,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC1D,MAAM,IAAI,UAAU,CAAC,2CAA2C,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC;IACD,gBAAgB,CAAC,KAAK,EAAE;QACtB,QAAQ,EAAE,CAAC,CAAC,CAAC;QACb,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;KACpB,CAAC,CAAC;IAEH,qBAAqB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAEzC,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;QAChC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACnC,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,WAAW,GAAG;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,SAAS;KAChB,CAAC;IAEF,MAAM,SAAS,GAAG,IAAI,iBAAiB,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG;QAClB,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,IAAI,EAAE,SAAS;KAChB,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,EAAE,WAAW,EAAE;QAChD,UAAU;QACV,IAAI,EAAE,SAAS;KAChB,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC;AACJ,CAAC"}
@@ -1,3 +0,0 @@
1
- export * from './compute_dssim.js';
2
- export * from './compute_ssim.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ssim/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
package/lib/ssim/index.js DELETED
@@ -1,3 +0,0 @@
1
- export * from './compute_dssim.js';
2
- export * from './compute_ssim.js';
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ssim/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC"}
package/src/ssim/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './compute_dssim.js';
2
- export * from './compute_ssim.js';