rgbx version 1.0 - How It Works





Multiple-run output of rgbscript, processed with some beginner level tinkering in Inkscape, created for no reason other than fun and marvel.






NOTE: this is the documentation for rgbx's direct predecessor, rgbscript version 0.7. Nothing of any significance has changed in the main code found in rgbx-1.0.py. Apart from a few configuration variable names (exceedpageborders -> spillover; objectstroke -> objectstrokecolor) this document still fully applies. Support for dynamin page sizing (pagewidth, pageheight) has been dropped. The user is supposed to create a page of the appropriate dimensions before running rgbx, which was the recommended practice all along. The major difference with rgbscript is that a GUI script (rgbx-gui-1.0.py) has been added, which takes care of maintaining rgbx's configuration file. This file has completely disappeared from the user's view. Maintaining it for every run was enormously cumbersome.

Pending a proper update of this doc, it works by and large as follows:

- open Inkscape and within it the Simple Inkscape Scripting extension

Exyensions -> Render -> Simple Inkscape Scripting

- fire up the gui from a terminal window:

./rgbx-gui-1.0.py &

- the terminal window itself can now be killed
- drag the rgbx gui onto the Inkscape window if necessary
- tinker away at its controls
- press the Write button; this will silently cause the rgbx configuration file to be written
- hit Apply on the SIS window and things should happen on the screen

It is far from perfect, but for now it should be a lot more fun and convenience than commenting and uncommenting entries in a text file.

The RGBX Configuration Editor window is configured to always stay on top. Even though this is in itself bad window etiquette, watching the window vanish into the background every time you activate the Inkscape window, for example for exporting the output, is incredibly annoying. The window can of course be minimized or closed if necessary.


Finding the SIS configuration directory


Finding the SIS configuration directory is easy. Create a text file with the following content:

import os
cwd = os.getcwd()
print('Running from %s' % cwd)

Name it something like 'sisconfigdir.py' (its name is in fact irrelevant) and load it as the Python file in the SIS extension window. Example output:

Running from /home/me/.config/inkscape/extensions/SimpInkScr

If the path displayed happens to be any other than ~/.config/inkscape/extensions/SimpInkScr, set the actual path in a file named rgbx-1.0.cf, located in the directory fom which rgbscipt-gui is run:

SISCONFIGDIR = '/path/to/sisconfigdir'

This will allow rgbx-gui to write the configuration file for rgbx (rgbx-config.txt) to the correct location.


The original documentation for rgbscript version 0.7 follows.




This is the documentation for rgbscript 0.7, which started out an experiment with RGB color rendering using simple artithmetic. Part I describes the the script's operation, in which hexadecimal RGB codes such as found in HTML source code play a key role. For those who are unfamiliar with RGB and/or hexadecimal numbering, an ultra-quick introduction to these topics is provided in part II.


CONTENTS

1. Introduction
1.1 Simple Inkscape Scripting
1.2 Page dimensions
1.3 The configuration file
1.4 Hex numbers in the rgbscript documentation and configuration
1.5 Errors and warnings
2. Page settings
3. Field settings
4. Color sets
4.1 Color set 'darkrgb'
4.2 Color set 'darkmyc'
4.3 Color set 'lightrgb'
4.4 Color set 'plainrgb'
4.5 Color set 'hybrid'
4.6 Color set 'web'
4.7 Color set 'rotate'
4.8 user-supplied color lists
5. BONUS CODE: circles and triangles

Appendix A. RGB
Appendix B. Hex RGB


1. Introduction


Rgbscript was born out of curiosity: 'What would happen if.. ?' It renders sequences of colors based on simple arithmetic performed on the RGB bytes which make up a color displayed on a screen. It displays these primarily in the form of a sequence of horizontal colored fields printed on an Inkscape page. Each field has a distinct color which will differ to some degree from the previous and next based on some calculated and methodical adjustment of the RGB values. Depending in the number and height of these fields the output will vary from sequences of horizontal colored bands to smooth gradients, with an almost imperceptible flow from one color to another.

Rgbscript is a piece of software of questionable application, the kind that struggles to find a purpose in life. It literally makes various issues concerning RGB color rendering visible, and as such could play a role in education. One of rgbscript's neatest features is that it can produce gradients free from banding which are beyond the capability of most graphics editors. This feature deserves further exploitation in future versions, and might perhaps fork off a dedicated project of its own. Rgbscript can produce neat color spectra. Work on refining these is ongoing. The script is quite flexible with regard to ways in which the output is presented. As demonstrated in the BONUS CODE section, it can generate color lists which may be used for purposes other than just printing sequences of colored fields. One nice feature of such lists is that the colors are somehow (arithmetically) related, and as such can be considered palettes or swatches in their own right.

As for the code itself, it is safe to say that it has reached a high level of maturity. At the same time it is by nature quite complex, and incredibly difficult to maintain. Even the slightest change can cause the script to stop rendering sensible output. Apart from that, not much should go wrong. The script doesn't write or alter anything on disk.


1.1 Simple Inkscape Scripting


The rgbscript code is processed by the Simple Inkscape Scripting extension, which is run from inside an Inkscape window. Information about Simple Inkscape Scripting can be found at:


https://inkscape.org/~pakin/%E2%98%85simple-inkscape-scripting

https://github.com/spakin/SimpInkScr


After installing the extension, SIS should be found in the menu as:


Extensions -> Render -> Simple Inkscape Scriping...


This should bring up a small dialog box. Experience has it that if the extension doesn't even show up in the menu, an upgrade to Inkscape 1.0 or higher might be required. The latest Inkscape version is available from Inkscape's own pages:


https://inkscape.org


The script itself has no prescribed location on the system, nor does it have to be executable. In order to run the code, just select its pathname from the 'Python file' field in the SIS dialog. Most of rgbscript is written in Python, but with SIS-specific statements taking care of a lot of the graphical rendering. For that reason it cannot be run directly through the Python interpreter.

