@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.
- package/LICENSE +22 -0
- package/README.md +371 -0
- package/README_zh.md +371 -0
- package/bin/gwr.mjs +12 -0
- package/package.json +76 -0
- package/skills/gemini-watermark-remover/SKILL.md +28 -0
- package/skills/gemini-watermark-remover/agents/openai.yaml +3 -0
- package/skills/gemini-watermark-remover/references/inputs-and-outputs.md +9 -0
- package/skills/gemini-watermark-remover/references/limitations.md +5 -0
- package/skills/gemini-watermark-remover/references/usage.md +19 -0
- package/skills/gemini-watermark-remover/scripts/run.mjs +153 -0
- package/src/cli/gwrCli.js +17 -0
- package/src/cli/gwrRemoveCommand.js +317 -0
- package/src/core/adaptiveDetector.js +488 -0
- package/src/core/alphaMap.js +30 -0
- package/src/core/blendModes.js +70 -0
- package/src/core/candidateSelector.js +1446 -0
- package/src/core/canvasBlob.js +26 -0
- package/src/core/embeddedAlphaMaps.js +49 -0
- package/src/core/geminiSizeCatalog.js +239 -0
- package/src/core/multiPassRemoval.js +93 -0
- package/src/core/previewAlphaCalibration.js +822 -0
- package/src/core/restorationMetrics.js +251 -0
- package/src/core/selectionDebug.js +47 -0
- package/src/core/watermarkConfig.js +146 -0
- package/src/core/watermarkDecisionPolicy.js +163 -0
- package/src/core/watermarkDisplay.js +60 -0
- package/src/core/watermarkEngine.js +150 -0
- package/src/core/watermarkPresence.js +12 -0
- package/src/core/watermarkProcessor.js +875 -0
- package/src/core/workerClient.js +114 -0
- package/src/sdk/browser.d.ts +13 -0
- package/src/sdk/browser.js +29 -0
- package/src/sdk/image-data.d.ts +14 -0
- package/src/sdk/image-data.js +55 -0
- package/src/sdk/index.d.ts +144 -0
- package/src/sdk/index.js +8 -0
- package/src/sdk/node.d.ts +42 -0
- 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
|
+
}
|