colours.ps


NAME

      colours.ps - Some useful colour-handling stuff in PostScript


SYNOPSIS

 (/home/wherever/ps/lib/colours.ps) run
 % if run fails with invalidaccess you may need to use  gv --nosafer
 % to send it to a printer see include_run . . .

 palegreen setrgbcolor

 blue 0.6 grey 0.4 rgbmix setrgbcolor

 /darkskin paleorange 0.4 brown 0.6 rgbmix rgbdef
 darkskin setrgbcolor

 /contourcolour [ 0 blue 50 yellow 100 green 150 grey 200 white ]
    altitude rgbinterpolate rgbdef

 paleorange rgb2gray setgray  % same brightness as the paleorange

 /equivalentgray palegreen rgb2gray def

 orange 0.9 adjustbrightness setrgbcolor
 violet palegreen rgb2gray adjustbrightness setrgbcolor

 50 100 500 170 darkblue white    true -0.8 rectgradientfill
 50 270 500 500 white    paleblue true  0.3 rectgradientfill
 250 270 50 100 yellow  red 0.3 radialgradientfill

/points [ 256 360 [0 359 blue] [255 359 orange] [0 60 red] [255 0 violet] ] def
 0 0 1000 1414  points  2.1  pointsgradientfill

[ red black darkgrey ] randomrgb setrgbcolor

/my3olours [ darkgrey  red orange yellow violet ] 3 randomrgbgetn def


DESCRIPTION

This module implements in PostScript some RGB colours and colour-handling procedures to help an artist using PostScript.


COLOURS

colours.ps defines the following colours:

You can use rgbmix and adjustbrightness to mix yourself any other colours that you may need, just like a painter would.
Arbitrary greys are easy to define with dup dup, for example:
    /grey42 0.42 dup dup rgbdef


PROCEDURES

rgbmix rgbinterpolate   rectgradientfill   radialgradientfill   pointsgradientfill
ryb_compliment   colorwheel   rgbdef   rgbget   rgblength
randomrgbget   randomrgbgetn   rgb2gray   adjustbrightness   pathbboxwh   redgreen_colorblind

colour1 weight1   colour2 weight2   rgbmix

The above invocation leaves on the stack, in r g b three-number form, a colour intermediate between colour1 and colour2. The arguments are:
colour1 is the first colour, in r g b three-number form
weight1 is the numerical weight that will be given to the first colour in the mixing
colour2 is the second colour, in r g b three-number form
weight2 is the numerical weight that will be given to the second colour in the mixing

The weights should add up to one, but don't have to; they get normalised to total 1.0 automatically.
rgbmix uses non-linear mixing, to conform to the way the eye sees these things.

[ a1 colour1 .. aN colourN ]   a   rgbinterpolate

The above invocation leaves on the stack, in r g b three-number form, a colour which depends on where the number a lies in relation to the series of numbers a1,a2..aN.

It is expected that a1,a2..aN are in ascending order !
If a is a1 or less, colour1 will be returned,
if a is between a1 and a2, rgbmix is used to interpolate between them,
If a is a2 colour2 will be returned,
if a is between a2 and a3 rgbmix is used to interpolate between them,
if a is aN or more, colourN will be returned.
For example:
[ .5 paleblue .51 white 1 mediumgray ] z rgbinterpolate setrgbcolor
would transform a brownian landscape in z into a sky with clouds ...

x y width height startrgb endrgb vertical convexity   rectgradientfill

The above invocation, conceived as a sort of extension of rectfill, fills the rectangle with a colour-gradient, starting at colour startrgb and ending with endrgb.
If vertical is true, the starting colour is at the bottom (y) and the ending colour at the top (y+height).
If vertical is false, the starting colour is on the left (x) and the ending colour on the right (x+width).
The convexity parameter should lie betwen -1.0 and 1.0. If it is zero, the colour is interpolated linearly; otherwise it is interpolated quadratically, such that if convexity is positive the colour changes fastest at the start (the bottom or left), and if convexity is negative the colour changes fastest towards the end (the top or right).

x y r1 r2 startrgb endrgb convexity   radialgradientfill

The above invocation, conceived in the spirit of rectgradientfill, fills a circular ring with a colour-gradient, starting at colour startrgb at radius r1 and ending with endrgb at radius r2.
The convexity parameter should lie betwen -1.0 and 1.0. If it is zero, the colour is interpolated linearly; otherwise it is interpolated quadratically, such that if convexity is positive the colour changes fastest at the start (r1), and if convexity is negative the colour changes fastest towards the end (r2).

x y width height  points  power   pointsgradientfill

