From a04488f5d7d113c312462c190bf1253165598332 Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Fri, 12 Dec 2025 16:35:48 -0500 Subject: [PATCH 1/6] Separate Additon and Deletion colors --- src/ImageDiff.js | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/ImageDiff.js b/src/ImageDiff.js index bf5ec37..b8ba03a 100644 --- a/src/ImageDiff.js +++ b/src/ImageDiff.js @@ -60,7 +60,8 @@ export default class ImageDiff { uniform sampler2D u_image2; uniform float u_threshold; uniform float u_alpha; - uniform vec3 u_diffColor; + uniform vec3 u_additionColor; + uniform vec3 u_deletionColor; varying vec2 v_texCoord; void main() { @@ -84,14 +85,33 @@ export default class ImageDiff { // Check if difference exceeds threshold if (delta > u_threshold || alphaDiff > u_threshold) { - // Highlight differences with custom color - gl_FragColor = vec4(u_diffColor, 1.0); + // Determine if this is an addition or deletion + float brightness1 = (y1 + color1.a) / 2.0; + float brightness2 = (y2 + color2.a) / 2.0; + + if (brightness2 > brightness1) { + // Addition: overlay has content, background doesn't + gl_FragColor = vec4(u_additionColor, 1.0); } else { - // Show original color from image1 with alpha blending - gl_FragColor = vec4(color1.rgb, color1.a * u_alpha); + // Deletion: background has content, overlay doesn't + // Only show if overlay alpha is high enough, otherwise hide + if (u_alpha > 0.5) { + gl_FragColor = vec4(u_deletionColor, 1.0); + } else { + // Hide deletions when overlay is hidden + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + } } + } else { + // Blend overlay on top of background - alpha only affects overlay + // Preserve background alpha, blend overlay based on u_alpha + float overlayFactor = color2.a * u_alpha; + vec3 blended = mix(color1.rgb, color2.rgb, overlayFactor); + float finalAlpha = max(color1.a, overlayFactor); + gl_FragColor = vec4(blended, finalAlpha); } - ` + } + ` this.#vertexShader = this.#createShader(gl, gl.VERTEX_SHADER, vertexShaderSource) this.#fragmentShader = this.#createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource) @@ -151,14 +171,16 @@ export default class ImageDiff { const { diffThreshold = 0.2, backgroundAlpha = 1.0, - diffColor = { r: 1, g: 0, b: 0 } + additionColor = { r: 1, g: 0, b: 0 }, + deletionColor = { r: 1, g: 1, b: 0 } } = options gl.uniform1i(gl.getUniformLocation(this.#program, 'u_image1'), 0) gl.uniform1i(gl.getUniformLocation(this.#program, 'u_image2'), 1) gl.uniform1f(gl.getUniformLocation(this.#program, 'u_threshold'), diffThreshold) gl.uniform1f(gl.getUniformLocation(this.#program, 'u_alpha'), backgroundAlpha) - gl.uniform3f(gl.getUniformLocation(this.#program, 'u_diffColor'), diffColor.r, diffColor.g, diffColor.b) + gl.uniform3f(gl.getUniformLocation(this.#program, 'u_additionColor'), additionColor.r, additionColor.g, additionColor.b) + gl.uniform3f(gl.getUniformLocation(this.#program, 'u_deletionColor'), deletionColor.r, deletionColor.g, deletionColor.b) } /** @@ -181,9 +203,10 @@ export default class ImageDiff { /** * @param {Object} options - * @param {Object} [options.diffColor={r:1,g:0,b:0}] - RGB color for highlighting differences (values between 0 and 1) + * @param {Object} [options.additionColor={r:1,g:0,b:0}] - RGB color for highlighting additions (values between 0 and 1) + * @param {Object} [options.deletionColor={r:1,g:1,b:0}] - RGB color for highlighting deletions (values between 0 and 1) * @param {number} [options.diffThreshold=0.2] - Threshold for detecting differences (0 to 1) - * @param {number} [options.backgroundAlpha=1.0] - Opacity for the background image (0 to 1) + * @param {number} [options.backgroundAlpha=1.0] - Opacity for the overlay image (0 to 1, does not affect background) * @returns {OffscreenCanvas} - Canvas with the diff result */ update(options) { From b8f0490c24c7b5012c44a925abbe50eda232266e Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Fri, 12 Dec 2025 16:46:35 -0500 Subject: [PATCH 2/6] Simplify addition color --- src/ImageDiff.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ImageDiff.js b/src/ImageDiff.js index b8ba03a..3e86809 100644 --- a/src/ImageDiff.js +++ b/src/ImageDiff.js @@ -88,19 +88,12 @@ export default class ImageDiff { // Determine if this is an addition or deletion float brightness1 = (y1 + color1.a) / 2.0; float brightness2 = (y2 + color2.a) / 2.0; - + if (brightness2 > brightness1) { // Addition: overlay has content, background doesn't gl_FragColor = vec4(u_additionColor, 1.0); } else { - // Deletion: background has content, overlay doesn't - // Only show if overlay alpha is high enough, otherwise hide - if (u_alpha > 0.5) { - gl_FragColor = vec4(u_deletionColor, 1.0); - } else { - // Hide deletions when overlay is hidden - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); - } + gl_FragColor = vec4(u_deletionColor, u_alpha); } } else { // Blend overlay on top of background - alpha only affects overlay From 3639a990ad09ea9dc5b7fd1ae7af5eae27bc98da Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Mon, 15 Dec 2025 10:07:03 -0500 Subject: [PATCH 3/6] Show/hide diffs one at a time --- src/ImageDiff.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ImageDiff.js b/src/ImageDiff.js index 3e86809..779927d 100644 --- a/src/ImageDiff.js +++ b/src/ImageDiff.js @@ -91,8 +91,13 @@ export default class ImageDiff { if (brightness2 > brightness1) { // Addition: overlay has content, background doesn't - gl_FragColor = vec4(u_additionColor, 1.0); + if (u_alpha < 1.0) { + gl_FragColor = vec4(u_additionColor, 1.0 - u_alpha); + } else { + gl_FragColor = vec4(u_additionColor, 0.0); + } } else { + // Deletion: background has content, overlay doesn't gl_FragColor = vec4(u_deletionColor, u_alpha); } } else { From 5b42e721b5039b7d7e64ab3fd12fa3588513d608 Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Mon, 15 Dec 2025 10:07:28 -0500 Subject: [PATCH 4/6] Update Package.json for delivery --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d8f6747..d1b408f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rolemodel/image-diff", - "version": "1.0.0", + "version": "1.1.0", "description": "Image Difference tool that compares pixel by pixel", "packageManager": "yarn@4.12.0", "type": "module", From a8e1f834c39519f1e5d19aea41b989bd16617c0a Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Mon, 15 Dec 2025 13:59:22 -0500 Subject: [PATCH 5/6] Update pages for addition and deletion --- index.html | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index e492819..ec84121 100644 --- a/index.html +++ b/index.html @@ -68,8 +68,12 @@
- - + + +
+
+ +
@@ -91,18 +95,25 @@ const diffThresholdInput = document.getElementById('diff-threshold') const backgroundAlphaInput = document.getElementById('background-alpha') - const diffColorInput = document.getElementById('diff-color') + const additionColorInput = document.getElementById('addition-color') + const deletionColorInput = document.getElementById('deletion-color') const diff = new ImageDiff(originalCanvas, modifiedCanvas) function diffOptions() { - const hexColor = diffColorInput.value - const r = parseInt(hexColor.slice(1, 3), 16) / 255 - const g = parseInt(hexColor.slice(3, 5), 16) / 255 - const b = parseInt(hexColor.slice(5, 7), 16) / 255 + const additionColor = additionColorInput.value + const r = parseInt(additionColor.slice(1, 3), 16) / 255 + const g = parseInt(additionColor.slice(3, 5), 16) / 255 + const b = parseInt(additionColor.slice(5, 7), 16) / 255 + + const deletionColor = deletionColorInput.value + const dr = parseInt(deletionColor.slice(1, 3), 16) / 255 + const dg = parseInt(deletionColor.slice(3, 5), 16) / 255 + const db = parseInt(deletionColor.slice(5, 7), 16) / 255 return { - diffColor: { r, g, b }, + additionColor: { r, g, b }, + deletionColor: { r: dr, g: dg, b: db }, threshold: parseFloat(diffThresholdInput.value), backgroundAlpha: parseFloat(backgroundAlphaInput.value) } From 9992b16c74f2a3ece4035b43ceada92e04a0e490 Mon Sep 17 00:00:00 2001 From: Braden Rich Date: Mon, 15 Dec 2025 14:05:07 -0500 Subject: [PATCH 6/6] Better handling of overlay --- src/ImageDiff.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ImageDiff.js b/src/ImageDiff.js index 779927d..097cfef 100644 --- a/src/ImageDiff.js +++ b/src/ImageDiff.js @@ -91,11 +91,7 @@ export default class ImageDiff { if (brightness2 > brightness1) { // Addition: overlay has content, background doesn't - if (u_alpha < 1.0) { - gl_FragColor = vec4(u_additionColor, 1.0 - u_alpha); - } else { - gl_FragColor = vec4(u_additionColor, 0.0); - } + gl_FragColor = vec4(u_additionColor, 1.0 - u_alpha); } else { // Deletion: background has content, overlay doesn't gl_FragColor = vec4(u_deletionColor, u_alpha);