## Ranginak: Python Tri-Shade Color Generator

Color be a harsh mistress.Aristotle developed the first color theory. He believed that colors were celestial rays sent by Gods for humans to perceive them based on four elements of fire, earth, air and water.

Two hundred years before Newton cracked the color spectrum, artist and heartthrob Leonardo of the planet Vinci theorized that whilst philosophers perceive white as the “receiver” and black as the “absence of color”, both are important. He later developed his color theory based on six colors that you see in the image above. Imagine colors are Boolean operators, white is True, black is False. If True is 1 and False is 0, blue is 0.5. That’s very close to how we perceive colors today.

Meanwhile, Persian painters who came before Da Vinci and Newton gave color theory an existentialist twist. Green was the color of Nobility. Blue was color of paradise. Red was color of passion. And so on.

In 1666, Sir Isaac Newton, using two prisms, generated what we today know as the White Light Color Spectrum.

Light is not particle. It’s not wave either. Light is made up of photons. Photons carry energy, and a prism cracks this energy and splits it into seven colors. That’s just White Light. If we heat up Hydrogen until it emits light, if we split up this light, it will create a 4-color spectrum called Emission Spectrum.

In real life, all the colors in existence are made up of 3 color: Red, Green, Yellow. Imagine we have a base color, and we want to increase the red-green-yellow value incrementally until we get a shade. But if we increase the value of all three, we’ll get a random shade of color. But if we increase it based on a state, if we treat this as a 3! state machine, we’ll get six conditions. Depending on the condition that we want a red-green shade, we increase red and green values without touching yellow. And so on.

In computers, yellow is blue. But that’s just one of the colorspaces we use in computers. We have CMYK for print. HSL, HSV, YIQ and so on. In this program, we’ll use HSV and RGB. You’ll see.

### Complementary Colors

Newton also discovered that if we create a circular spectrum, the opposite colors complement each other. Boutet created the following color wheel based on this discovery:

I talked about RGB complementary colors in this post. So I’ll cut it short. Just know that in this program, once we generate the base color, we invert the color and generate an shade of six colors based on the opposite color. You’ll see. Let’s continue.

### Ranginak Color Generator

Ranginak (meaning Small Color Shade in Persian) is a Python script that generates three six-colored shades of color and 3 original colors.

The source can be found here, also, you can learn about it in this post.

The first shade is used for background. The second shade is using for mid-ground. The third shade, which is the most saturated, is used for foreground.

How does it work? Let’s start. This code requires Gizeh, which you can install by:

pip install gizeh


It also uses colorsys, which is a built-in Python library. Colorsys converts between color systems. We’ll only use it once in this code. We also make use of random and time.

import gizeh as gz
import colorsys
import random
import time


We then write our first function.

def generate_color(s_min, s_max):
random.seed(time.time())
h = random.randint(0, 100) / 100
random.seed(time.time())
v = random.randint(0, 100) / 100
random.seed(time.time())
s = random.randint(s_min, s_max) / 100
color = colorsys.hsv_to_rgb(h, s, v)

return color


s_min and s_max are minimum and maximum saturation, respectively. Then we’ll fix the seed so each time we’ll call the function, randint() will generate a fixed random number. Otherwise it’ll go haywire and generate random colors. You’ll see why seed() is important in the next function. It then puts the converts the HSV value to RGB using colorsys and puts them in a tuple and returns them.

Which we’ll write now:

def generate_color_master():
color_master = []

color_master.append(generate_color(1, 33))
color_master.append(generate_color(33, 66))
color_master.append(generate_color(66, 100))

return color_master


color_master[] is a list that contains three color tuples. One for background, one for mid-ground, one for foreground. We change s_min and s_max based on our desire to create a less saturated color for the background, and a more saturated color for the mid-ground and foreground.

def invert():
inverted = []
colors = generate_color_master()

for color_tuple in colors:
r = 1 - color_tuple[0]
g = 1  - color_tuple[1]
b = 1 - color_tuple[2]

inverted.append((r, g, b))

return inverted


Our next functions creates the complementary color based on the main colors, and returns them in a list accordingly. Now, our main function.

def generate_shade_color(r, g, b, color_tuple):
new_color = 0