points is an array
    [ Nx Ny [ix1 iy1 r1 g1 b1] [ix2 iy2 r2 g2 b2] ... ]
The first two elements are the number of little rectangles into which the filled area is divided.
The other elements are arrays, with five elements describing a little rectangle whose colour you specify:   ix and iy are the integer coordinates of the little rectangle and can range from zero to Nx - 1 or Ny - 1 respectively, and r g b are the colour.
The ratios of Nx/Ny and width/height should be as close as possible, to keep the little rectangles roughly square.
power should lie between 1.0 and at most perhaps 15.0. Somewhere around 2.0 is generally a good value.
If it is low, each fixed point only influences a short range and most of the area tends to an average colour.
If it is high, the area becomes more dominated by the locally closest point, and so tends towards a jigsaw of pieces with straight fuzzy edges.   And if it is too high, numerical under-runs can occur which cause a division-by-zero error.

r g b   ryb_compliment

This procedure leaves on the stack the colour r2 g2 b2 which is the complimentary colour of r g b as understood by a painter who is used to the Red-Yellow-Blue colour-space.
So the ryb_compliment of red is green, the ryb_compliment of yellow is violet, and so on.
As far as possible, the compliment preserves the brightness and the greyness of the input r g b.  
The compliment of the compliment  r g b ryb_compliment ryb_compliment   is very close to the original r g b but not always completely identical.

angle   colorwheel This procedure leaves on the stack the colour r g b corresponding to a colour-wheel where an angle of 0 means red, 60 means orange, 120 means yellow, 180 means green. 240 means blue and 300 means violet.

/name_of_colour r g b   rgbdef

The above invocation causes name_of_colour to be defined as { r g b } so it's like a three-dimensional version of def.
Note that because a colour has three components, the common /x exch def idiom doesn't work with rgbdef; you'll need something like this instead:
    /mynewcolour 4 1 roll rgbdef

[ red black grey ]   1   rgbget

This extracts the colour black and puts it on the stack (in r g b form), so it's like a three-dimensional version of get.

[ red black grey ]   rgblength

This returns the number of colours in the array, namely 3 in this case, In other words, it uses length and divides by three, and is a very minimal procedure. It also converts to integer using cvi.

[ red black darkgrey ]   randomrgbget

The above invocation chooses at random one of the colours in the array (red, black and darkgrey in this example), and then leaves that colour on the stack (in r g b form).

By default it will make different a choice every time you load the page, so if you need consistency you should invoke srand first.

The function randomrgb is a synonym, retained for backward compatibility.

[ red black darkgrey violet blue ]   3   randomrgbgetn

This invocation leaves on the stack an array of 3 random colours chosen from the given array (i.e. from red, black, darkgrey, violet and blue in this example).

The chosen colours have distinct indices in the given array, so that if the colours of the given array are all distinct, the colours of the returned array will also be distinct.

By default it will make different choices every time you load the page, so if you need consistency you should invoke srand first.

Note that the colours are left on the stack in an array, eg:
  [ violet red ]
so if you want them on the stack raw and unpacked, then add   aload pop   to the end, eg:
  [ red black violet green ] 2 randomrgbgetn aload pop
which leaves on the stack eg:   violet red

r g b   rgb2gray

The above invocation causes the r g b colour to be converted to its equivalent gray value, which is then left on the stack. The conversion follows the NTSC video standard, which determines how a colour television signal is rendered on a black and white television: gray = .3 * red + .59 * green + .11 * blue

Printers and Graphic displays differ widely, and the NTSC standard does not necessarily produce a gray value which you will perceive, on your Graphic display, as having the same luminance as the original colour. If this becomes an issue for you on some particular display, then the callibrate_rgb2gray variable will allow you to callibrate the conversion.

r g b   gray   adjustbrightness

The above invocation causes the r g b colour to be adjusted in brightness until it matches the gray value, as judged by the rgb2gray subroutine. The resulting colour is left on the stack in r g b form.

Where possible, all three components of the colour are scaled by the same factor; this adjusts the Brightness of the colour. But if one of those components would as a result exceed 1.0, then it is fixed at 1.0 and the result is mixed with white until it matches gray; this reduces the Saturation of the colour.

An excellent discussion of the many uses of equiluminant colours of different hues can be found in Margret Livingstone's book Vision and Art, the Biology of Seeing.

pathbboxwh

This is the same as the standard pathbbox procedure, except that it leaves the box on the stack in the form:
  llx lly width height
ready for use by rectclip, rectfill or rectgradientfill.   The standard pathbbox leaves it in the form: llx lly urx ury

For example:
  (a string) charpath clip
  clippath pathbboxwh  red orange false 0.5 rectgradientfill

