############################################################################ # # File: cameleon.icn # # Subject: Program to allow user to change colors in an image # # Author: Ralph E. Griswold # # Date: May 19, 1999 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This application allows the user to change selected color in an image. # The colors are displayed in a palette on the application window. # Clicking on one brings up a color dialog in which the color can be # adjusted. # # The keyboard shortcuts are: # # @O open image File menu # @Q quit the application File menu # @R revert to original colors Colors menu # @S save image File menu # # Note: "cameleon" is a variant spelling of "chameleon". # ############################################################################ # # Requires: Version 9 graphics and mutable colors. # ############################################################################ # # Links: graphics, interact, numbers, tables # ############################################################################ link graphics link interact link numbers link tables global cellsize # size of palette cell global colors # mutable color list global count # table of pixel counts global image_window # window for user image global mutant # image with mutable colors global orig_colors # list of original colors global palette # color selection palette global panel # palette window global pixels # number of pixels in image window global x_pos # target location for mutant window global y_pos $define ColorRows 8 # number of palette rows $define ColorCols 16 # number of palette columns procedure main() local atts, vidgets atts := ui_atts() put(atts, "posx=0", "posy=0") (WOpen ! atts) | stop("*** cannot open application window") vidgets := ui() x_pos := WAttrib("width") + 3 * WAttrib("posx") y_pos := WAttrib("posy") palette := vidgets["palette"] cellsize := palette.uw / ColorCols panel := Clone("bg=black", "dx=" || palette.ux, "dy=" || palette.uy) Clip(panel, 0, 0, palette.uw, palette.uh) clear_palette() GetEvents(vidgets["root"], , shortcuts) end # Set up empty palette grid procedure clear_palette() local x, y Fg(panel, "black") EraseArea(panel) WAttrib(panel, "fillstyle=textured") Pattern(panel, "checkers") Bg(panel, "very dark gray") every x := 1 + (0 to ColorCols) * cellsize do every y := 1 + (0 to ColorRows) * cellsize do FillRectangle(panel, x, y, cellsize - 1, cellsize - 1) WAttrib(panel, "fillstyle=solid") Bg(panel, "black") return end # Handle File menu procedure file_cb(vidget, value) case value[1] of { "open @O" : image_open() "quit @Q" : quit() "revert @R" : image_revert() "save @S" : snapshot(mutant) } return end # Open new image procedure image_open() local i, x, y WClose(\image_window) repeat { if OpenDialog("Open image:") == "Cancel" then fail image_window := WOpen("canvas=hidden", "image=" || dialog_value) | { Notice("Cannot open image.") next } break } mutate(image_window) | fail Raise() # bring application window to front colors := vallist(copy(orig_colors)) clear_palette() i := 0 every y := 1 + (0 to ColorRows - 1) * cellsize do every x := 1 + (0 to ColorCols - 1) * cellsize do { Fg(panel, colors[i +:= 1]) | break break FillRectangle(panel, x, y, cellsize - 1, cellsize - 1) } return end # Save current image procedure image_save() snapshot(\mutant) return end # Restore original image colors procedure image_revert() local old, color every old := key(orig_colors) do { color := orig_colors[old] Color(panel, color, old) } return end # Get mutable colors and window from image procedure mutate() local c, width, height, n, x, y WClose(\mutant) orig_colors := table() count := table(0) width := WAttrib(image_window, "width") height := WAttrib(image_window, "height") pixels := width * height mutant := WOpen("width=" || width, "height=" || height, "posx=" || x_pos, "posy=" || y_pos) | { Notice("Cannot open image_window for mutant colors.") fail } every y := 0 to height - 1 do { x := 0 every c := Pixel(image_window, 0, y, width, 1) do { if not(n := \orig_colors[c]) then { orig_colors[c] := n := NewColor(c) | { Notice("Cannot get mutable color.") WClose(mutant) fail } } count[n] +:= 1 Fg(mutant, n) DrawPoint(mutant, x, y) x +:= 1 } } return end # Handle callbacks on palette procedure palette_cb(vidget, e, x, y) local color, new if e === (&lpress | &mpress | &rpress) then { color := Pixel(x, y, 1, 1) # get pixel color if not integer(color) then fail # not a mutable color new := Color(panel, color) # get color specification if ColorDialog( "Adjust color (" || count[color] || " pixels, " || frn((100.0 * count[color]) / pixels, , 2) || "%):", Color(panel, color), track, color ) == "Okay" then new := dialog_value Color(panel, color, new) Color(mutant, color, new) } return end # Quit the application procedure quit() snapshot(\mutant) exit() end # Handle keyboard shortcuts procedure shortcuts(e) if &meta then case(map(e)) of { "o" : image_open() "q" : quit() "r" : image_revert() "s" : image_save() } return end # Track the color in the color dialog procedure track(color, s) Color(panel, color, s) return end #===<>=== modify using vib; do not remove this marker line procedure ui_atts() return ["size=355,225", "bg=pale gray", "label=chameleon"] end procedure ui(win, cbk) return vsetup(win, cbk, [":Sizer:::0,0,355,225:chameleon",], ["file:Menu:pull::1,0,36,21:File",file_cb, ["open @O","save @S","revert @R","quit @Q"]], ["menubar:Line:::0,21,357,21:",], ["palette:Rect:invisible::19,41,320,160:",palette_cb], ) end #===<>=== end of section maintained by vib