addition_r = (random.randint(1, random.randint(5, 9)) / 10) * r
addition_g = (random.randint(1, random.randint(5, 9)) / 10) * g
addition_b = (random.randint(1, random.randint(5, 9)) / 10) * b

new_r = 0
new_g = 0
new_b = 0

if r == 0:
new_r = color_tuple[0] * 255
new_g = color_tuple[1] + addition_g * 255
new_b = color_tuple[2] + addition_b * 255
elif g == 0:
new_g = color_tuple[1] * 255
new_r = color_tuple[0] + addition_r * 255
new_b = color_tuple[2] + addition_b * 255
elif b == 0:
new_b = color_tuple[2] * 255
new_g = color_tuple[1] + addition_g * 255
new_r = color_tuple[0] + addition_r * 255

if int(new_r) <= 255 and int(new_g) <= 255 and int(new_g <= 255):
new_color = (new_r / 255, new_g / 255, new_b / 255)
elif int(new_r) > 255:
new_color = (1.00, new_g / 255, new_b / 255)
elif int(new_g) > 255:
new_color = (new_r / 255, 1.00, new_b / 255)
elif (new_b) > 255:
new_color = (new_r / 255, new_g / 255 , 1.00)

return new_color


Because it might get complicated, let me explain what it does in the list format:

1- r, g, and b are binary coefficients. If either is 0, it won’t change the color in our shade. If we want to disable, let’s say, r in our shade, we’ll pass r as 0 and the other two as 1. And so on. Color_tuple is the main color we wish to create a shade from.

2- addition_[channel] are random numbers between 0.1 and 0.9 that we add to the main color’s respective channel in order to create an increasing shade. Note that we multiply it by the coefficient so it’ll be 0 if the coefficient is 0.

3- We multiply the color by 255 so we can have an easier time checking if the color is out of bounds.

4- We check if the color is out of bounds. If it is, we make it 1, the maximum color.

5- We divide the color by 255 again and return the new color.

def generate_shade(r, g, b):
colors = invert()
bg = []
mg = []
fg = []

for i in range(6):

return [bg, mg, fg]


In this function, we create six colors for each layer.

Now, we get to the drawing part using Gizeh.

rect_w = 500
rect_h = 500

def generate_surface():
surface = gz.Surface(width=int(rect_w * 7), height=int(rect_h * 3))



We create a 3500*1500 window.

def draw_sqr(color, x, y):
sqr = gz.square(l=500, fill=color, xy=(x, y))

r = int(color[0] * 255)
g = int(color[1] * 255)
b = int(color[2] * 255)
string = "(" + str(r) + ", " + str(g) + ", " + str(b) + ")"
text2 = gz.text(string, fontfamily="Tahoma", fontsize=24, fill=(0, 0, 0), xy=(x + 20, y + 20))
text3 = gz.text(string, fontfamily="Tahoma", fontsize=23, fill=(1, 1, 1), xy=(x + 20, y + 20))

return gz.Group([sqr, text2, text3])


This function generates a square of the color color, and a text showing the colros RGB value.

Now, the main function.

def main_func(r, g, b):
original_color = generate_color_master()
items = []

bg = colors[0]
mg = colors[1]
fg = colors[2]

items.append(draw_sqr(bg[0], 250, 250))
items.append(draw_sqr(bg[1], 750, 250))
items.append(draw_sqr(bg[2], 750 + 500, 250))
items.append(draw_sqr(bg[3], 750 + 1000, 250))
items.append(draw_sqr(bg[4], 750 + 1500, 250))
items.append(draw_sqr(bg[5], 750 + 2000, 250))
items.append(draw_sqr(original_color[0], 750 + 2500, 250))

items.append(draw_sqr(mg[0], 250, 250 + 500))
items.append(draw_sqr(mg[1], 750, 250 + 500))
items.append(draw_sqr(mg[2], 750 + 500, 250 + 500))
items.append(draw_sqr(mg[3], 750 + 1000, 250 + 500))
items.append(draw_sqr(mg[4], 750 + 1500, 250 + 500))
items.append(draw_sqr(mg[5], 750 + 2000, 250 + 500))
items.append(draw_sqr(original_color[1], 750 + 2500, 250 + 500))

