############################################################################ # # File: imrutils.icn # # Subject: Procedures to deal with image records # # Author: Ralph E. Griswold # # Date: January 23, 2002 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # Procedures to manipulate image strings as records. # # imrcath(imr1, imr2) # concatenates imr1 and imr2 horizontally # # imrcatv(imr1, imr2) # concatenates imr1 and imr2 vertically # # imrcopy(imr) create copy of imr # # imrdraw(win, x, y, imr) # draws an image record # # imrfliph(imr) flips an image record horizontally # # imrflipv(imr) flips an image record vertically # # imrnegative(imr) # produces "negative" of image; intended for # grayscale palettes # # imropen(imr) opens a hidden window with an image record # # imror(imr) forms inclusive "or" of two images # # imrpshift(imr, ir) # shifts colors by mapping rotated palette # # imrrot180(imr) # rotates an image record 180 degrees # # imrrot90cw(imr) # rotates an image record 90 degrees clockwise # # imrshifth(imr, i) # shifts an image record horizontally by i pixels # with wrap-around; positive i to the right, # negative to the left. # # imrshiftv(imr, i) # shifts an image record vertically by i pixels # with wrap-around; positive i to the top, # negative to the bottom. # # imstoimr(s) converts an image string to an image record # # imrtoims(imr) converts an image record to an image string # # Note: All the procedures that produce image records modify their # argument records; they do not return modified copies. # ############################################################################ # # Possible additions: # # Make stripes from one (or more) rows/columns. # # Convert from one palette to another. # ############################################################################ # # Requires: Version 9 graphics # ############################################################################ # # Links: strings, wopen # ############################################################################ link strings link wopen record ImageRecord(width, palette, pixels) procedure imrcath(imr1, imr2) #: horizontally concatenate image records local imr, i, rows1, rows2 if *imr1.pixels / imr1.width ~= *imr2.pixels / imr2.width then fail if imr1.palette ~== imr2.palette then fail imr := ImageRecord() imr.width := imr1.width + imr2.width imr.palette := imr1.palette rows1 := [] imr1.pixels ? { while put(rows1, move(imr1.width)) } rows2 := [] imr2.pixels ? { while put(rows2, move(imr2.width)) } imr.pixels := "" every i := 1 to *rows1 do imr.pixels ||:= rows1[i] || rows2[i] return imr end procedure imrcatv(imr1, imr2) #: vertically concatenate image records local imr if imr1.width ~= imr2.width then fail if imr1.palette ~== imr2.palette then fail imr := ImageRecord() imr.width := imr1.width imr.palette := imr1.palette # CHECK imr.pixels := imr1.pixels || imr2.pixels return imr end procedure imrcopy(imr) return copy(imr) end procedure imrdraw(win, x, y, imr) #: draw image record if type(win) ~== "window" then { win :=: x :=: y :=: imr win := \&window | runerr(140, &window) } /x := 0 /y := 0 return DrawImage(win, x, y, imrtoims(imr)) end procedure imrflipd(imr) #: flip image record diagonally local height, columns, i, row height := *imr.pixels / imr.width columns := list(height, "") imr.pixels ? { while row := move(imr.width) do every i := 1 to imr.width do columns[i] ||:= row[i] } imr.pixels := "" every imr.pixels ||:= !columns imr.width := height return imr end procedure imrfliph(imr) #: flip image record horizontally local pixels pixels := "" imr.pixels ? { while pixels ||:= reverse(move(imr.width)) } imr.pixels := pixels return imr end procedure imrflipv(imr) #: flip image record vertically local pixels pixels := "" imr.pixels ? { while pixels := move(imr.width) || pixels } imr.pixels := pixels return imr end procedure imrnegative(imr) #: form negative of image record local chars chars := PaletteChars(imr.palette) imr.pixels := map(imr.pixels, chars, reverse(chars)) return imr end procedure imropen(imr) #: open window with image record local win win := WOpen("canvas=hidden","size=" || imr.width || "," || *imr.pixels / imr.width) imrdraw(win, 0, 0, imr) | { WClose(win) fail } return win end procedure imrpshift(imr, i) #: map shifted palette local chars chars := PaletteChars(imr.palette) imr.pixels := map(imr.pixels, chars, rotate(chars, i)) return imr end procedure imrrot180(imr) #: rotate image record 180 degrees imr.pixels := reverse(imr.pixels) return imr end procedure imrrot90cw(imr) #: rotate image record 90 deg. clockwise local height, columns, i, row height := *imr.pixels / imr.width columns := list(imr.width, "") imr.pixels ? { while row := move(imr.width) do every i := 1 to imr.width do columns[i] := row[i] || columns[i] } imr.pixels := "" every imr.pixels ||:= !columns imr.width := height return imr end # Note: Since shifted out pixels enter in the top or bottom row, depending # on the direction of the shift, one full pass over the width raises the # image one pixel. procedure imrshifth(imr, i) #: shift image record horizontally imr.pixels := rotate(imr.pixels, i) return imr end # See note on imrshifth() procedure imrshiftv(imr, i) #: shift image record vertically /i := 1 imr.pixels := rotate(imr.pixels, i * imr.width) return imr end procedure imrtoims(imr) #: convert image record to image string return imr.width || "," || imr.palette || "," || imr.pixels end procedure imstoimr(s) #: convert image string to image record local imr imr := ImageRecord() s ? { imr.width := tab(upto(',')) | fail move(1) imr.palette := tab(upto(',')) | fail move(1) imr.pixels := tab(0) } return imr end procedure imror(imr) #: form inclusive "or" of two images local chars chars := PaletteChars(imr.palette) imr.pixels := map(imr.pixels, chars, reverse(chars)) return imr end