@pilio/gemini-watermark-remover 1.0.10

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 (39) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +371 -0
  3. package/README_zh.md +371 -0
  4. package/bin/gwr.mjs +12 -0
  5. package/package.json +76 -0
  6. package/skills/gemini-watermark-remover/SKILL.md +28 -0
  7. package/skills/gemini-watermark-remover/agents/openai.yaml +3 -0
  8. package/skills/gemini-watermark-remover/references/inputs-and-outputs.md +9 -0
  9. package/skills/gemini-watermark-remover/references/limitations.md +5 -0
  10. package/skills/gemini-watermark-remover/references/usage.md +19 -0
  11. package/skills/gemini-watermark-remover/scripts/run.mjs +153 -0
  12. package/src/cli/gwrCli.js +17 -0
  13. package/src/cli/gwrRemoveCommand.js +317 -0
  14. package/src/core/adaptiveDetector.js +488 -0
  15. package/src/core/alphaMap.js +30 -0
  16. package/src/core/blendModes.js +70 -0
  17. package/src/core/candidateSelector.js +1446 -0
  18. package/src/core/canvasBlob.js +26 -0
  19. package/src/core/embeddedAlphaMaps.js +49 -0
  20. package/src/core/geminiSizeCatalog.js +239 -0
  21. package/src/core/multiPassRemoval.js +93 -0
  22. package/src/core/previewAlphaCalibration.js +822 -0
  23. package/src/core/restorationMetrics.js +251 -0
  24. package/src/core/selectionDebug.js +47 -0
  25. package/src/core/watermarkConfig.js +146 -0
  26. package/src/core/watermarkDecisionPolicy.js +163 -0
  27. package/src/core/watermarkDisplay.js +60 -0
  28. package/src/core/watermarkEngine.js +150 -0
  29. package/src/core/watermarkPresence.js +12 -0
  30. package/src/core/watermarkProcessor.js +875 -0
  31. package/src/core/workerClient.js +114 -0
  32. package/src/sdk/browser.d.ts +13 -0
  33. package/src/sdk/browser.js +29 -0
  34. package/src/sdk/image-data.d.ts +14 -0
  35. package/src/sdk/image-data.js +55 -0
  36. package/src/sdk/index.d.ts +144 -0
  37. package/src/sdk/index.js +8 -0
  38. package/src/sdk/node.d.ts +42 -0
  39. package/src/sdk/node.js +77 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Watermark engine main module
