rgbscript 0.6 README.txt USER INFO U1. Rgbscript How To Prints a color spectrum on an Inkscape page as a series of fields, each with its own color. The field size depends on the number of fields specified {fieldnum}. Fields maye be separated {fieldsep} and/or skipped {fieldskip}. An initial color may be specified {startcolor}: blue (0x0000ff), green (0x00ff00) or red (0xff0000). The default initial color is red. It determines the colors produced in the first (top) field set. After the field set for this color has been printed, the code will switch to the next color. The default sequence for printing field sets is R-B-G: a red(dish) set in top, followed by a blue(ish) one and a green(ish) one after that. Depending on the number of fields specified, the procedure is then repeated. The default R-B-G rendering can be changed to R-G-B by setting {swapgb}. In some cases a start color of red will result in a yellow first field. This is because of the fact that the G (green) bytes are also initially set high. The level of opacity of the fields printed can be specified with {fieldopacity}. RGB byte pairs are incremented or decremented by a specified amount {colorstep; default: 0x33}. The script will keep iterating through the range of colors in a circular fashion until the specified number of fields is reached. The field size is calculated dynamically from the page size and the number of fields (as well as a separator, if specified). This means that after the script has been executed, the entire page should be filled (with some margin due to rounding of values). In some cases the output will exceed the page boundaries. No warnings or error messages are ever issued, nor will the script ever exit because of for example a mangled user-supplied value. Any such errors will show up on the screen as garbled (and at times interesting) output. Blacked out fields are a sure sign of invalid input. RGB colors can be represented by hexadecimal byte pairs like 0x37 or 0xff. These byte pairs are at the heart of rgbscript's processing. The script does not know, and does not want to know about decimal RGB values like (324, 11, 215). It favors the elegance of 'hex'. Maybe in a future version a conversion routine will be added. A more useful thing to have for now would be a configuration parser, which would allow for the settings to be stored in a separate file. The colors displayed on the screen can be inverted with {invertcolors}. A background color will be printed if {showbackground} is set; its color can be specified with {backgroundcolor} (the background can still be hidden in Inkscape from the Layers tab). The default background color is white. The script can be run over and over again against a single Inkscape page. Not setting a bakground (or only setting one during the first run) can yield interesting overlaps in combination with field skipping {fieldskip, fieldoffset}. Field separation {fieldsep} is used for separating output fields, which tends to ENORMOUSLY enhance the aesthetics of the output (it really is a world of difference). Perhaps the most useful option for altering the standard behaviors is {turnaround}. It will limit the scope of colors printed, and can lead to quite wonderful results. The default value is 0xff (the 'ceiling' value) divided by the {colorstep}. Any value higher than this would result in an overflow of RGB values, and it is therefore automatically limited to this value. Rgbscript supplies five different so-called color sets, specified with {colorset}. If no color set is specified, the 'standard' color set is used. The color sets are: standard rather straightforward reds, greens and blues; this is the only set with a smooth transition between colors high somewhat pale and grayish colors bright neon-like colors dark yellow/magenta/cyan; these start bright, but quickly plunge into almost black primary like 'dark', but red/blue/green instead. More information about colors rendered is found in section M3 of the Maintainer Info part of this text. Feel free to ignore the diagrams and details. The settings marked as 'exotic' can be considered experimental. None of these can be expected to render anything meaningful or of any particular interest. The functionality of some of these settings overlaps. Field blackout and other signs of overflow/underflow can be prevented by setting {wrapcolors}, but the overall picture may look just as erratic, and the resulting colors won't necessarily display any underlying logic. Operation can be fairly complex because of the way in which different features interact. Some combinations will work, others won't. Many possible combinations of values do not even make logical sense. Getting one's mind around the various interactions may take time and experimentation. U2. Configurable parameters Color settings colorset the color set to use for this run startcolor initial color: 'red', 'green' or blue; 'red' is the default. invertcolors invert the colors? colorstep the value by which RGB bytes are incresed/decreased on every run turnaround the number of increments/decrements using colorstep before switching to the next color; this limits the scope of change for each color swapgb print R-G-B instead of R-B-G? showbackground print a background? backgroundcolor color of the background layer printvalues print a list of color values before printing output? Field settings fieldnum the number of fields to be printed; >>> THE ONLY REQUIRED SETTING <<< fieldopacity sets the opacity of the field printed fieldsep field separation in the Inkscape output, in pixels fieldskip number of fields to skip between two printed ones invertskip inverts the skipping skipoffset the position to start showing fields from; this is only used in combination with field skipping; the value should be less or equal to fieldskip Exotic ('never mind') settings: rgbthreshold value at which to declare underflow rgbceiling value at which to declare SWITCHTIME wrapcolors will 'wrap' color values exceeding the 000000-ffffff range affects the entire RGB triplet; much a best-guess effort gluefields (in development) fitfields with gluefields: fits fields onto the page -------------------------------------------------------------------------------------------------- Example: fieldnum = 45 colorstep = 0x11 startcolor = 'green invertcolors = 'yes' fieldsep = 4 turnaround = 5 -------------------------------------------------------------------------------------------------- One reason why there are so many options is that in this case the developer uses their own software (wouldn't it be great if that were always the case?). Each of these settings has proven very useful. For the same reason, the code has reached a high level of stability. U3. Known bugs - turnaround only works with standard color set ==================================================================================================== MAINTAINER INFO M1. Quick demonstration of principles by example Probably the best way to introduce the rgbscript internals is by concrete examples using actual RGB color codes. RGB color values are represented by byte pairs, like 0x99. These will be referred to as such below. Wherever it is clear from the context that hexadecimal numbers are being referred to, 0x99 may also be simply be called '99'. ------------------------------------------------------------------------------------------- Important: the terms [RGB] byte pair, RGB value and RGB color all refer to the same thing, only from different perspectives. In some cases even short forms like 'pair' will be used. ------------------------------------------------------------------------------------------- All examples below assume red as the start color, which is the default. Other start colors are handled analogously. Sticking with red for the examples should provide some consistency and avoid confusion. There is plenty of that already in the very principles covered. A run table for standard colors, starting with red (ff0000), with a colorstep of 0x33 and no fancy settings looks as follows: F display +l -r color 1 ff0000 +B -R red 2 cc0033 +B -R 3 990066 +B -R 4 660099 +B -R 5 3300cc +B -R switch 6 0000ff +G -B blue 7 0033cc +G -B 8 006699 +G -B 9 009966 +G -B 10 00cc33 +G -B switch 11 00ff00 +R -G green 12 33cc00 +R -G 13 669900 +R -G 14 996600 +R -G 15 cc3300 +R -G switch 16 ff0000 +B -R red <- back to start value Hex byte pair values are multiples of 00, 33, 66, 99, cc, ff (dec 51, 102, 153, 204, 255), which means that the colors rendered belong to the ancient 'web safe' ones. More or less visualized (F is field number, starting with 1): F 00 33 66 99 cc ff 1 ff0000 GB R 2 cc0033 G B R 3 990066 G B R 4 660099 G R B 5 3300cc G R B 6 0000ff RG B 7 0033cc R G B 8 006699 R G B 9 009966 R B G 10 00cc33 R B G 11 00ff00 BR G 12 33cc00 B R G 13 669900 B R G 14 996600 B G R 15 cc3300 B G R 16 ff0000 GB R <- back to start value It is clear that only a tiny subset of the possible byte combinations, i.e. colors, is generated. The highest amount of colors rendered, with an increment value of 1, is 255 (R) + 255 (G) + 255 (B) = 765. In particular, the algorith misses out on several key RGB combinations: values like 000000 (black), ffffff (white) or, more importantly, ff6600, which is the web idea of orange, are never reached. Being unable to render even a secondary color can be considered a shortcoming, since it severely restricts what could be called the 'spectral space'. This space is already expanded by supplying different color sets. Combining the results from these sets can be considered a TODO. For the 'high' color set the bigger picture looks quite similar. F: 00 33 66 99 cc ff 1 ffff00 B RG 2 cccc33 B RG 3 999966 B RG 4 666699 RG B 5 3333cc *R*G B 6 ff00ff G B*R* <- byte pair recharge for R 7 cc33cc G BR 8 996699 G BR 9 669966 BR G 10 33cc33 *B*R G 11 00ffff R G*B* <- byte pair recharge for B 12 33cccc R GB 13 669999 R GB 14 996666 GB R 15 cc3333 *G*B R 16 ffff00 B R*G* <- byte pair recharge for G: back to start value The color codes marked with asterisks (*) show a jump in the value during recharging: instead of becoming 00 (after 33) it is reset to ff for the next color run. This causes a 'jolt' between field sets in the output. This jolting will become even more dramatic with the color sets which follow. The flow for the primary color set, for example, is as follows: F value 00 33 66 99 cc ff 1: ff0000 GB R <- R set high at initialization 2: cc0000 GB R 3: 990000 GB R 4: 660000 GB R 5: 330000 GB R 6: 0000ff RG B <- recharge of B 7: 0000cc RG B 8: 000099 RG B 9: 000066 RG B 10: 000033 RG B 11: 00ff00 BR G <- recharge of G 12: 00cc00 BR G 13: 009900 BR G 14: 006600 BR G 15: 003300 BR G 16: ff0000 GB R <- recharge: back to initial value The recharges generate a sawtooth motion through the available values, which gives the output a bumpy quality, even more so than with high colors. For a smooth transition between color field sets, 'glue fields' would need to be inserted. This is a major TODO. The high colors feature doesn't expand the output color space, it merely alters it: the result is the exact same number of possible output colors as with the standard color set. The same key colors mentioned above, like orange, are still beyond reach. M2. RGB to LMR mapping LMR refers to a set of index pointers to elements of the RGB list, which allow the script to rotate through the list and offer a level of abstraction. The names of these indices are: lindex left index, points to whichever serves the role of 'left' byte pair mindex middle index, points to whichever serves the role of 'middle' byte pair rindex right index, points to whichever serves the role of 'right' byte pair The role played by a byte pair at any given time determines the way in which it is handled: the value may be incremented, decremented, or the byte pair is ignored. Most notably, a byte pair's role determines its final value before a switch, described shortly. The way in which RGB byte pairs are initially mapped to LMR indices depends on the start color: Start color: L: M: R: red R G B green G B R blue B R G This is the initial mapping. It is the only occasion on which 'LMR meets RGB'. After this, only LMR matters. Initialization is performed by anchoring the L index to a specific byte pair (color). The remaining indices are set relative to L. There are occasions (with the swapgb parameter set) on which the LMR scheme changes to LRM (see below: '4. LMR vs LRM, or: the R-B-G versus R-G-B output issue'). This case isn't covered in the following examples, since it is a mere administrative issue, and has no effect on the principles of operation which are to be explained. Once a particular RGB color has been processed a 'switch' occurs: the code moves to the next color in the list. During these switches the entire set of LMR indices is shifted one position to the left (default) or right (with swapgb), causing each to point to what was previously an adjacent RGB byte pair (color). To visualize the initial mapping for red as the start color: LMR: L M R -------------- -------------- -------------- RGB: | R | G | B | -------------- -------------- -------------- With startcolor = 'green', it looks like follows: LMR: L M R -------------- -------------- -------------- RGB: | G | B | R | -------------- -------------- -------------- A left shift of the LMR indices yields the following picture for red: LMR: M R L -------------- -------------- -------------- RGB: | R | G | B | -------------- -------------- -------------- This shifts L to point to blue, and since L is the determinant index, this means that a blue set of fields will be printed. Another shift yields green: LMR: R L M -------------- -------------- -------------- RGB: | R | G | B | -------------- -------------- -------------- This is equivalent to the picture shown for startcolor green. During execution the set of LMR pointers keeps rotating through the RGB set this way. The code focuses on these pointers and is completely oblivious to RGB colors. At initialization time, the L byte pair is always set high, regardless of color set and start color. The initial value of the other RGB byte pairs depends on the color set selected: L W R standard ff 00 00 high ff ff 00 bright ff ff 00 dark ff ff 00 primary ff 00 00 The distinction between these color sets is determined by the initial value, as well as by the way in which this value is subsequently handled: L W R standard -- ++ high -- -- ++ bright -- dark -- primary -- Mind-boggling? These things will become perfectly clear by looking at the different ways in which the RGB byte pairs are handled with each color set. M3. Color sets With an increment/decrement value {colorstep} of 0x33, the default, five different fields are printed before each switch (these are clearly hex numbers): 00 + 33 = 66 33 + 33 = 66 66 + 33 = 99 99 + 33 = cc cc + 33 = ff At this point these is nowhere else to go, since the topmost value an RGB byte pair (and of any byte pair of course) can represent is is 0xff, or decimal 255. The same story for an initial value being decremented in steps from 0xff to 0x00. As said, which byte pairs are set initially and changed afterwards, and in which way, depends on the color set selected. There are five different color sets: standard, high, bright, dark and primary. Each renders its distinct set of colors. The color sets will be covered in terms of LMR rather than specific colors. A single LMR iteration may apply to any of the RGB ones shown above. It can be considered RGB-neutral. M3.1 Primary colors 00 33 66 99 cc ff MR L MR L MR L MR L MR L (M*R*L) <- value at switch, not printed (this would be 0x000000: black) MR *L* <- switch: recharge the old R byte pair (blue) as the new L This is the simplest procedure of them all: it simply sets one byte pair high and decrements it. It does require a 'recharge' of the L pair however, which involves setting the value high (0xff) for the next color: Index: Color: Init value: End value: Next color: Init value: L red ff 00 blue *ff* <- recharge M green 00 00 red 00 R blue 00 *00* green 00 In other words, at switch time all byte pairs are 00, whereas an *ff* is required for the blue new L pair. This done manually, so to speak: there is no natural flow of one set of values into another. The entry for 'standard' colors will show that not in all cases is such a recharge required. The value 0x000000/black, the 'sixth color', is intercepted by the recharge performed during the switch, which sets the old R pair, now the L pair (with start color red and a left shift: blue, so far left 00), high. It therefore never gets shown in the output. Consisting of only one byte pair (RGB color), these 'primary' colors (which they are indeed: they show up as red, green and blue) start out looking bright and clear, but quickly veer off toward black with each successive iteration. If all this seems confusing: it is. ENORMOUSLY. M3.2 Standard colors 00 33 66 99 cc ff MR L M R L M R L M L R M L R (ML) (R) <- value at switch: the next 'pure' color, e.g. red -> blue MR L <- no recharge, a shift is enough; 'pure' color is printed Index: Color: Init value: End value: Next color: Init value: L red ff 00 blue ff M green 00 00 red 00 R blue 00 ff green 00 This simultaneous increment of one byte pair while decrementing another formed the initial challenge for writing the script. The switch requires the blue byte pair to be high, which is already naturally case, since it was incremented as the old R pair. No recharge is therefore needed. Note that, from a coding perspective, this does involve a degree of implicit behavior: the value is _assumed_ high, and is never tested as such (this is where the LMR vs LRM issue, described later, plays up). Again, with start color red and a left shift, the old R pair was blue, which now becomes the L one. This time, with a recharge skipped, rather than being intercepted (iverwritten), the 'sixth color' gets to serve as the first of the next field set. Also note that in this case too the M pair remains 00 throughout, which means that none of the colors produced contain any white (which may manifest itself as grayish tones), for in an RGB scheme white requires all RGB values to be non-zero. The result are again clear colors. With these two color sets the main principles of the script's operation (increments and decrements, switches, recharges) have been covered. The other color sets are no more than variations on these principles. M3.3 High colors 00 33 66 99 cc ff R LM R LM R LM LM R LM R (LM) (R) <- value at switch, not printed (e.g. 0x0000ff: 'pure' blue) R LM <- recharged to low/high/high (e.g. 0xff00ff: magenta) High colors run the same way as standard colors, but with the M pair set high and decremented along with the L one. The result is a lot of white, which shows itself in a rather grayish output. Index: Color: Init value: End value: Next color: Init value: L red ff *00* L blue ff M green ff 00 M red *ff* <- recharge R blue 00 ff R green 00 M3.4 Bright colors 00 33 66 99 cc ff R LM R M L R M L R M L R M L (RM) (L) <- value at switch, not printed (e.g. 0xff0000: 'pure' red) R LM <- recharged to low/high/high (e.g. 0xff00ff: magenta) These 'bright' colors do live up to their name: their intrusiveness and blatancy matches that of so-called neon colors. A lack of any white (in this case the R pair remains 00) causes them to look clear, and their lightness adds a brilliancy not found in any of the other sets. This lightness is provided by the L pair, which remains at its highest value throughout. This is the only color set in which ff6600/orange appears. Index: Color: Init value: End value: Next color: Init value: L red ff ff blue *ff* <- recharge M green ff 00 red ff R blue 00 00 green 00 M3.5 Dark colors 00 33 66 99 cc ff R LM R LM R LM R LM R LM (LMR) <- value at switch, not printed (again 0x000000: black) R LM <- recharged to low/high/high (e.g. 0xff00ff: magenta) This set produces an output very similar to that of the primary color set. Rather than a single byte pair, two adjacent ones are initially set high, and decremented. As two-color creations, these 'dark' colors start out looking vivid, without any graytones, and as with the primary colors they rapidly plunge into darkness. The colors rendered are the logical complements of the 'primary' ones: yellow vs blue, cyan vs red, magenta vs green. Index: Color: Init value: End value: Next color: Init value: L red ff 00 blue *ff* <- recharge M green 00 00 red *ff* <- recharge R blue ff 00 green 00 The fact that yellow appears in the high, bright and dark color sets may give rise to confusion, since it is a secondary color both in real life (i.e. with pigments) and in an RGB scheme. It may suggest that other secondary colors appear in these sets as well, which is not the case. The web colors labeled secondary, apart from 0xffff00 (yellow), are 6600ff (purple) and 0xff6600 (orange). These only happen to appear in the 'bright' color set. M4. LMR vs LRM, or: the R-B-G versus R-G-B output issue A left shift of the indices automatically results in blue coming after red, green after blue, red after green. As a result, the output follows a R-B-G scheme: red in top, followed by blue and then green, and back to red (all of course depending on the number of fields available). Turning this into R-G-B would seem straightforward: just perform a right shift of indices instead: green will follow red, blue follows green and after blue the output returns to red. It is not that simple, however, since a mere change in shift direction doesn't take into account the roles byte pairs play as L, M or R pairs. This can best be demonstrated by looking at the results of the two types of shift. Left shift: initial indices L M R after a left shift M R L M points to previous L has for example been decremented to 00 R points to previous M has for example been incremented to ff Right shift: initial indices L M R after a right shift R L M M points to previous R has for example been incremented to ff R points to previous L has for example been decremented to 00 Now, if the code says 'increment M and decrement R', this will lead to the desired result with the left shift. With the right shift it will generate erratic values, such as ff+11 or 00-33, clear cases of overflow and underflow, respectively. An exchange of the R and M indices is therfore required as well. This will effectively take into account the different PREVIOUS roles played by the byte pairs pointed to. Depending on the color set in question, various different side effects will show in the output. In some cases very interesting colors are produced, which may very well serve as a basis for creating new color sets at some point in the future.