resample.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. "use strict";
  2. /**
  3. * @module resample
  4. */
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.resampleInterleaved = exports.resampleBilinearInterleaved = exports.resampleNearestInterleaved = exports.resample = exports.resampleBilinear = exports.resampleNearest = void 0;
  7. function copyNewSize(array, width, height, samplesPerPixel = 1) {
  8. return new (Object.getPrototypeOf(array).constructor)(width * height * samplesPerPixel);
  9. }
  10. /**
  11. * Resample the input arrays using nearest neighbor value selection.
  12. * @param {TypedArray[]} valueArrays The input arrays to resample
  13. * @param {number} inWidth The width of the input rasters
  14. * @param {number} inHeight The height of the input rasters
  15. * @param {number} outWidth The desired width of the output rasters
  16. * @param {number} outHeight The desired height of the output rasters
  17. * @returns {TypedArray[]} The resampled rasters
  18. */
  19. function resampleNearest(valueArrays, inWidth, inHeight, outWidth, outHeight) {
  20. const relX = inWidth / outWidth;
  21. const relY = inHeight / outHeight;
  22. return valueArrays.map((array) => {
  23. const newArray = copyNewSize(array, outWidth, outHeight);
  24. for (let y = 0; y < outHeight; ++y) {
  25. const cy = Math.min(Math.round(relY * y), inHeight - 1);
  26. for (let x = 0; x < outWidth; ++x) {
  27. const cx = Math.min(Math.round(relX * x), inWidth - 1);
  28. const value = array[(cy * inWidth) + cx];
  29. newArray[(y * outWidth) + x] = value;
  30. }
  31. }
  32. return newArray;
  33. });
  34. }
  35. exports.resampleNearest = resampleNearest;
  36. // simple linear interpolation, code from:
  37. // https://en.wikipedia.org/wiki/Linear_interpolation#Programming_language_support
  38. function lerp(v0, v1, t) {
  39. return ((1 - t) * v0) + (t * v1);
  40. }
  41. /**
  42. * Resample the input arrays using bilinear interpolation.
  43. * @param {TypedArray[]} valueArrays The input arrays to resample
  44. * @param {number} inWidth The width of the input rasters
  45. * @param {number} inHeight The height of the input rasters
  46. * @param {number} outWidth The desired width of the output rasters
  47. * @param {number} outHeight The desired height of the output rasters
  48. * @returns {TypedArray[]} The resampled rasters
  49. */
  50. function resampleBilinear(valueArrays, inWidth, inHeight, outWidth, outHeight) {
  51. const relX = inWidth / outWidth;
  52. const relY = inHeight / outHeight;
  53. return valueArrays.map((array) => {
  54. const newArray = copyNewSize(array, outWidth, outHeight);
  55. for (let y = 0; y < outHeight; ++y) {
  56. const rawY = relY * y;
  57. const yl = Math.floor(rawY);
  58. const yh = Math.min(Math.ceil(rawY), (inHeight - 1));
  59. for (let x = 0; x < outWidth; ++x) {
  60. const rawX = relX * x;
  61. const tx = rawX % 1;
  62. const xl = Math.floor(rawX);
  63. const xh = Math.min(Math.ceil(rawX), (inWidth - 1));
  64. const ll = array[(yl * inWidth) + xl];
  65. const hl = array[(yl * inWidth) + xh];
  66. const lh = array[(yh * inWidth) + xl];
  67. const hh = array[(yh * inWidth) + xh];
  68. const value = lerp(lerp(ll, hl, tx), lerp(lh, hh, tx), rawY % 1);
  69. newArray[(y * outWidth) + x] = value;
  70. }
  71. }
  72. return newArray;
  73. });
  74. }
  75. exports.resampleBilinear = resampleBilinear;
  76. /**
  77. * Resample the input arrays using the selected resampling method.
  78. * @param {TypedArray[]} valueArrays The input arrays to resample
  79. * @param {number} inWidth The width of the input rasters
  80. * @param {number} inHeight The height of the input rasters
  81. * @param {number} outWidth The desired width of the output rasters
  82. * @param {number} outHeight The desired height of the output rasters
  83. * @param {string} [method = 'nearest'] The desired resampling method
  84. * @returns {TypedArray[]} The resampled rasters
  85. */
  86. function resample(valueArrays, inWidth, inHeight, outWidth, outHeight, method = 'nearest') {
  87. switch (method.toLowerCase()) {
  88. case 'nearest':
  89. return resampleNearest(valueArrays, inWidth, inHeight, outWidth, outHeight);
  90. case 'bilinear':
  91. case 'linear':
  92. return resampleBilinear(valueArrays, inWidth, inHeight, outWidth, outHeight);
  93. default:
  94. throw new Error(`Unsupported resampling method: '${method}'`);
  95. }
  96. }
  97. exports.resample = resample;
  98. /**
  99. * Resample the pixel interleaved input array using nearest neighbor value selection.
  100. * @param {TypedArray} valueArrays The input arrays to resample
  101. * @param {number} inWidth The width of the input rasters
  102. * @param {number} inHeight The height of the input rasters
  103. * @param {number} outWidth The desired width of the output rasters
  104. * @param {number} outHeight The desired height of the output rasters
  105. * @param {number} samples The number of samples per pixel for pixel
  106. * interleaved data
  107. * @returns {TypedArray} The resampled raster
  108. */
  109. function resampleNearestInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples) {
  110. const relX = inWidth / outWidth;
  111. const relY = inHeight / outHeight;
  112. const newArray = copyNewSize(valueArray, outWidth, outHeight, samples);
  113. for (let y = 0; y < outHeight; ++y) {
  114. const cy = Math.min(Math.round(relY * y), inHeight - 1);
  115. for (let x = 0; x < outWidth; ++x) {
  116. const cx = Math.min(Math.round(relX * x), inWidth - 1);
  117. for (let i = 0; i < samples; ++i) {
  118. const value = valueArray[(cy * inWidth * samples) + (cx * samples) + i];
  119. newArray[(y * outWidth * samples) + (x * samples) + i] = value;
  120. }
  121. }
  122. }
  123. return newArray;
  124. }
  125. exports.resampleNearestInterleaved = resampleNearestInterleaved;
  126. /**
  127. * Resample the pixel interleaved input array using bilinear interpolation.
  128. * @param {TypedArray} valueArrays The input arrays to resample
  129. * @param {number} inWidth The width of the input rasters
  130. * @param {number} inHeight The height of the input rasters
  131. * @param {number} outWidth The desired width of the output rasters
  132. * @param {number} outHeight The desired height of the output rasters
  133. * @param {number} samples The number of samples per pixel for pixel
  134. * interleaved data
  135. * @returns {TypedArray} The resampled raster
  136. */
  137. function resampleBilinearInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples) {
  138. const relX = inWidth / outWidth;
  139. const relY = inHeight / outHeight;
  140. const newArray = copyNewSize(valueArray, outWidth, outHeight, samples);
  141. for (let y = 0; y < outHeight; ++y) {
  142. const rawY = relY * y;
  143. const yl = Math.floor(rawY);
  144. const yh = Math.min(Math.ceil(rawY), (inHeight - 1));
  145. for (let x = 0; x < outWidth; ++x) {
  146. const rawX = relX * x;
  147. const tx = rawX % 1;
  148. const xl = Math.floor(rawX);
  149. const xh = Math.min(Math.ceil(rawX), (inWidth - 1));
  150. for (let i = 0; i < samples; ++i) {
  151. const ll = valueArray[(yl * inWidth * samples) + (xl * samples) + i];
  152. const hl = valueArray[(yl * inWidth * samples) + (xh * samples) + i];
  153. const lh = valueArray[(yh * inWidth * samples) + (xl * samples) + i];
  154. const hh = valueArray[(yh * inWidth * samples) + (xh * samples) + i];
  155. const value = lerp(lerp(ll, hl, tx), lerp(lh, hh, tx), rawY % 1);
  156. newArray[(y * outWidth * samples) + (x * samples) + i] = value;
  157. }
  158. }
  159. }
  160. return newArray;
  161. }
  162. exports.resampleBilinearInterleaved = resampleBilinearInterleaved;
  163. /**
  164. * Resample the pixel interleaved input array using the selected resampling method.
  165. * @param {TypedArray} valueArray The input array to resample
  166. * @param {number} inWidth The width of the input rasters
  167. * @param {number} inHeight The height of the input rasters
  168. * @param {number} outWidth The desired width of the output rasters
  169. * @param {number} outHeight The desired height of the output rasters
  170. * @param {number} samples The number of samples per pixel for pixel
  171. * interleaved data
  172. * @param {string} [method = 'nearest'] The desired resampling method
  173. * @returns {TypedArray} The resampled rasters
  174. */
  175. function resampleInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples, method = 'nearest') {
  176. switch (method.toLowerCase()) {
  177. case 'nearest':
  178. return resampleNearestInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples);
  179. case 'bilinear':
  180. case 'linear':
  181. return resampleBilinearInterleaved(valueArray, inWidth, inHeight, outWidth, outHeight, samples);
  182. default:
  183. throw new Error(`Unsupported resampling method: '${method}'`);
  184. }
  185. }
  186. exports.resampleInterleaved = resampleInterleaved;
  187. //# sourceMappingURL=resample.js.map