items.append(draw_sqr(fg[0], 250, 250 + 1000))
items.append(draw_sqr(fg[1], 750, 250 + 1000))
items.append(draw_sqr(fg[2], 750 + 500, 250 + 1000))
items.append(draw_sqr(fg[3], 750 + 1000, 250 + 1000))
items.append(draw_sqr(fg[4], 750 + 1500, 250 + 1000))
items.append(draw_sqr(fg[5], 750 + 2000, 250 + 1000))
items.append(draw_sqr(original_color[2], 750 + 2500, 250 + 1000))

return gz.Group(items)


First, we prepare our colors. Then, draw 21 square of different colors. Don’t ask why I didn’t use a loop. It brings back bad, bad memories. We return everything as a Gizeh group. Now, the near the end. We don’t want to make a function anymore, just a top-level code:

if __name__ == "__main__":
for i in range(12):
group = main_func(0, 1, 1)
surface = generate_surface()
group.draw(surface)


This code will create 12 images with a Green-Blue shade. Change g or b to 0 and change r to 1 to experiment with it. Don’t generate lots of images, just change the name of the image if you want more.

Well, that’s it. I hope you enjoyed it. Remember, the code can be found here. For now, hope you’ll have colorful dreams!

## Creating a Procedural Texture Using Gizeh

Gizeh is a small library for Python which you can install using pip. It doesn’t have any official documentation, so you have to suffice to the small documentation on it’s Github Page. Before starting this tutorial, read the README file carefully, as you may confused later on. Now, let’s see what we want to create. A procedural texture of a textile. Maybe a denim, maybe another pattern. I don’t know. Right now we can’t afford to be picky. The output is entirely randomized, and if you aren’t happy with the texture, you can just run the code again.

Not happy? Let’s run the code again (I’m using Pycharm to write and run this code, teaching you about setting up Python and a good IDE is beyond the scope of this tutorial):

But how? Simple:

1- A blue background.

2- 200 different groups of 50 circles that increase in alpha as they decrease in radius. colors are from rgb(200, 200, 200) to rgb(250, 250, 250).

3- Vertical and horizontal lines spaced together based on a coefficient of 0.01 and tilted by a random number between 1 and 8.

That’s it!

Let’s start. First, let’s setup a window, and a surface:

import gizeh as gz
import random

w = 640
h = 480

surface = gz.Surface(width=w, height=h, bg_color=(21/255, 96/255,189/255))


You can change w and h to change the height and the width. Now, let’s generate our radial gradient:

def circle_generator(x, y, r, c):
i = r
a = 0
while i > 0:
circle = gz.circle(r = i, xy=[x, y], fill=(c/255, c/255, c/255, a*0.70))
i -= 1
a += 1/2000

circle.draw(surface)


Besides the location of the circles, the function accepts two other parameters: the radius, which decreases in each while loop, and the color, which we divide by 255 since in Gizeh, rgb is between 0 and 1. We increase the alpha (a) by adding 1/2000 to it in each iteration.  At the end, we draw the circle.

Now, let’s make a line generator:

def generate_lines(x1, y1, x2, y2, s, a):
line = gz.polyline(points=[(x1, y1), (x1, y1), (x2, y2), (x2, y2)], stroke_width=s,
stroke=(0, 0, 0, a/255), fill=(0, 0, 0, a/255))

line.draw(surface)


This one just generates one line, we’re actually drawing a polygon were its origin is (x1, y1) and ends at (x2, y2). If we add a randomized number to the second coordinates, we can have a mangled shape, which will come to use if we want to generate some other pattern. s is stroke, and a is alpha. We set the fill to black, but it’s useless, as we don’t have a fill.

for i in range(200):
x = random.randint(0, w)
y = random.randint(0, h)
r = random.randint(20, 100)
c = random.randint(200, 255)
circle_generator(x, y, r, c)



we choose entirely random locations, a radius between 20 and 100, and a color between very light gray and white. Then we call the function.

Now, the lines!

s = random.randint(1, 3)
a = random.randint(50, 200)
coeff = 0.01

for i in range(w):
tilt = random.randint(1, 8)
generate_lines(w * (i * coeff), 0, w * (i * coeff) + tilt, h, s, a)

