# Walk through the color spectrum in an orderly fashion and display the colors in Inkscape
# Language: Simple Inkscape Scripting (SIS, apparently)
# Details: https://inkscape.org/~pakin/%E2%98%85simple-inkscape-scripting
# Github: https://github.com/spakin/SimpInkScr
# rgbscript version 0.7.1
#
# Copyright 2022 Joseph Smith
#
# Permission to use, copy, modify, and/or distribute this software for any purpose with or without
# fee is hereby granted, provided that the above copyright notice and this permission notice
# appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
# SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
# Bugs/shortcomings
# - turnaround only works with plainrgb color set, which suggests it doesn't survive a recharge
# - controlling the script from a config file is cumbersome
# - no repetitive output possible with rgblist
# TODO: maybe: fieldalign (left/center/right), for multiple runs
configfile = 'rgbscript.cf'
# ==================================================================================================
# Function definitions
# CONFIG
# Parse configuration file; sets globals directly
def loadconfig(cffile):
# For maintainers to maintain: expected types CAN be speciified; without, everything returns as str
expectint = ['pagewidth', 'pageheight', 'backgroundcolor', 'colorstep', 'fieldnum', 'fieldheight', 'fieldsep', 'fieldskip', 'skipoffset', 'turnaround', 'objectsize', 'minobjectsize', 'objectstrokewidth', 'rotatecolor']
expectfloat = ['fieldopacity', 'objectopacity']
cflist = []
with open(cffile) as fp:
lines = fp.readlines()
for line in lines:
if '#' in line:
parts = line.split('#')
line = parts[0].rstrip()
else:
line = line.rstrip()
if '=' in line:
entry = line.split('=')
cfname = entry[0].strip()
cfval = entry[1].strip()
cfval = cfval.replace("'", "")
cfval = cfval.replace('"', "")
configentry = [cfname, cfval]
cflist.append(configentry)
fp.close()
for i in range(len(cflist)):
name = cflist[i][0]
value = cflist[i][1]
if (value.startswith("0x")):
iv = int(value[2:], 16)
globals()[name] = int(iv)
elif name in expectint:
iv = int('%s' % value, 0)
globals()[name] = iv
elif name in expectfloat:
fv = float('%s' % value)
globals()[name] = float(fv)
else:
globals()[name] = value
return()
# CREATE PRINT LIST
# Create a list of fields to be printed or skipped
# This is in fact the MAIN LOOP - the highest-level function in this script
skipcount = 0
fieldcount = 0 # human idea of field numbers, starts at 1
def createprintlist():
global RGBCODE, CHANGEOP, fieldcount
for i in range(fieldnum):
fieldcount += 1
# Update the print list, keeping field skips into account
updateprintlist(fieldcount)
# Change values of color bytes for next rum
RGBCODE = updatergb(RGBCODE)
# Switch roles of color bytes after every N runs
if (fieldcount % turnaround == 0):
# R-B-G to R-G-B output: reverse shift
# Works only with an M/R index swap at initialization; see initlmr()
if (swapgb == 'yes'): shiftlmr('right')
else: shiftlmr('left')
if (colorset == 'web'):
# No need to recharge bytes
# The shift has taken care of the correct index switch (M becomes former L/M)
if (CHANGEOP == 'inc'): CHANGEOP = 'dec'
elif (CHANGEOP == 'dec'): CHANGEOP = 'inc'
elif (colorset != 'plainrgb'):
# Recharge bytes (set values high)
RGBCODE = rechargergb(RGBCODE)
# Read 0x-less hex rgb codes from a file
def readrgbfile(rgbf):
rgbl = []
with open(rgbf, 'r') as fp:
line = fp.readline()
while line:
if '#' in line:
parts = line.split('#')
line = parts[0]
line = line.strip()
if line:
rgbl.append(str2hex(line))
line = fp.readline()
fp.close()
return(rgbl)
# COLOR SET PROCESSING
# Change RGB byte values for next rum (called from main loop)
def updatergb(rgbval):
if (colorset == 'darkrgb'):
# RGB colors: decrement R bytes only
rgbval = changecolorbytes(rgbval, rgblist[lindex], 'ignore', 'ignore', -1, 0, 0, colorstep)
elif (colorset == 'plainrgb'):
# Plainrgb colors: increment L bytes, decrement R bytes; the W bytes remain 00 throughout
rgbval = changecolorbytes(rgbval, rgblist[lindex], 'ignore', rgblist[rindex], -1, 0, 1, colorstep)
elif (colorset == 'hybrid'):
# Hybrid colors: increment L bytes, decrement W and R bytes
rgbval = changecolorbytes(rgbval, rgblist[lindex], rgblist[mindex], rgblist[rindex], -1, -1, 1, colorstep)
elif (colorset == 'lightrgb'):
# Bright colors: decrement W bytes only
rgbval = changecolorbytes(rgbval, 'ignore', rgblist[mindex], 'ignore', 0, -1, 0, colorstep)
elif (colorset == 'darkmyc'):
# MYC colors: decrement W and R bytes
rgbval = changecolorbytes(rgbval, rgblist[lindex], 'ignore', rgblist[mindex], -1, 0, -1, colorstep)
elif (colorset == 'web'):
# 'Web safe' colors: decrement M __OR__ increment R bytes, depending on direction
if (CHANGEOP == 'inc'):
rgbval = changecolorbytes(rgbval, 'ignore', rgblist[mindex], 'ignore', 0, 1, 0, colorstep)
elif (CHANGEOP == 'dec'):
rgbval = changecolorbytes(rgbval, 'ignore', rgblist[mindex], 'ignore', 0, -1, 0, colorstep)
return(rgbval)
# Recharge bytes (set them to 0xff or ceiling value)
def rechargergb(rgbval):
if (colorset == 'hybrid'):
rgbval = chargecolorbytes(rgbval, rgblist[mindex])
elif (colorset == 'darkmyc'):
rgbval = chargecolorbytes(rgbval, rgblist[mindex])
rgbval = chargecolorbytes(rgbval, rgblist[lindex])
elif (colorset == 'lightrgb'):
rgbval = chargecolorbytes(rgbval, rgblist[lindex])
elif (colorset == 'darkrgb'):
### Could handle turnaround here
rgbval = chargecolorbytes(rgbval, rgblist[lindex])
return(rgbval)
# LOW LEVEL RGB MANAGEMENT
# Reset color values (vulnerable to overflow)
def chargecolorbytes(clr, clname):
curvalue = getbyteval(clr, clname)
if (clname == 'r'):
ceiling = CEILINGR
#threshold = THRESHOLDR
elif (clname == 'g'):
ceiling = CEILINGG
#threshold = THRESHOLDG
elif (clname == 'b'):
ceiling = CEILINGB
#threshold = THRESHOLDB
else:
return(-1)
newvalue = ceiling - curvalue
newclr = setbyteval(clr, newvalue, clname)
return(newclr)
# Change the rgb value
# The order of names doesn't really matter, as long as signs correspond
# If a name is tagged 'ignore', the value of the sign argument is irrelevant
def changecolorbytes(clr, lname, wname, rname, lsign, wsign, rsign, inc):
newrgbv = clr
cnames = (lname, wname, rname) # values: 'r', 'g', 'b', 'ignore'
csigns = (lsign, wsign, rsign) # values: -1, 1
for i in range(len(cnames)):
if (cnames[i] != 'ignore'):
newrgbv = setbyteval(newrgbv, csigns[i] * inc, cnames[i])
return(newrgbv)
# Change the value of a byte for specified color (vulnerable to overflow)
def setbyteval(clr, clbytes, clname):
if (clname == 'r'):
newclr = clr + clbytes * 0x10000
elif (clname == 'g'):
newclr = clr + clbytes * 0x100
elif (clname == 'b'):
newclr = clr + clbytes
else:
return(-1)
return(newclr)
# Retrieve the value of a byte for specified color
def getbyteval(clr, clname):
if (clname == 'r'):
# The modulo operation flushes out any overflow
clbytes = int(clr / 0x10000) % 0x100
elif (clname == 'g'):
clbytes = int(clr / 0x100) % 0x100
elif (clname == 'b'):
clbytes = int(clr) % 0x100
else:
return(-1)
return(clbytes)
# INDEX/SWITCH HANDLING FOR MAIN LOOP
# Set initial indices of RGB bytes in rgblist: 0, 1, 2; with red startcolor: R, G, B
# This is the only occasion where LMR meets RGB concretely, and only through the L index
# R and M values (positions in RGB list) are relative to that of L
# The heart of rotational complexity beats here; see the README about LMR vs LRM
def initlmr(rgboffs):
global rindex, mindex, lindex
lindex = rgboffs # L: offset in {r, g, b} list
if (swapgb == 'yes'): # This ALSO requires a shift R i.o. a shift L
mindex = (lindex + 2) % 3 # M = L + 2 }
rindex = (mindex + 2) % 3 # R = L + 1 } => LRM (swapped scheme RBG)
else:
rindex = (lindex + 2) % 3 # R = L + 2 }
mindex = (rindex + 2) % 3 # M = L + 1 } => LMR (plainrgb scheme RGB)
# Handle R/L index shifts
# Shift values: 'left', 'right'; anything other means no shift is performed
def shiftlmr(shift):
global rindex, mindex, lindex
if (shift == 'left'): # used with LMR (plainrgb scheme RGB)
# new X = old X - 1: left shift
rindex = (rindex + 2) % 3
mindex = (mindex + 2) % 3
lindex = (lindex + 2) % 3
if (shift == 'right'): # NEEDED with LRM (swapped scheme RBG)
# new X = old X + 1: right shift
rindex = (rindex + 4) % 3
mindex = (mindex + 4) % 3
lindex = (lindex + 4) % 3
# FIELD PRINTING
# Populate the print list
def updateprintlist(fnum):
global PRINTLIST, skipcount
if (testskip(skipcount) == 0):
PRINTLIST.append(RGBCODE)
if (printvalues == 'yes'): print('%d: %06x' % (fnum, RGBCODE))
else:
PRINTLIST.append('skip')
skipcount += 1
# Print items from the rgb list taking field skips into account
# This one should be easy to replace with various other routines
# E.g. print a bunch of circles (or Super Marios) using the colors from the list
def printfields(plist):
global ymin
for i in range(len(plist)):
if (plist[i] != 'skip'):
if (type(plist[i]) == int):
value = plist[i]
else:
value = int(plist[i], 0)
fld = fieldprep(xmin, ymin, xmin + fieldwidth, ymin + fieldheight, value)
l1.add(fld)
# The '- 1' should largely do away with annoying 1px-wide stipes
ymin = ymin + fieldheight + fieldsep - stripefix
# Examine field printing conditions; handle color inversion
def fieldprep(x0, y0, x1, y1, fcolor):
# Wrap color if its value exceeds the 000000-ffffff range. Best effort / quick fix.
# Could be handled per byte instead, with equally little meaning
if (wrapcolors == 'yes'):
if (fcolor < 0):
fcolor = -fcolor
while (fcolor > 0xffffff):
fcolor = int(fcolor / 0x10)
# Print first, adjust indices later
fld = writefield(x0, y0, x1, y1, fcolor)
return(fld)
# Function: display a color field
def writefield(x0, y0, x1, y1, clr):
fieldcolor = hex2str(clr)
f = rect((x0, y0), (x1, y1), stroke=0, stroke_width=0, opacity='%f' % fieldopacity, fill = '#%s' % fieldcolor)
return(f)
def writebackground(x0, y0, x1, y1, clr):
fieldcolor = hex2str(clr)
f = rect((x0, y0), (x1, y1), stroke=0, stroke_width=0, fill = '#%s' % fieldcolor)
return(f)
# SKIP HANDLING
# Decide whether to skip or display a field
def testskip(sc):
sc = skipoffset - sc
if (sc == 0): # first line
skip = 0
elif (sc % (fieldskip + 1) == 0):
skip = 0
else:
skip = 1
if (invertskip == 'yes'):
skip = 1 - skip
return(skip)
# LOW LEVEL
# Turn a numeric color value into a 6-digit (padded) hex string
def hex2str(value, chars = 6):
return('{0:0{1}x}'.format(value, chars))
# Turn a hex color string into a numeric value
# Unused, but has won its spurs for debugging
def str2hex(string):
rv = int('0x%s' % string, 0)
return(rv)
def restrict(v, minval, maxval):
if v < minval: return minval
if v > maxval: return maxval
return(v)
# -------------------------------------------------------------------------------
# BONUS CODE: print objects i.o printfields
# TODO: provide a better hook mechanism for insertable code.
# Return a random object position
def getobjectpos(pwidth, pheight, size):
if (exceedpageborders == 'yes'):
(x, y) = uniform(0, pwidth), uniform(0, pheight)
else:
(x, y) = uniform(size, pwidth - size), uniform(size, pheight - size)
return(x, y)
# Print randomly positioned squares using colors generated by this script
def printsquares(plist):
for i in range(len(plist)):
if (plist[i] != 'skip'):
(x, y) = getobjectpos(pagewidth, pageheight, objectsize)
if (minobjectsize != 0):
xsize = uniform(int(minobjectsize), int(objectsize))
size = (xsize, xsize)
else:
size = (float(objectsize), float(objectsize))
sqr = rect((0, 0), size, transform='translate(%g, %g)' % (x, y), stroke='%s' % objectstroke, stroke_width='%d' % objectstrokewidth, opacity='%f' % float(objectopacity), fill='#%06x' % plist[i])
l1.add(sqr)
# Print randomly positioned rectangles using colors generated by this script
# TODO: with an objectsize only things get rather vague (maybe add rectangle ratio to the config)
def printrectangles(plist):
for i in range(len(plist)):
if (plist[i] != 'skip'):
(x, y) = getobjectpos(pagewidth, pageheight, objectsize)
if (minobjectsize != 0):
xsize = uniform(int(minobjectsize), int(objectsize))
ysize = uniform(int(minobjectsize), int(objectsize))
size = (xsize, ysize)
else:
# This is a bit random
xsize = uniform(0, int(objectsize) * 2)
ysize = uniform(0, int(objectsize) * 2)
size = (xsize, ysize)
rct = rect((0, 0), size, transform='translate(%g, %g)' % (x, y), stroke='%s' % objectstroke, stroke_width='%d' % objectstrokewidth, opacity='%f' % float(objectopacity), fill='#%06x' % plist[i])
l1.add(rct)
# Print randomly positioned circles using colors generated by this script
def printcircles(plist):
for i in range(len(plist)):
if (plist[i] != 'skip'):
(x, y) = getobjectpos(pagewidth, pageheight, objectsize)
if (minobjectsize != 0):
size = uniform(int(minobjectsize), int(objectsize))
else:
size = float(objectsize)
# Ovals: ckl = circle((x, y), 50, transform='translate(%g, %g) scale(0.75, 1) rotate(45)' % (x, y), fill='#%06x' % PRINTLIST[i])
ckl = circle((0, 0), size, transform='translate(%g, %g)' % (x, y), stroke='%s' % objectstroke, stroke_width='%d' % objectstrokewidth, opacity='%f' % float(objectopacity), fill='#%06x' % plist[i])
l1.add(ckl)
# BONUS CODE: printtriangles - example alternative for printfields
# Print randomly positioned triangles in randomized perspective using colors generated by this script
def printtriangles(plist):
for i in range(len(plist)):
if (plist[i] != 'skip'):
(x, y) = getobjectpos(pagewidth, pageheight, objectsize)
if (minobjectsize != 0):
size = uniform(int(minobjectsize), int(objectsize))
else:
size = float(objectsize)
trg = regular_polygon(3, (x, y), size, 2, 0.0, 0.7, stroke='%s' % objectstroke, stroke_width='%d' % objectstrokewidth, opacity='%f' % float(objectopacity), fill='#%06x' % plist[i])
l1.add(trg)
# COLOR SET 'ROTATE'
# For color set 'rotate': rotate the hue by a specified amount of degrees.
# Code credit: Mark Ransom on Stack Overflow; adapted for specific use
# Original code: https://stackoverflow.com/questions/8507885/shift-hue-of-an-rgb-color
from math import sqrt,cos,sin,radians
rgbmatrix = [[1,0,0],[0,1,0],[0,0,1]]
def clamp(v):
if v < 0x00: return 0x00
if v > 0xff: return 0xff
return int(v + 0.5)
def rotatehue(degrees):
cosA = cos(radians(degrees))
sinA = sin(radians(degrees))
rgbmatrix[0][0] = cosA + (1.0 - cosA) / 3.0
rgbmatrix[0][1] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
rgbmatrix[0][2] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
rgbmatrix[1][0] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
rgbmatrix[1][1] = cosA + 1./3.*(1.0 - cosA)
rgbmatrix[1][2] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
rgbmatrix[2][0] = 1./3. * (1.0 - cosA) - sqrt(1./3.) * sinA
rgbmatrix[2][1] = 1./3. * (1.0 - cosA) + sqrt(1./3.) * sinA
rgbmatrix[2][2] = cosA + 1./3. * (1.0 - cosA)
def getrotatedvalue(rgbval):
r = getbyteval(rgbval, 'r')
g = getbyteval(rgbval, 'g')
b = getbyteval(rgbval, 'b')
rx = r * rgbmatrix[0][0] + g * rgbmatrix[0][1] + b * rgbmatrix[0][2]
gx = r * rgbmatrix[1][0] + g * rgbmatrix[1][1] + b * rgbmatrix[1][2]
bx = r * rgbmatrix[2][0] + g * rgbmatrix[2][1] + b * rgbmatrix[2][2]
rx = clamp(rx)
gx = clamp(gx)
bx = clamp(bx)
rv = 0x10000 * rx + 0x100 * gx + bx
return(rv)
def getnexthue(rgbv, hrot):
rotatehue(hrot)
newrgb = getrotatedvalue(rgbv)
if (printvalues == 'yes'): print('%06x' % RGBCODE)
return(newrgb)
#====================================================================================================
# Code section
loadconfig(configfile)
# Configuration defaults
# Shelved settings (dysfunctional)
###rgbthreshold = 0x333333 # DEFAULT is 0x000000; value at which to declare underflow
###rgbceiling = 0xcccccc # DEFAULT is 0xffffff; value at which to declare SWITCHTIME
###wrapcolors = 'yes' # DEFAULT is 'no'; affects the entire RGB triplet
if not 'fieldnum' in globals(): fieldnum = 0
if not 'fieldheight' in globals(): fieldheight = 0
if not 'colorstep' in globals(): colorstep = 0x33
if not 'fixstriping' in globals(): fixstriping = 'no'
if not 'fieldsep' in globals(): fieldsep = 0
if not 'fieldskip' in globals(): fieldskip = 0
if not 'skipoffset' in globals(): skipoffset = 0
if not 'invertskip' in globals(): invertskip = 'no'
if not 'pagemargin' in globals(): pagemargin = 0
if not 'showbackground' in globals(): showbackground = 'no'
if not 'backgroundcolor' in globals(): backgroundcolor = 0xffffff
if not 'colorset' in globals(): colorset = 'plainrgb'
if not 'startcolor' in globals(): startcolor = 'red'
if not 'invertcolors' in globals(): invertcolors = 'no'
if not 'fieldopacity' in globals(): fieldopacity = 1
if not 'huerotation' in globals(): huerotation = 30
if not 'rotatecolor' in globals(): rotatecolor = -1
if not 'rbgoutput' in globals(): rbgoutput = 'no'
if not 'turnaround' in globals(): turnaround = int(0xff / colorstep)
if not 'rgbfile' in globals(): rgbfile = ''
if not 'shufflecolors' in globals(): shufflecolors = 'no'
if not 'printvalues' in globals(): printvalues = 'no'
#----------------------------------------------------------------------------------------------------
# For BONUS CODE: print objects i.o. fields
if not 'showmesquares' in globals(): showmesquares = 'no'
if not 'showmerectangles' in globals(): showmerectangles = 'no'
if not 'showmecircles' in globals(): showmecircles = 'no'
if not 'showmetriangles' in globals(): showmetriangles = 'no'
if not 'objectsize' in globals(): objectsize = 10
if not 'minobjectsize' in globals(): minobjectsize = 0
if not 'objectstroke' in globals(): objectstroke = 'white'
if not 'objectstrokewidth' in globals(): objectstrokewidth = 0
if not 'objectopacity' in globals(): objectopacity = 1
if not 'exceedpageborders' in globals(): exceedpageborders = 'no'
#----------------------------------------------------------------------------------------------------
# Shelved
if not 'rgbthreshold' in globals(): rgbthreshold = 0x0
if not 'rgbceiling' in globals(): rgbceiling = 0xffffff
if not 'wrapcolors' in globals(): wrapcolors = 'no'
# The fairly unambiguous part of the initialization; no (little) hocus pocus here
# Threshold and ceiling for byte values, normally 0x00 and 0xff respectively
# rgbthreshold and rgbceiling are currently not in the configuration settings
THRESHOLDR = int(rgbthreshold / 0x10000) % 0x100
THRESHOLDG = int(rgbthreshold / 0x100) % 0x100
THRESHOLDB = rgbthreshold % 0x100
CEILINGR = int(rgbceiling / 0x10000) % 0x100
CEILINGG = int(rgbceiling / 0x100) % 0x100
CEILINGB = rgbceiling % 0x100
# These allow fieldnum and fieldheight to be reused
autofieldnum = 'no'
autofieldheight = 'no'
if (fieldnum == 0): autofieldnum = 'yes'
if (fieldheight == 0): autofieldheight = 'yes'
# Stripe fixing: shift field start up one pixel
stripefix = 0
if (fixstriping == 'yes'): stripefix = 1
# invertskip has no meaning without fieldskip; may result in no output at all
if (fieldskip == 0): invertskip = 0
# A turnaround value higher than the natural one makes no sense
if (turnaround > int(0xff / colorstep)): turnaround = int(0xff / colorstep)
# Retrieve page dimensions if not specifid above.
if ('pageheight' in globals()) and ('pagewidth' in globals()):
svg_root.set('width', '%spx' % pagewidth)
svg_root.set('height', '%spx' % pageheight)
width, height = svg_root.width, svg_root.height
svg_root.set('viewBox', '0 0 %.0f %.0f' % (width, height))
else:
pagewidth = float(svg_root.get('width').rstrip('px'))
pageheight = float(svg_root.get('height').rstrip('px'))
# Field width equalss pagewidth, unless a margin is set
pagemargin = float(pagemargin)
fieldwidth = pagewidth - 2 * pagemargin
# Xmin and Ymin can be easily determined; Xmax/Ymax depend on fieldheight, set later
if (pagemargin == 0): (xmin, ymin) = (0, 0)
else: (xmin, ymin) = (pagemargin, pagemargin)
# Hex color code of current color to be printed; referred to throughout this script
RGBCODE = None
# List of hex values for colors to be displayed
PRINTLIST = []
# For 'web' color set
CHANGEOP = 'inc'
# Make all color sets print R-G-B by default (only 'web' does that by nature)
# This is much easier and safer than tinkering with the near-inscrutable innards of the script
swapgb = 'no'
if (rbgoutput == 'yes'):
if (colorset == 'web'):
swapgb = 'yes'
elif (colorset != 'web'):
swapgb = 'yes'
#----------------------------------------------------------------------------------------------------
# The less unamiguous part of initialization
# Set uo the list of RGB color naes to rotate through
# Sets the byte to be pointed to by the L initial index high
rgblist = ('r', 'g', 'b')
RGBCODE = 0x000000
if (startcolor == 'red'):
RGBCODE = chargecolorbytes(RGBCODE, 'r')
rgboffset = 0
elif (startcolor == 'green'):
RGBCODE = chargecolorbytes(RGBCODE, 'g')
rgboffset = 1
elif (startcolor == 'blue'):
RGBCODE = chargecolorbytes(RGBCODE, 'b')
rgboffset = 2
# This hooks the initial L index onto a color name in the list. The other indices (M/R) are set
# relative to the L index. Each index will point to a different RGB color name, which is used for
# retrieving the corresponding part of the RGB value, processed (changed) over and over again.
initlmr(rgboffset)
# Initialize (set high) the M bytes (not with 'plainrgb' or 'darkrgb')
if (colorset == 'hybrid' or colorset == 'lightrgb' or colorset == 'darkmyc'):
RGBCODE = chargecolorbytes(RGBCODE, rgblist[mindex])
# VAGUE but functional: set the R byte moderately high so that the colors repeat
# Has no menaing for 'darkrgb' (because it wouldn't render primary colors)
if (colorset == 'hybrid' or colorset == 'lightrgb' or colorset == 'darkmyc'):
# Vulnerable to underflow: depends on turnaround and colorstep values
highrbytes = 0xff - turnaround * colorstep
# Failsafe
if (highrbytes < 0): highrbytes = 0
RGBCODE = RGBCODE + highrbytes
# Automatic field number calculation
if (autofieldnum == 'yes'):
if (colorset == 'rotate'):
fieldnum = int(360 / int(huerotation))
elif (colorset == 'web'):
# Color set 'web' requires twice as many fields as the others to complete a round
fieldnum = int(CEILINGR / int(colorstep)) * 6
else:
fieldnum = int(CEILINGR / int(colorstep)) * 3
# Automatic field alignment
if (autofieldheight == 'yes'):
emptypagespace = 2 * pagemargin + (fieldnum - 1) * (fieldsep - stripefix)
fieldheight = (pageheight - emptypagespace) / fieldnum
#====================================================================================================
# POPULATE PRINT LIST
# Create the list of fields to be printed or skipped
if (rgbfile != ''):
PRINTLIST = readrgbfile(rgbfile)
elif (colorset == 'rotate'):
huerotation = int(huerotation)
testhr = int(huerotation % 360)
if (testhr == 0):
PRINTLIST = []
else:
if (rotatecolor != -1): RGBCODE = rotatecolor
PRINTLIST = [RGBCODE]
if (autofieldnum == 'yes'):
rotatesteps = int(360 / huerotation)
else:
rotatesteps = fieldnum
for step in range(rotatesteps - 1):
RGBCODE = getnexthue(RGBCODE, huerotation)
PRINTLIST.append(RGBCODE)
else:
createprintlist()
# Reshuffle print list and invert colors is necessary
if (shufflecolors == 'yes'):
from random import random, shuffle
shuffle(PRINTLIST)
if (invertcolors == 'yes'):
for i in range(len(PRINTLIST)):
if (PRINTLIST[i] != 'skip'):
PRINTLIST[i] = 0xffffff - PRINTLIST[i]
# PRINT STUFF
# Add a background layer on request
if (showbackground == 'yes'):
l0 = layer('Background')
bg = writebackground(0, 0, pagewidth, pageheight, backgroundcolor)
l0.add(bg)
# Add a layer for field output
l1 = layer('Fields')
# For BONUS CODE: print onbjects i.o. fields
# Number of objects is determined by fieldnum. If less shown than expected, disable fieldskip.
# Cause stuff to appear on the screen
if (showmesquares == 'yes'):
printsquares(PRINTLIST)
if (showmerectangles == 'yes'):
printrectangles(PRINTLIST)
if (showmecircles == 'yes'):
printcircles(PRINTLIST)
if (showmetriangles == 'yes'):
printtriangles(PRINTLIST)
if (showmesquares == 'no' and showmerectangles == 'no' and showmecircles == 'no' and showmetriangles == 'no'):
# Normal output: fields
printfields(PRINTLIST)