3
+ * Coordinate watermark detection, alpha map calculation, and removal operations
4
+ */
5
+
6
+ import { getEmbeddedAlphaMap } from './embeddedAlphaMaps.js';
7
+ import { removeRepeatedWatermarkLayers } from './multiPassRemoval.js';
8
+ import { processWatermarkImageData } from './watermarkProcessor.js';
9
+ import {
10
+ interpolateAlphaMap,
11
+ } from './adaptiveDetector.js';
12
+ import {
13
+ detectWatermarkConfig,
14
+ calculateWatermarkPosition,
15
+ } from './watermarkConfig.js';
16
+ export { detectWatermarkConfig, calculateWatermarkPosition } from './watermarkConfig.js';
17
+
18
+ function createRuntimeCanvas(width, height) {
19
+ if (typeof OffscreenCanvas !== 'undefined') {
20
+ return new OffscreenCanvas(width, height);
21
+ }
22
+
23
+ if (typeof document !== 'undefined') {
24
+ const canvas = document.createElement('canvas');
25
+ canvas.width = width;
26
+ canvas.height = height;
27
+ return canvas;
28
+ }
29
+
30
+ throw new Error('Canvas runtime not available');
31
+ }
32
+
33
+ function getCanvasContext2D(canvas) {
34
+ const ctx = canvas.getContext('2d', { willReadFrequently: true });
35
+ if (!ctx) {
36
+ throw new Error('Failed to get 2D canvas context');
37
+ }
38
+ return ctx;
39
+ }
40
+
41
+ /**
42
+ * Watermark engine class
43
+ * Coordinate watermark detection, alpha map calculation, and removal operations
44
+ */
45
+ export class WatermarkEngine {
46
+ constructor() {
47
+ this.alphaMaps = {};
48
+ }
49
+
50
+ static async create() {
51
+ return new WatermarkEngine();
52
+ }
53
+
54
+ /**
55
+ * Get alpha map from background captured image based on watermark size
56
+ * @param {number} size - Watermark size (48 or 96)
57
+ * @returns {Promise<Float32Array>} Alpha map
58
+ */
59
+ async getAlphaMap(size) {
60
+ // For non-standard watermark size, interpolate from 96x96 alpha map.
61
+ if (size !== 48 && size !== 96) {
62
+ if (this.alphaMaps[size]) return this.alphaMaps[size];
63
+ const alpha96 = await this.getAlphaMap(96);
64
+ const interpolated = interpolateAlphaMap(alpha96, 96, size);
65
+ this.alphaMaps[size] = interpolated;
66
+ return interpolated;
67
+ }
68
+
69
+ // If cached, return directly
70
+ if (this.alphaMaps[size]) {
71
+ return this.alphaMaps[size];
72
+ }
73
+
74
+ const alphaMap = getEmbeddedAlphaMap(size);
75
+ if (!alphaMap) {
76
+ throw new Error(`Missing embedded alpha map for size ${size}`);
77
+ }
78
+
79
+ // Cache result
80
+ this.alphaMaps[size] = alphaMap;
81
+
82
+ return alphaMap;
83
+ }
84
+
85
+ /**
86
+ * Remove watermark from image based on watermark size
87
+ * @param {HTMLImageElement|HTMLCanvasElement} image - Input image
88
+ * @returns {Promise<HTMLCanvasElement>} Processed canvas
89
+ */
90
+ async removeWatermarkFromImage(image, options = {}) {
91
+ const now = () => {
92
+ if (typeof globalThis.performance?.now === 'function') {
93
+ return globalThis.performance.now();
94
+ }
95
+ return Date.now();
96
+ };
97
+ const canvas = createRuntimeCanvas(image.width, image.height);
98
+ const ctx = getCanvasContext2D(canvas);
99
+ const drawStartedAt = now();
100
+ ctx.drawImage(image, 0, 0);
101
+ const drawMs = now() - drawStartedAt;
102
+ const readStartedAt = now();
103
+ const originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
104
+ const getImageDataMs = now() - readStartedAt;
105
+ const alpha48 = await this.getAlphaMap(48);
106
+ const alpha96 = await this.getAlphaMap(96);
107
+ const processingStartedAt = now();
108
+ const result = processWatermarkImageData(originalImageData, {
109
+ alpha48,
110
+ alpha96,
111
+ adaptiveMode: options.adaptiveMode,
112
+ maxPasses: options.maxPasses,
113
+ debugTimings: options.debugTimings === true,
114
+ getAlphaMap: (size) => this.alphaMaps[size] || interpolateAlphaMap(alpha96, 96, size)
115
+ });
116
+ const processWatermarkImageDataMs = now() - processingStartedAt;
117
+ const writeStartedAt = now();
118
+ ctx.putImageData(result.imageData, 0, 0);
119
+ const putImageDataMs = now() - writeStartedAt;
120
+ canvas.__watermarkMeta = result.meta;
121
+ canvas.__watermarkTiming = {
122
+ drawMs,
123
+ getImageDataMs,
124
+ processWatermarkImageDataMs,
125
+ putImageDataMs,
126
+ processor: result.debugTimings ?? null
127
+ };
128
+
129
+ return canvas;
130
+ }
131
+
132
+ /**
133
+ * Get watermark information (for display)
134
+ * @param {number} imageWidth - Image width
135
+ * @param {number} imageHeight - Image height
136
+ * @returns {Object} Watermark information {size, position, config}
137
+ */
138
+ getWatermarkInfo(imageWidth, imageHeight) {
139
+ const config = detectWatermarkConfig(imageWidth, imageHeight);
140
+ const position = calculateWatermarkPosition(imageWidth, imageHeight, config);
141
+
142
+ return {
143
+ size: config.logoSize,
144
+ position: position,
145
+ config: config
146
+ };
147
+ }
148
+ }
149
+
150
+ export { removeRepeatedWatermarkLayers } from './multiPassRemoval.js';
@@ -0,0 +1,12 @@
1
+ import {
2
+ classifyAdaptiveWatermarkSignal,
3
+ classifyStandardWatermarkSignal
4
+ } from './watermarkDecisionPolicy.js';
5
+
6
+ export function hasReliableStandardWatermarkSignal({ spatialScore, gradientScore }) {
7
+ return classifyStandardWatermarkSignal({ spatialScore, gradientScore }).tier === 'direct-match';
8
+ }
9
+
10
+ export function hasReliableAdaptiveWatermarkSignal(adaptiveResult) {
11
+ return classifyAdaptiveWatermarkSignal(adaptiveResult).tier === 'direct-match';
12
+ }