summaryrefslogtreecommitdiff
path: root/ipl/gprogs/img.icn
blob: 557c41bda72cf4721a1d6788e5d31e6ab0fed306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
############################################################################
#
#	File:     img.icn
#
#	Subject:  Program to create and edit tiny images
#
#	Authors:  Gregg M. Townsend and Nolan Clayton
#
#	Date:     April 9, 2004
#
############################################################################
#
#  This file is in the public domain.
#
############################################################################
#
#  img is a simple editor of Icon image strings and other tiny images.
#  An image size of 64 x 64 pixels is around the practical maximum.
#
#  usage:  img [-cn | -gn] [filename | width [height]]
#
#  -c or -g specifies a palette; the default is -c1.
#
#  An input file may contain an image string or an image readable by Icon.
#  If no filename is given, a new image (default size 16 x 16) is created.
#
#  img brings up a window within which:
#
#	-- clicking on the color palette sets the color of that mouse button
#	-- clicking on the cell grid sets the color of a cell
#	-- shift-clicking on the cell grid sets the button color from the cell
#
#	-- pressing "W" writes the image string to standard output
#	-- pressing "Q" writes the image string and then exits
#	-- pressing "Z" clears all cells to the color of the left mouse button
#	-- pressing "O" or "L" toggles palette outlining or labeling
#	-- pressing "T" sets the left mouse button to '~' the transparent color
#	-- pressing "R" changes pixels matching the right button color
#		to be the color of the left button
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################
#
#  Links: graphics, imscolor
#
############################################################################

#  To Do:
#  clearer display of transparent button & pixels
#  add "save as" function to write GIF (or whatever) file
#  use standard utils for row<->image translation


link graphics, imscolor

$define Border 16		# window border

$define ColorW 12		# width of color indicator
$define ColorH 24		# height of color indicator

$define LMar 150		# left margin of cell area
$define MaxCell 24		# maximum cell size


global rows, imspec		# current image
global palette			# color palette
global palx, paly, palw, palh	# palette display area
global palf			# palette display flags
global buttons			# button colors


#  main program

