image-js 1.1.0 → 1.3.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 (90) hide show
  1. package/dist/image-js.esm.js +268 -54
  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 +236 -20
  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 +26 -2
  10. package/lib/Image.d.ts +17 -1
  11. package/lib/Image.d.ts.map +1 -1
  12. package/lib/Image.js +38 -1
  13. package/lib/Image.js.map +1 -1
  14. package/lib/draw/drawLineOnImage.d.ts.map +1 -1
  15. package/lib/draw/drawLineOnImage.js.map +1 -1
  16. package/lib/extra/draw/draw_text.d.ts +47 -0
  17. package/lib/extra/draw/draw_text.d.ts.map +1 -0
  18. package/lib/extra/draw/draw_text.js +108 -0
  19. package/lib/extra/draw/draw_text.js.map +1 -0
  20. package/lib/extra/draw/index.d.ts +3 -0
  21. package/lib/extra/draw/index.d.ts.map +1 -0
  22. package/lib/extra/draw/index.js +3 -0
  23. package/lib/extra/draw/index.js.map +1 -0
  24. package/lib/{ssim → extra/ssim}/compute_dssim.d.ts +2 -2
  25. package/lib/extra/ssim/compute_dssim.d.ts.map +1 -0
  26. package/lib/{ssim → extra/ssim}/compute_dssim.js +1 -1
  27. package/lib/extra/ssim/compute_dssim.js.map +1 -0
  28. package/lib/{ssim → extra/ssim}/compute_ssim.d.ts +1 -1
  29. package/lib/extra/ssim/compute_ssim.d.ts.map +1 -0
  30. package/lib/{ssim → extra/ssim}/compute_ssim.js +2 -2
  31. package/lib/extra/ssim/compute_ssim.js.map +1 -0
  32. package/lib/extra/ssim/index.d.ts +3 -0
  33. package/lib/extra/ssim/index.d.ts.map +1 -0
  34. package/lib/extra/ssim/index.js +3 -0
  35. package/lib/extra/ssim/index.js.map +1 -0
  36. package/lib/index_browser.d.ts +3 -0
  37. package/lib/index_browser.d.ts.map +1 -0
  38. package/lib/index_browser.js +5 -0
  39. package/lib/index_browser.js.map +1 -0
  40. package/lib/index_full.d.ts +4 -0
  41. package/lib/index_full.d.ts.map +1 -0
  42. package/lib/index_full.js +5 -0
  43. package/lib/index_full.js.map +1 -0
  44. package/lib/load/decodePng.d.ts.map +1 -1
  45. package/lib/load/decodePng.js +16 -0
  46. package/lib/load/decodePng.js.map +1 -1
  47. package/lib/load/decodeTiff.d.ts.map +1 -1
  48. package/lib/load/decodeTiff.js +35 -0
  49. package/lib/load/decodeTiff.js.map +1 -1
  50. package/lib/load/load.types.d.ts +6 -0
  51. package/lib/load/load.types.d.ts.map +1 -1
  52. package/lib/load/read.d.ts +1 -1
  53. package/lib/load/read.js +1 -1
  54. package/lib/save/write.d.ts +1 -1
  55. package/lib/save/write.js +1 -1
  56. package/lib/utils/cross_platform.d.ts +8 -0
  57. package/lib/utils/cross_platform.d.ts.map +1 -1
  58. package/lib/utils/cross_platform.js +34 -2
  59. package/lib/utils/cross_platform.js.map +1 -1
  60. package/lib/utils/setBlendedPixel.d.ts +1 -1
  61. package/lib/utils/setBlendedPixel.js +1 -1
  62. package/lib/utils/setBlendedVisiblePixel.d.ts +1 -1
  63. package/lib/utils/setBlendedVisiblePixel.js +1 -1
  64. package/package.json +17 -3
  65. package/src/Image.ts +44 -4
  66. package/src/draw/drawLineOnImage.ts +0 -1
  67. package/src/extra/draw/draw_text.ts +194 -0
  68. package/src/extra/draw/index.ts +2 -0
  69. package/src/{ssim → extra/ssim}/compute_dssim.ts +3 -3
  70. package/src/{ssim → extra/ssim}/compute_ssim.ts +3 -3
  71. package/src/extra/ssim/index.ts +2 -0
  72. package/src/index_browser.ts +4 -0
  73. package/src/index_full.ts +4 -0
  74. package/src/load/decodePng.ts +18 -0
  75. package/src/load/decodeTiff.ts +38 -1
  76. package/src/load/load.types.ts +8 -0
  77. package/src/load/read.ts +1 -1
  78. package/src/save/write.ts +1 -1
  79. package/src/utils/cross_platform.ts +47 -4
  80. package/src/utils/setBlendedPixel.ts +1 -1
  81. package/src/utils/setBlendedVisiblePixel.ts +1 -1
  82. package/lib/ssim/compute_dssim.d.ts.map +0 -1
  83. package/lib/ssim/compute_dssim.js.map +0 -1
  84. package/lib/ssim/compute_ssim.d.ts.map +0 -1
  85. package/lib/ssim/compute_ssim.js.map +0 -1
  86. package/lib/ssim/index.d.ts +0 -3
  87. package/lib/ssim/index.d.ts.map +0 -1
  88. package/lib/ssim/index.js +0 -3
  89. package/lib/ssim/index.js.map +0 -1
  90. package/src/ssim/index.ts +0 -2
