How do i calculate four colors linear grdient? - linear-gradients

If I have four colours (A, B, C & D) on four points on a line and I want to fill with a gradient that blends nicely between the four colours how would I calculate the colour of the point E?
and A is starting point and D is ending point, before starting point and after ending point fill starting colour and end colour. inside line need to blend colour according to the distance and angle.
The closer E is to any of the other points, the strong that colour should affect the result.
I need like this one.
Any idea how to do that? Speed and simplicity is preferred to accuracy.

Well, in simple terms, take point ß that is halfway between A and B. Assuming the use of RGB colors, if A is red rgb(255, 0, 0) and B is yellow rgb(255, 255, 0), then ß's color will be halfway between these: rgb(255, 128, 0), that is, orange.
As you can see this can be calculated by using a weighted average per color channel - weighted by how close your point is to A and B.
Here's a code example you can run right here:
const slider = document.getElementById("range")
const between = document.getElementById("between")
slider.addEventListener("input", ev => {
const distFromA = ev.target.value
const G = distFromA / 3.92
// Not calculating R and B values, as these don't change in this specific example
const R = 255
const B = 0
between.style.background = `rgb(${R}, ${G}, ${B})`
})
#A { background: red; color: white; }
#B { background: yellow; }
#between { background: gainsboro; }
#between, #A, #B { display: inline-block; width: 50px; height: 50px; }
<aside id=A>A</aside>
<aside id=between>ß</aside>
<aside id=B>B</aside>
<nav><input type=range min=0 max=1000 id=range /></nav>
Do this for each pixel and you get a gradient 👍

Related

Explaining coordinate's calculation with map()

Could someone explain the meaning of this value/position: 300-400/2+10. I know it makes that the red circle won't go out of the square but I don't really understand the calculation..? Is there a page where I can read how it works because I personally would do it like this
float redCircle = map(mouseX,0,width,116,485);
circle(redCircle,map(mouseY,0,height,114,485),20);
with one number positions and not a calculation like in the code. I tried to understand it but I don't. I would really appreciate it if someone could explain the proceed.
void setup() {
size(600, 600);
surface.setTitle("Mapping");
surface.setLocation(CENTER, CENTER);
}
void draw() {
background(0);
stroke(255);
fill(255, 255, 255);//weißer Kreis
circle(mouseX, mouseY, 20);
mouseMoved();
text("Maus X/Y:"+mouseX+"/"+mouseY, 250, 300); //Text für weiße Position
fill(255, 0, 0); //Roter Kreis
float posFromMouseX = map(mouseX, 0, width, 300-400/2+10, 300-400/2+400-10);
float posFromMouseY = map(mouseY, 0, height, 300-400/2+10, 300-400/2+400-10);
ellipse(posFromMouseX, posFromMouseY, 20, 20);
text("map to: "+posFromMouseX+" / "+posFromMouseY, 255, 320); //Text für rote Position
// Transparentes Rechteck in der Mitte
noFill();
rect(300-400/2, 300-400/2, 400, 400);
}
map() will adjust the scale of a number accordingly to a range.
For an example, if you have these values:
MouseX: 200
width: 1000
You can easily calculate that, if the screen had a width of 2000 your mouse X position would need to be 400 to be proportional.
But this is an easy example. In the code you pasted here, the same thing is happening, but the coordinates compared are:
The whole window
The white rectangle
The map() function takes 5 args:
map(value, start1, stop1, start2, stop2)
value: float: the incoming value to be converted
start1: float: lower bound of the value's current range
stop1: float: upper bound of the value's current range
start2: float: lower bound of the value's target range
stop2: float: upper bound of the value's target range
So... you can totally write this line without the calculations:
float posFromMouseX = map(mouseX, 0, width, 110, 300-400/2+400-10);
// is the same thing than:
float posFromMouseX = map(mouseX, 0, width, 110, 490);
The probables reasons to write it that way are:
The author may not have wanted to do the simple math
The author may want to know where these numbers come from later (seeing how they were calculated would help on this front)
The author may want to change the hardcoded numbers for variables and make his white rectangle's size dynamic later
Hope it makes sense to you. Have fun!