procedure main(args)
   local wwidth, wheight
   local hcells, vcells, cellsize, x0, y0
   local black, white
   local i, j, x, y, k, e, c
   local imgstr, imgtemp, L

   Window(args)
   wwidth := WAttrib("width")			# window width
   wheight := WAttrib("height")			# window height

   palette := "c1"
   args[1] ? if ="-" then {
      palette := tab(0)
      get(args)
      }

   if *args > 0 & not integer(args[1]) then {	# if filename supplied
      imgstr := readicon(args[1])
      palette := imspalette(imgstr)
      hcells := imswidth(imgstr)              	# cells horizontally
      vcells := imsheight(imgstr)		# cells vertically
      }
   else {
      hcells := integer(args[1]) | 16		# cells horizontally
      vcells := integer(args[2]) | hcells	# cells vertically
      c := PaletteKey(palette, "white")
      imgstr := hcells || "," || palette || "," || repl(c, vcells * hcells)
      }

   cellsize := MaxCell				# cell size on window
   cellsize >:= wheight / (vcells + 4)
   cellsize >:= (wwidth - LMar) / (hcells + 4)
   if cellsize < 2 then
      stop("image is too large for this window")

   palx := Border
   paly := Border + vcells + Border
   palw := LMar - 2 * Border
   palh := wheight - Border - paly
   palf := "u"
   drawpalette(palette, palx, paly, palw, palh, palf)

   x0 := wwidth / 2 - (cellsize * hcells) / 2 + LMar / 2  # UL corner of cells
   y0 := wheight / 2 - (cellsize * vcells) / 2
   Fg("gray")
   every x := x0 to x0 + (hcells - 1) * cellsize by cellsize do
      every y := y0 to y0 + (vcells - 1) * cellsize by cellsize do
         DrawRectangle(x, y, cellsize, cellsize)

   black := PaletteKey(palette, "black")
   white := PaletteKey(palette, "white")
   buttons := table()
   setbutton(&lpress, black)
   setbutton(&mpress, black)
   setbutton(&rpress, white)

   imgtemp := imgstr[find(imspalette(imgstr), imgstr) : 0]
   imgtemp := imgtemp[find(',', imgtemp) + 1 : 0]

   rows := []			# list of row values
   L := ""

   every y := 1 to vcells do {
      every x := 1 to hcells do {
         k := imgtemp[((y - 1) * hcells) + x]
         L ||:= k
         Fg(PaletteColor(palette, k))
         FillRectangle(x0 + ((x - 1) * cellsize),
            y0 + ((y - 1) * cellsize), cellsize, cellsize)
         }
      put(rows, L)
      L :=""
      }

   Fg("gray")
   every x := x0 to x0 + (hcells - 1) * cellsize by cellsize do
      every y := y0 to y0 + (vcells - 1) * cellsize by cellsize do
         DrawRectangle(x, y, cellsize, cellsize)

   newimage()

   repeat case e := Event() of {

      &lpress | &mpress | &rpress | &ldrag | &mdrag | &rdrag: {

         # mouse on palette: set color
         if k := pickpalette(palette, &x - palx, &y - paly, palw, palh) then {
            case e of {
               &lpress | &ldrag:  setbutton(&lpress, k)
               &mpress | &mdrag:  setbutton(&mpress, k)
               &rpress | &rdrag:  setbutton(&rpress, k)
               }
            next
            }

         # mouse on cell: set color
         j := (&x - x0) / cellsize
         i := (&y - y0) / cellsize
         if j < 0 | j >= hcells | i < 0 | i >= vcells then
            next
         x := x0 + j * cellsize + 1
         y := y0 + i * cellsize + 1

         # if shifted, pick color from grid 
         if &shift then {
            k := rows[i + 1, j + 1]
            case e of {
               &lpress | &ldrag:  setbutton(&lpress, k)
               &mpress | &mdrag:  setbutton(&mpress, k)
               &rpress | &rdrag:  setbutton(&rpress, k)
               }
            next
            }

         case e of {
            &lpress | &ldrag:  k := buttons[&lpress]
            &mpress | &mdrag:  k := buttons[&mpress]
            &rpress | &rdrag:  k := buttons[&rpress]
            }
         Fg(PaletteColor(palette, k))
         FillRectangle(x, y, cellsize - 1, cellsize - 1)
         rows[i + 1, j + 1] := k
         newimage()
         }

      !"oOlL": {			# O or L: toggle outlining / labeling
         e := map(e)
         if palf ? find(e) then
            palf := string(palf -- e)
         else
            palf ||:= e
         drawpalette(palette, palx, paly, palw, palh, palf)
         }
      QuitEvents(): {			# Q (etc): quit
         imswrite(, imspec)
         exit()
         }
      !"wW": {				# W: write pattern to stdout
         imswrite(, imspec)
         }

      !"tT": {				# T: set left mouse button transparent
         setbutton(&lpress, '~')
         }

      !"rR": {				# R: replace colors
         colorreplace(buttons[&rpress], buttons[&lpress])

         every y := 1 to vcells do {
            every x := 1 to hcells do {
               k := rows[y][x]
               Fg(PaletteColor(palette, k))
               FillRectangle(x0 + ((x - 1) * cellsize),
                  y0 + ((y - 1) * cellsize), cellsize, cellsize)
               }
            }

         Fg("gray")
         every x := x0 to x0 + (hcells - 1) * cellsize by cellsize do
            every y := y0 to y0 + (vcells - 1) * cellsize by cellsize do
               DrawRectangle(x, y, cellsize, cellsize)
         }


      !"zZ": {				# Z: clear pattern

         k := buttons[&lpress]
         Fg(PaletteColor(palette, k))
         rows := list(vcells, repl(k, hcells))

         FillRectangle(x0, y0, hcells * cellsize, vcells * cellsize)
         Fg("gray")
         every x := x0 to x0 + (hcells - 1) * cellsize by cellsize do
            every y := y0 to y0 + (vcells - 1) * cellsize by cellsize do
               DrawRectangle(x, y, cellsize, cellsize)

         newimage()

         }
      }
end


#  setbutton(event, key) -- set the color of a button

procedure setbutton(e, k)
   local i, x, y

   buttons[e] := k
   i := case e of {
      &lpress: 2
      &mpress: 1
      &rpress: 0
      }
   x := palx + palw - ColorW - i * (ColorW * 3 / 2)
   y := (paly - ColorH) / 2
   Fg(PaletteColor(palette, k))
   FillArc(x, y, ColorW, ColorH)
   Fg("black")
   DrawArc(x, y, ColorW, ColorH)
end


#  newimage() -- update image (in memory and onscreen) from rows

procedure newimage()
   imspec := rowstoims(palette, rows)
   DrawImage(Border, Border, imspec)
   return
end


#  rowstoims(pal, rows) -- convert array of rows into image string

procedure rowstoims(pal, rows)
   local w, s, im

   w := *rows[1] | fail
   im := w || "," || pal || ","
   every s := !rows do {
      if *s ~= w then fail
      im ||:= s
      }
   return im
end


# replacecolor(color1, color2) -- replace color1 with color2

procedure colorreplace(color1, color2)
   local i, j

   every i := 1 to *rows do
      while j := find(color1, rows[i]) do
         rows[i][j] := color2

   newimage()

end


#  readicon(fname) -- read image, returning image string

procedure readicon(fname)
   local res, f, x

   f := open(fname) | stop("cannot open " || fname)

   res := ""

   while x := read(f) do {
      x ? {
         if ="#" then
            next

         ="\""
         res ||:= tab(0)
         }

      if res[-1] == "_" then
            res[-1] := ""
      else
         break
      }
   close(f)

   #
   # Check for reasonably valid image
   #
   if imsheight(res) then
      return res
   else {
      if f := open(fname, "g", "image=" || fname, "canvas=hidden") then {
         res := Capture(f, palette)
         close(f)
         if imsheight(res) then return res
         }
      stop("invalid image: " || fname)
      }

end