for i in range(h):
tilt = random.randint(1, 8)
generate_lines(0, h * (i * coeff), w, h  * (i * coeff) + tilt, s, a)


First, we choose a random opacity. and a random stroke. Then we set the coefficient to 0.01. You can experience with other coefficient values, but be warned that if you randomize it, it sometimes may take you 10 runs to get a right pattern. We then create a new random number in each iteration to use it as a tilt. We then generate the horizontal lines w times and vertical lines h times.

At the end, we save the file as a PNG. This is why you should use PyCharm, it shows the picture and updates it in a different window. Other IDEs don’t do that.

surface.write_to_png("only_bg.png")


Well, that’s it! You can experiment with it, use diagonal lines, creates woven textiles, et al. Hope you enjoyed it.

## Generating Tons of Complementary Colors with Processing

Well, this blog should be about Processing! But no, I’m just practicing game asset creation, as I wish to become a master of all trades (and jack of none). Therefore, I’m relaxing my programming muscles a bit with Processing while I’m doing graphics. And maybe, someday, music? I dunno.

So we’ve all heard of the RGB colorspace. Back in the 90s, Apple and Microsoft created this colorspace because HSL wasn’t enough for the creative programming market. Displays were becoming a lot more sophisticated and less happened in monochrome and teletypes. So sRGB was born.

RGB has three to four channels. Red, Green, Blue nad Alpha. Each have a value between 0 and 255. The higher we go, the lighter we get. There are two ways of implementing an RGB color, HEX and Decimal. For HEX display, each channel is converted to its hexadecimal notation and then put together in succession, such as (255, 255, 255) -> #FFFFFF.

In sRGB color wheel, each opposite color go together like America and apple pie. Let me show you what I mean:

In fact, this is true about all colorspaces such as HSL and HSV and CMYK, and in fact, it’s not a new concept: in 1810, painters were already using complementary colors using the traditional RGY color spectrum (in real life, colors are made up of red, green and yellow, not red, green and blue!?).

So, is there an algorithm to generate a complementary color? Of course. Imagine each color is a angle in the unit circle of the color wheel. Imagine FF is 2PI and the color we want is PI/4. So to calculate the opposite angle, we subtract 2PI (360d) from PI/4. As easy as that -> In order to generate the opposing color, we must subtract 255 from each channel.

So how can Processing help us choose the appropriate complementary color? By generating HUNDREDS and THOUSAND of complementary colors in a jiff. Let’s see how it works:

void setup() {
size(500, 500);

}

void draw() {
float r = random(255);
float g = random(255);
float b = random(255);
color bgc = color(r, g, b);

background(bgc);
textSize(16);
text("Background: ", 20, height * 0.10);
text(r, width * 0.5, 20);
text(g, width * 0.5, 50);
text(b, width * 0.5, 80);

float comp_r = 255 - r;
float comp_g = 255 - g;
float comp_b = 255 - b;
color rc = color(comp_r, comp_g, comp_b);

fill(rc);
rect(width * 0.25, height * 0.25, 200, 200);

fill(255);
textSize(16);
text("Complement: ", 20, height * 0.90);
text(r, width * 0.5, 420);
text(g, width * 0.5, 450);
text(b, width * 0.5, 480);

saveFrame("complementary_colors#####.png");

}


In each draw() loop, we generate r, g, and b. Then we display it in the background. Then we display the channel values for reference. Then we generate the complementary color, and display it in a rectangle. You can do it with a circle too. Depends on your taste.

Then, we save it in the folder you’ve saved the .pde file using saveFrame(). That’s it!

Well, hope you’ve enjoyed this tutorial. Next up: How pixel art with Photshop.

## Pixel Perfect Crosshair with Processing

Have you ever wondered how is it possible to create a pixel-perfect crosshair? Well, wonder no more. Processing is here.

Well, no time to lose. Let us start off by writing the setup() function.

void setup(){
size(500, 500);
noLoop();
}


It simply creates a 500*500 image, and sets the loop to noLoop, so draw() function won’t go on indefinitely. Now, the draw function. Before that, save the code. So the image will be saved in the same folder as your code. Alright, let’s have a looksie.

