web-sdk-pp-detection 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -141,6 +141,7 @@ interface PPDetectionProgressEvent {
141
141
  readonly fallback?: PPDetectionFallback;
142
142
  }
143
143
  interface CreatePPDetectionOptions {
144
+ readonly allowExperimental?: boolean;
144
145
  readonly allowFallback?: boolean;
145
146
  readonly backend?: BackendPreference;
146
147
  readonly cache?: boolean | "memory" | "indexeddb";
@@ -401,6 +402,7 @@ declare class PPDetectionError extends Error {
401
402
  }
402
403
 
403
404
  interface SelectExecutionOptions {
405
+ readonly allowExperimental?: boolean;
404
406
  readonly backend?: BackendPreference;
405
407
  readonly precision?: Precision;
406
408
  readonly executionMode?: ExecutionMode;
@@ -633,7 +635,7 @@ declare class IndexedDBModelCache implements ModelCache {
633
635
  declare global {
634
636
  var __PPDETECTION_SCRIPT_URL__: string | undefined;
635
637
  }
636
- declare const CURRENT_SDK_VERSION = "0.2.0";
638
+ declare const CURRENT_SDK_VERSION = "0.3.1";
637
639
 
638
640
  declare function probePPDetectionCapabilities(options?: CapabilityProbeOptions): DetectionCapabilities;
639
641
 
package/dist/index.js CHANGED
@@ -371,34 +371,58 @@ function clipBicubic(value) {
371
371
  const rounded = value >> BICUBIC_PRECISION_BITS;
372
372
  return Math.max(0, Math.min(255, rounded));
373
373
  }
374
- function bicubicChannel(raster, resizedWidth, resizedHeight, channel) {
374
+ function writeBicubicChannels(raster, resizedWidth, resizedHeight, target) {
375
375
  const horizontal = createBicubicAxis(raster.width, resizedWidth);
376
376
  const vertical = createBicubicAxis(raster.height, resizedHeight);
377
- const intermediate = new Uint8Array(raster.height * resizedWidth);
377
+ const rowStride = resizedWidth * 3;
378
+ const intermediate = new Uint8Array(raster.height * rowStride);
378
379
  for (let y = 0; y < raster.height; y += 1) {
380
+ const sourceRow = y * raster.width * 4;
381
+ const targetRow = y * rowStride;
379
382
  for (let x = 0; x < resizedWidth; x += 1) {
380
383
  const [start, count] = horizontal.bounds[x];
381
384
  const coefficients = horizontal.coefficients[x];
382
- let sum = BICUBIC_ROUNDING;
385
+ let red = BICUBIC_ROUNDING;
386
+ let green = BICUBIC_ROUNDING;
387
+ let blue = BICUBIC_ROUNDING;
388
+ let source2 = sourceRow + start * 4;
383
389
  for (let index = 0; index < count; index += 1) {
384
- sum += raster.rgba[(y * raster.width + start + index) * 4 + channel] * coefficients[index];
390
+ const coefficient = coefficients[index];
391
+ red += raster.rgba[source2] * coefficient;
392
+ green += raster.rgba[source2 + 1] * coefficient;
393
+ blue += raster.rgba[source2 + 2] * coefficient;
394
+ source2 += 4;
385
395
  }
386
- intermediate[y * resizedWidth + x] = clipBicubic(sum);
396
+ const offset = targetRow + x * 3;
397
+ intermediate[offset] = clipBicubic(red);
398
+ intermediate[offset + 1] = clipBicubic(green);
399
+ intermediate[offset + 2] = clipBicubic(blue);
387
400
  }
388
401
  }
389
- const output = new Uint8Array(resizedWidth * resizedHeight);
402
+ const plane = target.inputWidth * target.inputHeight;
390
403
  for (let y = 0; y < resizedHeight; y += 1) {
391
404
  const [start, count] = vertical.bounds[y];
392
405
  const coefficients = vertical.coefficients[y];
406
+ const sourceRow = start * rowStride;
407
+ const targetRow = (y + target.padTop) * target.inputWidth + target.padLeft;
393
408
  for (let x = 0; x < resizedWidth; x += 1) {
394
- let sum = BICUBIC_ROUNDING;
409
+ let red = BICUBIC_ROUNDING;
410
+ let green = BICUBIC_ROUNDING;
411
+ let blue = BICUBIC_ROUNDING;
412
+ let source2 = sourceRow + x * 3;
395
413
  for (let index = 0; index < count; index += 1) {
396
- sum += intermediate[(start + index) * resizedWidth + x] * coefficients[index];
414
+ const coefficient = coefficients[index];
415
+ red += intermediate[source2] * coefficient;
416
+ green += intermediate[source2 + 1] * coefficient;
417
+ blue += intermediate[source2 + 2] * coefficient;
418
+ source2 += rowStride;
397
419
  }
398
- output[y * resizedWidth + x] = clipBicubic(sum);
420
+ const offset = targetRow + x;
421
+ target.data[offset] = target.values[clipBicubic(red)];
422
+ target.data[plane + offset] = target.values[256 + clipBicubic(green)];
423
+ target.data[plane * 2 + offset] = target.values[512 + clipBicubic(blue)];
399
424
  }
400
425
  }
401
- return output;
402
426
  }
403
427
  function preprocessImage(raster, preprocessing) {
404
428
  const inputWidth = preprocessing.size.width;
@@ -425,18 +449,35 @@ function preprocessImage(raster, preprocessing) {
425
449
  const mean = normalize ? preprocessing.mean ?? [0, 0, 0] : [0, 0, 0];
426
450
  const std = normalize ? preprocessing.std ?? [1, 1, 1] : [1, 1, 1];
427
451
  const interpolation2 = preprocessing.interpolation ?? "bilinear";
452
+ const bicubicValues = doResize && interpolation2 === "bicubic" ? new Float32Array(256 * 3) : void 0;
428
453
  for (let channel = 0; channel < 3; channel += 1) {
429
454
  const padding = normalize && mean[channel] !== 0 ? -mean[channel] / std[channel] : 0;
430
455
  data.fill(padding, channel * plane, (channel + 1) * plane);
431
- const bicubic = doResize && interpolation2 === "bicubic" ? bicubicChannel(raster, resizedWidth, resizedHeight, channel) : void 0;
456
+ if (bicubicValues) {
457
+ for (let pixel = 0; pixel < 256; pixel += 1) {
458
+ const scaled = rescale ? pixel * preprocessing.rescaleFactor : pixel;
459
+ bicubicValues[channel * 256 + pixel] = normalize ? (scaled - mean[channel]) / std[channel] : scaled;
460
+ }
461
+ continue;
462
+ }
432
463
  for (let y = 0; y < resizedHeight; y += 1) {
433
464
  for (let x = 0; x < resizedWidth; x += 1) {
434
- const pixel = bicubic ? bicubic[y * resizedWidth + x] : doResize ? bilinearChannel(raster, x, y, resizedWidth, resizedHeight, channel) : sampleChannel(raster, x, y, channel);
465
+ const pixel = doResize ? bilinearChannel(raster, x, y, resizedWidth, resizedHeight, channel) : sampleChannel(raster, x, y, channel);
435
466
  const scaled = rescale ? pixel * preprocessing.rescaleFactor : pixel;
436
467
  data[channel * plane + (y + padTop) * inputWidth + x + padLeft] = normalize ? (scaled - mean[channel]) / std[channel] : scaled;
437
468
  }
438
469
  }
439
470
  }
471
+ if (bicubicValues) {
472
+ writeBicubicChannels(raster, resizedWidth, resizedHeight, {
473
+ data,
474
+ inputWidth,
475
+ inputHeight,
476
+ padLeft,
477
+ padTop,
478
+ values: bicubicValues
479
+ });
480
+ }
440
481
  return {
441
482
  data,
442
483
  dims: [1, 3, inputHeight, inputWidth],
@@ -2031,13 +2072,19 @@ function selectExecutionPlan(options, capabilities, manifest) {
2031
2072
  if (executionMode === "worker" && !capabilities.worker) {
2032
2073
  fail("CAPABILITY_UNSUPPORTED", "\u8BF7\u6C42\u7684 worker \u4E0D\u53EF\u7528", { executionMode });
2033
2074
  }
2034
- const variant3 = manifest.variants?.find(
2035
- (candidate) => candidate.precision === requestedPrecision && candidate.status !== "labs" && candidate.status !== "blocked"
2036
- );
2075
+ const matchingVariants = manifest.variants?.filter(
2076
+ (candidate) => candidate.precision === requestedPrecision && candidate.status !== "blocked"
2077
+ ) ?? [];
2078
+ const variant3 = matchingVariants.find((candidate) => candidate.status !== "labs") ?? (options.allowExperimental === true ? matchingVariants.find((candidate) => candidate.status === "labs") : void 0);
2037
2079
  if (!variant3) {
2038
- fail("MODEL_INCOMPATIBLE", `manifest \u6CA1\u6709\u53EF\u7528\u7684 ${requestedPrecision} \u7A33\u5B9A\u53D8\u4F53`, {
2039
- requestedPrecision
2040
- });
2080
+ fail(
2081
+ "MODEL_INCOMPATIBLE",
2082
+ options.allowExperimental === true ? `manifest \u6CA1\u6709\u53EF\u7528\u7684 ${requestedPrecision} \u53D8\u4F53` : `manifest \u6CA1\u6709\u53EF\u7528\u7684 ${requestedPrecision} \u7A33\u5B9A\u53D8\u4F53`,
2083
+ {
2084
+ requestedPrecision,
2085
+ allowExperimental: options.allowExperimental === true
2086
+ }
2087
+ );
2041
2088
  }
2042
2089
  const candidates = candidatesForBackend(requestedBackend, capabilities).filter(
2043
2090
  (backend) => variant3.backends.includes(backend)
@@ -2213,7 +2260,7 @@ var WorkerBridge = class {
2213
2260
  };
2214
2261
 
2215
2262
  // src/index.ts
2216
- var CURRENT_SDK_VERSION = "0.2.0";
2263
+ var CURRENT_SDK_VERSION = "0.3.1";
2217
2264
  function probePPDetectionCapabilities(options = {}) {
2218
2265
  return probeCapabilities(options);
2219
2266
  }
@@ -2328,6 +2375,7 @@ async function createPPDetection(options = {}) {
2328
2375
  options.onProgress?.({ phase: "manifest", status: "complete" });
2329
2376
  const plan = selectExecutionPlan(
2330
2377
  {
2378
+ allowExperimental: options.allowExperimental,
2331
2379
  backend: options.backend,
2332
2380
  precision: options.precision === "auto" ? void 0 : options.precision,
2333
2381
  executionMode: options.executionMode,