@@ -1,5 +1,5 @@
1
1
  /*
2
- * image-js v1.1.0
2
+ * image-js v1.3.0
3
3
  * Image processing and manipulation in JavaScript
4
4
  * https://github.com/image-js/image-js#readme
5
5
  *
@@ -5109,11 +5109,11 @@ matrix.solve = solve;
5109
5109
  matrix.wrap = wrap;
5110
5110
 
5111
5111
  const EigenvalueDecomposition = EigenvalueDecomposition_1;
5112
- const Matrix = Matrix_1;
5112
+ const Matrix$1 = Matrix_1;
5113
5113
  const SVD = SVD$1;
5114
5114
  const SingularValueDecomposition = SingularValueDecomposition_1;
5115
5115
  const WrapperMatrix1D = WrapperMatrix1D_1;
5116
- var Matrix$1 = _default.Matrix ? _default.Matrix : Matrix_1;
5116
+ var Matrix = _default.Matrix ? _default.Matrix : Matrix_1;
5117
5117
  const determinant = determinant_1;
5118
5118
  const inverse = inverse_1;
5119
5119
  const pseudoInverse = pseudoInverse_1;
@@ -5125,7 +5125,7 @@ const pseudoInverse = pseudoInverse_1;
5125
5125
  * @returns The centroid.
5126
5126
  */
