color adjustment algorithm Got a problem I'm not sure how to approach.
I'm being given a string of text with indeterminate length, around typical &quot;body text&quot; size. The text is a solid color, and the background can be a solid OR a gradient of one or more colors of varying luminance. The goal is to make the text readable across the entire background while adjusting the color channels as little as possible.
How could I find the SMALLEST possible color adjustments to the foreground and/or background that would make the text readable, according to WCA standards or others?
The text has a luminance value $t_0$ and the background occupies a luminance interval $[L_0,H_0]$, $L_0 \le H_0$. I think what you want is to ensure a separation of at least some $s$ between them. There are many degrees of freedom here; one way to capture most of them is to decide beforehand on a way to penalise changes in these variables, as well as the penalty for changing the background interval width $H-L$, and then look for a solution that minimises this penalty cost.
We could use a linear cost model, where the absolute value of the change in each variable is penalised, but this has the disadvantage that optimal solutions are not always unique. So let's use a quadratic cost model (least squares), with penalty weights $c_t, c_L$ and $c_H$ for changes to the main variables, and also a weight $c_d$ for the penalty for changing $H-L$ (i.e., stretching or squashing the background luminance range). Then you want to choose $t, L$ and $H$ to minimise $$p = c_t(t-t_0)^2 + c_L(L-L_0)^2 + c_H(H-H_0)^2 + c_d(H-L-H_0+L_0)^2$$ such that $L \le H$ and either $t \ge H + s$ or $t \le L - s$. This gives a lot of flexibility: Set any of the $c$-parameters to zero to express that you don't care about changes in the corresponding quantity; set it extremely high to try hard to avoid changing it. A sensible first choice might be to set them all equal to 1, and if that yields solutions that &quot;look wrong&quot;, increase the weights of whichever values moved around too much.
If $t_0$ is already separated from $[L_0, H_0]$ by $s$, then leaving it unchanged is the optimal solution. Otherwise, intuitively, an optimal solution must have a tight gap, i.e., either $t = H+s$ or $t = L-s$. This can be solved by solving for each of the two cases separately and choosing the better one.
To solve for the first case, substitute $t = H+s$, find the partial derivatives of $p$ w.r.t. the two remaining variables $H$ and $L$, set these to zero:
$$\begin{align}
p &amp; = c_t(H+s-t_0)^2 + c_L(L-L_0)^2 + c_H(H-H_0)^2 + c_d(H-L-H_0+L_0)^2\\
\frac{\partial p}{\partial L} &amp; = 2c_L(L-L_0) + 2c_d(H-L-H_0+L_0) = 0\\
\frac{\partial p}{\partial H} &amp; = 2c_t(H+s-t_0) + 2c_H(H-H_0) + 2c_d(H-L-H_0+L_0) = 0
\end{align}$$, and solve the resulting set of simultaneous equations for these variables to find the minimum:
$$\begin{align}
L &amp; = \frac{c_LL_0 + c_d(H_0-H-L_0)}{c_L - c_d}\\
H &amp; = \frac{c_t(t_0-s) + c_HH_0 + c_d(L+H_0-L_0)}{c_t + c_H + c_d}\\
&amp; = \frac{c_t(t_0-s) + c_HH_0 + c_d(\frac{c_LL_0 + c_d(H_0-H-L_0)}{c_L - c_d}+H_0-L_0)}{c_t + c_H + c_d}
\end{align}$$
Having computed the optimal value of $H$, you can substitute this back into the expressions for $L$ and $t$, and then calculate $p$ for this case. The derivation for the $t=L-s$ case is very similar. Finally, pick whichever gives the lower $p$ value.