As some of the graphics found on this page may already suggest, no advanced knowledge of Inkscape or higher editing skills are required for running rgbscript in SIS. Rgbscript can be run using the most basic of actions and commands. The following have proven especially useful.


Creating a template SVG

If you are planning to work with fixed page dimensions, creating a template SVG is very much worth the effort:

- open a new Inkscape page
- create a page of the required dimensions
- set the appropriate units (see the 'Page dimensions' section below)
- set any other parameters you wish to save as defaults
- save the page as an SVG (Ctrl+S)

This way, next time you will have a page with the right settings readily available. All you need to do is to open the saved page.


Selecting layer contents

Rgbscript creates Inkscape layers. All fields or other objects from a single run are placed on the same layer. If a background is reqired, it will be printed on a layer of its own. If there are multiple layers present, then attepting to select the objects from one layer by drawing a selection rectangle around them will automatically drag in all objects on all other layers as well. Selecting objects from a single layer only can be done by performing the following steps:

- open the Layers menu (Shift+Ctrl+L)
- click on the name the layer to be selected
- click somewhere on the page in order to bring back the focus
- hit Ctrl+A

This will select all objects on the layer in question only. Any actions performed, from moving the objects to exporting a PNG, will apply to this layer only. Rgbscript can produce layers containing lots of transparency. Such layers can be stacked on top of each other by running rgbscript more than once against the same page. These layers can then be selected and edited individually, as has been done with the picture in top of this page. When working with rgbscript this way, Ctrl+A is your friend. And of course, individual objects (fields) can be selected and edited as well.

Inkscape's layers are naturally somewhat alien to its overall concept. They aren't necessarily the most bug-free part of Inkscape. Expect some strange behavior at times. For rgbscript in particular they are nonetheless extremely useful.


1.2 Page dimensions


Simple Inkscape Scripting, and therefore rgbscript as well, runs against an existing Inkscape page. Page height and width can be specified in the configuration file, but with success by far not guaranteed. A far better practice is to create an Inkscape page with the desired page dimensions and document settings in advance. The most important settings are:


Shift+Ctrl+D Document Properties -> Display units


.. and, if the image is to be exported to a PNG file:


Shift+Ctrl+E Export PNG Image -> Units


While the second is useful for gaining control over print output, the first is citical. If it is set to 'px', the script should automatically retrieve the correct page dimensions from Inkscape.


1.3 The configuration file


Rgbscript is run by manipulating settings in the configuration file rgbscript.cf. This file is expected to be present in the SIS configuration directory, which on Linux systems would be something like:


.config/inkscape/extensions/SimpInkScr


Perhaps the safest and most convient way to install the configuration file is to copy it to a location which is within easy reach, and to create a symbolic link from the configuration directory. Alternatively, an absolute path can be set in top of the script itself, for example:


configfile = '/home/me/rgbscript.cf'


1.4 Hex numbers in the rgbscript documentation and configuration


Hexadecimal values supplied in the rgbscript configuration file require a '0x' prefix, for example:


colorstep = 0x11


In these cases the corresponding decimal value is merrily accepted as well:


colorstep = 17


.. will produce the same result.

String literals require (single or double) quotes, just as they would in a Python script. This applies to the boolean values 'yes' and 'no' as well.

Rgbscript is very much hex-oriented, that is to say both in the code as well as in the documentation hexadecimal numbers play a central role. These take on a form of 'RRGGBB', for example 'ff0099'. Decimal RGB color strings such as (123, 45, 237) are not (yet) supported.