yesorno redgreen_colorblind

This procedure overwrites the standard setrgbcolor, or restores it.

true redgreen_colorblind   causes all setrgbcolor calls to average their red and green arguments, thus displaying everything as a red/green colourblind person would see it. This means if you're normally-sighted you can check how your work would be perceived by a red/green colourblind person.

false redgreen_colorblind   restores the default setrgbcolor call.


Callibrating rgb2gray to fit your display

Printers and graphic displays differ widely, and the NTSC standard which is used by rgb2gray and adjustbrightness does not necessarily produce a gray value which you will perceive, on your display, as having the same luminance as the original colour. If this becomes an issue for you, a simple one-parameter adjustment is available to help you customise the formula to fit your display. Usage:

 (/home/wherever/ps/lib/colours.ps) run
 . . .
 /callibrate_rgb2gray 0.4 def   % between 0.0 and 1.0
 orange rgb2gray setgray ...

If you set callibrate_rgb2gray to 0.0, then the standard NTSC conversion will be performed. The NTSC formula converts evenly mixed (greyish) colours correctly. But the NTSC formula thinks that red has the same luminance as 0.3 setgray, whereas your printer or display may well show the gray as being much darker. As you increase the value of callibrate_rgb2gray, the purer colours (reddish, greeninsh, blueish) will be converted lighter, without affecting the conversion of the more neutral (greyish) colours. For example, on my CRT, /callibrate_rgb2gray 0.4 def gave the best results. If you leave callibrate_rgb2gray unset, its default value is now 0.15

A PostScript page callibrate_rgb2gray.ps is supplied to help you measure what callibrate_rgb2gray should be to suit a particular display or printer. Various values of callibrate_rgb2gray are printed down the left side of the page; choose the value which gives each grey rectangle in the row the same luminance as its neighbouring colour rectangles. Choose the best compromise value across all the colour columns.

As mentioned, for my CRT the best setting was 0.4, and for my current monitor it is 0.2. I'd enjoy hearing what the optimum is for other devices; if they cluster around a particular value I'll make that the default.


INSTALL

To install: go to www.pjb.com.au/comp/free/colours.ps.txt and save the file to your local disc.
Rename it to colours.ps and move it into some appropriate directory such as ~/ps/lib . . .
Or, first change directory to where you keep your PostScript libraries:
    cd /home/wherever/ps/lib/
(or wherever)   and then either:
    wget -O colours.ps http://www.pjb.com.au/comp/free/colours.ps.txt
or:
    curl http://www.pjb.com.au/comp/free/colours.ps.txt -o colours.ps

Or, get it from gitlab:
    git clone https://gitlab.com/peterbillam/postscriptlib


AUTHOR

Peter J Billam   www.pjb.com.au/comp/contact.html


CHANGES

 20210213 add colorwheel
 20210210 add ryb_compliment
 20201208 add pointsgradientfill
 20200329 add redgreen_colorblind
 20200130 the gray* synonyms now work at last
 20191018 add grey10 grey20 grey30 grey40 grey50 grey60 grey70 grey80 grey90
 20170819 add randomrgbgetn
 20160629 add paleyellow
 20160623 add radialgradientfill
 20160519 add pathbboxwh
 20160515 add darkorange
 20160425 fix the small gap rectgradientfill left at the beginning
 20160421 add randomrgb, useful eg. for foliage
 20140703 add rectgradientfill, useful eg. for art deco and psychedelia
 20060121 callibrate_rgb2gray now defaults to 0.15
 20060121 adjustbrightness defends against division by zero
 20031024 add callibrate_rgb2gray mechanism
 20031020 add pink as synonym for palered
 20031017 add adjustbrightness
 20031016 add rgb2gray
 20030610 some extra colours
 20030313 roll in some stuff from line_drawing.ps
 20030303 rgbinterpolate now working :-)
 20030225 add nonlinearise and nonlinearrgbmix
 20001214 rgbmix does non-linear mixing
 20001213 corrected some colours after visual test
 20001212 Colour-Handling Utilities for Postscript

SEE ALSO

As examples, see www.pjb.com.au/art/posters/ . . .

See also sample1.ps.txt and sample4.ps.txt . . .   Save the file to your local disc, rename it to sample1.ps or sample4.ps and edit it so that the run statement(s) near the beginning point to the directory where line_drawing.ps and colours.ps are installed on your system. Then use GhostView  gv -nosafer  or equivalent to view it. If you wish to print it out, feel free to use something like include_run to roll the run-files in.
For easy viewing, PDF versions of the results are in sample1.pdf and sample4.pdf . . .

See also


Back to P J B Computing or to www.pjb.com.au . . .