Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/image.e | 0 | 18 | 0.00% | 0 | 227 | 0.00% | 227 |
Routine | Executed | Lines | Unexecuted | |
read_bitmap() | 0 | 49 | 0.00% | 49 |
unpack() | 0 | 43 | 0.00% | 43 |
putBmpFileHeader() | 0 | 29 | 0.00% | 29 |
putOneRowImage() | 0 | 17 | 0.00% | 17 |
save_bitmap() | 0 | 16 | 0.00% | 16 |
putImage1() | 0 | 14 | 0.00% | 14 |
get_c_block() | 0 | 8 | 0.00% | 8 |
get_rgb_block() | 0 | 8 | 0.00% | 8 |
putColorTable() | 0 | 8 | 0.00% | 8 |
get_rgb() | 0 | 7 | 0.00% | 7 |
get_word() | 0 | 6 | 0.00% | 6 |
get_dword() | 0 | 4 | 0.00% | 4 |
region() | 0 | 4 | 0.00% | 4 |
graphics_point() | 0 | 2 | 0.00% | 2 |
positive_atom() | 0 | 2 | 0.00% | 2 |
row_bytes() | 0 | 2 | 0.00% | 2 |
text_point() | 0 | 2 | 0.00% | 2 |
two_seq() | 0 | 2 | 0.00% | 2 |
# | Executed | |
1 | -- (c) Copyright - See License.txt | |
2 | -- | |
3 | namespace image | |
4 | ||
5 | public include std/graphcst.e | |
6 | include std/convert.e | |
7 | include std/machine.e | |
8 | ||
9 | --**** | |
10 | -- == Graphics - Image Routines | |
11 | -- | |
12 | -- < | |
13 | -- | |
14 | ||
15 | 0 | constant BMPFILEHDRSIZE = 14 |
16 | 0 | constant OLDHDRSIZE = 12, NEWHDRSIZE = 40 |
17 | 0 | constant EOF = -1 |
18 | ||
19 | integer fn, error_code | |
20 | ||
21 | 0 | |
22 | 0 | return length(p) = 2 and p[1] >= 0 and p[2] >= 0 |
23 | end type | |
24 | ||
25 | 0 | |
26 | -- read 2 bytes | |
27 | integer lower, upper | |
28 | ||
29 | 0 | lower = getc(fn) |
30 | 0 | upper = getc(fn) |
31 | 0 | if upper = EOF then |
32 | 0 | error_code = BMP_UNEXPECTED_EOF |
33 | end if | |
34 | 0 | return upper * 256 + lower |
35 | end function | |
36 | ||
37 | 0 | |
38 | -- read 4 bytes | |
39 | integer lower, upper | |
40 | ||
41 | 0 | lower = get_word() |
42 | 0 | upper = get_word() |
43 | 0 | return upper * 65536 + lower |
44 | end function | |
45 | ||
46 | 0 | |
47 | -- read num_bytes bytes | |
48 | sequence s | |
49 | ||
50 | 0 | s = repeat(0, num_bytes) |
51 | 0 | for i = 1 to num_bytes do |
52 | 0 | s[i] = getc(fn) |
53 | 0 | end for |
54 | 0 | if s[$] = EOF then |
55 | 0 | error_code = BMP_UNEXPECTED_EOF |
56 | end if | |
57 | 0 | return s |
58 | end function | |
59 | ||
60 | 0 | |
61 | -- get red, green, blue palette values | |
62 | integer red, green, blue | |
63 | ||
64 | 0 | blue = getc(fn) |
65 | 0 | green = getc(fn) |
66 | 0 | red = getc(fn) |
67 | 0 | if set_size = 4 then |
68 | 0 | if getc(fn) then |
69 | end if | |
70 | end if | |
71 | 0 | return {red, green, blue} |
72 | end function | |
73 | ||
74 | 0 | |
75 | -- reads palette | |
76 | sequence s | |
77 | ||
78 | 0 | s = {} |
79 | 0 | for i = 1 to num_dwords do |
80 | 0 | s = append(s, get_rgb(set_size)) |
81 | 0 | end for |
82 | 0 | if s[$][3] = EOF then |
83 | 0 | error_code = BMP_UNEXPECTED_EOF |
84 | end if | |
85 | 0 | return s |
86 | end function | |
87 | ||
88 | 0 | |
89 | -- number of bytes per row of pixel data | |
90 | 0 | return floor(((BitCount * Width) + 31) / 32) * 4 |
91 | end function | |
92 | ||
93 | 0 | |
94 | -- unpack the 1-d byte sequence into a 2-d sequence of pixels | |
95 | sequence pic_2d, row, bits | |
96 | integer bytes, next_byte, byte | |
97 | ||
98 | 0 | pic_2d = {} |
99 | 0 | bytes = row_bytes(BitCount, Width) |
100 | 0 | next_byte = 1 |
101 | 0 | for i = 1 to Height do |
102 | 0 | row = {} |
103 | 0 | if BitCount = 1 then |
104 | 0 | for j = 1 to bytes do |
105 | 0 | byte = image[next_byte] |
106 | 0 | next_byte += 1 |
107 | 0 | bits = repeat(0, 8) |
108 | 0 | for k = 8 to 1 by -1 do |
109 | 0 | bits[k] = and_bits(byte, 1) |
110 | 0 | byte = floor(byte/2) |
111 | 0 | end for |
112 | 0 | row &= bits |
113 | 0 | end for |
114 | 0 | elsif BitCount = 2 then |
115 | 0 | for j = 1 to bytes do |
116 | 0 | byte = image[next_byte] |
117 | 0 | next_byte += 1 |
118 | 0 | bits = repeat(0, 4) |
119 | 0 | for k = 4 to 1 by -1 do |
120 | 0 | bits[k] = and_bits(byte, 3) |
121 | 0 | byte = floor(byte/4) |
122 | 0 | end for |
123 | 0 | row &= bits |
124 | 0 | end for |
125 | 0 | elsif BitCount = 4 then |
126 | 0 | for j = 1 to bytes do |
127 | 0 | byte = image[next_byte] |
128 | 0 | row = append(row, floor(byte/16)) |
129 | 0 | row = append(row, and_bits(byte, 15)) |
130 | 0 | next_byte += 1 |
131 | 0 | end for |
132 | 0 | elsif BitCount = 8 then |
133 | 0 | row = image[next_byte..next_byte+bytes-1] |
134 | 0 | next_byte += bytes |
135 | else | |
136 | 0 | error_code = BMP_UNSUPPORTED_FORMAT |
137 | 0 | exit |
138 | end if | |
139 | 0 | pic_2d = prepend(pic_2d, row[1..Width]) |
140 | 0 | end for |
141 | 0 | return pic_2d |
142 | end function | |
143 | ||
144 | --**** | |
145 | -- === Bitmap handling | |
146 | -- | |
147 | ||
148 | --** | |
149 | -- Read a bitmap (.BMP) file into a 2-d sequence of sequences (image) | |
150 | -- | |
151 | -- Parameters: | |
152 | -- # ##file_name## : a sequence, the path to a .bmp file to read from. The extension is not assumed if missing. | |
153 | -- | |
154 | -- Returns: | |
155 | -- An **object**, on success, a sequence of the form ##{palette,image}##. On failure, an error code is returned. | |
156 | -- | |
157 | -- Comments: | |
158 | -- In the returned value, the first element is a list of mixtures, each of which defines | |
159 | -- a color, and the second, a list of point rows. Each pixel in a row is represented by its color index. | |
160 | -- | |
161 | -- The file should be in the bitmap format. The most common variations of the format are supported. | |
162 | -- | |
163 | -- Bitmaps of 2, 4, 16 or 256 colors are supported. If the file is not in a good format, an error | |
164 | -- code (atom) is returned instead | |
165 | -- | |
166 | -- | |
167 | -- public constant | |
168 | -- BMP_OPEN_FAILED = 1, | |
169 | -- BMP_UNEXPECTED_EOF = 2, | |
170 | -- BMP_UNSUPPORTED_FORMAT = 3 | |
171 | -- | |
172 | -- | |
173 | -- You can create your own bitmap picture files using Windows Paintbrush and many other | |
174 | -- graphics programs. You can then incorporate these pictures into your Euphoria programs. | |
175 | -- | |
176 | -- Example 1: | |
177 | -- | |
178 | -- | |
179 | -- x = read_bitmap("c:\\windows\\arcade.bmp") | |
180 | -- | |
181 | -- | |
182 | -- Note: | |
183 | -- double backslash needed to get single backslash in a string | |
184 | -- | |
185 | -- See Also: | |
186 | -- [[:save_bitmap]] | |
187 | ||
188 | 0 | |
189 | atom Size | |
190 | integer Type, X_hot, Y_hot, Planes, BitCount | |
191 | atom Width, Height, Compression, OffBits, SizeHeader, | |
192 | SizeImage, XPelsPerMeter, YPelsPerMeter, ClrUsed, | |
193 | ClrImportant, NumColors | |
194 | sequence Palette, Bits, two_d_bits | |
195 | ||
196 | 0 | error_code = 0 |
197 | 0 | fn = open(file_name, "rb") |
198 | 0 | if fn = -1 then |
199 | 0 | return BMP_OPEN_FAILED |
200 | end if | |
201 | 0 | Type = get_word() |
202 | 0 | Size = get_dword() |
203 | 0 | X_hot = get_word() |
204 | 0 | Y_hot = get_word() |
205 | 0 | OffBits = get_dword() |
206 | 0 | SizeHeader = get_dword() |
207 | ||
208 | 0 | if SizeHeader = NEWHDRSIZE then |
209 | 0 | Width = get_dword() |
210 | 0 | Height = get_dword() |
211 | 0 | Planes = get_word() |
212 | 0 | BitCount = get_word() |
213 | 0 | Compression = get_dword() |
214 | 0 | if Compression != 0 then |
215 | 0 | close(fn) |
216 | 0 | return BMP_UNSUPPORTED_FORMAT |
217 | end if | |
218 | 0 | SizeImage = get_dword() |
219 | 0 | XPelsPerMeter = get_dword() |
220 | 0 | YPelsPerMeter = get_dword() |
221 | 0 | ClrUsed = get_dword() |
222 | 0 | ClrImportant = get_dword() |
223 | 0 | NumColors = (OffBits - SizeHeader - BMPFILEHDRSIZE) / 4 |
224 | 0 | if NumColors < 2 or NumColors > 256 then |
225 | 0 | close(fn) |
226 | 0 | return BMP_UNSUPPORTED_FORMAT |
227 | end if | |
228 | 0 | Palette = get_rgb_block(NumColors, 4) |
229 | ||
230 | 0 | elsif SizeHeader = OLDHDRSIZE then |
231 | 0 | Width = get_word() |
232 | 0 | Height = get_word() |
233 | 0 | Planes = get_word() |
234 | 0 | BitCount = get_word() |
235 | 0 | NumColors = (OffBits - SizeHeader - BMPFILEHDRSIZE) / 3 |
236 | 0 | SizeImage = row_bytes(BitCount, Width) * Height |
237 | 0 | Palette = get_rgb_block(NumColors, 3) |
238 | else | |
239 | 0 | close(fn) |
240 | 0 | return BMP_UNSUPPORTED_FORMAT |
241 | end if | |
242 | 0 | if Planes != 1 or Height <= 0 or Width <= 0 then |
243 | 0 | close(fn) |
244 | 0 | return BMP_UNSUPPORTED_FORMAT |
245 | end if | |
246 | 0 | Bits = get_c_block(row_bytes(BitCount, Width) * Height) |
247 | 0 | close(fn) |
248 | 0 | two_d_bits = unpack(Bits, BitCount, Width, Height) |
249 | 0 | if error_code then |
250 | 0 | return error_code |
251 | end if | |
252 | 0 | return {Palette, two_d_bits} |
253 | end function | |
254 | ||
255 | -- type graphics_point(sequence p) | |
256 | -- return length(p) = 2 and p[1] >= 0 and p[2] >= 0 | |
257 | -- end type | |
258 | -- | |
259 | 0 | |
260 | 0 | return length(p) = 2 and p[1] >= 1 and p[2] >= 1 |
261 | and p[1] <= 200 and p[2] <= 500 -- rough sanity check | |
262 | end type | |
263 | ||
264 | 0 | |
265 | 0 | return x >= 1 |
266 | end type | |
267 | ||
268 | integer numXPixels, numYPixels, bitCount, numRowBytes | |
269 | 0 | integer startXPixel =0, startYPixel = 0, endYPixel = 0 |
270 | ||
271 | 0 | |
272 | -- a region on the screen | |
273 | 0 | if atom(r) then |
274 | 0 | return r = 0 |
275 | else | |
276 | 0 | return length(r) = 2 and graphics_point(r[1]) and |
277 | graphics_point(r[2]) | |
278 | end if | |
279 | end type | |
280 | ||
281 | 0 | |
282 | -- a two element sequence, both elements are sequences | |
283 | 0 | return length(s) = 2 and sequence(s[1]) and sequence(s[2]) |
284 | end type | |
285 | ||
286 | 0 | |
287 | integer offBytes | |
288 | ||
289 | -- calculate bitCount, ie, color bits per pixel, (1, 2, 4, 8, or error) | |
290 | 0 | if numColors = 256 then |
291 | 0 | bitCount = 8 -- 8 bits per pixel |
292 | 0 | elsif numColors = 16 then |
293 | 0 | bitCount = 4 -- 4 bits per pixel |
294 | 0 | elsif numColors = 4 then |
295 | 0 | bitCount = 2 -- 2 bits per pixel |
296 | 0 | elsif numColors = 2 then |
297 | 0 | bitCount = 1 -- 1 bit per pixel |
298 | else | |
299 | 0 | error_code = BMP_INVALID_MODE |
300 | 0 | return |
301 | end if | |
302 | ||
303 | 0 | puts(fn, "BM") -- file-type field in the file header |
304 | 0 | offBytes = 4 * numColors + BMPFILEHDRSIZE + NEWHDRSIZE |
305 | 0 | numRowBytes = row_bytes(bitCount, numXPixels) |
306 | -- put total size of the file | |
307 | 0 | puts(fn, int_to_bytes(offBytes + numRowBytes * numYPixels)) |
308 | ||
309 | 0 | puts(fn, {0, 0, 0, 0}) -- reserved fields, must be 0 |
310 | 0 | puts(fn, int_to_bytes(offBytes)) -- offBytes is the offset to the start |
311 | -- of the bitmap information | |
312 | 0 | puts(fn, int_to_bytes(NEWHDRSIZE)) -- size of the secondary header |
313 | 0 | puts(fn, int_to_bytes(numXPixels)) -- width of the bitmap in pixels |
314 | 0 | puts(fn, int_to_bytes(numYPixels)) -- height of the bitmap in pixels |
315 | ||
316 | 0 | puts(fn, {1, 0}) -- planes, must be a word of value 1 |
317 | ||
318 | 0 | puts(fn, {bitCount, 0}) -- bitCount |
319 | ||
320 | 0 | puts(fn, {0, 0, 0, 0}) -- compression scheme |
321 | 0 | puts(fn, {0, 0, 0, 0}) -- size image, not required |
322 | 0 | puts(fn, {0, 0, 0, 0}) -- XPelsPerMeter, not required |
323 | 0 | puts(fn, {0, 0, 0, 0}) -- YPelsPerMeter, not required |
324 | 0 | puts(fn, int_to_bytes(numColors)) -- num colors used in the image |
325 | 0 | puts(fn, int_to_bytes(numColors)) -- num important colors in the image |
326 | 0 | end procedure |
327 | ||
328 | 0 | |
329 | -- write out one row of image data | |
330 | integer j, byte, numBytesFilled | |
331 | ||
332 | 0 | x &= repeat(0, 7) -- 7 zeros is safe enough |
333 | ||
334 | 0 | numBytesFilled = 0 |
335 | 0 | j = 1 |
336 | 0 | while j <= numXPixels do |
337 | 0 | byte = x[j] |
338 | 0 | for k = 1 to numPixelsPerByte - 1 do |
339 | 0 | byte = byte * shift + x[j + k] |
340 | 0 | end for |
341 | ||
342 | 0 | puts(fn, byte) |
343 | 0 | numBytesFilled += 1 |
344 | 0 | j += numPixelsPerByte |
345 | 0 | end while |
346 | ||
347 | 0 | for m = 1 to numRowBytes - numBytesFilled do |
348 | 0 | puts(fn, 0) |
349 | 0 | end for |
350 | 0 | end procedure |
351 | ||
352 | 0 | |
353 | -- Write color table information to the .BMP file. | |
354 | -- palette data is given as a sequence {{r,g,b},..,{r,g,b}}, where each | |
355 | -- r, g, or b value is 0 to 255. | |
356 | ||
357 | 0 | for i = 1 to numColors do |
358 | 0 | puts(fn, pal[i][3]) -- blue first in .BMP file |
359 | 0 | puts(fn, pal[i][2]) -- green second |
360 | 0 | puts(fn, pal[i][1]) -- red third |
361 | 0 | puts(fn, 0) -- reserved, must be 0 |
362 | 0 | end for |
363 | 0 | end procedure |
364 | ||
365 | 0 | |
366 | -- Write image data packed according to the bitCount information, in the order | |
367 | -- last row ... first row. Data for each row is padded to a 4-byte boundary. | |
368 | -- Image data is given as a 2-d sequence in the order first row... last row. | |
369 | object x | |
370 | integer numPixelsPerByte, shift | |
371 | ||
372 | 0 | numPixelsPerByte = 8 / bitCount |
373 | 0 | shift = power(2, bitCount) |
374 | 0 | for i = numYPixels to 1 by -1 do |
375 | 0 | x = image[i] |
376 | 0 | if atom(x) then |
377 | 0 | error_code = BMP_INVALID_MODE |
378 | 0 | return |
379 | 0 | elsif length(x) != numXPixels then |
380 | 0 | error_code = BMP_INVALID_MODE |
381 | 0 | return |
382 | end if | |
383 | 0 | putOneRowImage(x, numPixelsPerByte, shift) |
384 | 0 | end for |
385 | 0 | end procedure |
386 | ||
387 | --** | |
388 | -- Create a .BMP bitmap file, given a palette and a 2-d sequence of sequences of colors. | |
389 | -- | |
390 | -- Parameters: | |
391 | -- # ##palette_n_image## : a {palette, image} pair, like [[:read_bitmap()]] returns | |
392 | -- # ##file_name## : a sequence, the name of the file to save to. | |
393 | -- | |
394 | -- Returns: | |
395 | -- An **integer**, 0 on success. | |
396 | -- | |
397 | -- Comments: | |
398 | -- This routine does the opposite of [[:read_bitmap]](). | |
399 | -- The first element of ##palette_n_image## is a sequence of [[:mixture]]s defining each | |
400 | -- color in the bitmap. The second element is a sequence of sequences of colors. The inner | |
401 | -- sequences must have the same length. | |
402 | -- | |
403 | -- The result will be one of the following codes: | |
404 | -- | |
405 | -- public constant | |
406 | -- BMP_SUCCESS = 0, | |
407 | -- BMP_OPEN_FAILED = 1, | |
408 | -- BMP_INVALID_MODE = 4 -- invalid graphics mode | |
409 | -- -- or invalid argument | |
410 | -- | |
411 | -- | |
412 | -- | |
413 | -- ##save_bitmap##() produces bitmaps of 2, 4, 16, or 256 colors and these can all be read with | |
414 | -- ##read_bitmap##(). Windows Paintbrush and some other tools do not support 4-color bitmaps. | |
415 | -- | |
416 | -- Example 1: | |
417 | -- | |
418 | -- code = save_bitmap({paletteData, imageData}, | |
419 | -- "c:\\example\\a1.bmp") | |
420 | -- | |
421 | -- | |
422 | -- See Also: | |
423 | -- [[:read_bitmap]] | |
424 | ||
425 | 0 | |
426 | sequence color, image | |
427 | integer numColors | |
428 | ||
429 | 0 | error_code = BMP_SUCCESS |
430 | 0 | fn = open(file_name, "wb") |
431 | 0 | if fn = -1 then |
432 | 0 | return BMP_OPEN_FAILED |
433 | end if | |
434 | ||
435 | 0 | color = palette_n_image[1] |
436 | 0 | image = palette_n_image[2] |
437 | 0 | numYPixels = length(image) |
438 | 0 | numXPixels = length(image[1]) -- assume the same length with each row |
439 | 0 | numColors = length(color) |
440 | ||
441 | 0 | putBmpFileHeader(numColors) |
442 | ||
443 | 0 | if error_code = BMP_SUCCESS then |
444 | 0 | putColorTable(numColors, color) |
445 | 0 | putImage1(image) |
446 | end if | |
447 | 0 | close(fn) |
448 | 0 | return error_code |
449 | end function | |
450 |