Convert 24-bit color to 4-bit RGBI

I need to convert 24-bit colors to 4-bit RGBI (1 bit for Red, Green, Blue + Intensity).
Converting to 3-bit RGB is rather simple: set color bit if greater than 127, clear otherwise. However, there's only one intensity bit for all three channels, so what's the correct way to set it (if any)?
First I thought about dividing 8-bit channel to three parts like below:
if 0 <= color <= 85, then clear rgbi-color bit
if 86 <= color <= 170, then set rgbi-color bit
if 171 <= color <= 255, then set rgbi-color bit and intensity
But then I thought that probably the correct way would be to set intensity bit only if two of three channels are greater than 127. But in that case pure R, G, or B will not have intensity ever set (for example, in case of rbg(0,0,200)
Any advice is highly appreciated
A simple way to find the closest 4-bit RGBI approximation of a color is to consider the two possibilities for the intensity bit separately. That is to say, first find the closest RGB0 and RGB1 approximations for the color (which is easy to do, just by dividing each color axis at the appropriate point), and the determine which of these approximations is better.
Here's a simple C-ish pseudocode description of this algorithm:
// find the closest RGBx approximation of a 24-bit RGB color, for x = 0 or 1
function rgbx_approx(red, green, blue, x) {
threshold = (x + 1) * 255 / 3;
r = (red > threshold ? 1 : 0);
g = (green > threshold ? 1 : 0);
b = (blue > threshold ? 1 : 0);
return (r, g, b);
}
// convert a 4-bit RGBI color back to 24-bit RGB
function rgbi_to_rgb24(r, g, b, i) {
red = (2*r + i) * 255 / 3;
green = (2*g + i) * 255 / 3;
blue = (2*b + i) * 255 / 3;
return (red, green, blue);
}
// return the (squared) Euclidean distance between two RGB colors
function color_distance(red_a, green_a, blue_a, red_b, green_b, blue_b) {
d_red = red_a - red_b;
d_green = green_a - green_b;
d_blue = blue_a - blue_b;
return (d_red * d_red) + (d_green * d_green) + (d_blue * d_blue);
}
// find the closest 4-bit RGBI approximation (by Euclidean distance) to a 24-bit RGB color
function rgbi_approx(red, green, blue) {
// find best RGB0 and RGB1 approximations:
(r0, g0, b0) = rgbx_approx(red, green, blue, 0);
(r1, g1, b1) = rgbx_approx(red, green, blue, 1);
// convert them back to 24-bit RGB:
(red0, green0, blue0) = rgbi_to_rgb24(r0, g0, b0, 0);
(red1, green1, blue1) = rgbi_to_rgb24(r1, g1, b1, 1);
// return the color closer to the original:
d0 = color_distance(red, green, blue, red0, green0, blue0);
d1 = color_distance(red, green, blue, red1, green1, blue1);
if (d0 <= d1) return (r0, g0, b0, 0);
else return (r1, g1, b1, 1);
}
Alternatively, you could simply use any generic fixed-palette color quantization algorithm. This may yield better results if your actual color palette is not a pure evenly spaced RGBI palette like the code above assumes, but rather something like e.g. the CGA tweaked RGBI palette.

How to randomize between two set colors?

I want to know how to be able to have my program generate random color between two set colors and all inbetween the two. For example just the way that I would say:
fill(random(255),0,0));
in order to get a range reds.
I want to be able to choose two colors, let's say orange and blue, and have it generate colors from these two sets of colors. So for it to randomly generate a color from that shade of blue, any shade in between that and into a specific shade of orange.
How do I go about doing that?
Let's say you have 3 variables that hold the "base" color:
float baseR = 50;
float baseG = 100;
float baseB = 200;
You could then add a random number to those values to get a new shade "around" that color:
float shadeDistance = 10;
float r = baseR + random(-shadeDistance, shadeDistance);
float g = baseG + random(-shadeDistance, shadeDistance);
float b = baseB + random(-shadeDistance, shadeDistance);
fill(r, g, b);
Or if you have two colors that you want to blend, you can use the lerpColor() function:
stroke(255);
background(51);
color from = color(204, 102, 0);
color to = color(0, 102, 153);
color interA = lerpColor(from, to, .33);
color interB = lerpColor(from, to, .66);
fill(from);
rect(10, 20, 20, 60);
fill(interA);
rect(30, 20, 20, 60);
fill(interB);
rect(50, 20, 20, 60);
fill(to);
rect(70, 20, 20, 60);
(source: processing.org)

