Color equivalency calculator

This Javascript file has three different calculations for color equivalency. These can be helpful if you want a color to have the optical appearance as a specific color when semi-transparent.

  1. matchAlphaByColor returns an alpha value (0-1) to match colorToMatch relative to backgroundColor. This is most reliable with grayscale, it tends to be somewhat unreliable for colors w/ any significant saturation.
  2. matchColorAtAlpha returns the color at alpha opacity that matches colorToMatch set on backgroundColor
  3. getRGBforTransparentColor returns the RGB value at 100% opacity to match colorToMatch at colorToMatchAlpha opacity set on backgroundColor

Instructions

  1. Copy the code below into a file on your machine. Let’s name it colors.js
  2. Install Node.js
  3. Edit BACKGROUND_COLOR, COLOR_TO_MATCH and COLOR_TO_CHANGE to fit your needs
  4. Fire up a Terminal window and cd to the directory where you saved the colors.js file
  5. Run node colors.js in your terminal
  6. Read out the results returned in the terminal
            
/* 
 * Change these variables for your specific needs 
 */

const BACKGROUND_COLOR = {r: 34, g: 114, b: 37}
const COLOR_TO_MATCH = {r: 46, g: 153, b: 50}
const COLOR_TO_CHANGE = {r: 126, g: 216, b: 129}

/*
 * Returns the alpha of `colorToChange` to match colorToMatch relative to `backgroundColor`
 * This is most reliable with grayscale, it tends to be somewhat unreliable for colors w/ any significant saturation
*/
function matchAlphaByColor(backgroundColor, colorToMatch, colorToChange) {
    let alphaR = (colorToMatch.r-backgroundColor.r) / (colorToChange.r-backgroundColor.r)
    let alphaG = (colorToMatch.g-backgroundColor.g) / (colorToChange.g-backgroundColor.g)
    let alphaB = (colorToMatch.b-backgroundColor.b) / (colorToChange.b-backgroundColor.b)
    
    alphaR = isNaN(alphaR) ? 0 : alphaR
    alphaG = isNaN(alphaG) ? 0 : alphaG
    alphaB = isNaN(alphaB) ? 0 : alphaB

    let blendR = (colorToChange.r/(colorToChange.r+colorToChange.g+colorToChange.b) + backgroundColor.r/(backgroundColor.r+backgroundColor.g+backgroundColor.b))/2
	let blendG = (colorToChange.g/(colorToChange.r+colorToChange.g+colorToChange.b) + backgroundColor.g/(backgroundColor.r+backgroundColor.g+backgroundColor.b))/2
	let blendB = (colorToChange.b/(colorToChange.r+colorToChange.g+colorToChange.b) + backgroundColor.b/(backgroundColor.r+backgroundColor.g+backgroundColor.b))/2

	alphaR *= blendR
	alphaG *= blendG
	alphaB *= blendB

    return alphaR + alphaG + alphaB;;
}

/* 
 * Returns the color at `alpha` opacity that matches `colorToMatch` set on `backgroundColor` 
 */
function matchColorAtAlpha(backgroundColor, colorToMatch, alpha) {
    let r = (colorToMatch.r - backgroundColor.r + backgroundColor.r*alpha)/alpha
    let g = (colorToMatch.g - backgroundColor.g + backgroundColor.g*alpha)/alpha
    let b = (colorToMatch.b - backgroundColor.b + backgroundColor.b*alpha)/alpha

    return {r:r, g:g, b:b, a:alpha}
}

/* 
 * Returns the RGB value at 100% opacity to match `colorToMatch` at `colorToMatchAlpha` opacity set on `backgroundColor`
 */
function matchTransparentColor(backgroundColor, colorToMatch, colorToMatchAlpha) {
    let r = ((colorToMatch.r - backgroundColor.r)*colorToMatchAlpha + backgroundColor.r)
    let g = ((colorToMatch.g - backgroundColor.g)*colorToMatchAlpha + backgroundColor.g)
    let b = ((colorToMatch.b - backgroundColor.b)*colorToMatchAlpha + backgroundColor.b)

    return {r:r, g:g, b:b}
}

console.log('Matching alpha for ' + COLOR_TO_MATCH.r + ', ' + COLOR_TO_MATCH.g + ', ' + COLOR_TO_MATCH.b + ' set on ' + BACKGROUND_COLOR.r + ', ' + BACKGROUND_COLOR.g + ', ' + BACKGROUND_COLOR.g + ':', matchAlphaByColor(BACKGROUND_COLOR, COLOR_TO_MATCH, COLOR_TO_CHANGE))

console.log('\n------------------\n');

console.log('Matching color for ' + COLOR_TO_MATCH.r + ', ' + COLOR_TO_MATCH.g + ', ' + COLOR_TO_MATCH.b + ' set on ' + BACKGROUND_COLOR.r + ', ' + BACKGROUND_COLOR.g + ', ' + BACKGROUND_COLOR.g + ' at 75% opacity:', matchColorAtAlpha(BACKGROUND_COLOR, COLOR_TO_MATCH, .75))
console.log('\n');
console.log('Matching color for ' + COLOR_TO_MATCH.r + ', ' + COLOR_TO_MATCH.g + ', ' + COLOR_TO_MATCH.b + ' set on ' + BACKGROUND_COLOR.r + ', ' + BACKGROUND_COLOR.g + ', ' + BACKGROUND_COLOR.g + ' at 50% opacity:', matchColorAtAlpha(BACKGROUND_COLOR, COLOR_TO_MATCH, .5))

console.log('\n------------------\n');

console.log('Matching color for ' + COLOR_TO_MATCH.r + ', ' + COLOR_TO_MATCH.g + ', ' + COLOR_TO_MATCH.b + ' at 75% opacity set on ' + BACKGROUND_COLOR.r + ', ' + BACKGROUND_COLOR.g + ', ' + BACKGROUND_COLOR.g + ':', matchTransparentColor(BACKGROUND_COLOR, COLOR_TO_MATCH, .75))
console.log('\n');
console.log('Matching color for ' + COLOR_TO_MATCH.r + ', ' + COLOR_TO_MATCH.g + ', ' + COLOR_TO_MATCH.b + ' at 50% opacity set on ' + BACKGROUND_COLOR.r + ', ' + BACKGROUND_COLOR.g + ', ' + BACKGROUND_COLOR.g + ':', matchTransparentColor(BACKGROUND_COLOR, COLOR_TO_MATCH, .50))