5127
5127
  function getCentroid(points) {
5128
- let result = new Matrix$1(3, 1);
5128
+ let result = new Matrix(3, 1);
5129
5129
  const nbPoints = points.columns;
5130
5130
  let xSum = 0;
5131
5131
  let ySum = 0;
@@ -5166,7 +5166,7 @@ function getAffineTransform$1(source, destination) {
5166
5166
  ratioSum += getDistanceToOrigin(destinationPoint) / getDistanceToOrigin(sourcePoint);
5167
5167
  }
5168
5168
  const scale = ratioSum / nbPoints;
5169
- const scaledSource = Matrix$1.mul(translatedSource, scale);
5169
+ const scaledSource = Matrix.mul(translatedSource, scale);
5170
5170
  // computing rotation
5171
5171
  const covarianceMatrix = scaledSource.mmul(translatedDestination.transpose());
5172
5172
  const svd = new SingularValueDecomposition(covarianceMatrix);
@@ -5182,7 +5182,7 @@ function getAffineTransform$1(source, destination) {
5182
5182
  angleDegrees = 180;
5183
5183
  }
5184
5184
  // computing translation
5185
- const translation = Matrix$1.sub(destinationCentroid, Matrix$1.mul(rotation.mmul(sourceCentroid), scale));
5185
+ const translation = Matrix.sub(destinationCentroid, Matrix.mul(rotation.mmul(sourceCentroid), scale));
5186
5186
  return {
5187
5187
  translation: {
5188
5188
  x: translation.get(0, 0),
@@ -6263,9 +6263,9 @@ function F(t) {
6263
6263
  var index_umd$1 = {exports: {}};
6264
6264
 
6265
6265
  var index_umd = index_umd$1.exports;
6266
- (function (module, exports) {
6266
+ (function (module, exports$1) {
6267
6267
  (function (N, J) {
6268
- J(exports) ;
6268
+ J(exports$1) ;
6269
6269
  })(index_umd, function (N) {
6270
6270
 
6271
6271
  function J(f, a, o, t, e) {
@@ -6949,7 +6949,7 @@ function getHarrisScore(image, origin, options = {}) {
6949
6949
  const xxSum = xx.sum();
6950
6950
  const xySum = xy.sum();
6951
6951
  const yySum = yy.sum();
6952
- const structureTensor = new Matrix([[xxSum, xySum], [xySum, yySum]]);
6952
+ const structureTensor = new Matrix$1([[xxSum, xySum], [xySum, yySum]]);
6953
6953
  const eigenValues = new EigenvalueDecomposition(structureTensor).realEigenvalues;
6954
6954
  return eigenValues[0] * eigenValues[1] - harrisConstant * (eigenValues[0] + eigenValues[1]) ** 2;
6955
6955
  }
@@ -8662,7 +8662,7 @@ function getDefaultColor(image) {
8662
8662
  * @param image - The image with which to blend.
8663
8663
  * @param column - Column of the target pixel.
8664
8664
  * @param row - Row of the target pixel.
8665
- * @param color - Color with which to blend the image pixel. @default `'Opaque black'`.
8665
+ * @param color - Color with which to blend the image pixel. Default: `Opaque black`.
8666
8666
  */
8667
8667
  function setBlendedPixel(image, column, row, color) {
8668
8668
  color = color ?? getDefaultColor(image);
@@ -8692,7 +8692,7 @@ function setBlendedPixel(image, column, row, color) {
8692
8692
  * @param image - The image with which to blend.
8693
8693
  * @param column - Column of the target pixel.
8694
8694
  * @param row - Row of the target pixel.
8695
- * @param color - Color with which to blend the image pixel. @default `'Opaque black'`.
8695
+ * @param color - Color with which to blend the image pixel. Default: `Opaque black`.
8696
8696
  */
8697
8697
  function setBlendedVisiblePixel(image, column, row, color) {
8698
8698
  if (column >= 0 && column < image.width && row >= 0 && row < image.height) {
@@ -9444,9 +9444,9 @@ function robustSubtract(e, f) {
9444
9444
  })(orientation);
9445
9445
  var orientationExports = orientation.exports;
9446
9446
 
9447
- var robustPnp = robustPointInPolygon;
9447
+ var robustPnp = robustPointInPolygon$1;
9448
9448
  var orient = orientationExports;
9449
- function robustPointInPolygon(vs, point) {
9449
+ function robustPointInPolygon$1(vs, point) {
9450
9450
  var x = point[0];
9451
9451
  var y = point[1];
9452
9452
  var n = vs.length;
@@ -9542,7 +9542,7 @@ function robustPointInPolygon(vs, point) {
9542
9542
  }
9543
9543
  return 2 * inside - 1;
9544
9544
  }
9545
- var robustPointInPolygon$1 = /*@__PURE__*/getDefaultExportFromCjs(robustPnp);
9545
+ var robustPointInPolygon = /*@__PURE__*/getDefaultExportFromCjs(robustPnp);
9546
9546
 
9547
9547
  /**
9548
9548
  * Convert object points into array points.
@@ -9590,7 +9590,7 @@ function drawPolygonOnImage(image, points, options = {}) {
9590
9590
  const arrayPoints = arrayPointsToObjects(filteredPoints);
9591
9591
  for (let row = 0; row < newImage.height; row++) {
9592
9592
  for (let column = 0; column < newImage.width; column++) {
9593
- if (robustPointInPolygon$1(arrayPoints, [column, row]) === -1) {
9593
+ if (robustPointInPolygon(arrayPoints, [column, row]) === -1) {
9594
9594
  setBlendedVisiblePixel(newImage, Math.round(origin.column) + column, Math.round(origin.row) + row, fillColor);
9595
9595
  }
9596
9596
  }
@@ -9631,7 +9631,7 @@ function drawPolygonOnMask(mask, points, options = {}) {
9631
9631
  const arrayPoints = arrayPointsToObjects(filteredPoints);
9632
9632
  for (let row = 0; row < newMask.height; row++) {
9633
9633
  for (let column = 0; column < newMask.width; column++) {
9634
- if (robustPointInPolygon$1(arrayPoints, [column, row]) === -1) {
9634
+ if (robustPointInPolygon(arrayPoints, [column, row]) === -1) {
9635
9635
  newMask.setBit(Math.round(origin.column) + column, Math.round(origin.row) + row, 1);
9636
9636
  }
9637
9637
  }
@@ -12606,7 +12606,7 @@ function transform(image, transformMatrix, options = {}) {
12606
12606
  height = Math.round(height);
12607
12607
  }
12608
12608
  if (!options.inverse) {
12609
- transformMatrix = inverse(new Matrix(transformMatrix)).to2DArray();
12609
+ transformMatrix = inverse(new Matrix$1(transformMatrix)).to2DArray();
12610
12610
  }
12611
12611
  const newImage = Image.createFrom(image, {
12612
12612
  width,
@@ -12845,8 +12845,8 @@ function getPerspectiveWarp(pts, options = {}) {
12845
12845
  const [x2, y2] = [widthRect - 1, 0];
12846
12846
  const [x3, y3] = [widthRect - 1, heightRect - 1];
12847
12847
  const [x4, y4] = [0, heightRect - 1];
12848
- const S = new Matrix([[x1, y1, 1, 0, 0, 0, -x1 * tl.column, -y1 * tl.column], [x2, y2, 1, 0, 0, 0, -x2 * tr.column, -y2 * tr.column], [x3, y3, 1, 0, 0, 0, -x3 * br.column, -y3 * br.column], [x4, y4, 1, 0, 0, 0, -x4 * bl.column, -y4 * bl.column], [0, 0, 0, x1, y1, 1, -x1 * tl.row, -y1 * tl.row], [0, 0, 0, x2, y2, 1, -x2 * tr.row, -y2 * tr.row], [0, 0, 0, x3, y3, 1, -x3 * br.row, -y3 * br.row], [0, 0, 0, x4, y4, 1, -x4 * bl.row, -y4 * bl.row]]);
12849
- const D = Matrix.columnVector([tl.column, tr.column, br.column, bl.column, tl.row, tr.row, br.row, bl.row]);
12848
+ const S = new Matrix$1([[x1, y1, 1, 0, 0, 0, -x1 * tl.column, -y1 * tl.column], [x2, y2, 1, 0, 0, 0, -x2 * tr.column, -y2 * tr.column], [x3, y3, 1, 0, 0, 0, -x3 * br.column, -y3 * br.column], [x4, y4, 1, 0, 0, 0, -x4 * bl.column, -y4 * bl.column], [0, 0, 0, x1, y1, 1, -x1 * tl.row, -y1 * tl.row], [0, 0, 0, x2, y2, 1, -x2 * tr.row, -y2 * tr.row], [0, 0, 0, x3, y3, 1, -x3 * br.row, -y3 * br.row], [0, 0, 0, x4, y4, 1, -x4 * bl.row, -y4 * bl.row]]);
12849
+ const D = Matrix$1.columnVector([tl.column, tr.column, br.column, bl.column, tl.row, tr.row, br.row, bl.row]);
12850
12850
  const svd = new SingularValueDecomposition(S);
12851
12851
  const T = svd.solve(D).to1DArray(); // solve S*T = D
12852
12852
  T.push(1);
@@ -13241,7 +13241,7 @@ class PolynomialRegression2D extends BaseRegression2D {
13241
13241
  // @ts-expect-error internal use only
13242
13242
  if (inputs === true) {
13243
13243
  // @ts-expect-error internal use only
13244
- this.coefficients = Matrix.columnVector(outputs.coefficients);
13244
+ this.coefficients = Matrix$1.columnVector(outputs.coefficients);
13245
13245
  // @ts-expect-error internal use only
13246
13246
  this.order = outputs.order;
13247
13247
  // @ts-expect-error internal use only
@@ -13356,8 +13356,8 @@ function powColVector(x, power) {
13356
13356
  * @param y - A vector of the prediction values.
13357
13357
  */
13358
13358
  function train(input, y, order) {
13359
- if (!Matrix.isMatrix(y)) y = Matrix.columnVector(y);
13360
- const x = new Matrix(y.rows, 2);
13359
+ if (!Matrix$1.isMatrix(y)) y = Matrix$1.columnVector(y);
13360
+ const x = new Matrix$1(y.rows, 2);
13361
13361
  x.setColumn(0, input.x);
13362
13362
  x.setColumn(1, input.y);
13363
13363
  if (y.rows !== x.rows) {
@@ -13382,7 +13382,7 @@ function train(input, y, order) {
13382
13382
  x1.mulColumn(0, scaleX1);
13383
13383
  x2.mulColumn(0, scaleX2);
13384
13384
  y.mulColumn(0, scaleY);
13385
- const A = new Matrix(examples, nbCoefficients);
13385
+ const A = new Matrix$1(examples, nbCoefficients);
13386
13386
  let col = 0;
13387
13387
  for (let i = 0; i <= order; ++i) {
13388
13388
  const limit = order - i;
@@ -13397,11 +13397,11 @@ function train(input, y, order) {
13397
13397
  computeRightSingularVectors: true,
13398
13398
  autoTranspose: false
13399
13399
  });
13400
- let qqs = Matrix.rowVector(svd.diagonal);
13400
+ let qqs = Matrix$1.rowVector(svd.diagonal);
13401
13401
  qqs = qqs.apply((i, j) => {
13402
13402
  if (qqs.get(i, j) >= 1e-15) qqs.set(i, j, 1 / qqs.get(i, j));else qqs.set(i, j, 0);
13403
13403
  });
13404
- const qqs1 = Matrix.zeros(examples, nbCoefficients);
13404
+ const qqs1 = Matrix$1.zeros(examples, nbCoefficients);
13405
13405
  for (let i = 0; i < nbCoefficients; ++i) {
13406
13406
  qqs1.set(i, i, qqs.get(0, i));
13407
13407
  }
@@ -16069,8 +16069,8 @@ class MultivariateLinearRegression {
16069
16069
  this.outputs = y.outputs;
16070
16070
  this.intercept = y.intercept;
16071
16071
  } else {
16072
- x = new Matrix(x);
16073
- y = new Matrix(y);
16072
+ x = new Matrix$1(x);
16073
+ y = new Matrix$1(y);
16074
16074
  if (intercept) {
16075
16075
  x.addColumn(new Array(x.rows).fill(1));
16076
16076
  }
@@ -16112,8 +16112,8 @@ class MultivariateLinearRegression {
16112
16112
  }
16113
16113
  return y;
16114
16114
  }
16115
- } else if (Matrix.isMatrix(x)) {
16116
- const y = new Matrix(x.rows, this.outputs);
16115
+ } else if (Matrix$1.isMatrix(x)) {
16116
+ const y = new Matrix$1(x.rows, this.outputs);
16117
16117
  for (let i = 0; i < x.rows; i++) {
16118
16118
  y.setRow(i, this._predict(x.getRow(i)));
16119
16119
  }
@@ -16811,6 +16811,10 @@ class Image {
16811
16811
  * Origin of the image relative to a the parent image.
16812
16812
  */
16813
16813
  origin;
16814
+ /**
16815
+ * Original image resolution.
16816
+ */
16817
+ originalResolution;
16814
16818
  meta;
16815
16819
  /**
16816
16820
  * Typed array holding the image data.
@@ -16831,7 +16835,8 @@ class Image {
16831
16835
  row: 0,
16832
16836
  column: 0
16833
16837
  },
16834
- meta
16838
+ meta,
16839
+ resolution
16835
16840
  } = options;
16836
16841
  if (width < 1 || !Number.isInteger(width)) {
16837
16842
  throw new RangeError(`width must be an integer and at least 1. Received ${width}`);
@@ -16846,6 +16851,7 @@ class Image {
16846
16851
  this.colorModel = colorModel;
16847
16852
  this.origin = origin;
16848
16853
  this.meta = meta;
16854
+ this.originalResolution = resolution;
16849
16855
  const colorModelDef = colorModels[colorModel];
16850
16856
  this.components = colorModelDef.components;
16851
16857
  this.alpha = colorModelDef.alpha;
@@ -16866,6 +16872,38 @@ class Image {
16866
16872
  this.data = data;
16867
16873
  }
16868
16874
  }
16875
+ /**
16876
+ * Returns normalized resolution in pixels per centimeter. If resolution unit is unknown, return null.
16877
+ * @returns Object with x and y resolutions in pixel/cm.
16878
+ */
16879
+ get normalizedResolution() {
16880
+ if (!this.originalResolution) {
16881
+ return undefined;
16882
+ }
16883
+ const centimetersPerInch = 2.54;
16884
+ const centimetersPerMeter = 100;
16885
+ switch (this.originalResolution.unit) {
16886
+ case 'inch':
16887
+ return {
16888
+ x: this.originalResolution.x / centimetersPerInch,
16889
+ y: this.originalResolution.y / centimetersPerInch
16890
+ };
16891
+ case 'centimeter':
16892
+ return {
16893
+ x: this.originalResolution.x,
16894
+ y: this.originalResolution.y
16895
+ };
16896
+ case 'meter':
16897
+ return {
16898
+ x: this.originalResolution.x / centimetersPerMeter,
16899
+ y: this.originalResolution.y / centimetersPerMeter
16900
+ };
16901
+ case 'unknown':
16902
+ return null;
16903
+ default:
16904
+ throw new Error('Unknown resolution unit.');
16905
+ }
16906
+ }
16869
16907
  /**
16870
16908
  * Create a new Image based on the properties of an existing one.
16871
16909
  * @param other - Reference image.
@@ -28673,7 +28711,7 @@ function encode(image, options = defaultPng) {
28673
28711
  * @returns - The `fs`, `path` and `url` Node.js modules.
28674
28712
  */
28675
28713
  function getNodeApiOrThrow(methodName) {
28676
- if (typeof process === 'undefined' || typeof process.getBuiltinModule !== 'function') {
28714
+ if (!isNode()) {
28677
28715
  throw new Error(`${methodName} is only implemented for Node.js`);
28678
28716
  }
28679
28717
  return {
@@ -28682,6 +28720,35 @@ function getNodeApiOrThrow(methodName) {
28682
28720
  url: process.getBuiltinModule('node:url')
28683
28721
  };
28684
28722
  }
28723
+ let CanvasCtorBrowser;
28724
+ let CanvasCtorNode;
28725
+ /**
28726
+ * Returns a 2D canvas context for rendering on the browser or Node.js.
28727
+ * @param width - Width of the canvas.
28728
+ * @param height - Height of the canvas.
28729
+ * @returns The initialised canvas context.
28730
+ */
28731
+ function getCanvasContext(width, height) {
28732
+ if (isNode()) {
28733
+ CanvasCtorNode ??= getRequireFn()('skia-canvas').Canvas;
28734
+ return new CanvasCtorNode(width, height).getContext('2d');
28735
+ } else {
28736
+ CanvasCtorBrowser ??= globalThis.OffscreenCanvas;
28737
+ const context = new CanvasCtorBrowser(width, height).getContext('2d');
28738
+ if (!context) {
28739
+ throw new Error('Failed to create canvas context');
28740
+ }
28741
+ return context;
28742
+ }
28743
+ }
28744
+ function isNode() {
28745
+ return typeof process !== 'undefined' && typeof process.getBuiltinModule === 'function';
28746
+ }
28747
+ let requireFn;
28748
+ function getRequireFn() {
28749
+ requireFn ??= process.getBuiltinModule('node:module').createRequire(import.meta.url);
28750
+ return requireFn;
28751
+ }
28685
28752
 
28686
28753
  /**
28687
28754
  * Asynchronously write an image to the disk.
@@ -28708,7 +28775,7 @@ async function write(path, image, options) {
28708
28775
  await nodeApi.fs.promises.writeFile(path, toWrite);
28709
28776
  }
28710
28777
  /**
28711
- * Synchronous version of @see {@link write}.
28778
+ * Synchronous version of {@link write}.
28712
28779
  * This method is only implemented for Node.js.
28713
28780
  * @param path - Path where the image should be written.
28714
28781
  * @param image - Image to save.
@@ -28858,7 +28925,7 @@ function encodeDataURL(image, options = defaultPng) {
28858
28925
  * @returns The matrix.
28859
28926
  */
28860
28927
  function getMatrixFromPoints(points) {
28861
- const matrix = new Matrix(3, points.length);
28928
+ const matrix = new Matrix$1(3, points.length);
28862
28929
  for (let i = 0; i < points.length; i++) {
28863
28930
  matrix.set(0, i, points[i].column);
28864
28931
  matrix.set(1, i, points[i].row);
@@ -30168,18 +30235,18 @@ var fileTypeExports = fileType$1.exports;
30168
30235
 
30169
30236
  const fileType = fileTypeExports;
30170
30237
  const imageExts = new Set(['jpg', 'png', 'gif', 'webp', 'flif', 'cr2', 'tif', 'bmp', 'jxr', 'psd', 'ico', 'bpg', 'jp2', 'jpm', 'jpx', 'heic', 'cur', 'dcm']);
30171
- const imageType = input => {
30238
+ const imageType$1 = input => {
30172
30239
  const ret = fileType(input);
30173
30240
  return imageExts.has(ret && ret.ext) ? ret : null;
30174
30241
  };
30175
- imageType$2.exports = imageType;
30242
+ imageType$2.exports = imageType$1;
30176
30243
  // TODO: Remove this for the next major release
30177
- imageType$2.exports.default = imageType;
30178
- Object.defineProperty(imageType, 'minimumBytes', {
30244
+ imageType$2.exports.default = imageType$1;
30245
+ Object.defineProperty(imageType$1, 'minimumBytes', {
30179
30246
  value: fileType.minimumBytes
30180
30247
  });
30181
30248
  var imageTypeExports = imageType$2.exports;
30182
- var imageType$1 = /*@__PURE__*/getDefaultExportFromCjs(imageTypeExports);
30249
+ var imageType = /*@__PURE__*/getDefaultExportFromCjs(imageTypeExports);
30183
30250
 
30184
30251
  /**
30185
30252
  * Decode a BMP. See the fast-bmp npm module.
@@ -31511,10 +31578,23 @@ function decodePng(buffer) {
31511
31578
  default:
31512
31579
  throw new RangeError(`invalid number of channels: ${png.channels}`);
31513
31580
  }
31581
+ let resolution;
31582
+ if (png.resolution) {
31583
+ resolution = png.resolution.unit === 1 ? /*If the resolution unit is meters*/{
31584
+ x: png.resolution.x,
31585
+ y: png.resolution.y,
31586
+ unit: 'meter'
31587
+ } : /*If resolution unit is unknown */{
31588
+ x: png.resolution.x,
31589
+ y: png.resolution.y,
31590
+ unit: 'unknown'
31591
+ };
31592
+ }
31514
31593
  return new Image(png.width, png.height, {
31515
31594
  colorModel,
31516
31595
  bitDepth,
31517
- data: png.data
31596
+ data: png.data,
31597
+ resolution
31518
31598
  });
31519
31599
  }
31520
31600
  /**
@@ -31584,6 +31664,7 @@ function getImageFromIFD(ifd) {
31584
31664
  if (ifd.data instanceof Float32Array || ifd.data instanceof Float64Array) {
31585
31665
  throw new Error('Float TIFF data is not supported.');
31586
31666
  }
31667
+ const resolution = getTiffResolution(ifd);
31587
31668
  if (ifd.type === 3) {
31588
31669
  const hasAlpha = ifd.samplesPerPixel === 2;
31589
31670
  const pixelLength = hasAlpha ? 4 : 3;
@@ -31611,7 +31692,8 @@ function getImageFromIFD(ifd) {
31611
31692
  data,
31612
31693
  colorModel: hasAlpha ? 'RGBA' : 'RGB',
31613
31694
  bitDepth: 16,
31614
- meta: getMetadata(ifd)
31695
+ meta: getMetadata(ifd),
31696
+ resolution
31615
31697
  });
31616
31698
  } else if (ifd.type === 1 || ifd.type === 0) {
31617
31699
  if (ifd.bitsPerSample !== 1) {
@@ -31619,14 +31701,16 @@ function getImageFromIFD(ifd) {
31619
31701
  data: ifd.data,
31620
31702
  bitDepth: ifd.bitsPerSample,
31621
31703
  colorModel: ifd.alpha ? 'GREYA' : 'GREY',
31622
- meta: getMetadata(ifd)
31704
+ meta: getMetadata(ifd),
31705
+ resolution
31623
31706
  });
31624
31707
  } else {
31625
31708
  return new Image(ifd.width, ifd.height, {
31626
31709
  data: ifd.data.map(pixel => pixel * 255),
31627
31710
  bitDepth: 8,
31628
31711
  colorModel: 'GREY',
31629
- meta: getMetadata(ifd)
31712
+ meta: getMetadata(ifd),
31713
+ resolution
31630
31714
  });
31631
31715
  }
31632
31716
  } else {
@@ -31634,10 +31718,41 @@ function getImageFromIFD(ifd) {
31634
31718
  data: ifd.data,
31635
31719
  bitDepth: ifd.bitsPerSample,
31636
31720
  colorModel: ifd.alpha ? 'RGBA' : 'RGB',
31637
- meta: getMetadata(ifd)
31721
+ meta: getMetadata(ifd),
31722
+ resolution
31638
31723
  });
31639
31724
  }
31640
31725
  }
31726
+ /**
31727
+ * Gets image resolution from its metadata and converts it into Pixels per meter, when it's possible. Also keeps original resolution values and units.
31728
+ * @param ifd - Tiff metadata.
31729
+ * @returns Resolution object.
31730
+ */
31731
+ function getTiffResolution(ifd) {
31732
+ if (!ifd.xResolution || !ifd.yResolution) {
31733
+ return undefined;
31734
+ }
31735
+ switch (ifd.resolutionUnit) {
31736
+ case 1:
31737
+ return {
31738
+ x: ifd.xResolution,
31739
+ y: ifd.yResolution,
31740
+ unit: 'unknown'
31741
+ };
31742
+ case 3:
31743
+ return {
31744
+ x: ifd.xResolution,
31745
+ y: ifd.yResolution,
31746
+ unit: 'centimeter'
31747
+ };
31748
+ default:
31749
+ return {
31750
+ x: ifd.xResolution,
31751
+ y: ifd.yResolution,
31752
+ unit: 'inch'
31753
+ };
31754
+ }
31755
+ }
31641
31756
 
31642
31757
  /**
31643
31758
  * Decode input data. Data format is automatically detected.
@@ -31647,7 +31762,7 @@ function getImageFromIFD(ifd) {
31647
31762
  */
31648
31763
  function decode(data) {
31649
31764
  const typedArray = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
31650
- const type = imageType$1(typedArray);
31765
+ const type = imageType(typedArray);
31651
31766
  return M$2(type).with({
31652
31767
  mime: 'image/png'
31653
31768
  }, () => decodePng(typedArray)).with({
@@ -31674,7 +31789,7 @@ async function read(path) {
31674
31789
  return decode(data);
31675
31790
  }
31676
31791
  /**
31677
- * Synchronous version of @see {@link read}.
31792
+ * Synchronous version of {@link read}.
31678
31793
  * This method is only implemented for Node.js.
31679
31794
  * @param path - The path to the image.
31680
31795
  * @returns Image instance.
@@ -32747,7 +32862,7 @@ class RoiMapManager {
32747
32862
  * @returns The ROI map matrix.
32748
32863
  */
32749
32864
  getMapMatrix() {
32750
- return Matrix.from1DArray(this.map.height, this.map.width, this.map.data).to2DArray();
32865
+ return Matrix$1.from1DArray(this.map.height, this.map.width, this.map.data).to2DArray();
32751
32866
  }
32752
32867
  getRois(options = {}) {
32753
32868
  return getRois(this, options);
@@ -32887,7 +33002,7 @@ function commonjsRequire(path) {
32887
33002
 
32888
33003
  var priorityQueue = {exports: {}};
32889
33004
 
32890
- (function (module, exports) {
33005
+ (function (module, exports$1) {
32891
33006
  (function (f) {
32892
33007
  {
32893
33008
  module.exports = f();
@@ -32917,7 +33032,7 @@ var priorityQueue = {exports: {}};
32917
33032
  for (var o = 0; o < r.length; o++) s(r[o]);
32918
33033
  return s;
32919
33034
  }({
32920
- 1: [function (_dereq_, module, exports) {
33035
+ 1: [function (_dereq_, module, exports$1) {
32921
33036
  var AbstractPriorityQueue,
32922
33037
  ArrayStrategy,
32923
33038
  BHeapStrategy,
@@ -32962,7 +33077,7 @@ var priorityQueue = {exports: {}};
32962
33077
  "./PriorityQueue/BHeapStrategy": 4,
32963
33078
  "./PriorityQueue/BinaryHeapStrategy": 5
32964
33079
  }],
32965
- 2: [function (_dereq_, module, exports) {
33080
+ 2: [function (_dereq_, module, exports$1) {
32966
33081
  module.exports = function () {
32967
33082
  function AbstractPriorityQueue(options) {
32968
33083
  var ref;
@@ -33000,7 +33115,7 @@ var priorityQueue = {exports: {}};
33000
33115
  return AbstractPriorityQueue;
33001
33116
  }();
33002
33117
  }, {}],
33003
- 3: [function (_dereq_, module, exports) {
33118
+ 3: [function (_dereq_, module, exports$1) {
33004
33119
  var binarySearchForIndexReversed;
33005
33120
  binarySearchForIndexReversed = function (array, value, comparator) {
33006
33121
  var high, low, mid;
@@ -33043,7 +33158,7 @@ var priorityQueue = {exports: {}};
33043
33158
  return ArrayStrategy;
33044
33159
  }();
33045
33160
  }, {}],
33046
- 4: [function (_dereq_, module, exports) {
33161
+ 4: [function (_dereq_, module, exports$1) {
33047
33162
  module.exports = function () {
33048
33163
  function BHeapStrategy(options) {
33049
33164
  var arr, j, k, len, ref, ref1, shift, value;
@@ -33181,7 +33296,7 @@ var priorityQueue = {exports: {}};
33181
33296
  return BHeapStrategy;
33182
33297
  }();
33183
33298
  }, {}],
33184
- 5: [function (_dereq_, module, exports) {
33299
+ 5: [function (_dereq_, module, exports$1) {
33185
33300
  module.exports = function () {
33186
33301
  function BinaryHeapStrategy(options) {
33187
33302
  var ref;
@@ -33580,7 +33695,7 @@ function decodeStackFromTiff(buffer) {
33580
33695
  */
33581
33696
  function decodeStack(data) {
33582
33697
  const typedArray = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
33583
- const type = imageType$1(typedArray);
33698
+ const type = imageType(typedArray);
33584
33699
  return M$2(type).with({
33585
33700
  mime: 'image/tiff'
33586
33701
  }, () => decodeStackFromTiff(typedArray)).with({
@@ -33843,5 +33958,104 @@ const channelLabels = {
33843
33958
  BINARY: ['Mask']
33844
33959
  };
33845
33960
 
33846
- export { BorderType, DerivativeFilter, GreyAlgorithm, Image, ImageColorModel, ImageCoordinates, ImageFormat, InterpolationType, Mask, Montage, MontageDisposition, Roi, RoiKind, RoiMapManager, RoisColorMode, Stack, ThresholdAlgorithm, add, alignMinDifference, and, blur, bottomHat, bruteForceOneMatch, cannyEdgeDetector, channelLabels, clearBorder, close, colorModels, colorRois, computeConvolutionValue, computeMse, computePsnr, computeRmse, computeRois, computeThreshold, convertBinaryToGrey, convertBinaryToRgb, convertBitDepth, convertColor, copyAlpha, copyTo, correctBackground, correctColor, crop, cropAlpha, cropRectangle, crosscheck, decode, decodeJpeg, decodePng, decodeStack, decodeTiff, defaultPng, derivativeFilter, dilate, directConvolution, divide, drawCircleOnImage, drawKeypoints, drawLineOnImage, drawLineOnMask, drawMarker, drawMarkers, drawMatches, drawPoints, drawPolygonOnImage, drawPolygonOnMask, drawPolylineOnImage, drawPolylineOnMask, drawRectangle, encode, encodeDataURL, encodeJpeg, encodePng, erode, extendBorders, extract, fetchURL, flip, floodFill, fromMask, gaussianBlur, getAffineTransform, getBestKeypointsInRadius, getBorderPoints, getBriefDescriptors, getCrosscheckMatches, getDirection, getExtrema, getFastKeypoints, getImageFromIFD, getIntensityCentroid, getMask, getOrientedFastKeypoints, getPerspectiveWarp, getRegressionVariables, getRois, gradientFilter, grey, histogram$1 as histogram, hypotenuse, increaseContrast, invert, level, mean, median, medianFilter, merge, morphologicalGradient, multiply, open, or, order4Points, overlapImages, paintMaskOnImage, paintMaskOnMask, pixelate, rawDirectConvolution, read, readCanvas, readImg, readSync, removeClosePoints, resize, rotate, separableConvolution, solidFill, split, subtract, threshold, topHat, transform, transformRotate, variance, waterShed, write, writeCanvas, writeSync };
33961
+ /**
33962
+ * Draws text on an image.
33963
+ * @param image - Image to write text on.
33964
+ * @param text - Text to write on the image.
33965
+ * @param options - Out Options
33966
+ * @returns Image with drawn text.
33967
+ */
33968
+ function drawText(image, text, options) {
33969
+ if (Array.isArray(text) && text.length === 0) {
33970
+ throw new Error('At least one text element must be provided');
33971
+ }
33972
+ const newImage = getOutputImage(image, options, {
33973
+ clone: true
33974
+ });
33975
+ const defaultFont = options?.font ?? '12px Helvetica';
33976
+ const defaultColor = options?.fontColor ?? [255, 255, 255, 255];
33977
+ const ctx = getCanvasContext(image.width, image.height);
33978
+ if (!Array.isArray(text)) {
33979
+ drawTextElement(image, ctx, text, defaultFont, defaultColor);
33980
+ } else {
33981
+ for (const label of text) {
33982
+ drawTextElement(image, ctx, label, defaultFont, defaultColor);
33983
+ }
33984
+ }
33985
+ layerCanvas(newImage.getRawImage().data, ctx.getImageData(0, 0, image.width, image.height).data, image.channels, image.bitDepth);
33986
+ return newImage;
33987
+ }
33988
+ function drawTextElement(image, ctx, text, defaultFont, defaultColor) {
33989
+ ctx.font = text.font ?? defaultFont;
33990
+ const fontColor = text.fontColor ?? defaultColor;
33991
+ validateValues(fontColor, image);
33992
+ const alpha = fontColor[3] ? fontColor[3] / 255 : 1;
33993
+ const normalizedColor = [fontColor[0] ?? 0, fontColor[1] ?? 0, fontColor[2] ?? 0, alpha];
33994
+ ctx.fillStyle = `rgba(${normalizedColor.join(',')})`;
33995
+ ctx.fillText(String(text.content), text.position.column, text.position.row);
33996
+ }
33997
+ /**
33998
+ * Draws labels on the image data from canvas.
33999
+ * @param imageData - Image data to draw text on.
34000
+ * @param canvasData - Canvas data to draw on the image.
34001
+ * @param numberOfChannels - Number of channels of the initial image.
34002
+ * @param bitDepth - Bit depth of the initial image.
34003
+ */
34004
+ function layerCanvas(imageData, canvasData, numberOfChannels, bitDepth) {
34005
+ const config = CHANNEL_CONFIGS[numberOfChannels] || CHANNEL_CONFIGS[1];
34006
+ const pixelCount = canvasData.length >>> 2;
34007
+ const bitShift = bitDepth - 8;
34008
+ let imageIndex = 0;
34009
+ let canvasIndex = 0;
34010
+ for (let pixel = 0; pixel < pixelCount; pixel++) {
34011
+ const canvasAlpha = canvasData[canvasIndex + 3] / 255;
34012
+ // Skip transparent canvas pixels completely
34013
+ if (canvasAlpha === 0) {
34014
+ imageIndex += numberOfChannels;
34015
+ canvasIndex += 4;
34016
+ continue;
34017
+ }
34018
+ const invAlpha = 1 - canvasAlpha;
34019
+ for (const channel of config.channelOffsets) {
34020
+ const targetIndex = imageIndex + channel;
34021
+ imageData[targetIndex] = Math.round(canvasData[canvasIndex + channel] * canvasAlpha + imageData[targetIndex] * invAlpha) << bitShift;
34022
+ }
34023
+ if (config.hasAlpha) {
34024
+ const alphaIndex = imageIndex + config.alphaOffset;
34025
+ const imageAlpha = (imageData[alphaIndex] >>> bitShift) / 255;
34026
+ const newAlpha = canvasAlpha + imageAlpha * (1 - canvasAlpha);
34027
+ imageData[alphaIndex] = Math.round(newAlpha * 255) << bitShift;
34028
+ }
34029
+ imageIndex += numberOfChannels;
34030
+ canvasIndex += 4;
34031
+ }
34032
+ }
34033
+ const CHANNEL_CONFIGS = {
34034
+ // GREY
34035
+ 1: {
34036
+ channelOffsets: [0],
34037
+ hasAlpha: false,
34038
+ alphaOffset: undefined
34039
+ },
34040
+ // GREYA
34041
+ 2: {
34042
+ channelOffsets: [0],
34043
+ hasAlpha: true,
34044
+ alphaOffset: 1
34045
+ },
34046
+ 3: {
34047
+ // RGB
34048
+ channelOffsets: [0, 1, 2],
34049
+ hasAlpha: false,
34050
+ alphaOffset: undefined
34051
+ },
34052
+ 4: {
34053
+ // RGBA
34054
+ channelOffsets: [0, 1, 2],
34055
+ hasAlpha: true,
34056
+ alphaOffset: 3
34057
+ }
34058
+ };
34059
+
34060
+ export { BorderType, DerivativeFilter, GreyAlgorithm, Image, ImageColorModel, ImageCoordinates, ImageFormat, InterpolationType, Mask, Montage, MontageDisposition, Roi, RoiKind, RoiMapManager, RoisColorMode, Stack, ThresholdAlgorithm, add, alignMinDifference, and, blur, bottomHat, bruteForceOneMatch, cannyEdgeDetector, channelLabels, clearBorder, close, colorModels, colorRois, computeConvolutionValue, computeMse, computePsnr, computeRmse, computeRois, computeThreshold, convertBinaryToGrey, convertBinaryToRgb, convertBitDepth, convertColor, copyAlpha, copyTo, correctBackground, correctColor, crop, cropAlpha, cropRectangle, crosscheck, decode, decodeJpeg, decodePng, decodeStack, decodeTiff, defaultPng, derivativeFilter, dilate, directConvolution, divide, drawCircleOnImage, drawKeypoints, drawLineOnImage, drawLineOnMask, drawMarker, drawMarkers, drawMatches, drawPoints, drawPolygonOnImage, drawPolygonOnMask, drawPolylineOnImage, drawPolylineOnMask, drawRectangle, drawText, encode, encodeDataURL, encodeJpeg, encodePng, erode, extendBorders, extract, fetchURL, flip, floodFill, fromMask, gaussianBlur, getAffineTransform, getBestKeypointsInRadius, getBorderPoints, getBriefDescriptors, getCrosscheckMatches, getDirection, getExtrema, getFastKeypoints, getImageFromIFD, getIntensityCentroid, getMask, getOrientedFastKeypoints, getPerspectiveWarp, getRegressionVariables, getRois, gradientFilter, grey, histogram$1 as histogram, hypotenuse, increaseContrast, invert, level, mean, median, medianFilter, merge, morphologicalGradient, multiply, open, or, order4Points, overlapImages, paintMaskOnImage, paintMaskOnMask, pixelate, rawDirectConvolution, read, readCanvas, readImg, readSync, removeClosePoints, resize, rotate, separableConvolution, solidFill, split, subtract, threshold, topHat, transform, transformRotate, variance, waterShed, write, writeCanvas, writeSync };
33847
34061
  //# sourceMappingURL=image-js.esm.js.map