These so-called hex codes or hex numbers (in a strict sense hex color codes aren't numbers) are the natural format in which sotware processes RGB color codes. Even though they tend to intimidate humans, with the right approach, as explained in the 'Reading RGB in hex and why' section of part II, they turn out to be far more manageable than may seem, and with some practice are in fact much easier to interpret. Hex numbers are typically listed without the 0x prefix in the documentation. The ones to remember in this context are:


33 66 99 cc ff


These happen to be the values used generate the so-called 'web-safe colors' of ancient times. The hex number 33 is rgbscript's default color step value, the value which determines the transition from one color to the next. This value typically yields five corresponding fields being printed for each of the three R, G and B basic colors.

The reason for leaving out the '0x' prefix in most of the examples is that it tends to intimidate people even more than the hex number does iself. Wherever it is clear from the context that a hex number is being referred to, as with for example 'ff6699', it isn't needed either. In cases where it isn't, or where there is room for confusion, a hex value may be referred to as 'hex NN', for example 'hex 99', which happens to correspond with decimal 153(!).

In any case:

The 0x prefix must be supplied in the configuration file wherever a hex number is expected.

The web prefix '#', used to indicate that a hex number will follow, as found in HTML sources as well as in countless online examples, plays no role whatsoever in the configuration.

1.5 Errors and warnings


Rgbscript produces no error or warning mesages of its own whatsoever. Division by zero and type errors may be thrown by the SIS interpreter. These may indicate errors in the configuration. Alternatively, either SIS or Inkscape may be throwing errors where there aren't any. A typical case is a 'list index out or range' error. If after checking the configuration the source of error still isn't clear, it is worth closing and relaunching Inkscape. In many cases the error will have simply gone.


2. Page settings


Rgbscript is primarily page-oriented, meaning the entire output us usually made to fit onto the Inkscape page. A page margin can be set with pagemargin. The margin will run around the page at a fixed width. A page margin is no more than an area of transparency around the output. Only a background or the output from a previous run will give it color. If showbackground is set to 'yes' a background layer will be included below the fields layer. Its color can be set with backgroundcolor. The background is made to fit the page. Apart from a page margin, a page background is particularly useful in combination with field separation and field skipping, described below, which will render part of the output transparent.






Image 1a: Background: color set 'plainrgb', color step 5, invertcolors, fixstriping. Foreground: color set 'web', color step 5, fixstriping, page margin 40px on a 1000x01000px page.



Image 1b: Same, but now the foreground has a field separation of 12px and a 20px margin.



Image 1c: Color set 'web', color step 0x33, field separation 12px against a 0xfefecc cream background.



Image 1d: Color set 'web', color step 0x55, field separation 20px with a 20px margin against a 0x1c6b78 teal background.




Settings


pagemargin = N margin size in pixels
showbackground = 'yes'|'no' no background layer is included by default
backgroundcolor = 0xfefecc the default color is white (ffffff)




3. Field settings


The number of fields to be printed and their size depends primarily on the number of steps required to fill a 'field set' (for lack of a better name), . This number of steps depends on the value of the colorstep setting (or, in the case of color rotation, on that of huerotation). High values will poduce a small number of large steps, which will result in a small number of wide fields being printed. Low values will yield a high number of narrow fields which may be almost indistinguishable, resulting in a smooth flow from one color into another. This produces gradients which are entirely free from the dreaded banding encountered in most graphics software. Stripes may occur instead, which can be suppressed with fixstriping, described below.






Image 2a: Color set 'darkmyc' with the default colors step of 0x33: three distinct field sets of five fields each.



Image 2b: Same with a color step of 0x11.



Image 2c: Same with a color step of 1 and significant striping (open in new page/tab for a better view; see Striping below).



Image 2d: Same again with a color step of 1 and striping fixed (see Striping below).




Normally rgbscript wiill try and squeeze the entire output onto the supplied Inkscape page, regardless of the number of fields to be printed. These will be automatically resized to fit the page. The standard approach is to complete a single run for all three field sets (R, G, B) to be printed. This can be overridden by manipulating fieldnum and/or fieldheight in the configuration file.

With fieldnum set to N, exactly N fields will be printed. These are aligned to fit the entire page, unless a value is supplied with fieldsize. In that case N fields of the specified size are printed. This may cause either the page to not be filled entirely, or the output to 'walk off the page'. This way, with low colorstep values, truly gigantic spectra (or quasi-spectra) can be printed. By forcing Inkscape to export a specific part if the output (normally the page size), this allows for easy creation of crystal clear gradients. Supplying a fieldheight alone, without setting fieldnum, will result in the default number of fields being printed with the specified height. This again may cause the output to be smaller or bigger than the actual page size. A field separator specified with fieldsep will not cause the field height to be recalculated and will therefore increase the output size. Field separation GREATLY enhances the aesthetics of the output. Not even a margin set with pagemargin will trigger a recalculation of the field height, although it will obviously affect the width.






Image 3a: Color set 'plainrgb' with fieldnum = 15: one complete iteration through all three R, G and B colors.



Image 3b: Same with fieldnum = 45: three full iterations.



Image 3c: With fieldnum = 600.



Image 3d: The same as image 3a, but with a 12 pixel field separation and a 20 pixel margin against a black background.









Image 4: Color set 'web': a full spectrum with colorstep = 1 and fieldheight = 4, which caused the output to walk off the 1000x1000px page, gaining a height of 4591px.



Image 5: A gradient seized and somewhat resized by the GIMP from the output of color set 'lightrgb', generated with the same settings. Open in new tab/window for full appreciation.





While fiddling manually with the field settings, some number crunching is inevitable. The key value is that of colorstep. The max value which can be assigned to a byte is 0xff (hex ff), or decimal 255. The min value is 0x00 or simply 0 (for single digis N and 0xN are the same thing). Therefore there are potentially 256 different values to be assigned to this particular byte. A field for each of these values will be printed if colorstep is set to 1. However, the color corresponding with the bottom value of 0 (black, if the other bytes remain 00) is never printed, which means that in reality there are 'only' 255 different values available.

As said, three field sets are produced, one per RGB color. The creation of a field set shall be referred to as a 'run' for the color in question. All three field sets combined are referred to as a (full) iteration. If the field number supplied exceeds that of a full iteration, it is repeated from the start. This way the result of multiple iterations can be displayed on a single page. For example, if a single iteration produces 15 fields, then setting fieldnum to 45 will result in three full iterations being printed.

The default value of colorstep is 0x33 or decimal 51. Given the max value of 0xff (255), the number of steps required for the byte in question to reach 00 is 0xff / 0x33, or 255 / 51 = 5. Therefore, by default 5 fields will be printed for each RGB byte traversed, i.e. for every field set. Since there are three R, G and B bytes (three field sets) to be printed for a single run to complete, the result will be a page containing 15 fields.

Striping

With low colorstep and huerotation values striping may occur. The stripes are caused by one-pixel wide gaps in the output, most likely the result of rounding of field sizes somewhere along the way (rgbscript -> SIS -> Inkscape). Graphics software (including Inkscape itself) typically can't handle these and tends to display them in an even exaggerated form. This striping can be supprssed with fixstriping, which simply causes the start of a field to be printed one pixel before the calculated value. The reason why this is not the default behavior is that with many field sizes it is not needed. In some cases setting the fixstriping switch may somewhat shrink the output, causing it to not align precisely with the page margin or the bottom of the page, although normally this will hardly be noticeable.






Image 6a: Color set 'darkrgb' with a color step of 1: visible striping (open image in a new tab or window for a clearer view).



Image 6b: The dreaded stripes (the light bands) under 32x (L) and 128x (R) zoom. The fact that they are colored rather than clear (transparent) indicates a layer from a previous run below the current one.



Image 6c: With stripe fixing applied.





Image 1c also shows a clear case of striping, with it being fixed in image 1d.

An alternative way to deal with striping is to increase or decrease the number of fields printed by a few fields by specifying a fieldnum value. This is a matter of trial and error however.

Striping is different from color banding, which is far cruder. In principle, gradients created with rgbscript can be considered entirely free from banding. The is a sense of horizontal lining caused by the fact that even at the highest degree of resolution (i.e. the lowest solor step or hue rotation values), each field is several pixels wide. It might appear as if the output were painted with a brush, leaving fine lines. The degree to which this is a nuisance depends on the image rendering software involved. Inkscape tends to exaggerate such effects, whereas web browsers typically mask them.

It is the interdependence between number of fields, field height, field separation, page margin, and color step can make aligning the output with the page boundaries, as well as understanding what is happening to begin with, a bit of a task.

Settings


fieldnum = N number of fields to be printed
fieldheight = N field heigth
colorstep = N color step
fixstriping = 'yes'|'no try to suppress stripes in the output
fieldsep = N field separation in pixels
pagemargin = N margin size in pixels


Not all color step values will produce sensible output with all color sets. Factors of 255 should be failsafe: 1 (0x1), 3 (0x3), 5 (0x5), 15 (0xf), 17 (0x11), 51 (0x33), and 85 (0x55). The numbers of fields printed per field set and per full iteration for each color step is as follows:


1 0x1 255 765
3 0x3 85 255
5 0x5 51 153
15 0xf 17 51
17 0x11 15 45
51 0x33 5 15 (this is the default)
85 0x55 3 9


With color set 'web' the number of fields printed will be doubled.


Field skipping

Fields can be skipped. The primary setting is fieldskip, which specifies the number of fields to be skipped. Normally the first field is printed, then the number of fields specified are skipped, then a field is printed and so on. With 'fieldskip = 2' this would result in print-skip-skip-print-skip-skip-.. With fieldoffset a number of initial skips can be supplied. Values higher than that of fieldskip are wrapped around, since these are essentially meaningless. The skipping behavior can be inverted with invertskip. Print-skip-skip then becomes skip-print-print.






Image 7a: Color set 'hybrid' with a fieldskip value of 1 against a white background



Image 7b: same with a fieldskip value of 2: two fields are skipped at a time



Image 7c: previous with a skip offset of 1, causing printin to start from field 2



Image 7d: previous with the skipping inverted




Settings


fieldskip = N skip N fields, starting from the second field
skipoffset = N start with skipping N fields, then follow the usual pattern
invertskip = 'yes'|'no' invert the skipping


The image in top of this document shows the output from multiple rgbscript runs involving field skipping, taking advantage of the transparency of skipped layers to form a single composite image.


4. Color sets


The various different ways to calculate and manipulate the values of RGB bytes have resulted in seven different color sets. Each produces its own distinct set of output colors. Three of these deliver proper spectra in the sense that the colors flow naturally into one another. As will be demonstrated, each has its own shortcomings. The four remaining ones cannot be considered spectral, as they produce color jumps, where at intervals one color is followed by an entirely unrelated one. These jumps are the result of 'recharging' bytes. This is probably best demonstrated by looking at the color sets in ascending order of complexity under the hood. In addition to color sets a list of user-supplied hex RGB values can be read from a file.

In rgbscript 0.7 there are eight different color sets available: 'plainrgb', 'hybrid', 'lightrgb', 'darkrgb', 'darkcym', 'web' and 'rotate'. Each of these will be decribed later.

General settings

Some settings apply to all or most color sets. These affect the overall appearance of the output. To begin with, each run has a 'main' color which is initially set high, known as the start color. Normally this is red. With those color sets which are centered around primary colors, the first field printed will therefore be red (ff0000). With secondary colors it will be magenta (ffff00). The startcolor can be changed with startcolor, which takes a name: either 'red' (the default), 'green' or 'blue'. With some color sets, an additional byte is set high before running, and as a result the first field will be a secondary color: magenta (BR), yellow (RG) or cyan (GB). In such cases the color of the first field won't literally match the 'start color'.






Image 8a: Color set 'lightrgb' with the default settings, which imply a.o. a start color of red.



Image 8b: Same with start color green.



Image 8c: With start color blue.



Image 8d: The previous with rbgoutput set. This one shows non-standard behavior which begs for closer examination (not everything about rgbscript's inner workings is fully understood yet).




Field sets are printed in R-G-B order, i.e. first a red-based field set, followed by a green-based one and finally a blue-based one. This can be changed into R-B-G with rbgoutput. This is in fact an inversion of the normal behavior: the code naturally produces R-B-G. In the case of the 'darkmyc' color set, this will render Y-M-C i.o. C-Y-M. Neither of these settings (start color and RBG output) have any effect on the 'rotate' color set. Setting shufflecolors to 'yes' will cause the list of colors to be reshuffled. This causes the colored fields to appear on the screen in a random order. This is especially useful with objects, since it prevents the same colors from appearing in the foreground on each subsequent run. Finally, the entire output can be inverted with invertcolors.






Image 9a: Color set 'plainrgb' with the default settings.



Image 9b: same with rbgoutput set to 'yes'. The bottom two field sets G and B have been swapped, which is the normal behavior.



Image 9c: Color set 'darkmyc' with the default settings.



Image 9d: same with rbgoutput set to 'yes'. Note how in this case the top two field sets (R and G, which render as M and Y) are swapped.




There is no other reason for these discrepancies in behavior other than that they grew with the code. The same goes for the fact that 'darkmyc' follows an M-Y-C system by default, rather than a C-M-Y one. Maybe in future versions things will be harmonized. For the time being the priority of these issues is little to none. The main reason why rbgoutput exists at all is that it was initially used to turn the natural R-B-G output of the script into a more obvious R-G-B.

Settings


startcolor = 'red'|'green'|'blue' color to start with
rbgoutput = 'yes'|'no' print field sets in R-B-G order i.o. R-G-B


Application

Apart from color rotation (colorset = 'rotate'), which is borrowed code and a late addition to the script, these so-called color sets first and before all represent methods for manipulation RGB values based on simpe arithmetical operations. As such they can serve to gain some understanding in the inner workings of the RGB approach to rendering colors. Because of their systematic nature, they do render sets of specific and related colors, which can be considered swatches, and possibly used as such. A list of colors produced by a color set can be obtained by setting the printvalues switch in the configuration files. These colors are listed in the form 'NNNNNN', without any prefix. They will be shown in the SIS window before any fields are printed.

Settings


printvalues = 'yes'|'no'


The list of values printed for color set 'darkrgb' with rbgoutput set (arrows and text following these were added as comment):


1: ff0000 <- red
2: cc0000
3: 990000
4: 660000
5: 330000
6: 0000ff <- blue
7: 0000cc
8: 000099
9: 000066
10: 000033
11: 00ff00 <- green
12: 00cc00
13: 009900
14: 006600
15: 003300


Spectra versus quasi-spectra

In some modes rgbscript wil produce a spectrum (color set 'web') or a quasi-spectrum (color sets 'plainrgb' and 'rotate'). The latter has the appearance of a spectrum but with certain, typically secondary, colors missing. As with a full spectrum, the colors do flow gradually from one into another.






Image 9a: A full spectrum rendered by color set 'web' with color step 0x11 and stripe fixing.



Image 9b: A quasi-spectrum from color set ' with a 5 degree hue rotation and stripe fixing. The absence of yellow in particular is immediately noticeable.






Calculations performed on RGB values

The simplest possible arithmetic operation which can be performed on an RGB triplet is an addition of subtraction on the entire RGB value as such. The output of such an operation might look like this (the image was created with one of rgbscript's predecessors called colorscript):



From an RGB perspective, this makes no sense at all, since an RGB code isn't a value at all; it is a set of three distinct values. Simply counting upward from 000000 will certainly render values which can be translated to colors, but it violates the structure of the code as such. Decimal 255 (0x0000ff - blue) + 65025 (0x00fe01) will certainly render a 'color' (65280 or 0x00ff00 - green), but from an RGB viewpoint it is an invalid operation, not just because it isn't clear exactly which bytes are being affected, and how, but also because it triggers an overflow of the B byte: 0xff + 1 = 0x100. And no such thing as an RGB value of 0x100 exists. The effect will be that the value of the B (blue) byte instantly drops from ff to 00, which will show as a 'jolt' in the output. This method therefore cannot possibly yield a 'spectral' image, in which one color flows harmoniously into the next.

The purpose of rgbscript was to explore methods to a) produce palette or swatch-like collections of related colors and d) do so in a 'spectral' manner. Not all available color sets meet both criteria. Some require a 'recharge' or one or two bytes, which will show in the output as 'bumps' which look very similar to those produced by the brute arithmetic described above. In all cases, however, additions and subtractions are performed on individual, selected bytes rather than the RGB value as a whole. In this sense the procedure is much more systematic, and true to the idea of RGB. Arithmetic operations are performed in steps, which are specified by the colorstep variable. The default step is 0x33 (dec 51), which will yield as set of 5 fields per RGB color: 0xff/0x33 (255/51) = 5. The smallest possible value is 1, which will render smooth gradients with a high number of RGB values being generated, and as a result a high number of narrow fields being printed. Color step values greater than 0xff will result in a division by zero error. Anything in between is subject to experimentation.

The color step is central to the idea of rgbscript as a whole.









4.1 Color set 'darkrgb'


Type: recharged, non-spectral

As far as the underlying algorithm is concerned, this is the simplest color set of them all. One byte, normally R (red), is initially set to its max value while the others remain 00. This value is decremented in steps until it almost reaches 00 (which would result in a black field). Each step corresponds with a color field printed on the Inkscape page. Then the next byte, G (green), is 'recharged', i.e. set to its highest value, and the process repeats itself. Finally, the B (blue) byte is handled in the same way. This results in three distinct field sets being displayed, one for each color, with a sharp transition between one set and the other due to the recharge.

The flow is as follows:





The hex values on the vertical are those rendered for each byte with the default color step of 0x33. The numbers on the horizontal are the field numbers for each R, G or B field set.

Because at any time only one byte has a none-zero value, each field set has a primary color of red, green or blue, in descending levels of brightness. The default behaviors is to render the field sets in this order. This is labeled an R-G-B output. As explained above, the system can be turned into R-B-G instead (a red field set followed by a blue one and finally green) from the configuration. An alternative start color, which corresponds with the color to display in top, can be set as well. Invert the output will result in C-M-Y, with increasing levels of brightness.

Settings


colorset = 'darkrgb'










4.2 Color set 'darkmyc'


Type: recharged, non-spectral

With this color set, two bytes are initially set high, and subsequently decreased in value in the same way as described with the 'darkrgb' set. The output will be in RGB's idea of secondary colors: magenta, yellow and blue. This M-Y-C system can be turned into Y-M-C with rbgoutput. Note that in this case the top two field sets are swapped rather than the bottom two.

Flow:





Settings


colorset = 'darkmyc'










4.3 Color set 'lightrgb'


Type: recharged, non-spectral

The next step in experimenting with RGB bytes is logically to decrement the value of one byte, as described above, while leaving that of another high. The result is the 'lightrgb' color set, one of the most festive of the collection. It produces bright and vivid colors which lean toward 'neon'.

Flow:





Settings


colorset = 'lightrgb'


In this case too a recharge is required.









4.4 Color set 'plainrgb'


Type: continuous, quasi-spectral

The 'plainrgb' color set can be considered quasi-spectral: it offers a smooth flow from one color to another, but the secondary colors are notably missing. This is the one which rgbscript owes its exstence to, and in earlier versions it was therefore known as 'standard'. It is the default set if none is specified in the configuration. With this set one byte is decremented, while another is incremented at the same time. Because this second byte will end up being set high as a result, no recharge is needed. This allows for a smooth flow from one color into another. The output does reveal a major challenge when it comes to creating spectral images: the pure primary colors (ff0000, 00ff00, 0000ff) appear to jump off the page as it were. Its overall appearance is very unbalanced, with great contrasts especially in brightness. An approach to fixing this imbalance will be demonstrated with the 'rotate' color set.

In a graphical representation, the flow displays a winding quality:





Settings


colorset = 'plainrgb'










4.5 Color set 'hybrid'


Type: recharged, non-spectral

This one is a combination of the winding flow of the 'plainrgb' color set and the double-decrement of 'darkmyc': rather than just a single byte, two are set high, and subsequently decremented at once, while the third is incremented at the same time. It is the first color set so far to produce any white, since only assigning a non-zero value to three byte paits at once can poduce white. The colors generated follow a C-Y-M pattern by default, and the flow of colors within a field set may seem rather random at first. It almost represents an inversion, e.g. ff00ff (magenta) to 00ff00 (green), except that the final value is intercepted by a recharge, and in this case becomes ffff00 instead.

Flow:





The recharge is needed because only one byte is incremented and two need to be set high to start a new cycle. Due to the recharge there is a again sudden transition between field sets, although it is less pronounced than was the case with the first three color sets described so far, since the adjacent colors are at least somewhat related: magenta follows (an almost pure) red for example. The presence of white manifests itself in rather unappealing grayish colors.

At low resolutions the output from this color set looks rather chaotic, whereas at high ones it shows interesting gradients, with the gradient running from one (CMY) color to its (RGB) complement:




Color set 'hybrid' with a color step of 1.



Settings


colorset = 'hybrid'










4.6 Color set 'web'


Type: continuous, spectral

This is the only color sets which can properly be labeled spectral. It contains all primary and secondary colors from the RGB colo system as well as orange. It is distinct from the color sets described so far in that twice the number of fields are printed for each RGB color. The corresponding byte is set high, and remains high during the first half of its run. Another is incremented until it reaches its max, then this is held high while the first byte is decremented. All the time the third byte is held low. Once this byte has reached its low value, the one left low becomes the new byte to be incremented.

Flow:





This alternating up-and-down motion allows for RGB values to be accessed in combinations which have been out of reach of the color sets described so far. The combination of primary a (what the web considers) secondary colors allows the 'web' color set to be labeled truly spectral. No recharges are needed, and the flow of colors is gradual as a result. The 'web' color set does suffer from the same imbalance mentioned with 'plainrgb'. In this case it are the secondary colors which stand out obtrusively, due to their brightness. The 'web' color set owes its name to the fact that with the default color step of 0x33 it renders only colors which were among those once considered 'web safe'.

Settings


colorset = 'web'










4.7 Color set 'rotate'


Type: continuous, quasi-spectral

This color set is based on borrowed code (see the Pythin code on the same page referred to above: https://stackoverflow.com/questions/8507885/shift-hue-of-an-rgb-color ). The 'rotate' color set uses quite inscrutable trigonometric calculations rather than simple arithmeic to determine the color of the next field. These allow for a virtual rotation through the RGB color space. At least as important as the trigonometry itself is a matrix in which the results are stored, which takes the shape of RGBxRGB. Each result for an RGB byte is therefore stored twice. The combination of trigonometric functions and the the matrix allows the values of the 'other' RGB values to be taken into account whenever the next of a particular one is to be determined.

In terms of colors rendered, it looks like a luxury version of the 'plainrgb' color set, and just like that one it cannot be considered truly spectral for a lack of secondary colors. Yellow in particular lacks notably (the lack of cyan and magenta is less conspicuous because these aren't 'traditional' secondary colors to begin with). In its overall appearance it allows for a more balanced output than any produced so far: no single color stands out from the rest. As a result it also excels in blandness.




The 'rotate' color set with a huerotation of 10 (L), versus 'plainrgb' with colorstep 0x11 (R). The set of available hues is very similar, but 'rotate' renders them more smoothly.



It should be added that the routines involved were never intended to generate spectra. They are primarily used for rotating the hues in graphics software. Note that on the web page referred to, it is the 'web' color set, rather than the color rotation, which provides the solution to the problem stated initially. It provides precisely the requested flow.

With this color set the colorstep has no effect. It is replaced with huerotation instead, which specifies a rotation in degrees. Valid values are 1-359. Others will either trigger a division by zero error from SIS or result in no output being generated at all. With low values fixstriping might be required.

An alternative color to star from can be set with rotatecolor. With multiple iterations, it is not guaranteed that the output will ever return to this color. This is an issue which needs addressing.

Settings


colorset = 'rotate'
huerotation = 10 rotation in degrees; the default is 30, which will result in 12 fields for a full iteration
rotatecolor = 0xff3399 the numeric (decimal/hex) value of a color to start rotating from





4.8 user-supplied color lists


A list of colors can be passed through a file specified with rgbfile. These will be processed one after another, whic means the order of fields printed on the page will match that of the color codes listed in the file. A plain list of hecadecimal RGB codes without prefixes is expected, with no room for comments of any kind.

Settings


rgbfile = 'colors.txt


The process in this case is non-repetitive: printing of fields will continue until the last color listed has been processed. This may leave the page only partly filled.


5. BONUS CODE: circles and triangles


A byte of routines have been added to rgbscript which are intended to serve merel as a demonstration of how the colors generated by the different color sets might be put to pracical use. One prints circles onto the page, the other triangles. The functionality of both routines overlaps to a high degree, and so do the available settings. In a future version these might be combined. The available configurable options will speak for themselves.

The behavior in some cases is a bit random. The 'showme*' settings are incremental: setting both showmesquares and showmecircles to 'yes' will cause both squares and circles to be printed. The entire set of colors generated or read from a file is used up for each type of object. The shufflecolors setting pertains in particular to these objects. Without it the same colors would apear on top on every run.


showmesquares = 'yes'|'no' print squares i.o. fields
showmerectangles = 'yes'|'no' print rectangles i.o. fields
showmecircles = 'yes'|'no' print circles i.o. fields
showmetriangles = 'yes'|'no' print triangles i.o. fields


A number of object parameters are available which apply in either case:


objectsize = N circle size in pixels; indicates the max circle size in combination with mincirclesize
minobjectsize = N a value of 0 (the default) renders fixed size according to circlesize
objectstroke = '<name>' stroke color, default is 'white'; SIS appears to only support color names
objectstrokewidth = N stroke width in pixels
objectopacity = N.M a value between 0.0 and 1.0 (not included)
exceedpageborders = 'yes'|'no' allow the objects to partially exceed the page borders






Appendix A. RGB



RGB is a color system which defines how the primary colors red, green and blue are mixed in otder to obtain specific colors. Its logical counterpart is CMY, which has cyan, magenta and yellow as its primary colors. In the RGB color system cyan, magenta and yellow happen to be the complements (inversions) of red, green and blue, respectively. Each system has its scope of application. CMY is used primarily for printing. It is applied to surfaces which reflect light, like the paper a photo has been printed on. This paper acts as a passive object, from which light is reflected after part of it has been absorbed. RGB on the other hand is used with surfaces which emit light, such as an LCD screen. These require a different approach to mixing primary colors.







As the picture shows, CMY and RGB are indeed one another's inverse: the primary colors in one are the complements of those in the other, where they appear as secondary ones. It could also be said that CMY can be obtained by shifting the colors in RGB one position to the right, while folding the last color back to the start. If the colors shown above are looked upon the building blocks of a color spectrum, this does show the cyclic nature of a spectrum, or better: of human color perception. Rgbscript exploits this cyclic nature at various levels.

It is easy to see why RGB wouldn't work in the 'physical' world, such as with paint or crayons: a mix of red and green would never produce yellow.

As a color system, CMY is of little concern to rgbscript. A far more interesting comparison is that between RGB and another 'physical' color system, RYB, often labeled the 'traditional' model. This system is based on the common behavior of paints, chalks, crayons and the like. Its primary colors are red, yellow and blue. Mixing these in equal amounts will yield secondary colors: red plus yellow gives orange, yellow plus blue gives green, blue plus red gives purple or violet.







RYB's secondary colors are of special interest to rgbscript, which moves from one primary color to another in a series of steps. However, this skipping from one primary color to another doesn't automatically imply that RGB's own secondary colors will appear among the intermediate ones. Including RYB's secondary orange as well as purple in the output poses an even greater challenge. Unlike some of the graphics published online suggest, the purple/violet in RYB differs from the magenta which appears as a secondary color in RGB. It has a much darker tone. Cyan isn't even among RYB's secondary colors (and as such doesn not appear on a RYB spectrum). It is impossible to create the intensely bright cyan from RGB by mixing common paints. Even the primary cyan used in CMY lacks its full intensity.







In RGB yellow has been replaced with green, and mixing equal amounts of red and green together will produce yellow, which is now a secondary color. In addition, two 'new' secondary colors appear, cyan and magenta (RYB hapens to have different complementary colors as well: green is the complement of red, purple that of yellow, orange that of blue).

Rgbscript was born from the idea to traverse the color spectrum by means of simple arithmetical operations: add some value to one byte, subtract it from another, and do so without exceptions. The challenge was to find an algorithm which covers all primary and secondary colors, as defined by both RGB and RYB. This was achieved in the 'web' colors set, which is the only one to include all the desired colors. The other color sets can be considered spinoff from the process of working toward this goal.

As said, the fact that orange and purple aren't among RGB's secondary colors makes them somewhat problematic for rgbscript. While moving stepwise from red to green, they may be picked up, so to speak, but they can easily be missed out altogether. And as will be shown, even RGB's own secondary colors may be missed completely. In this context it seems appropriate to have a look at the very basics of RGB: how it defines a color.


RGB is based on three different colors of emitted light: red, green, and blue. Mixed together in varying combinations, at different levels of intensity, these can cover a vast swathe of possible colors. The intensity of each color is stored on a device as a value ranging from 0 up to and including 255, or 00-ff in hexadecimal notation. With three bytes, one per R, G or B color, the result is a color space of about 16 million different colors which can be produced on a screen.

The three values can be visualized as stacks:







It is instantly clear that red dominates here: it is set to its maximum value. Adding half the max of blue should yield a purplish color, which because of the dominance of red will be some sort of violet rather than a purple. Finally, a small amount of green will add some yellow (!) to the color, which should result in a somehwat orangy violet, probably leaning toward hot pink.

The bar approach can be applied to the way in which rgbscript attempts to produce color. If a transition from red to green is required, the most obvious way to do so is by initially setting the R byte high while setting R and B low, then decrementing R while simultaneously incrementing the G byte. This is the procedure followed by rgbscript's 'plainrgb' color set.







Neither orange nor yellow appear using this method. Both require entirely different combinations of R and G:







Some 'detour' through the color space will therefore have to be made in order to pick those up as well. At some point both the R and G bytes will have to be at their max in order to produce pure yellow, and if orange is to be rendered, the value ff6600 will have to be passed as well. This is achieved by the 'web' color set, which uses a more complex method of dealing with RGB than the 'plainrgb' color set. Other color sets use yet different approaches. Some of these 'recharge' a byte periodically, setting it from min to max 'artificially', which does however break the smooth flow from one color to another. Details are found in the 'Color sets' section.

Finally, CMY colors appear whenever two RGB bytes are at their highest value and the third one at its lowest. Consequently, these CMY colors appear as the initial colors in some color sets, in which two bytes are initially set high. In such cases setting the start color to red in the configuration will result in the first field showing up yellow. This is an oddity of the script. Why red is still considered the start color shall be explained below.





Appendix B. Hex RGB



In its current state, rgbscript is very much hex-oriented, meaning that values in the configuration are entered primarily in their hexadecimal form. There is no support for decimal RGB strings in the form of '(RRR, GGG, BBB)'. Future versions may be equipped with a decimal-to-hex conversion tool, but for now, if you are planning to use the script, some affinity with hexadecimal numbers will be required. Fortunately, not that much.

Hex RGB values appear in HTML sources as well as in certain dialog boxes of image editors, such as typically the Color Picker. They appear in Inkscape's Fill and Stroke menu. They are often listed with colors found online, often accompanied by decimal notation as well. In these cases the hex code is far more useful, because it can copied directly into the appropriate field of an image editor in order to obtain the particular color. Decades of "user friendly" use of decimal RGB codes have certainly not caused them to vanish into the background of computing. All in all there seems enough reason to get acquainted with at least their very basics.

Hexadecimal numbers are naturally intimidating to humans, since the majority of us aren't accustomed to using them from an early age. Mentally translating a hex value like '3efac1' into something meaningful isn't quite obvious for most people, let alone performing arithmetic operations on such values. When used with RGB however, a string like '3efac1' isn't a value to begin with. It is a set of three small, two-digit values instead. Values of more than two digits do not occur in RGB. This already greatly reduces the complexity of hex RGB. And since a pair of digits does represent a value, it is possible to alter it using simple arithmetic. This fact lies at the very heart of most routines in rgbscript.

As with decimal numbers, hex has its own set of digits:


Value: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Dec: 0 1 2 3 4 5 6 7 8 9

Hex: 0 1 2 3 4 5 6 7 8 9 a b c d e f


In comparison with the decimal digits, six new ones have been added to the set, bringing the total up to 16 (0-f) rather than 10 (0-9). For lack of numeric symbols it was once decided to represent these extra digits by letters of the alphabet. In a decimal system the highest digit is 9, which means that when counting beyond 9, a single-digit representation is no longer possible, and an extra position is required to represent the value: after 9 comes 10. So too with hex numbers, except that the highest digit is f, which represents the value 15. It too is followed by 10, which in this case represents the value 16(!).


Value: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Dec: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

Hex: 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12


And so on..

It is of great importance to distinguish between digits and numbers: the numeric digits have the exact same meaning both in the decimal and hexadecimal systems: they point to the same values. This does not apply to compound numbers: decimal 11 and hexadecimal 11 (0x11) are not the same thing. Hexadecimal 11 follows hexadecimal 10, the value of which is 16. The value of 0x11 is therefore 17. It is important to remember that double-digit hex numbers never have the same value as their decimal counterparts. It means that in the rgbscript configuration, for single-digit numbers it makes no difference whether they are entered as decimal of hex. For compound numbers it does.

As the highest digit in the hexadecimal system of enumeration, 'f' can not only be considered the hex equivalent of the decimal '9'. It also happens to "fill" a sequence of four bits: f represents binary 1111 (four 1's). It is the highest number that can be stored using four bits. A single R/G/B value is stored in one byte, which can represent 256 or ff different numbers. The highest value that can be stores in a byte is therefore ff.

The highest possible RGB "value" as a whole is therefore ffffff, which represents every constituent color set to its max. It is the RGB code for white. All three RGB bytes set to their lowest value is represented by 000000, the RGB code for black. If the cells in a screen are looked upon as little lamps, then 000000 means as much as 'all lights off'.

The 256 different values which can be represented by the range 00-ff (or 0-255) correspond directly with 256 levels of brightness of the R, G and B components of the screen. It are these brightness levels which are made visual in the stack model from Appendix A, which can now be equipped in with actual values:







The image shows the following R, G and B values, listed below with their correspoding decimals:



Color Hex Decimal
R ff 255
G 40 64
B 80 128


The full hex RGB value of the color in question is then ff4080. Entering 'ff4080 color' in a search engine should cause this precise color to present itself in its full glory.


While dealing with hex RGB values it is hardly necessary to remember the exact value of each letter in order to get an idea of what the resulting color will look like. Following few basic guidelines will suffice.

Hex RGB codes are read fom left to right. The leftmost byte is for red. The code for pure red at its full brightness is consequentially ff0000. Green takes up the center byte; pure green at its full brightness is represented as 00ff00. Finally, pure blue at its full brightness has the notation 0000ff.

Hexadecimal values are preceded by a hash tag '#' in HTML code. In math-oriented environments they are usually prefixed with '0x', in order to rule out any ambiguity: decimal 11 and (hexadecimal) 0x11 represent different values. As shown above, for single digits, N and 0xN are the same thing: decimal 1 and 0x1 are equivalent: they both point to the same value '1'. Again, it is important to distinguish between the value and its notation. Wherever 0xff is expected in the rgbscript configuration, 255 is accepted as well. To the software they are the same thing.

When using rgbscript there normally is little reason to be able to interepret RGB color codes, but on some occasions it can be useful to be able to "think hex". Interpreting hex RGB codes can be made easier as follows.


Break up the sequence

The RGB code for Hot Pink is FF69B4 or ff69b4 (hex numbers are case-insensitive). This can be split into their components:



ff69b4 becomes ff 69 b4



Focus on the left digit

Just as weith decimals, hexadecimal numbering is positional, which means that in any given number the leftmost digit matters most. In the decimal number 58, the 5 is more significant than the 8, even if as a digit an 8 is 'higher' than a 5. Due to its position the 5 carries more weight. It is the same with hex numbers: as an R, G or B value, the number 3f represents a relatively low value because the left digit is a 3. The right digit can generally safely be discarded. In other words, as far as color is concerned, the string 'ff 69 b4' contains little more information than 'f 6 b'.



ff 69 b4 becomes f 6 b



Focus on letters vs numbers

Letters represent high values, since as digits they're all in the upper range of 10-15. A hex RGB value like c7 can therefore be considered 'high', while 1e is clearly 'low'. If the letter H, M, L are used for high, medium and low respectively, these can be substituted for the hex digits to represent a rough representation.


f 6 b becomes H M H
3 e f becomes L H H
...


This is almost like staring at the R, G and B components of a pixel themselves.