Color over color: how to get the resulting color?

I have the next task:
let's say, there are two colors: color1 and color2
color1 is semi-transparent (color2 maybe too)
I know ARGB values of color1 and color2
how to get the ARGB value of color which you get by overlaying color1 and color2 and vice versa?
Here is an image of what I am looking for:
And here is a code snippet (C#):
private Color getOverlapColor(Color frontColor, Color backColor)
{
//return...
}
The simplest way is to assume a linear scale.
int blend(int front, int back, int alpha)
=> back + (front - back) * alpha / 255;
And then:
Color getOverlapColor(Color front, Color back)
{
var r = blend(front.Red, back.Red, front.Alpha);
var g = blend(front.Green, back.Green, front.Alpha);
var b = blend(front.Blue, back.Blue, front.Alpha);
var a = unsure;
return new Color(r, g, b, a);
}
I'm unsure about how to calculate the resulting alpha:
if both front.Alpha and back.Alpha are 0, the resulting is also 0.
if front.Alpha is 0, the result is back.Alpha.
if front.Alpha is 255, the value of back.Alpha doesn't matter.
if front.Alpha and back.Alpha are both 50%, the result must be larger than 50%.
But I'm sure someone already figured out all of the above. Some SVG renderer, or GIMP, or some other image processing library should already have this code, carefully tested and proven in practice.

Can't get susy to use gutter in 'px' while in math:static mode

I want to create a fixed non-flexible very damn static grid of 1200px.
So I figured out, I need 90px for column-width, 12 columnts, 10px of gutter and 1200px of max-width.
Well.. the following are my settings and it gives me an error "invalid null opearation: 11 times null "
$susy: (
flow: ltr,
math: static,
output: float,
gutter-position: after,
container: auto,
container-position: center,
columns: 12,
gutters: 10px,
column-width: 90px,
global-box-sizing: content-box,
last-flow: to,
debug: (
image: show,
color: rgba(#66f, .25),
output: overlay,
toggle: top right,
),
use-custom: (
background-image: true,
background-options: false,
box-sizing: true,
clearfix: false,
rem: true,
)
);
style.scss>
#import "grids";
body{
#include container($susy);
max-width: 1200px;
border: solid thin red;
height:10px;
}
You need to specify gutters proportionally to your columns.
In this case:
gutters: 1/9,
The end result (being your columns 90px) would be gutters 10px wide. You can specify your gutters width in pixels by expressing it as a proportion.
As per the docs, you can speficy gutter width in pixels, by putting the column width as well. E.g.:
gutters: 10px/90px
Alhtough the result is exactly the same. And if you put in a value that doesn't match with your column width, you won't get the pixel width you say, but the appropriate fraction.
So having:
column-width: 100px,
gutters: 10px/50px,
will leave you with 20px wide gutters. Because of math. :)
Pen showing it working here.
And finally, your layout is 1190px wide and not 1200px because:
12 columns * 90px = 1080px
11 gutters * 10px = 110px.
1180px + 110px = 1190px.

Resources