Можно ли узнать исходный цвет, если известна степень прозрачности имеющегося?

Есть блок некоторого оттенка синего:

введите сюда описание изображения

ColorPic определяет его код как #4493b1 или rgba(68, 147, 177, 1). Но доподлинно известно, что этот цвет получился в результате придания прозрачности (opacity: 0.7). И при этом данный блок лежит поверх фона у body #dfe2d9.

Можно ли как-то узнать код исходного цвета? Есть ли какая-то формула? Или некий сервис, позволяющий это сделать?


Ответы (1 шт):

Автор решения: yar85

Формула (каждый цветовой канал считается отдельно):

XR,G,B = (mixColorR,G,B - knownColorR,G,B × knownColoropacity) ÷ Xopacity

Она получена на базе обычной математики, которой в школе научили. Я не вижу проблемы с уравнением (всего два простых переноса), но если все-таки будут вопросы по формуле - в комментарии. Критика от математиков так же приветствуется :)

Как нетрудно догадаться, эта формула применяется только к аддитивным цветовым моделям. То есть, для излучаемого света (цвета на мониторе) - но не для отражаемого/преломляемого (цвета физических объектов, всякие YRB, CMYK, и т.д.).


Очень простенький калькулятор, только для проверки:

const [bgInp, mixInp, opcInp] = document.querySelectorAll('input'),
      outputEl = document.querySelector('#result'); 
const inputHandler = () => {
  // установка цвета контейнеров по значению дочернего инпута 
  [bgInp, mixInp].forEach(inp => setColor(inp.parentElement, inp.value)); 
  // преобразование значений инпутов в числовые (r, g, b, и их "вес" по opacity)
  const bgClr  = hexColorToObj(bgInp.value), 
        mixClr = hexColorToObj(mixInp.value), 
        mixWeight = Math.min(1, Math.max(0, +opcInp.value || 1)), 
        bgWeight  = 1 - mixWeight; 
  // вычисление искомого цвета
  const result = ['r', 'g', 'b'].reduce((rslt, chnl) => (
    rslt += toByteHex((mixClr[chnl] - bgClr[chnl] * bgWeight) / mixWeight)
  ), '#'); 
  // скрытие/показ элемента с результатом, по наличию ошибок
  const hasError = document.querySelector(':invalid') || !/^#[a-f\d]{6}$/.test(result); 
  document.body.classList.toggle('has-error', hasError); 
  if (hasError) return; 
  // вывод результата
  [...outputEl.children].forEach((el, idx) => {
    setColor(el, !idx ? result : result + toByteHex(255 * mixWeight)); 
  });
}; 

// добавление обработчика, и его вызов для инициализации
for (const inp of [bgInp, mixInp, opcInp])
  inp.addEventListener('input', inputHandler); 
inputHandler(); 


// вспомогательные функции 
function setColor(el, clr) {
  el.style.background = el.dataset.clr = clr; 
}
function hexColorToObj(hexColor) {
  const [r, g, b] = hexColor.slice(1).padStart(6, '0').match(/../g).map(v => parseInt(v, 16)); 
  return { r, g, b }; 
}
function toByteHex(num) {
  return Math.round(num).toString(16).padStart(2, '0'); 
}
* { position: relative; box-sizing: border-box; margin: 0; padding: 0; font: 1.125rem monospace; }
:invalid { border-color: #d44; color: #d44; }

div { width: 32ch; max-width: 100%; margin: 0.5em 0 0; padding: 0.5em; }
input { width: 9ch; padding: 0.2em 0.3em; border: 2px solid transparent; outline: 1px solid #fff; }
#result { display: flex; height: 2.5em; margin: 0; padding: 0; }
#result > span { flex: 1 1; padding: 0.5em; }

#result > span::before {
  content: '? ' attr(data-clr);
  display: inline;
  color: #fff;
  mix-blend-mode: difference;
}
#result > :last-child::before { content: 'Проверка'; }
#result > :last-child::after {
  content: '◯\a⇅\a◯';
  position: absolute;
  top: -0.1em; right: 0.3em;
  transform: translateY(-50%);
  font: 1.2em/1 monospace;
  white-space: pre;
  opacity: 0.3;
}

.has-error #result { visibility: hidden !important; }
<div>
  <input value="#dfe2d9" pattern="#[a-f\d]{6}">
  <div>
    <input value="#4493b1" pattern="#[a-f\d]{6}">
    <input value="0.7" type="number" min="0.01" max="1" step="0.01">
  </div>
  <div id="result">
    <span></span>
    <span></span>
  </div>
</div>

При итоговых значениях с некорректным форматом, калькулятор просто скрывает результат - то есть, он не исправляет ввод, не конвертирует из коротких трехсимвольных hex'ов и rgba/hsl, и не вычисляет мин. непрозрачность с которой получение смешанного цвета будет возможным.

→ Ссылка