void draw(){
noFill();
strokeWeight(10);
arc(width / 2, height / 2, 300, 300, QUARTER_PI, PI);
strokeWeight(8);
arc(width / 2, height / 2, 250, 250, QUARTER_PI, PI);
strokeWeight(6);
arc(width / 2, height / 2, 200, 200, 0, QUARTER_PI);
strokeWeight(4);
arc(width / 2, height / 2, 200, 200, 0, 3);
strokeWeight(6);
arc(width / 2, height / 2, 250, 250, PI, TWO_PI);
fill(0);
ellipse(width / 2, height / 2, 30, 30);
strokeWeight(12);
line(width * 0.25, height * 0.76, width / 2, height / 2);
line(width * 0.75, height * 0.75, width / 2, height / 2);
line(width * 0.25, height * 0.26, width / 2, height / 2);
line(width * 0.75, height * 0.25, width / 2, height / 2);

saveFrame("crosshair.png");
}


noFill() will disable the color fill, so we’ll only have strokes. strokeWeight() which we use religiously sets the size of the stroke in pixels. And arc() creates an arc. This is the main part of this short tutorial, the arc function goes if defined as:

arc(postion_x, position_x, radius_x, radius_y, start_angle, end_angle);


start_angle and end_angle are in Radians. You can use QUARTER_PI (45d), HALF_PI (perpendicular), PI (180d), and PI_TWO (circular) like:

You can add these together to create PI/3 (35d) and 2*PI/3 (275d).

At the end, we add four lines like so:

line(x1, y1, x2, y2);


We use math to access quarter and a third of the screen. All x2 and y2s are the center of the screen.

At the end, we save the frame.

### Coming up next…

I have prepared a Processing and Illustrator tutorial for creating two types of planets. Stay tuned!

## Generating Color Scheme with Processing (Part 1)

Let me christen this blog through a Processing tutorial.

I hereby promise to fill this blog with game assets that I myself have created, graphics-related tutorials such as After Effects, Cinema 4D and Blender plugin development tutorials, Processing tutorials and scripts, and of course, game development tutorials! I don’t know much, but I’ll share what I know. And that’s how you get into heaven.

Chubak Bidpaa

And now, break the champagne bottle!

Anyways, in this tutorial, I want to teach you how to find out how a color matches the theme of your game wonderfully by using scripting language of Processing. Processing is a Java library that helps with aides artists and programmers in creating artwork. You can download it from here.

### The Raw Power of Processing

Processign is a very powerful language, and it’s very useful. Processing is a Java library, so it’s very similar to  its container language. It has OOP support, and each code has a setup() and draw() method which cater to initiation and the main loop, respectively.

Let’s say your level has a red theme, and by red theme I mean the overall feel of the level. And out want to know what colors beset our main color. So let’s start by setting up a window with a red background:

void setup() {
size(400, 400);
color c = color(255, 0, 0);
background(c);
noLoop();
}


This will create a 400*400 window with a red background. noLoop() later comes into play, when we write a draw() function, it’ll make it so that the draw() does not loop.

Now, to write the draw function. It’ll be much more complicated, by a small margin.

void draw(){

float red = random(255);
float green = random(255);
float blue = random(255);
color random_color = color(red, green, blue);

textSize(16);
text(red, 10, 350);
text(green, 10, 370);
text(blue, 10, 390);

fill(random_color);
rect(100, 100, 200, 200);

}


First, we create three floating point integers that hold a random number between 0 and 255. Then we create a color object with it. Then, we print those numbers for later reference, as there must be a way to assess what RGB values makes up our new color. We then change the color to the new color and draw a rectangle in the middle of the screen (origin point is top-left).

As we see, the green rectangle does not elate the red color. So we discard it and generate a new color.

As we can clearly see, purple does not go with red either. We’re not lucky today, are we?

Well, there’s no need to beat around the bush. Let’s make a hundred million colors!

In order to do so, add this line:

saveFrame("color_swatch########.png") //org jpg


At the end of the draw() function. Also, remove the noLoop() line from the setup() function. But before running the code, save the file in a separate folder. Once you run the code, it’ll save images in a folder where you’ve saved the file. Peruse through them, and maybe you’ll find your swatch!

### In Part 2…

In Part 2 of this tutorial, I’ll teach you a bit about color theory and how to generate opposing colors.

For now, Semper Fi!