#!/usr/local/euphoria/bin/exu -- Colours! - A colourful demonstration of Euphoria's graphics. -- Copyright (C) May 2004 Neil Fraser -- http://neil.fraser.name/ -- This program is free software; you can redistribute it and/or -- modify it under the terms of version 2 of the GNU General -- Public License as published by the Free Software Foundation. -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- http://www.gnu.org/ -- Requires Boutell's GD and Sales de Andrade's GD wrapper. include /usr/local/euphoria/include/gd.e -- Requires Aku's CGI support routines. -- (only used to read x/y parameters from URL) include /usr/local/euphoria/include/cgia-en.e parseGet() object param -- Height and width of the image. -- All values work, but 2^n+1 squares are ideal (65x65, 129x129, 257x257, etc). integer cols cols = 257 param = getValue("x") if (sequence(param)) then param = value(param) if sequence(param) and param[1] = GET_SUCCESS and integer(param[2]) then cols = param[2]-2 if cols > 512+1 then -- Limit the width to avoid denial of service attacks on my server. cols = 512+1 end if end if end if integer rows rows = 257 param = getValue("y") if (sequence(param)) then param = value(param) if sequence(param) and param[1] = GET_SUCCESS and integer(param[2]) then rows = param[2]-2 if rows > 512+1 then -- Limit the height to avoid denial of service attacks on my server. rows = 512+1 end if end if end if -- The grid of points that make up the image. object grid grid = repeat(repeat(0, rows), cols) -- Apparently Euphoria doesn't have a built-in abs() function. function abs(atom a) if a > 0 then return a else return -a end if end function -- Pick a random number between two end values. function midpoint(integer end1, integer end2) if (end1 > end2) then return rand(end1 - end2) + end2 end if if (end1 < end2) then return rand(end2 - end1) + end1 end if return end1 end function -- Recursively fill one row. -- Used to bootstrap the recursive area fill. -- Also used to fudge our way out of ?x2 rectangles. procedure fillrow(integer row, integer endleft, integer endright) integer middleX if (endleft + 1 = endright) then return end if -- Set the dot in the middle. middleX = floor((endright - endleft) / 2 + endleft) grid[middleX][row] = midpoint(grid[endleft][row], grid[endright][row]) -- Go fill the two new sub-rows fillrow(row, endleft, middleX) fillrow(row, middleX, endright) end procedure -- Recursively fill one column. -- Used to bootstrap the recursive area fill. -- Also used to fudge our way out of ?x2 rectangles. procedure fillcol(integer col, integer endtop, integer endbottom) integer middleY if (endtop + 1 = endbottom) then return end if -- Set the dot in the middle. middleY = floor((endbottom - endtop) / 2 + endtop) grid[col][middleY] = midpoint(grid[col][endtop], grid[col][endbottom]) -- Go fill the two new sub-columns fillcol(col, endtop, middleY) fillcol(col, middleY, endbottom) end procedure -- Recursively fill the area. procedure fillarea(integer endtop, integer endbottom, integer endleft, integer endright) integer middleX, middleY, centre1, centre2 if ((endleft + 1 = endright) and (endtop + 1 = endbottom)) then -- This is just a 2x2 square. Nothing to do. elsif (endleft + 1 = endright) then -- This is just a 2x? rectangle. Fill in some vertical space. fillcol(endright, endtop, endbottom) elsif (endtop + 1 = endbottom) then -- This is just a ?x2 rectangle. Fill in some horizontal space. fillrow(endbottom, endleft, endright) else -- Wide open space; something to sink our recursive teeth into... -- Set the dot half way along the bottom row. middleX = floor((endright - endleft) / 2 + endleft) grid[middleX][endbottom] = midpoint(grid[endleft][endbottom], grid[endright][endbottom]) -- Set the dot half way along the right column. middleY = floor((endbottom - endtop) / 2 + endtop) grid[endright][middleY] = midpoint(grid[endright][endtop], grid[endright][endbottom]) -- Set the dot in the middle (midpoint of two midpoints). centre1 = midpoint(grid[middleX][endtop], grid[middleX][endbottom]) centre2 = midpoint(grid[endright][middleY], grid[endleft][middleY]) grid[middleX][middleY] = midpoint(centre1, centre2) -- Go fill the four new quadrants. fillarea(endtop, middleY, endleft, middleX) fillarea(middleY, endbottom, endleft, middleX) fillarea(endtop, middleY, middleX, endright) fillarea(middleY, endbottom, middleX, endright) end if end procedure -- Flip a coin to determine which diagonally opposite corners get the master colours. if rand(2) = 1 then grid[1][1] = 0 grid[cols][rows] = 255 grid[cols][1] = rand(255) grid[1][rows] = rand(255) else grid[1][rows] = 0 grid[cols][1] = 255 grid[1][1] = rand(255) grid[cols][rows] = rand(255) end if -- Draw the top row and left column. fillrow(1, 1, cols) fillcol(1, 1, rows) -- Now we have the top edge, the left edge, and the bottom/right dot. -- We are all setup to fill the remaining area. fillarea(1, rows, 1, cols) -- pretty_print(1, grid, {0}) -- RGB colour declarations for the master colours integer c1r, c1g, c1b integer c2r, c2g, c2b c1r = 0 c2r = 0 c1g = 0 c2g = 0 c1b = 0 c2b = 0 while ((abs(c1r - c2r) + abs(c1g - c2g) + abs(c1b - c2b)) < 256) do -- Get random numbers between 0 and 255 c1r = midpoint(0, 255) c1g = midpoint(0, 255) c1b = midpoint(0, 255) c2r = midpoint(0, 255) c2g = midpoint(0, 255) c2b = midpoint(0, 255) -- Keep looping until you get dissimilar colours. end while gdImagePtr image image = gdImageCreateTrueColor(cols+2, rows+2) -- Precompute all 256 colours. sequence colourtable colourtable = {} integer r, g, b for x = 0 to 255 do r = floor(c1r * x / 255 + c2r * (1 - x / 255)) g = floor(c1g * x / 255 + c2g * (1 - x / 255)) b = floor(c1b * x / 255 + c2b * (1 - x / 255)) colourtable = append(colourtable, gdImageColorAllocate(image, r, g, b)) -- ? {r, g, b} end for for x = 1 to cols do for y = 1 to rows do gdImageSetPixel(image, x, y, colourtable[grid[x][y]+1]) end for end for -- Add some text. integer colour colour = gdImageColorResolve(image, 127, 127, 127) object brect brect = gdImageStringFT(image, colour, "/home/fraser/html/software/colours/tahoma.ttf", 8, 3.14/2, cols-1, rows-1, "http://neil.fraser.name/") -- Output the image puts (1, "Content-type: image/png\n\n") include /usr/local/euphoria/include/file.e flush(1) gdImagePng(image, GD_FILE_STDIO)