This is the whole of the PHP script that drew the 2008 colour wheel: 64 lines, one section at a time, each with a plain-language explanation. The idea in one sentence: every colour name is printed in its own colour, at an angle set by its hue and a distance from the centre set by its value (the “V” of HSV).
The script needs PHP with the PDFlib extension and a MySQL table of colour names. Colourwheel was written for PHP 5, most likely 5.2.x, and MySQL 5.0 or 5.1 (5.5 also works), in 2008.
Download the plain script · Back to the colour wheel
The file opens with the author's own reminder about PDFlib's text rotation: the angle is absolute (not relative to the previous text), positive means anticlockwise, and 0 points along the horizontal. Everything below leans on that convention.
1 2 3 4 5 | <?php //rotate is absolute //positive is anticlockwise //rotate starts at horizontal. |
The page is a 2000 × 2000 point square and every colour name is set in 12 point type. Change these two numbers to get a bigger or denser wheel.
7 8 | $size = 2000; $fontsize=12; |
new PDFlib() creates a PDF writer from the PDFlib extension. begin_document("","") with an empty filename means “build the file in memory”, which is why the script fetches the bytes with get_buffer() at the end. set_info fills in the PDF's metadata fields.
10 11 12 13 14 15 | $pdf = new PDFlib(); $pdf->begin_document("",""); $pdf->set_info("Creator","colourwheel.php"); $pdf->set_info("Author","Telyn Z."); $pdf->set_info("Title","Colour Wheel"); |
Opens a single page the size of the square, then fills a rectangle covering all of it. The commented-out setcolor line is how the author's note says to uncomment for a black background; PDF's default fill colour is black anyway, so the published wheel is coloured text on black either way. Helvetica is one of the 14 standard PDF fonts, so nothing needs embedding.
17 18 19 20 21 22 23 | $pdf->begin_page_ext($size,$size,""); //$pdf->setcolor("fill","rgb",0,0,0,0); //uncomment this line to get a black background $pdf->rect(0,0,$size,$size); $pdf->fill(); $font = $pdf->load_font("Helvetica","iso8859-1",""); $pdf->setfont($font,$fontsize); |
Defines the circle. ($ox, $oy) is the centre of the page. $radius is 80% of the half-width (800 points), leaving a 10% margin so the longest names at the rim do not run off the page. DEG_TO_RAD is the usual π/180, as PHP's trig functions take radians but the angle arithmetic below is easier in degrees.
25 26 27 28 29 | define("DEG_TO_RAD",M_PI/180); //define the origin $ox = $size/2; $oy = $ox; $radius = $ox - $size/10; |
Connects to a MySQL database called colourwheel and pulls every row of the colours table: the name people gave a colour, its RGB (for painting the text) and its HSV (for placing it). The host, user and password here are placeholders for a local Docker setup, not real credentials. The table was loaded from the Dolores Labs colour-names data set, which is not part of this repository. The loop then handles one colour name per pass.
30 31 32 | $mysql = new MySQLi("mysql","root","password","colourwheel"); $result = $mysql->query("SELECT name,red,green,blue,hue,saturation,value FROM colours"); while($colour = $result->fetch_array()) { |
Hue, saturation, value and RGB are all stored as fractions from 0 to 1. Hue 0 starts at 12 o'clock (−90°) and each extra hue × 360 degrees is subtracted, so as hue increases the name moves anticlockwise round the wheel.
33 34 35 | //Each colour's hsv & rgb are between 0 and 1. $angle = -90; //this puts the angle at the top right now. $angle -= ($colour['hue']*360); //puts the angle in the right place. |
Measures how wide the name is when printed, then decides how far from the centre to anchor it: value × radius (dark colours near the middle, bright ones near the rim), plus half the text width as a nudge so long names do not pile up in the middle. The angle is also converted to radians here.
36 37 38 39 | $width = $pdf->stringwidth($colour['name'],$font,$fontsize); $distance = ($width/2) + ($colour['value']*$radius); //offset text length. $radians = $angle*DEG_TO_RAD; |
Ordinary trigonometry: cos and sin turn (angle, distance) into an x and y offset from the centre. PDF's y axis points up, so the y offset is flipped ($oy - $y) and both values are finally shifted by the centre point.
41 42 43 44 | $x = cos($radians)*$distance; $y = sin($radians)*$distance; $y = $oy-$y; $x += $ox; |
Sets the fill colour to the name's own RGB colour (the last 0 is an unused fourth component, as PDFlib's setcolor takes up to four), then fit_textline places the text at (x, y) rotated by -$angle. That rotation is the same direction as the name's position, so each name reads outwards along its own spoke of the wheel.
46 47 48 | $pdf->setcolor("fill","rgb",$colour['red'],$colour['green'],$colour['blue'],0); $pdf->fit_textline($colour['name'],$x,$y,"rotate=".-$angle); } |
Closes the page and the document, copies the finished file out of PDFlib's memory into a PHP string, and frees the PDFlib object.
50 51 52 53 54 55 56 | $pdf->end_page_ext(""); $pdf->end_document(""); $buffer = $pdf->get_buffer(); $length = strlen($buffer); $pdf->delete(); |
The commented-out header() lines would turn this into a web page that serves the PDF inline (note $len there should be $length). As written, the script just echoes the raw PDF bytes to standard output, so on the command line you would run php colourwheel.php > colourwheel.pdf.
58 59 60 61 62 63 64 | # header("Content-Type: application/pdf"); # header("Content-Length: $len"); # header("Content-Disposition: inline; filename=colourwheel.pdf"); echo $buffer; ?> |