1 | // This file is part of SmallBASIC |
2 | // |
3 | // Image handling |
4 | // |
5 | // This program is distributed under the terms of the GPL v2.0 or later |
6 | // Download the GNU Public License (GPL) from www.gnu.org |
7 | // |
8 | // Copyright(C) 2002-2019 Chris Warren-Smith. |
9 | |
10 | #include "common/sys.h" |
11 | #include "common/messages.h" |
12 | #include "common/pproc.h" |
13 | #include "common/fs_socket_client.h" |
14 | #include "lib/maapi.h" |
15 | #include "lib/lodepng/lodepng.h" |
16 | #include "ui/image.h" |
17 | #include "ui/system.h" |
18 | #include "ui/rgb.h" |
19 | |
20 | #define IMG_X "x" |
21 | #define IMG_Y "y" |
22 | #define IMG_OFFSET_TOP "offsetTop" |
23 | #define IMG_OFFSET_LEFT "offsetLeft" |
24 | #define IMG_WIDTH "width" |
25 | #define IMG_HEIGHT "height" |
26 | #define IMG_ZINDEX "zIndex" |
27 | #define IMG_OPACITY "opacity" |
28 | #define IMG_ID "ID" |
29 | #define IMG_BID "BID" |
30 | |
31 | extern System *g_system; |
32 | unsigned nextId = 0; |
33 | strlib::List<ImageBuffer *> buffers; |
34 | |
35 | extern "C" int xpm_decode32(uint8_t **image, unsigned *width, unsigned *height, const char *const *xpm); |
36 | |
37 | void reset_image_cache() { |
38 | buffers.removeAll(); |
39 | } |
40 | |
41 | ImageBuffer::ImageBuffer() : |
42 | _filename(nullptr), |
43 | _image(nullptr), |
44 | _bid(0), |
45 | _width(0), |
46 | _height(0) { |
47 | } |
48 | |
49 | ImageBuffer::ImageBuffer(ImageBuffer &o) : |
50 | _filename(o._filename), |
51 | _image(o._image), |
52 | _bid(o._bid), |
53 | _width(o._width), |
54 | _height(o._height) { |
55 | } |
56 | |
57 | ImageBuffer::~ImageBuffer() { |
58 | free(_filename); |
59 | free(_image); |
60 | _filename = nullptr; |
61 | _image = nullptr; |
62 | } |
63 | |
64 | ImageDisplay::ImageDisplay() : |
65 | Shape(0, 0, 0, 0), |
66 | _offsetLeft(0), |
67 | _offsetTop(0), |
68 | _zIndex(0), |
69 | _opacity(0), |
70 | _id(0), |
71 | _bid(0), |
72 | _buffer(nullptr) { |
73 | } |
74 | |
75 | ImageDisplay::ImageDisplay(ImageDisplay &o) : |
76 | ImageDisplay() { |
77 | copyImage(o); |
78 | } |
79 | |
80 | void ImageDisplay::copyImage(ImageDisplay &o) { |
81 | _x = o._x; |
82 | _y = o._y; |
83 | _offsetLeft = o._offsetLeft; |
84 | _offsetTop = o._offsetTop; |
85 | _width = o._width; |
86 | _height = o._height; |
87 | _zIndex = o._zIndex; |
88 | _opacity = o._opacity; |
89 | _id = o._id; |
90 | _bid = o._bid; |
91 | _buffer = o._buffer; |
92 | } |
93 | |
94 | void ImageDisplay::draw(int x, int y, int w, int h, int cw) { |
95 | if (_buffer != nullptr) { |
96 | MAPoint2d dstPoint; |
97 | MARect srcRect; |
98 | |
99 | dstPoint.x = x; |
100 | dstPoint.y = y; |
101 | srcRect.left = MIN(_buffer->_width, _offsetLeft); |
102 | srcRect.top = MIN(_buffer->_height, _offsetTop); |
103 | srcRect.width = MIN(w, MIN(_buffer->_width, _width)); |
104 | srcRect.height = MIN(h, MIN(_buffer->_height, _height)); |
105 | dev_map_point(&dstPoint.x, &dstPoint.y); |
106 | |
107 | if (unsigned(srcRect.top + srcRect.height) > _buffer->_height) { |
108 | srcRect.height = _buffer->_height - srcRect.top; |
109 | } |
110 | if (unsigned(srcRect.left + srcRect.width) > _buffer->_width) { |
111 | srcRect.width = _buffer->_width - srcRect.left; |
112 | } |
113 | |
114 | maDrawRGB(&dstPoint, _buffer->_image, &srcRect, _opacity, _buffer->_width); |
115 | } |
116 | } |
117 | |
118 | void to_argb(unsigned char *image, unsigned w, unsigned h) { |
119 | #if defined(_SDL) |
120 | // convert from LCT_RGBA to ARGB |
121 | for (unsigned y = 0; y < h; y++) { |
122 | unsigned yoffs = (y * w * 4); |
123 | for (unsigned x = 0; x < w; x++) { |
124 | unsigned offs = yoffs + (x * 4); |
125 | uint8_t r = image[offs + 2]; |
126 | uint8_t b = image[offs + 0]; |
127 | image[offs + 2] = b; |
128 | image[offs + 0] = r; |
129 | } |
130 | } |
131 | #endif |
132 | } |
133 | |
134 | unsigned decode_png(unsigned char **image, unsigned *w, unsigned *h, const unsigned char *buffer, size_t size) { |
135 | unsigned error = lodepng_decode32(image, w, h, buffer, size); |
136 | if (!error) { |
137 | to_argb(*image, *w, *h); |
138 | } |
139 | return error; |
140 | } |
141 | |
142 | unsigned decode_png_file(unsigned char **image, unsigned *w, unsigned *h, const char *filename) { |
143 | unsigned error = lodepng_decode32_file(image, w, h, filename); |
144 | if (!error) { |
145 | to_argb(*image, *w, *h); |
146 | } |
147 | return error; |
148 | } |
149 | |
150 | unsigned encode_png_file(const char *filename, const unsigned char *image, unsigned w, unsigned h) { |
151 | unsigned result; |
152 | #if defined(_SDL) |
153 | unsigned size = w * h * 4; |
154 | auto imageCopy = (uint8_t *)malloc(size); |
155 | if (!imageCopy) { |
156 | // lodepng memory error code |
157 | result = 83; |
158 | } else { |
159 | // convert from ARGB to LCT_RGBA |
160 | for (unsigned y = 0; y < h; y++) { |
161 | unsigned yoffs = (y * w * 4); |
162 | for (unsigned x = 0; x < w; x++) { |
163 | int offs = yoffs + (x * 4); |
164 | uint8_t a, r, g, b; |
165 | GET_IMAGE_ARGB(image, offs, a, r, g, b); |
166 | imageCopy[offs + 3] = a; |
167 | imageCopy[offs + 2] = b; |
168 | imageCopy[offs + 1] = g; |
169 | imageCopy[offs + 0] = r; |
170 | } |
171 | } |
172 | result = lodepng_encode32_file(filename, imageCopy, w, h); |
173 | free(imageCopy); |
174 | } |
175 | #else |
176 | result = lodepng_encode32_file(filename, image, w, h); |
177 | #endif |
178 | return result; |
179 | } |
180 | |
181 | dev_file_t *eval_filep() { |
182 | dev_file_t *result = nullptr; |
183 | code_skipnext(); |
184 | if (code_getnext() == '#') { |
185 | int handle = par_getint(); |
186 | if (!prog_error) { |
187 | result = dev_getfileptr(handle); |
188 | } |
189 | } |
190 | return result; |
191 | } |
192 | |
193 | uint8_t *get_image_data(int x, int y, int w, int h) { |
194 | MARect rc; |
195 | rc.left = x; |
196 | rc.top = y; |
197 | rc.width = w; |
198 | rc.height = h; |
199 | int size = w * h * 4; |
200 | auto result = (uint8_t *)malloc(size); |
201 | if (result != nullptr) { |
202 | g_system->getOutput()->redraw(); |
203 | maGetImageData(HANDLE_SCREEN, result, &rc, w * 4); |
204 | } |
205 | return result; |
206 | } |
207 | |
208 | ImageBuffer *get_image(unsigned bid) { |
209 | ImageBuffer *result = nullptr; |
210 | List_each(ImageBuffer *, it, buffers) { |
211 | ImageBuffer *next = (*it); |
212 | if (next->_bid == (unsigned)bid) { |
213 | result = next; |
214 | break; |
215 | } |
216 | } |
217 | return result; |
218 | } |
219 | |
220 | ImageBuffer *load_image(var_int_t x) { |
221 | var_int_t y, w, h; |
222 | int count = par_massget("iii" , &y, &w, &h); |
223 | int width = g_system->getOutput()->getWidth(); |
224 | int height = g_system->getOutput()->getHeight(); |
225 | ImageBuffer *result = nullptr; |
226 | |
227 | if (prog_error || count == 0 || count == 2) { |
228 | err_throw(ERR_PARAM); |
229 | } else { |
230 | if (count == 1) { |
231 | w = width; |
232 | h = height; |
233 | } else { |
234 | w = MIN(w, width); |
235 | h = MIN(h, height); |
236 | } |
237 | uint8_t* image = get_image_data(x, y, w, h); |
238 | if (image == nullptr) { |
239 | err_throw(ERR_IMAGE_LOAD, "Failed to load screen image" ); |
240 | } else { |
241 | result = new ImageBuffer(); |
242 | result->_bid = ++nextId; |
243 | result->_width = w; |
244 | result->_height = h; |
245 | result->_filename = nullptr; |
246 | result->_image = image; |
247 | buffers.add(result); |
248 | } |
249 | } |
250 | return result; |
251 | } |
252 | |
253 | // share image buffer from another image variable |
254 | ImageBuffer *load_image(var_t *var) { |
255 | ImageBuffer *result = nullptr; |
256 | if (var->type == V_MAP) { |
257 | int bid = map_get_int(var, IMG_BID, -1); |
258 | if (bid != -1) { |
259 | result = get_image((unsigned)bid); |
260 | } |
261 | } else if (var->type == V_ARRAY && v_maxdim(var) == 2) { |
262 | int h = ABS(v_ubound(var, 0) - v_lbound(var, 0)) + 1; |
263 | int w = ABS(v_ubound(var, 1) - v_lbound(var, 1)) + 1; |
264 | int size = w * h * 4; |
265 | auto image = (uint8_t *)malloc(size); |
266 | for (int y = 0; y < h; y++) { |
267 | int yoffs = (y * w * 4); |
268 | for (int x = 0; x < w; x++) { |
269 | int pos = y * w + x; |
270 | uint8_t a, r, g, b; |
271 | v_get_argb(v_getint(v_elem(var, pos)), a, r, g, b); |
272 | SET_IMAGE_ARGB(image, yoffs + (x * 4), a, r, g, b); |
273 | } |
274 | } |
275 | result = new ImageBuffer(); |
276 | result->_bid = ++nextId; |
277 | result->_width = w; |
278 | result->_height = h; |
279 | result->_filename = nullptr; |
280 | result->_image = image; |
281 | buffers.add(result); |
282 | } |
283 | return result; |
284 | } |
285 | |
286 | ImageBuffer *load_image(const unsigned char *buffer, int32_t size) { |
287 | ImageBuffer *result = nullptr; |
288 | unsigned w, h; |
289 | unsigned char *image; |
290 | |
291 | unsigned error = decode_png(&image, &w, &h, buffer, size); |
292 | if (!error) { |
293 | result = new ImageBuffer(); |
294 | result->_bid = ++nextId; |
295 | result->_width = w; |
296 | result->_height = h; |
297 | result->_filename = nullptr; |
298 | result->_image = image; |
299 | buffers.add(result); |
300 | } else { |
301 | err_throw(ERR_IMAGE_LOAD, lodepng_error_text(error)); |
302 | } |
303 | return result; |
304 | } |
305 | |
306 | ImageBuffer *load_image(dev_file_t *filep) { |
307 | ImageBuffer *result = nullptr; |
308 | List_each(ImageBuffer *, it, buffers) { |
309 | ImageBuffer *next = (*it); |
310 | if (next->_filename != nullptr && strcmp(next->_filename, filep->name) == 0) { |
311 | result = next; |
312 | break; |
313 | } |
314 | } |
315 | |
316 | if (result == nullptr) { |
317 | unsigned w, h; |
318 | unsigned char *image; |
319 | unsigned error = 0; |
320 | unsigned network_error = 0; |
321 | var_t *var_p; |
322 | |
323 | switch (filep->type) { |
324 | case ft_http_client: |
325 | // open "http://localhost/image1.gif" as #1 |
326 | if (filep->handle == -1) { |
327 | network_error = 1; |
328 | } else { |
329 | var_p = v_new(); |
330 | http_read(filep, var_p); |
331 | error = decode_png(&image, &w, &h, (unsigned char *)var_p->v.p.ptr, var_p->v.p.length); |
332 | v_free(var_p); |
333 | v_detach(var_p); |
334 | } |
335 | break; |
336 | case ft_stream: |
337 | error = decode_png_file(&image, &w, &h, filep->name); |
338 | break; |
339 | default: |
340 | error = 1; |
341 | break; |
342 | } |
343 | if (network_error) { |
344 | err_throw(ERR_IMAGE_LOAD, ERR_NETWORK); |
345 | } else if (error) { |
346 | err_throw(ERR_IMAGE_LOAD, lodepng_error_text(error)); |
347 | } else { |
348 | result = new ImageBuffer(); |
349 | result->_bid = ++nextId; |
350 | result->_width = w; |
351 | result->_height = h; |
352 | result->_filename = strdup(filep->name); |
353 | result->_image = image; |
354 | buffers.add(result); |
355 | } |
356 | } |
357 | return result; |
358 | } |
359 | |
360 | ImageBuffer *load_xpm_image(char **data) { |
361 | unsigned w, h; |
362 | unsigned char *image; |
363 | unsigned error = xpm_decode32(&image, &w, &h, data); |
364 | ImageBuffer *result = nullptr; |
365 | if (!error) { |
366 | result = new ImageBuffer(); |
367 | result->_bid = ++nextId; |
368 | result->_width = w; |
369 | result->_height = h; |
370 | result->_filename = nullptr; |
371 | result->_image = image; |
372 | buffers.add(result); |
373 | } else { |
374 | err_throw(ERR_IMAGE_LOAD, ERR_XPM_IMAGE); |
375 | } |
376 | return result; |
377 | } |
378 | |
379 | void get_image_display(var_s *self, ImageDisplay *image) { |
380 | image->_bid = map_get_int(self, IMG_BID, -1); |
381 | |
382 | List_each(ImageBuffer *, it, buffers) { |
383 | ImageBuffer *next = (*it); |
384 | if (next->_bid == image->_bid) { |
385 | image->_buffer = next; |
386 | break; |
387 | } |
388 | } |
389 | |
390 | var_int_t x, y, z, op; |
391 | int count = par_massget("iiii" , &x, &y, &z, &op); |
392 | |
393 | if (prog_error || image->_buffer == nullptr || count == 1 || count > 4) { |
394 | err_throw(ERR_PARAM); |
395 | } else { |
396 | // 0, 2, 3, 4 arguments accepted |
397 | if (count >= 2) { |
398 | image->_x = x; |
399 | image->_y = y; |
400 | map_set_int(self, IMG_X, x); |
401 | map_set_int(self, IMG_Y, y); |
402 | } else { |
403 | image->_x = map_get_int(self, IMG_X, -1); |
404 | image->_y = map_get_int(self, IMG_Y, -1); |
405 | } |
406 | if (count >= 3) { |
407 | image->_zIndex = z; |
408 | map_set_int(self, IMG_ZINDEX, z); |
409 | } else { |
410 | image->_zIndex = map_get_int(self, IMG_ZINDEX, -1); |
411 | } |
412 | if (count == 4) { |
413 | image->_opacity = op; |
414 | map_set_int(self, IMG_OPACITY, op); |
415 | } else { |
416 | image->_opacity = map_get_int(self, IMG_OPACITY, -1); |
417 | } |
418 | |
419 | image->_offsetLeft = map_get_int(self, IMG_OFFSET_LEFT, -1); |
420 | image->_offsetTop = map_get_int(self, IMG_OFFSET_TOP, -1); |
421 | image->_width = map_get_int(self, IMG_WIDTH, -1); |
422 | image->_height = map_get_int(self, IMG_HEIGHT, -1); |
423 | image->_id = map_get_int(self, IMG_ID, -1); |
424 | } |
425 | } |
426 | |
427 | // |
428 | // png.show(x, y, zindex, opacity) |
429 | // |
430 | void cmd_image_show(var_s *self, var_s *) { |
431 | ImageDisplay image; |
432 | get_image_display(self, &image); |
433 | if (!prog_error) { |
434 | g_system->getOutput()->addImage(image); |
435 | } |
436 | } |
437 | |
438 | // |
439 | // png.draw(x, y, opacity) |
440 | // |
441 | void cmd_image_draw(var_s *self, var_s *) { |
442 | ImageDisplay image; |
443 | get_image_display(self, &image); |
444 | if (!prog_error) { |
445 | image._opacity = image._zIndex; |
446 | g_system->getOutput()->drawImage(image); |
447 | } |
448 | } |
449 | |
450 | // |
451 | // png.hide() |
452 | // |
453 | void cmd_image_hide(var_s *self, var_s *) { |
454 | int id = map_get_int(self, IMG_ID, -1); |
455 | g_system->getOutput()->removeImage(id); |
456 | } |
457 | |
458 | // |
459 | // Output the image to a PNG file |
460 | // |
461 | // png.save("horse1.png") |
462 | // png.save(#1) |
463 | // |
464 | void cmd_image_save(var_s *self, var_s *) { |
465 | unsigned id = map_get_int(self, IMG_BID, -1); |
466 | ImageBuffer *image = get_image(id); |
467 | var_t *array = nullptr; |
468 | dev_file_t *file = nullptr; |
469 | if (code_peek() == kwTYPE_SEP) { |
470 | file = eval_filep(); |
471 | } else { |
472 | array = par_getvar_ptr(); |
473 | } |
474 | |
475 | bool saved = false; |
476 | if (!prog_error && image != nullptr) { |
477 | unsigned w = image->_width; |
478 | unsigned h = image->_height; |
479 | if (file != nullptr && file->open_flags == DEV_FILE_OUTPUT) { |
480 | if (!encode_png_file(file->name, image->_image, w, h)) { |
481 | saved = true; |
482 | } |
483 | } else if (array != nullptr) { |
484 | v_tomatrix(array, h, w); |
485 | // x0 x1 x2 (w=3,h=2) |
486 | // y0 rgba rgba rgba ypos=0 |
487 | // y1 rgba rgba rgba ypos=12 |
488 | // |
489 | for (unsigned y = 0; y < h; y++) { |
490 | unsigned yoffs = (y * w * 4); |
491 | for (unsigned x = 0; x < w; x++) { |
492 | uint8_t a, r, g, b; |
493 | GET_IMAGE_ARGB(image->_image, yoffs + (x * 4), a, r, g, b); |
494 | pixel_t px = v_get_argb_px(a, r, g, b); |
495 | unsigned pos = y * w + x; |
496 | v_setint(v_elem(array, pos), px); |
497 | } |
498 | } |
499 | saved = true; |
500 | } |
501 | } |
502 | |
503 | if (!saved) { |
504 | err_throw(ERR_IMAGE_SAVE); |
505 | } |
506 | } |
507 | |
508 | |
509 | // |
510 | // Reduces the size of the image |
511 | // arguments: left, top, right, bottom |
512 | // |
513 | // png.clip(10, 10, 10, 10) |
514 | // |
515 | void cmd_image_clip(var_s *self, var_s *) { |
516 | if (self->type == V_MAP) { |
517 | int bid = map_get_int(self, IMG_BID, -1); |
518 | if (bid != -1) { |
519 | ImageBuffer *image = get_image((unsigned)bid); |
520 | var_int_t left, top, right, bottom; |
521 | if (image != nullptr && par_massget("iiii" , &left, &top, &right, &bottom)) { |
522 | map_set_int(self, IMG_OFFSET_LEFT, left); |
523 | map_set_int(self, IMG_OFFSET_TOP, top); |
524 | map_set_int(self, IMG_WIDTH, right); |
525 | map_set_int(self, IMG_HEIGHT, bottom); |
526 | } |
527 | } |
528 | } |
529 | } |
530 | |
531 | void create_image(var_p_t var, ImageBuffer *image) { |
532 | map_init(var); |
533 | map_add_var(var, IMG_X, 0); |
534 | map_add_var(var, IMG_Y, 0); |
535 | map_add_var(var, IMG_OFFSET_TOP, 0); |
536 | map_add_var(var, IMG_OFFSET_LEFT, 0); |
537 | map_add_var(var, IMG_ZINDEX, 100); |
538 | map_add_var(var, IMG_OPACITY, 0); |
539 | map_add_var(var, IMG_ID, ++nextId); |
540 | map_add_var(var, IMG_WIDTH, image->_width); |
541 | map_add_var(var, IMG_HEIGHT, image->_height); |
542 | map_add_var(var, IMG_BID, image->_bid); |
543 | v_create_func(var, "draw" , cmd_image_draw); |
544 | v_create_func(var, "hide" , cmd_image_hide); |
545 | v_create_func(var, "save" , cmd_image_save); |
546 | v_create_func(var, "show" , cmd_image_show); |
547 | v_create_func(var, "clip" , cmd_image_clip); |
548 | } |
549 | |
550 | // loads an image for the form image input type |
551 | ImageDisplay *create_display_image(var_p_t var, const char *name) { |
552 | ImageDisplay *result = nullptr; |
553 | if (name != nullptr && var != nullptr) { |
554 | dev_file_t file; |
555 | strlcpy(file.name, name, sizeof(file.name)); |
556 | file.type = ft_stream; |
557 | ImageBuffer *buffer = load_image(&file); |
558 | if (buffer != nullptr) { |
559 | result = new ImageDisplay(); |
560 | result->_buffer = buffer; |
561 | result->_bid = buffer->_bid; |
562 | result->_width = buffer->_width; |
563 | result->_height = buffer->_height; |
564 | result->_zIndex = 0; |
565 | result->_offsetLeft = map_get_int(var, IMG_OFFSET_LEFT, -1); |
566 | result->_offsetTop = map_get_int(var, IMG_OFFSET_TOP, -1); |
567 | result->_opacity = map_get_int(var, IMG_OPACITY, -1); |
568 | |
569 | if (result->_offsetLeft == -1) { |
570 | result->_offsetLeft = 0; |
571 | } |
572 | if (result->_offsetTop == -1) { |
573 | result->_offsetTop = 0; |
574 | } |
575 | if (result->_opacity == -1) { |
576 | result->_opacity = 0; |
577 | } |
578 | } else { |
579 | err_throw(ERR_IMAGE_LOAD, name); |
580 | } |
581 | } else { |
582 | err_throw(ERR_IMAGE_LOAD, "name field empty" ); |
583 | } |
584 | return result; |
585 | } |
586 | |
587 | void screen_dump() { |
588 | int width = g_system->getOutput()->getWidth(); |
589 | int height = g_system->getOutput()->getHeight(); |
590 | auto image = get_image_data(0, 0, width, height); |
591 | if (image != nullptr) { |
592 | const char *path = gsb_bas_dir; |
593 | #if defined(_ANDROID) |
594 | path = getenv("EXTERNAL_DIR" ); |
595 | #endif |
596 | for (int i = 0; i < 1000; i++) { |
597 | String file; |
598 | if (strstr(path, "://" ) == nullptr) { |
599 | file.append(path); |
600 | } |
601 | if (file.lastChar() != '/') { |
602 | file.append("/" ); |
603 | } |
604 | file.append("sbasic_dump_" ); |
605 | file.append(i); |
606 | file.append(".png" ); |
607 | if (access(file.c_str(), R_OK) != 0) { |
608 | g_system->systemPrint("Saving screen to %s\n" , file.c_str()); |
609 | unsigned error = encode_png_file(file.c_str(), image, width, height); |
610 | if (error) { |
611 | g_system->systemPrint("Error: %s\n" , lodepng_error_text(error)); |
612 | } |
613 | break; |
614 | } |
615 | } |
616 | free(image); |
617 | } |
618 | } |
619 | |
620 | extern "C" void v_create_image(var_p_t var) { |
621 | var_t arg; |
622 | ImageBuffer *image = nullptr; |
623 | dev_file_t *filep = nullptr; |
624 | |
625 | byte code = code_peek(); |
626 | switch (code) { |
627 | case kwTYPE_SEP: |
628 | filep = eval_filep(); |
629 | if (filep != nullptr) { |
630 | image = load_image(filep); |
631 | } |
632 | break; |
633 | |
634 | case kwTYPE_LINE: |
635 | case kwTYPE_EOC: |
636 | break; |
637 | |
638 | default: |
639 | v_init(&arg); |
640 | eval(&arg); |
641 | if (arg.type == V_STR && !prog_error) { |
642 | dev_file_t file; |
643 | strlcpy(file.name, arg.v.p.ptr, sizeof(file.name)); |
644 | file.type = ft_stream; |
645 | image = load_image(&file); |
646 | } else if (arg.type == V_ARRAY && v_asize(&arg) > 0 && !prog_error) { |
647 | var_p_t elem0 = v_elem(&arg, 0); |
648 | if (elem0->type == V_STR) { |
649 | char **data = new char*[v_asize(&arg)]; |
650 | for (unsigned i = 0; i < v_asize(&arg); i++) { |
651 | var_p_t elem = v_elem(&arg, i); |
652 | data[i] = elem->v.p.ptr; |
653 | } |
654 | image = load_xpm_image(data); |
655 | delete [] data; |
656 | } else if (v_maxdim(&arg) == 2) { |
657 | // load from 2d array |
658 | image = load_image(&arg); |
659 | } else if (elem0->type == V_INT) { |
660 | unsigned char *data = new unsigned char[v_asize(&arg)]; |
661 | for (unsigned i = 0; i < v_asize(&arg); i++) { |
662 | var_p_t elem = v_elem(&arg, i); |
663 | data[i] = (unsigned char)elem->v.i; |
664 | } |
665 | image = load_image(data, v_asize(&arg)); |
666 | delete [] data; |
667 | } |
668 | } else if (arg.type == V_INT && !prog_error) { |
669 | image = load_image(arg.v.i); |
670 | } else { |
671 | image = load_image(&arg); |
672 | } |
673 | v_free(&arg); |
674 | break; |
675 | }; |
676 | |
677 | if (image != nullptr) { |
678 | create_image(var, image); |
679 | } else { |
680 | err_throw(ERR_BAD_FILE_HANDLE); |
681 | } |
682 | } |
683 | |