@pilio/gemini-watermark-remover 1.0.26 → 1.0.27

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pilio/gemini-watermark-remover",
3
3
  "description": "Automatically removes watermarks from Gemini AI generated images",
4
- "version": "1.0.26",
4
+ "version": "1.0.27",
5
5
  "author": "GargantuaX",
6
6
  "sideEffects": false,
7
7
  "files": [
@@ -147,12 +147,12 @@ const PREVIEW_ANCHOR_MIN_SIZE_RATIO = 0.55;
147
147
  const PREVIEW_ANCHOR_MARGIN_WINDOW = 16;
148
148
  const PREVIEW_ANCHOR_MARGIN_EXTENSION = 8;
149
149
  const PREVIEW_ANCHOR_SIZE_STEP = 2;
150
- const PREVIEW_ANCHOR_MARGIN_STEP = 2;
151
- const PREVIEW_ANCHOR_TOP_K = 8;
152
- const PREVIEW_ANCHOR_MIN_SCORE = 0.2;
153
- const PREVIEW_ANCHOR_LOCAL_DELTAS = [-1, 0, 1];
154
- const PREVIEW_TEMPLATE_ALIGN_SHIFTS = [-1, -0.5, 0, 0.5, 1];
155
- const PREVIEW_TEMPLATE_ALIGN_SCALES = [0.985, 1, 1.015];
150
+ const PREVIEW_ANCHOR_MARGIN_STEP = 2;
151
+ const PREVIEW_ANCHOR_TOP_K = 8;
152
+ const PREVIEW_ANCHOR_MIN_SCORE = 0.2;
153
+ const PREVIEW_ANCHOR_LOCAL_DELTAS = [-1, 0, 1];
154
+ const PREVIEW_TEMPLATE_ALIGN_SHIFTS = [-1, -0.5, 0, 0.5, 1];
155
+ const PREVIEW_TEMPLATE_ALIGN_SCALES = [0.985, 1, 1.015];
156
156
  const PREVIEW_ANCHOR_GAIN_SKIP_RESIDUAL_THRESHOLD = 0.24;
157
157
  const PREVIEW_ANCHOR_GAIN_SKIP_GRADIENT_THRESHOLD = 0.24;
158
158
  const CORE_ALPHA_PRIORITY_GAINS = Object.freeze([0.6, 1, 1.1, 1.15, 1.3, 0.45, 0.7, 0.85, 0.55]);
@@ -103,6 +103,13 @@ const KNOWN_48_LUMA_EDGE_PRESETS = Object.freeze([
103
103
  { name: 'mid', minAlpha: 0.012, maxAlpha: 0.7, referenceAlphaMax: 0.04, radius: 3, strength: 0.42, colorSigma: 34, maxDelta: 32 },
104
104
  { name: 'wide', minAlpha: 0.012, maxAlpha: 0.7, referenceAlphaMax: 0.055, radius: 4, strength: 0.48, colorSigma: 34, maxDelta: 40 }
105
105
  ]);
106
+ const KNOWN_48_MID_CORE_BIAS_STRENGTH = 0.25;
107
+ const KNOWN_48_MID_CORE_BIAS_MIN_HALO = 8;
108
+ const KNOWN_48_MID_CORE_BIAS_MIN_HALO_REDUCTION = 0.5;
109
+ const KNOWN_48_MID_CORE_BIAS_MAX_GRADIENT_DRIFT = 0.01;
110
+ const KNOWN_48_MID_CORE_BIAS_MAX_SPATIAL_DRIFT = 0.02;
111
+ const KNOWN_48_MID_CORE_BIAS_MAX_ARTIFACT_DRIFT = 0.001;
112
+ const KNOWN_48_MID_CORE_BIAS_MAX_NEW_CLIP_DRIFT = 0.001;
106
113
  const PREVIEW_EDGE_CLEANUP_SPATIAL_THRESHOLD = 0.08;
107
114
  const PREVIEW_EDGE_CLEANUP_GRADIENT_THRESHOLD = 0.1;
108
115
  const PREVIEW_EDGE_CLEANUP_MIN_GRADIENT_IMPROVEMENT = 0.03;
@@ -1477,6 +1484,171 @@ function refineKnown48LumaEdgeResidual({
1477
1484
  return best;
1478
1485
  }
1479
1486
 
1487
+ function alphaBandBiasWeight(alpha, {
1488
+ outerMinAlpha = 0.12,
1489
+ innerMinAlpha = 0.18,
1490
+ innerMaxAlpha = 0.35,
1491
+ outerMaxAlpha = 0.42
1492
+ } = {}) {
1493
+ if (alpha < outerMinAlpha || alpha > outerMaxAlpha) return 0;
1494
+ if (alpha >= innerMinAlpha && alpha <= innerMaxAlpha) return 1;
1495
+ if (alpha < innerMinAlpha) {
1496
+ return smoothstep(outerMinAlpha, innerMinAlpha, alpha);
1497
+ }
1498
+ return 1 - smoothstep(innerMaxAlpha, outerMaxAlpha, alpha);
1499
+ }
1500
+
1501
+ function smoothstep(edge0, edge1, value) {
1502
+ if (edge0 === edge1) return value >= edge1 ? 1 : 0;
1503
+ const t = clamp01((value - edge0) / (edge1 - edge0));
1504
+ return t * t * (3 - 2 * t);
1505
+ }
1506
+
1507
+ function applyMidCoreBiasCorrection({ sourceImageData, alphaMap, position, positiveHaloLum, strength }) {
1508
+ const candidate = cloneImageData(sourceImageData);
1509
+ const bias = Math.max(0, positiveHaloLum) * strength;
1510
+ if (bias <= 0) return candidate;
1511
+
1512
+ for (let row = 0; row < position.height; row++) {
1513
+ for (let col = 0; col < position.width; col++) {
1514
+ const localIndex = row * position.width + col;
1515
+ const alpha = alphaMap[localIndex] ?? 0;
1516
+ const weight = alphaBandBiasWeight(alpha);
1517
+ if (weight <= 0) continue;
1518
+
1519
+ const pixelIndex = ((position.y + row) * candidate.width + position.x + col) * 4;
1520
+ const delta = bias * weight;
1521
+ candidate.data[pixelIndex] = clampChannel(candidate.data[pixelIndex] - delta);
1522
+ candidate.data[pixelIndex + 1] = clampChannel(candidate.data[pixelIndex + 1] - delta);
1523
+ candidate.data[pixelIndex + 2] = clampChannel(candidate.data[pixelIndex + 2] - delta);
1524
+ }
1525
+ }
1526
+
1527
+ return candidate;
1528
+ }
1529
+
1530
+ function positiveBandDelta(imageData, position, alphaMap, minAlpha, maxAlpha) {
1531
+ const halo = assessAlphaBandHalo({
1532
+ imageData,
1533
+ position,
1534
+ alphaMap,
1535
+ minAlpha,
1536
+ maxAlpha,
1537
+ outsideAlphaMax: 0.012,
1538
+ outerMargin: 4
1539
+ });
1540
+ return halo.positiveDeltaLum ?? 0;
1541
+ }
1542
+
1543
+ function hasDominantMidCoreHalo({ imageData, position, alphaMap }) {
1544
+ const edge = positiveBandDelta(imageData, position, alphaMap, 0.02, 0.12);
1545
+ const midCore = positiveBandDelta(imageData, position, alphaMap, 0.18, 0.35);
1546
+ const highCore = positiveBandDelta(imageData, position, alphaMap, 0.35, 0.78);
1547
+ return midCore > edge && midCore > highCore;
1548
+ }
1549
+
1550
+ function refineKnown48MidCoreBiasResidual({
1551
+ originalImageData,
1552
+ currentImageData,
1553
+ alphaMap,
1554
+ position,
1555
+ source,
1556
+ alphaGain,
1557
+ baselineSpatialScore,
1558
+ baselineGradientScore
1559
+ }) {
1560
+ if (
1561
+ position?.width < KNOWN_48_EDGE_CLEANUP_MIN_SIZE ||
1562
+ position?.width > KNOWN_48_EDGE_CLEANUP_MAX_SIZE ||
1563
+ typeof source !== 'string' ||
1564
+ !source.includes('edge-cleanup') ||
1565
+ source.includes('v2-small-edge-cleanup')
1566
+ ) {
1567
+ return null;
1568
+ }
1569
+
1570
+ const baselineVisibility = assessWatermarkResidualVisibility({
1571
+ imageData: currentImageData,
1572
+ position,
1573
+ alphaMap
1574
+ });
1575
+ if (
1576
+ baselineVisibility?.visiblePositiveHalo !== true ||
1577
+ (baselineVisibility.positiveHaloLum ?? 0) < KNOWN_48_MID_CORE_BIAS_MIN_HALO ||
1578
+ !hasDominantMidCoreHalo({ imageData: currentImageData, position, alphaMap })
1579
+ ) {
1580
+ return null;
1581
+ }
1582
+
1583
+ const baselineArtifacts = assessRemovalDiffArtifacts({
1584
+ originalImageData,
1585
+ candidateImageData: currentImageData,
1586
+ alphaMap,
1587
+ position,
1588
+ alphaGain
1589
+ });
1590
+ const baselineArtifactCost = Number(baselineArtifacts?.visualArtifactCost);
1591
+ if (!Number.isFinite(baselineArtifactCost)) return null;
1592
+
1593
+ const candidate = applyMidCoreBiasCorrection({
1594
+ sourceImageData: currentImageData,
1595
+ alphaMap,
1596
+ position,
1597
+ positiveHaloLum: baselineVisibility.positiveHaloLum,
1598
+ strength: KNOWN_48_MID_CORE_BIAS_STRENGTH
1599
+ });
1600
+ const spatialScore = computeRegionSpatialCorrelation({
1601
+ imageData: candidate,
1602
+ alphaMap,
1603
+ region: { x: position.x, y: position.y, size: position.width }
1604
+ });
1605
+ const gradientScore = computeRegionGradientCorrelation({
1606
+ imageData: candidate,
1607
+ alphaMap,
1608
+ region: { x: position.x, y: position.y, size: position.width }
1609
+ });
1610
+ const residualVisibility = assessWatermarkResidualVisibility({
1611
+ imageData: candidate,
1612
+ position,
1613
+ alphaMap
1614
+ });
1615
+ const artifacts = assessRemovalDiffArtifacts({
1616
+ originalImageData,
1617
+ candidateImageData: candidate,
1618
+ alphaMap,
1619
+ position,
1620
+ alphaGain
1621
+ });
1622
+ const artifactCost = Number(artifacts?.visualArtifactCost);
1623
+ if (!Number.isFinite(artifactCost)) return null;
1624
+
1625
+ const haloReduction = (baselineVisibility.positiveHaloLum ?? 0) - (residualVisibility?.positiveHaloLum ?? 0);
1626
+ const gradientDrift = gradientScore - baselineGradientScore;
1627
+ const spatialDrift = Math.abs(spatialScore) - Math.abs(baselineSpatialScore);
1628
+ const artifactDrift = artifactCost - baselineArtifactCost;
1629
+ const newClipDrift = (artifacts?.newlyClippedRatio ?? 0) - (baselineArtifacts?.newlyClippedRatio ?? 0);
1630
+ if (
1631
+ haloReduction < KNOWN_48_MID_CORE_BIAS_MIN_HALO_REDUCTION ||
1632
+ gradientDrift > KNOWN_48_MID_CORE_BIAS_MAX_GRADIENT_DRIFT ||
1633
+ spatialDrift > KNOWN_48_MID_CORE_BIAS_MAX_SPATIAL_DRIFT ||
1634
+ artifactDrift > KNOWN_48_MID_CORE_BIAS_MAX_ARTIFACT_DRIFT ||
1635
+ newClipDrift > KNOWN_48_MID_CORE_BIAS_MAX_NEW_CLIP_DRIFT
1636
+ ) {
1637
+ return null;
1638
+ }
1639
+
1640
+ return {
1641
+ imageData: candidate,
1642
+ spatialScore,
1643
+ gradientScore,
1644
+ residualVisibility,
1645
+ cost: artifactCost,
1646
+ haloReduction,
1647
+ artifactDrift,
1648
+ newClipDrift
1649
+ };
1650
+ }
1651
+
1480
1652
  function expandPosition(position, imageData, pad) {
1481
1653
  const left = Math.max(0, position.x - pad);
1482
1654
  const top = Math.max(0, position.y - pad);
@@ -4553,6 +4725,37 @@ export function processWatermarkImageData(imageData, options = {}) {
4553
4725
  suppressionGain = originalSpatialScore - finalProcessedSpatialScore;
4554
4726
  source = `${source}+quantized-body-correction`;
4555
4727
  }
4728
+
4729
+ const midCoreBiasStartedAt = nowMs();
4730
+ const midCoreBiasCorrection = refineKnown48MidCoreBiasResidual({
4731
+ originalImageData,
4732
+ currentImageData: finalImageData,
4733
+ alphaMap,
4734
+ position,
4735
+ source,
4736
+ alphaGain,
4737
+ baselineSpatialScore: finalProcessedSpatialScore,
4738
+ baselineGradientScore: finalProcessedGradientScore
4739
+ });
4740
+ if (midCoreBiasCorrection) {
4741
+ recordAlphaAdjustmentStage({
4742
+ stage: 'known-48-mid-core-bias-correction',
4743
+ fromAlphaGain: alphaGain,
4744
+ toAlphaGain: alphaGain,
4745
+ beforeSpatialScore: finalProcessedSpatialScore,
4746
+ beforeGradientScore: finalProcessedGradientScore,
4747
+ afterSpatialScore: midCoreBiasCorrection.spatialScore,
4748
+ afterGradientScore: midCoreBiasCorrection.gradientScore,
4749
+ suppressionGain: originalSpatialScore - midCoreBiasCorrection.spatialScore,
4750
+ cost: midCoreBiasCorrection.cost,
4751
+ allowSameAlphaGain: true
4752
+ });
4753
+ finalImageData = midCoreBiasCorrection.imageData;
4754
+ finalProcessedSpatialScore = midCoreBiasCorrection.spatialScore;
4755
+ finalProcessedGradientScore = midCoreBiasCorrection.gradientScore;
4756
+ suppressionGain = originalSpatialScore - finalProcessedSpatialScore;
4757
+ source = `${source}+mid-core-bias`;
4758
+ }
4556
4759
  if (debugTimingsEnabled) {
4557
4760
  debugTimings.previewEdgeCleanupMs = previewEdgeCleanupElapsedMs;
4558
4761
  debugTimings.smallPreviewRefinementMs = nowMs() - smallPreviewRefinementStartedAt;
@@ -4562,7 +4765,8 @@ export function processWatermarkImageData(imageData, options = {}) {
4562
4765
  debugTimings.powerProfileRescueMs = boundaryRepairRescueStartedAt - powerProfileRescueStartedAt;
4563
4766
  debugTimings.boundaryRepairRescueMs = darkHaloRescueStartedAt - boundaryRepairRescueStartedAt;
4564
4767
  debugTimings.darkHaloRescueMs = quantizedBodyCorrectionStartedAt - darkHaloRescueStartedAt;
4565
- debugTimings.quantizedBodyCorrectionMs = nowMs() - quantizedBodyCorrectionStartedAt;
4768
+ debugTimings.quantizedBodyCorrectionMs = midCoreBiasStartedAt - quantizedBodyCorrectionStartedAt;
4769
+ debugTimings.midCoreBiasCorrectionMs = nowMs() - midCoreBiasStartedAt;
4566
4770
  debugTimings.totalMs = nowMs() - totalStartedAt;
4567
4771
  }
4568
4772