@pilio/gemini-watermark-remover 1.0.26 → 1.0.28
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/README.md +91 -91
- package/README_zh.md +414 -414
- package/package.json +10 -1
- package/skills/gemini-watermark-remover/SKILL.md +32 -32
- package/skills/gemini-watermark-remover/references/usage.md +23 -23
- package/src/core/candidateEvaluation.js +182 -0
- package/src/core/candidateSelector.js +46 -28
- package/src/core/imageWatermarkPipeline.js +127 -0
- package/src/core/imageWatermarkPipelineRequest.js +39 -0
- package/src/core/pipelineAcceptedExecutor.js +299 -0
- package/src/core/pipelineAcceptedExecutorRequest.js +44 -0
- package/src/core/pipelineAcceptedFinalizationRequest.js +21 -0
- package/src/core/pipelineAlphaStageSpecs.js +573 -0
- package/src/core/pipelineAlphaTraceContract.js +56 -0
- package/src/core/pipelineAlphaTrial.js +223 -0
- package/src/core/pipelineDecisionPath.js +161 -0
- package/src/core/pipelineDetectionCandidate.js +128 -0
- package/src/core/pipelineFinalization.js +46 -0
- package/src/core/pipelineInitialContext.js +52 -0
- package/src/core/pipelineInitialSelection.js +61 -0
- package/src/core/pipelineLayerContracts.js +163 -0
- package/src/core/pipelineMeta.js +201 -0
- package/src/core/pipelineMetrics.js +88 -0
- package/src/core/pipelinePassState.js +36 -0
- package/src/core/pipelineRepairGates.js +124 -0
- package/src/core/pipelineRepairStageSpecs.js +491 -0
- package/src/core/pipelineRepairTrial.js +156 -0
- package/src/core/pipelineResult.js +128 -0
- package/src/core/pipelineRuntime.js +689 -0
- package/src/core/pipelineRuntimeBootstrap.js +78 -0
- package/src/core/pipelineState.js +134 -0
- package/src/core/pipelineTimings.js +36 -0
- package/src/core/pipelineTrace.js +28 -0
- package/src/core/watermarkProcessor.js +1188 -1297
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export const PIPELINE_LAYER_ORDER = Object.freeze([
|
|
2
|
+
'detection',
|
|
3
|
+
'alpha',
|
|
4
|
+
'repair',
|
|
5
|
+
'evaluation'
|
|
6
|
+
]);
|
|
7
|
+
|
|
8
|
+
export const PIPELINE_LAYER_CONTRACTS = Object.freeze({
|
|
9
|
+
detection: Object.freeze({
|
|
10
|
+
layer: 'detection',
|
|
11
|
+
owns: 'candidate-localization-and-evidence',
|
|
12
|
+
inputFields: Object.freeze([
|
|
13
|
+
'originalImageData',
|
|
14
|
+
'resolvedConfig',
|
|
15
|
+
'position',
|
|
16
|
+
'alpha48',
|
|
17
|
+
'alpha96',
|
|
18
|
+
'alpha96Variants',
|
|
19
|
+
'allowAdaptiveSearch',
|
|
20
|
+
'alphaGainCandidates',
|
|
21
|
+
'alphaPriorityGains'
|
|
22
|
+
]),
|
|
23
|
+
outputFields: Object.freeze([
|
|
24
|
+
'selectedTrial',
|
|
25
|
+
'source',
|
|
26
|
+
'decisionTier',
|
|
27
|
+
'adaptiveConfidence',
|
|
28
|
+
'standardSpatialScore',
|
|
29
|
+
'standardGradientScore'
|
|
30
|
+
]),
|
|
31
|
+
moduleAnchors: Object.freeze([
|
|
32
|
+
'pipelineDetectionCandidate',
|
|
33
|
+
'pipelineInitialContext',
|
|
34
|
+
'pipelineInitialSelection',
|
|
35
|
+
'candidateSelector'
|
|
36
|
+
]),
|
|
37
|
+
testAnchors: Object.freeze([
|
|
38
|
+
'pipelineDetectionCandidate.test',
|
|
39
|
+
'pipelineInitialContext.test',
|
|
40
|
+
'pipelineInitialSelection.test',
|
|
41
|
+
'candidateEvaluation.test'
|
|
42
|
+
])
|
|
43
|
+
}),
|
|
44
|
+
alpha: Object.freeze({
|
|
45
|
+
layer: 'alpha',
|
|
46
|
+
owns: 'alpha-map-selection-and-alpha-fit',
|
|
47
|
+
inputFields: Object.freeze([
|
|
48
|
+
'acceptedPipelineState',
|
|
49
|
+
'runtimeBootstrap',
|
|
50
|
+
'alpha96',
|
|
51
|
+
'getAlphaMap',
|
|
52
|
+
'alpha96Variants',
|
|
53
|
+
'alphaGain',
|
|
54
|
+
'alphaMapSource'
|
|
55
|
+
]),
|
|
56
|
+
outputFields: Object.freeze([
|
|
57
|
+
'alphaTrialEvents',
|
|
58
|
+
'alphaAdjustmentStages',
|
|
59
|
+
'alphaGain',
|
|
60
|
+
'alphaMap',
|
|
61
|
+
'subpixelShift',
|
|
62
|
+
'pipelineState'
|
|
63
|
+
]),
|
|
64
|
+
moduleAnchors: Object.freeze([
|
|
65
|
+
'pipelineAlphaTraceContract',
|
|
66
|
+
'pipelineAlphaTrial',
|
|
67
|
+
'pipelineAlphaStageSpecs',
|
|
68
|
+
'pipelineAcceptedExecutor',
|
|
69
|
+
'pipelineRuntime'
|
|
70
|
+
]),
|
|
71
|
+
testAnchors: Object.freeze([
|
|
72
|
+
'pipelineAlphaTraceContract.test',
|
|
73
|
+
'pipelineAlphaTrial.test',
|
|
74
|
+
'pipelineAlphaStageSpecs.test',
|
|
75
|
+
'pipelineAcceptedExecutor.test',
|
|
76
|
+
'pipelineRuntime.test'
|
|
77
|
+
])
|
|
78
|
+
}),
|
|
79
|
+
repair: Object.freeze({
|
|
80
|
+
layer: 'repair',
|
|
81
|
+
owns: 'texture-repair-and-artifact-gated-cleanup',
|
|
82
|
+
inputFields: Object.freeze([
|
|
83
|
+
'pipelineState',
|
|
84
|
+
'passState',
|
|
85
|
+
'cleanupFlags',
|
|
86
|
+
'repairCleanupConfig',
|
|
87
|
+
'visualPostProcessingEnabled'
|
|
88
|
+
]),
|
|
89
|
+
outputFields: Object.freeze([
|
|
90
|
+
'repairTrial',
|
|
91
|
+
'passState',
|
|
92
|
+
'passes',
|
|
93
|
+
'source',
|
|
94
|
+
'finalImageData',
|
|
95
|
+
'finalProcessedSpatialScore',
|
|
96
|
+
'finalProcessedGradientScore'
|
|
97
|
+
]),
|
|
98
|
+
moduleAnchors: Object.freeze([
|
|
99
|
+
'pipelineRepairTrial',
|
|
100
|
+
'pipelineRepairStageSpecs',
|
|
101
|
+
'pipelineRepairGates',
|
|
102
|
+
'pipelineAcceptedExecutor'
|
|
103
|
+
]),
|
|
104
|
+
testAnchors: Object.freeze([
|
|
105
|
+
'pipelineRepairTrial.test',
|
|
106
|
+
'pipelineRepairStageSpecs.test',
|
|
107
|
+
'pipelineRepairGates.test',
|
|
108
|
+
'pipelineAcceptedExecutor.test'
|
|
109
|
+
])
|
|
110
|
+
}),
|
|
111
|
+
evaluation: Object.freeze({
|
|
112
|
+
layer: 'evaluation',
|
|
113
|
+
owns: 'decision-path-and-risk-gated-arbitration',
|
|
114
|
+
inputFields: Object.freeze([
|
|
115
|
+
'detectionCandidate',
|
|
116
|
+
'alphaTrial',
|
|
117
|
+
'repairTrial',
|
|
118
|
+
'selectedTrial',
|
|
119
|
+
'alphaTrialEvents',
|
|
120
|
+
'residualVisibility'
|
|
121
|
+
]),
|
|
122
|
+
outputFields: Object.freeze([
|
|
123
|
+
'decisionPath',
|
|
124
|
+
'evaluationDecision',
|
|
125
|
+
'blockedGate',
|
|
126
|
+
'riskFlags',
|
|
127
|
+
'selectionDebug',
|
|
128
|
+
'meta'
|
|
129
|
+
]),
|
|
130
|
+
moduleAnchors: Object.freeze([
|
|
131
|
+
'pipelineDecisionPath',
|
|
132
|
+
'candidateEvaluation',
|
|
133
|
+
'pipelineMeta',
|
|
134
|
+
'pipelineFinalization',
|
|
135
|
+
'pipelineResult'
|
|
136
|
+
]),
|
|
137
|
+
testAnchors: Object.freeze([
|
|
138
|
+
'pipelineDecisionPath.test',
|
|
139
|
+
'candidateEvaluation.test',
|
|
140
|
+
'pipelineMeta.test',
|
|
141
|
+
'pipelineFinalization.test',
|
|
142
|
+
'pipelineResult.test'
|
|
143
|
+
])
|
|
144
|
+
})
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
export function getPipelineLayerContract(layer) {
|
|
148
|
+
return PIPELINE_LAYER_CONTRACTS[layer] ?? null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function createPipelineLayerContractSummary() {
|
|
152
|
+
return PIPELINE_LAYER_ORDER.map((layer) => {
|
|
153
|
+
const contract = getPipelineLayerContract(layer);
|
|
154
|
+
return {
|
|
155
|
+
layer,
|
|
156
|
+
owns: contract.owns,
|
|
157
|
+
inputCount: contract.inputFields.length,
|
|
158
|
+
outputCount: contract.outputFields.length,
|
|
159
|
+
moduleAnchors: [...contract.moduleAnchors],
|
|
160
|
+
testAnchors: [...contract.testAnchors]
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAcceptedDecisionPath,
|
|
3
|
+
createRejectedDecisionPath
|
|
4
|
+
} from './candidateEvaluation.js';
|
|
5
|
+
|
|
6
|
+
function normalizeMetaPosition(position) {
|
|
7
|
+
if (!position) return null;
|
|
8
|
+
|
|
9
|
+
const { x, y, width, height } = position;
|
|
10
|
+
if (![x, y, width, height].every((value) => Number.isFinite(value))) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return { x, y, width, height };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizeMetaConfig(config) {
|
|
18
|
+
if (!config) return null;
|
|
19
|
+
|
|
20
|
+
const { logoSize, marginRight, marginBottom } = config;
|
|
21
|
+
if (![logoSize, marginRight, marginBottom].every((value) => Number.isFinite(value))) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
logoSize,
|
|
27
|
+
marginRight,
|
|
28
|
+
marginBottom,
|
|
29
|
+
...(typeof config.alphaVariant === 'string' && config.alphaVariant.length > 0
|
|
30
|
+
? { alphaVariant: config.alphaVariant }
|
|
31
|
+
: {})
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function createWatermarkMeta({
|
|
36
|
+
position = null,
|
|
37
|
+
config = null,
|
|
38
|
+
adaptiveConfidence = null,
|
|
39
|
+
originalSpatialScore = null,
|
|
40
|
+
originalGradientScore = null,
|
|
41
|
+
processedSpatialScore = null,
|
|
42
|
+
processedGradientScore = null,
|
|
43
|
+
suppressionGain = null,
|
|
44
|
+
residualVisibility = null,
|
|
45
|
+
templateWarp = null,
|
|
46
|
+
alphaGain = 1,
|
|
47
|
+
passCount = 0,
|
|
48
|
+
attemptedPassCount = 0,
|
|
49
|
+
passStopReason = null,
|
|
50
|
+
passes = null,
|
|
51
|
+
source = 'standard',
|
|
52
|
+
decisionTier = null,
|
|
53
|
+
applied = true,
|
|
54
|
+
skipReason = null,
|
|
55
|
+
subpixelShift = null,
|
|
56
|
+
selectionDebug = null,
|
|
57
|
+
alphaAdjustmentStages = null,
|
|
58
|
+
alphaMapSource = null,
|
|
59
|
+
decisionPath = null
|
|
60
|
+
} = {}) {
|
|
61
|
+
const normalizedPosition = normalizeMetaPosition(position);
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
applied,
|
|
65
|
+
skipReason: applied ? null : skipReason,
|
|
66
|
+
size: normalizedPosition ? normalizedPosition.width : null,
|
|
67
|
+
position: normalizedPosition,
|
|
68
|
+
config: normalizeMetaConfig(config),
|
|
69
|
+
detection: {
|
|
70
|
+
adaptiveConfidence,
|
|
71
|
+
originalSpatialScore,
|
|
72
|
+
originalGradientScore,
|
|
73
|
+
processedSpatialScore,
|
|
74
|
+
processedGradientScore,
|
|
75
|
+
suppressionGain,
|
|
76
|
+
residualVisibility
|
|
77
|
+
},
|
|
78
|
+
templateWarp: templateWarp ?? null,
|
|
79
|
+
alphaGain,
|
|
80
|
+
passCount,
|
|
81
|
+
attemptedPassCount,
|
|
82
|
+
passStopReason,
|
|
83
|
+
passes: Array.isArray(passes) ? passes : null,
|
|
84
|
+
// decisionTier is the normalized contract used by UI and attribution.
|
|
85
|
+
// source remains as a verbose execution trace for debugging/tests.
|
|
86
|
+
source,
|
|
87
|
+
decisionTier,
|
|
88
|
+
subpixelShift: subpixelShift ?? null,
|
|
89
|
+
selectionDebug,
|
|
90
|
+
alphaAdjustmentStages: Array.isArray(alphaAdjustmentStages) ? alphaAdjustmentStages : null,
|
|
91
|
+
alphaMapSource: alphaMapSource ?? null,
|
|
92
|
+
decisionPath: decisionPath ?? null
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function createAcceptedWatermarkMeta({
|
|
97
|
+
selectedTrial = null,
|
|
98
|
+
selectionSource = null,
|
|
99
|
+
position = null,
|
|
100
|
+
config = null,
|
|
101
|
+
adaptiveConfidence = null,
|
|
102
|
+
originalSpatialScore = null,
|
|
103
|
+
originalGradientScore = null,
|
|
104
|
+
processedSpatialScore = null,
|
|
105
|
+
processedGradientScore = null,
|
|
106
|
+
suppressionGain = null,
|
|
107
|
+
residualVisibility = null,
|
|
108
|
+
templateWarp = null,
|
|
109
|
+
alphaGain = 1,
|
|
110
|
+
passCount = 0,
|
|
111
|
+
attemptedPassCount = 0,
|
|
112
|
+
passStopReason = null,
|
|
113
|
+
passes = null,
|
|
114
|
+
source = 'standard',
|
|
115
|
+
decisionTier = null,
|
|
116
|
+
subpixelShift = null,
|
|
117
|
+
selectionDebug = null,
|
|
118
|
+
alphaAdjustmentStages = null,
|
|
119
|
+
alphaTrialEvents = null,
|
|
120
|
+
alphaMapSource = null
|
|
121
|
+
} = {}) {
|
|
122
|
+
const decisionPath = createAcceptedDecisionPath({
|
|
123
|
+
selectedTrial,
|
|
124
|
+
selectionSource,
|
|
125
|
+
source,
|
|
126
|
+
decisionTier,
|
|
127
|
+
config,
|
|
128
|
+
position,
|
|
129
|
+
adaptiveConfidence,
|
|
130
|
+
alphaGain,
|
|
131
|
+
alphaMapSource,
|
|
132
|
+
templateWarp,
|
|
133
|
+
alphaAdjustmentStages,
|
|
134
|
+
alphaTrialEvents,
|
|
135
|
+
originalSpatialScore,
|
|
136
|
+
originalGradientScore,
|
|
137
|
+
processedSpatialScore,
|
|
138
|
+
processedGradientScore,
|
|
139
|
+
suppressionGain,
|
|
140
|
+
residualVisibility
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return createWatermarkMeta({
|
|
144
|
+
position,
|
|
145
|
+
config,
|
|
146
|
+
adaptiveConfidence,
|
|
147
|
+
originalSpatialScore,
|
|
148
|
+
originalGradientScore,
|
|
149
|
+
processedSpatialScore,
|
|
150
|
+
processedGradientScore,
|
|
151
|
+
suppressionGain,
|
|
152
|
+
residualVisibility,
|
|
153
|
+
templateWarp,
|
|
154
|
+
alphaGain,
|
|
155
|
+
passCount,
|
|
156
|
+
attemptedPassCount,
|
|
157
|
+
passStopReason,
|
|
158
|
+
passes,
|
|
159
|
+
source,
|
|
160
|
+
decisionTier,
|
|
161
|
+
applied: true,
|
|
162
|
+
subpixelShift,
|
|
163
|
+
alphaAdjustmentStages,
|
|
164
|
+
alphaMapSource,
|
|
165
|
+
selectionDebug,
|
|
166
|
+
decisionPath
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function createRejectedWatermarkMeta({
|
|
171
|
+
reason = 'no-watermark-detected',
|
|
172
|
+
source = 'skipped',
|
|
173
|
+
decisionTier = 'insufficient',
|
|
174
|
+
adaptiveConfidence = null,
|
|
175
|
+
originalSpatialScore = null,
|
|
176
|
+
originalGradientScore = null,
|
|
177
|
+
selectionDebug = null
|
|
178
|
+
} = {}) {
|
|
179
|
+
return createWatermarkMeta({
|
|
180
|
+
adaptiveConfidence,
|
|
181
|
+
originalSpatialScore,
|
|
182
|
+
originalGradientScore,
|
|
183
|
+
processedSpatialScore: originalSpatialScore,
|
|
184
|
+
processedGradientScore: originalGradientScore,
|
|
185
|
+
suppressionGain: 0,
|
|
186
|
+
alphaGain: 1,
|
|
187
|
+
source,
|
|
188
|
+
decisionTier,
|
|
189
|
+
applied: false,
|
|
190
|
+
skipReason: reason,
|
|
191
|
+
selectionDebug,
|
|
192
|
+
decisionPath: createRejectedDecisionPath({
|
|
193
|
+
reason,
|
|
194
|
+
source,
|
|
195
|
+
decisionTier,
|
|
196
|
+
originalSpatialScore,
|
|
197
|
+
originalGradientScore,
|
|
198
|
+
adaptiveConfidence
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeRegionGradientCorrelation,
|
|
3
|
+
computeRegionSpatialCorrelation
|
|
4
|
+
} from './adaptiveDetector.js';
|
|
5
|
+
import { calculateNearBlackRatio } from './candidateSelector.js';
|
|
6
|
+
|
|
7
|
+
const FIRST_PASS_SIGN_FLIP_GRADIENT_THRESHOLD = 0.08;
|
|
8
|
+
const FIRST_PASS_SIGN_FLIP_MIN_GRADIENT_DROP = 0.2;
|
|
9
|
+
|
|
10
|
+
export function shouldStopAfterFirstPass({
|
|
11
|
+
originalSpatialScore,
|
|
12
|
+
originalGradientScore,
|
|
13
|
+
firstPassSpatialScore,
|
|
14
|
+
firstPassGradientScore
|
|
15
|
+
}) {
|
|
16
|
+
if (Math.abs(firstPassSpatialScore) <= 0.25) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return originalSpatialScore >= 0 &&
|
|
21
|
+
firstPassSpatialScore < 0 &&
|
|
22
|
+
firstPassGradientScore <= FIRST_PASS_SIGN_FLIP_GRADIENT_THRESHOLD &&
|
|
23
|
+
(originalGradientScore - firstPassGradientScore) >= FIRST_PASS_SIGN_FLIP_MIN_GRADIENT_DROP;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function createRegionCorrelationMetrics({
|
|
27
|
+
imageData,
|
|
28
|
+
alphaMap,
|
|
29
|
+
position,
|
|
30
|
+
includeNearBlackRatio = false
|
|
31
|
+
} = {}) {
|
|
32
|
+
const region = { x: position.x, y: position.y, size: position.width };
|
|
33
|
+
const metrics = {
|
|
34
|
+
spatialScore: computeRegionSpatialCorrelation({
|
|
35
|
+
imageData,
|
|
36
|
+
alphaMap,
|
|
37
|
+
region
|
|
38
|
+
}),
|
|
39
|
+
gradientScore: computeRegionGradientCorrelation({
|
|
40
|
+
imageData,
|
|
41
|
+
alphaMap,
|
|
42
|
+
region
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
if (includeNearBlackRatio) {
|
|
46
|
+
metrics.nearBlackRatio = calculateNearBlackRatio(imageData, position);
|
|
47
|
+
}
|
|
48
|
+
return metrics;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function createFirstPassMetrics({
|
|
52
|
+
imageData,
|
|
53
|
+
alphaMap,
|
|
54
|
+
position,
|
|
55
|
+
originalSpatialScore,
|
|
56
|
+
originalGradientScore
|
|
57
|
+
} = {}) {
|
|
58
|
+
const firstPassMetrics = createRegionCorrelationMetrics({
|
|
59
|
+
imageData,
|
|
60
|
+
alphaMap,
|
|
61
|
+
position,
|
|
62
|
+
includeNearBlackRatio: true
|
|
63
|
+
});
|
|
64
|
+
const clearedResidual = shouldStopAfterFirstPass({
|
|
65
|
+
originalSpatialScore,
|
|
66
|
+
originalGradientScore,
|
|
67
|
+
firstPassSpatialScore: firstPassMetrics.spatialScore,
|
|
68
|
+
firstPassGradientScore: firstPassMetrics.gradientScore
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
spatialScore: firstPassMetrics.spatialScore,
|
|
73
|
+
gradientScore: firstPassMetrics.gradientScore,
|
|
74
|
+
nearBlackRatio: firstPassMetrics.nearBlackRatio,
|
|
75
|
+
clearedResidual,
|
|
76
|
+
passStopReason: clearedResidual ? 'residual-low' : 'single-pass',
|
|
77
|
+
passRecord: {
|
|
78
|
+
index: 1,
|
|
79
|
+
beforeSpatialScore: originalSpatialScore,
|
|
80
|
+
beforeGradientScore: originalGradientScore,
|
|
81
|
+
afterSpatialScore: firstPassMetrics.spatialScore,
|
|
82
|
+
afterGradientScore: firstPassMetrics.gradientScore,
|
|
83
|
+
improvement: Math.abs(originalSpatialScore) - Math.abs(firstPassMetrics.spatialScore),
|
|
84
|
+
gradientDelta: firstPassMetrics.gradientScore - originalGradientScore,
|
|
85
|
+
nearBlackRatio: firstPassMetrics.nearBlackRatio
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function finiteOrFallback(value, fallback) {
|
|
2
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function createEmptyPipelinePassState() {
|
|
6
|
+
return {
|
|
7
|
+
passCount: 0,
|
|
8
|
+
attemptedPassCount: 0,
|
|
9
|
+
passStopReason: null,
|
|
10
|
+
passes: null
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function createFirstPassPipelinePassState({
|
|
15
|
+
firstPassMetrics = null
|
|
16
|
+
} = {}) {
|
|
17
|
+
return {
|
|
18
|
+
passCount: 1,
|
|
19
|
+
attemptedPassCount: 1,
|
|
20
|
+
passStopReason: firstPassMetrics?.passStopReason ?? null,
|
|
21
|
+
passes: [firstPassMetrics?.passRecord]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function applyPipelinePassOutcome({
|
|
26
|
+
current,
|
|
27
|
+
outcome
|
|
28
|
+
} = {}) {
|
|
29
|
+
const passIncrement = Math.max(0, finiteOrFallback(outcome?.passIncrement, 0));
|
|
30
|
+
return {
|
|
31
|
+
passCount: finiteOrFallback(current?.passCount, 0) + passIncrement,
|
|
32
|
+
attemptedPassCount: finiteOrFallback(current?.attemptedPassCount, 0) + passIncrement,
|
|
33
|
+
passStopReason: outcome?.passStopReason ?? current?.passStopReason ?? null,
|
|
34
|
+
passes: current?.passes ?? null
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const DEFAULT_PREVIEW_EDGE_CLEANUP_MAX_SIZE = 40;
|
|
2
|
+
const DEFAULT_KNOWN_48_EDGE_CLEANUP_MIN_SIZE = 40;
|
|
3
|
+
const DEFAULT_KNOWN_48_EDGE_CLEANUP_MAX_SIZE = 56;
|
|
4
|
+
const DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE = 36;
|
|
5
|
+
const DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE_TOLERANCE = 2;
|
|
6
|
+
|
|
7
|
+
export function shouldUsePreviewAnchorFastCleanup(
|
|
8
|
+
selectedTrial,
|
|
9
|
+
position,
|
|
10
|
+
{ previewEdgeCleanupMaxSize = DEFAULT_PREVIEW_EDGE_CLEANUP_MAX_SIZE } = {}
|
|
11
|
+
) {
|
|
12
|
+
return selectedTrial?.provenance?.previewAnchor === true &&
|
|
13
|
+
position?.width >= 24 &&
|
|
14
|
+
position?.width <= previewEdgeCleanupMaxSize;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isKnown48AnchorConfig(
|
|
18
|
+
config,
|
|
19
|
+
{
|
|
20
|
+
known48EdgeCleanupMinSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MIN_SIZE,
|
|
21
|
+
known48EdgeCleanupMaxSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MAX_SIZE
|
|
22
|
+
} = {}
|
|
23
|
+
) {
|
|
24
|
+
if (!config || config.logoSize < known48EdgeCleanupMinSize || config.logoSize > known48EdgeCleanupMaxSize) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const marginRight = Number(config.marginRight);
|
|
29
|
+
const marginBottom = Number(config.marginBottom);
|
|
30
|
+
if (!Number.isFinite(marginRight) || !Number.isFinite(marginBottom)) return false;
|
|
31
|
+
|
|
32
|
+
const isCurrentLargeMargin = Math.abs(marginRight - 96) <= 2 && Math.abs(marginBottom - 96) <= 2;
|
|
33
|
+
const isCurrentStandardMargin = marginRight >= 28 && marginRight <= 36 && marginBottom >= 28 && marginBottom <= 36;
|
|
34
|
+
return isCurrentLargeMargin || isCurrentStandardMargin;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function shouldUseKnown48EdgeCleanup({
|
|
38
|
+
selectedTrial,
|
|
39
|
+
position,
|
|
40
|
+
source,
|
|
41
|
+
known48EdgeCleanupMinSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MIN_SIZE,
|
|
42
|
+
known48EdgeCleanupMaxSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MAX_SIZE
|
|
43
|
+
} = {}) {
|
|
44
|
+
if (selectedTrial?.provenance?.previewAnchor === true) return false;
|
|
45
|
+
if (position?.width < known48EdgeCleanupMinSize || position?.width > known48EdgeCleanupMaxSize) return false;
|
|
46
|
+
if (!isKnown48AnchorConfig(selectedTrial?.config, {
|
|
47
|
+
known48EdgeCleanupMinSize,
|
|
48
|
+
known48EdgeCleanupMaxSize
|
|
49
|
+
})) return false;
|
|
50
|
+
|
|
51
|
+
const sourceText = String(source || '');
|
|
52
|
+
return sourceText === 'standard' ||
|
|
53
|
+
sourceText.startsWith('standard+gain') ||
|
|
54
|
+
sourceText.includes('catalog') ||
|
|
55
|
+
sourceText.includes('fixed-local');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isV2SmallAnchorConfig(
|
|
59
|
+
config,
|
|
60
|
+
{ v2SmallEdgeCleanupSize = DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE } = {}
|
|
61
|
+
) {
|
|
62
|
+
if (!config || config.logoSize !== v2SmallEdgeCleanupSize || config.alphaVariant !== 'v2') {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const marginRight = Number(config.marginRight);
|
|
67
|
+
const marginBottom = Number(config.marginBottom);
|
|
68
|
+
return Number.isFinite(marginRight) &&
|
|
69
|
+
Number.isFinite(marginBottom) &&
|
|
70
|
+
marginRight >= 48 &&
|
|
71
|
+
marginBottom >= 48;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function shouldUseV2SmallEdgeCleanup({
|
|
75
|
+
selectedTrial,
|
|
76
|
+
position,
|
|
77
|
+
source,
|
|
78
|
+
v2SmallEdgeCleanupSize = DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE,
|
|
79
|
+
v2SmallEdgeCleanupSizeTolerance = DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE_TOLERANCE
|
|
80
|
+
} = {}) {
|
|
81
|
+
if (selectedTrial?.provenance?.previewAnchor === true) return false;
|
|
82
|
+
if (
|
|
83
|
+
position?.width < v2SmallEdgeCleanupSize - v2SmallEdgeCleanupSizeTolerance ||
|
|
84
|
+
position?.width > v2SmallEdgeCleanupSize + v2SmallEdgeCleanupSizeTolerance
|
|
85
|
+
) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (!isV2SmallAnchorConfig(selectedTrial?.config, { v2SmallEdgeCleanupSize })) return false;
|
|
89
|
+
if (selectedTrial?.provenance?.catalogFamily !== 'gemini-v2-small') return false;
|
|
90
|
+
|
|
91
|
+
const sourceText = String(source || '');
|
|
92
|
+
return sourceText.includes('catalog');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function createRepairCleanupFlags({
|
|
96
|
+
selectedTrial,
|
|
97
|
+
position,
|
|
98
|
+
source,
|
|
99
|
+
previewEdgeCleanupMaxSize = DEFAULT_PREVIEW_EDGE_CLEANUP_MAX_SIZE,
|
|
100
|
+
known48EdgeCleanupMinSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MIN_SIZE,
|
|
101
|
+
known48EdgeCleanupMaxSize = DEFAULT_KNOWN_48_EDGE_CLEANUP_MAX_SIZE,
|
|
102
|
+
v2SmallEdgeCleanupSize = DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE,
|
|
103
|
+
v2SmallEdgeCleanupSizeTolerance = DEFAULT_V2_SMALL_EDGE_CLEANUP_SIZE_TOLERANCE
|
|
104
|
+
} = {}) {
|
|
105
|
+
return {
|
|
106
|
+
usePreviewAnchorFastCleanup: shouldUsePreviewAnchorFastCleanup(selectedTrial, position, {
|
|
107
|
+
previewEdgeCleanupMaxSize
|
|
108
|
+
}),
|
|
109
|
+
useKnown48EdgeCleanup: shouldUseKnown48EdgeCleanup({
|
|
110
|
+
selectedTrial,
|
|
111
|
+
position,
|
|
112
|
+
source,
|
|
113
|
+
known48EdgeCleanupMinSize,
|
|
114
|
+
known48EdgeCleanupMaxSize
|
|
115
|
+
}),
|
|
116
|
+
useV2SmallEdgeCleanup: shouldUseV2SmallEdgeCleanup({
|
|
117
|
+
selectedTrial,
|
|
118
|
+
position,
|
|
119
|
+
source,
|
|
120
|
+
v2SmallEdgeCleanupSize,
|
|
121
|
+
v2SmallEdgeCleanupSizeTolerance
|
|
122
|
+
})
|
|
123
|
+
};
|
|
124
|
+
}
|