77//
88// Copyright(C) 2002-2019 Chris Warren-Smith.
99
10+ #include " common/sberr.h"
1011#include " common/sys.h"
1112#include " common/messages.h"
1213#include " common/pproc.h"
1314#include " common/fs_socket_client.h"
15+ #include " include/var.h"
1416#include " lib/maapi.h"
1517#include " lib/lodepng/lodepng.h"
1618#include " ui/image.h"
1719#include " ui/system.h"
1820#include " ui/rgb.h"
21+ #include < cstdint>
1922
2023#define IMG_X " x"
2124#define IMG_Y " y"
@@ -211,9 +214,47 @@ ImageBuffer *get_image(unsigned bid) {
211214 return result;
212215}
213216
217+ void scaleImage (ImageBuffer* image, var_num_t scaling) {
218+ if (scaling == 1.0 || scaling <= 0.0 ) {
219+ return ;
220+ }
221+
222+ uint16_t xx, yy, w, h;
223+ uint32_t offsetImage, offsetScaledImage;
224+
225+ w = round ((var_num_t )image->_width * scaling);
226+ h = round ((var_num_t )image->_height * scaling);
227+
228+ uint8_t * scaledImage = (uint8_t *)malloc (w * h * 4 );
229+ if (!scaledImage) {
230+ err_throw (ERR_IMAGE_LOAD, " Failed to allocate RAM" );
231+ return ;
232+ }
233+
234+ uint32_t * image32bit = (uint32_t *)image->_image ;
235+ uint32_t * scaledImage32bit = (uint32_t *)scaledImage;
236+
237+ for (yy = 0 ; yy < h; yy++) {
238+ for (xx = 0 ; xx < w; xx++) {
239+ offsetScaledImage = yy * w + xx;
240+ offsetImage = floor ((var_num_t )yy / scaling) * image->_width + floor ((var_num_t )xx / scaling);
241+ scaledImage32bit[offsetScaledImage] = image32bit[offsetImage];
242+ }
243+ }
244+
245+ free (image->_image );
246+ image->_width = w;
247+ image->_height = h;
248+ image->_image = scaledImage;
249+ }
250+
251+ //
252+ // Copy from screen
253+ //
214254ImageBuffer *load_image (var_int_t x) {
215255 var_int_t y, w, h;
216- int count = par_massget (" iii" , &y, &w, &h);
256+ var_num_t scaling = 1.0 ;
257+ int count = par_massget (" iiif" , &y, &w, &h, &scaling);
217258 int width = g_system->getOutput ()->getWidth ();
218259 int height = g_system->getOutput ()->getHeight ();
219260 ImageBuffer *result = nullptr ;
@@ -238,49 +279,92 @@ ImageBuffer *load_image(var_int_t x) {
238279 result->_height = h;
239280 result->_filename = nullptr ;
240281 result->_image = image;
282+ scaleImage (result, scaling);
241283 buffers.add (result);
242284 }
243285 }
244286 return result;
245287}
246288
289+ //
247290// share image buffer from another image variable
291+ //
248292ImageBuffer *load_image (var_t *var) {
249293 ImageBuffer *result = nullptr ;
294+ var_num_t scaling = 1.0 ;
295+
296+ if (code_peek () == kwTYPE_SEP) {
297+ code_skipsep ();
298+ scaling = par_getnum ();
299+ }
300+
250301 if (var->type == V_MAP) {
251302 int bid = map_get_int (var, IMG_BID, -1 );
252303 if (bid != -1 ) {
253- result = get_image ((unsigned )bid);
304+ if (scaling == 1.0 || scaling <= 0.0 ) {
305+ result = get_image ((unsigned )bid);
306+ } else {
307+ ImageBuffer *inputImage = nullptr ;
308+ inputImage = get_image ((unsigned )bid);
309+ uint8_t * imageData = (uint8_t *)malloc (inputImage->_width * inputImage->_height * 4 );
310+ if (!imageData) {
311+ err_throw (ERR_IMAGE_LOAD, " Failed to allocate RAM" );
312+ return result;
313+ }
314+ result = new ImageBuffer;
315+ result->_bid = ++nextId;
316+ result->_width = inputImage->_width ;
317+ result->_height = inputImage->_height ;
318+ result->_filename = nullptr ;
319+ memcpy (imageData, inputImage->_image , inputImage->_width * inputImage->_height * 4 );
320+ result->_image = imageData;
321+ scaleImage (result, scaling);
322+ buffers.add (result);
323+ }
254324 }
255325 } else if (var->type == V_ARRAY && v_maxdim (var) == 2 ) {
256326 int h = ABS (v_ubound (var, 0 ) - v_lbound (var, 0 )) + 1 ;
257327 int w = ABS (v_ubound (var, 1 ) - v_lbound (var, 1 )) + 1 ;
258328 int size = w * h * 4 ;
259- auto image = (uint8_t *)malloc (size);
329+ auto imageData = (uint8_t *)malloc (size);
330+ if (!imageData) {
331+ err_throw (ERR_IMAGE_LOAD, " Failed to allocate RAM" );
332+ return result;
333+ }
260334 for (int y = 0 ; y < h; y++) {
261335 int yoffs = (y * w * 4 );
262336 for (int x = 0 ; x < w; x++) {
263337 int pos = y * w + x;
264338 uint8_t a, r, g, b;
265339 v_get_argb (v_getint (v_elem (var, pos)), a, r, g, b);
266- SET_IMAGE_ARGB (image , yoffs + (x * 4 ), a, r, g, b);
340+ SET_IMAGE_ARGB (imageData , yoffs + (x * 4 ), a, r, g, b);
267341 }
268342 }
269343 result = new ImageBuffer ();
270344 result->_bid = ++nextId;
271345 result->_width = w;
272346 result->_height = h;
273347 result->_filename = nullptr ;
274- result->_image = image;
348+ result->_image = imageData;
349+ scaleImage (result, scaling);
275350 buffers.add (result);
276351 }
277352 return result;
278353}
279354
355+ //
356+ // Load from file
357+ //
280358ImageBuffer *load_image (const unsigned char *buffer, int32_t size) {
281359 ImageBuffer *result = nullptr ;
282360 unsigned w, h;
283361 unsigned char *image;
362+ var_num_t scaling = 1.0 ;
363+
364+ if (code_peek () == kwTYPE_SEP) {
365+ code_skipsep ();
366+ scaling = par_getnum ();
367+ }
284368
285369 unsigned error = decode_png (&image, &w, &h, buffer, size);
286370 if (!error) {
@@ -290,26 +374,38 @@ ImageBuffer *load_image(const unsigned char *buffer, int32_t size) {
290374 result->_height = h;
291375 result->_filename = nullptr ;
292376 result->_image = image;
377+ scaleImage (result, scaling);
293378 buffers.add (result);
294379 } else {
295380 err_throw (ERR_IMAGE_LOAD, lodepng_error_text (error));
296381 }
297382 return result;
298383}
299384
385+ //
386+ // Load from file
387+ //
300388ImageBuffer *load_image (dev_file_t *filep) {
301389 ImageBuffer *result = nullptr ;
302- List_each (ImageBuffer *, it, buffers) {
303- ImageBuffer *next = (*it);
304- if (next->_filename != nullptr && strcmp (next->_filename , filep->name ) == 0 ) {
305- result = next;
306- break ;
307- }
390+ var_num_t scaling = 1.0 ;
391+
392+ if (code_peek () == kwTYPE_SEP) {
393+ code_skipsep ();
394+ scaling = par_getnum ();
308395 }
309396
397+ if (scaling == 1.0 || scaling <= 0.0 ) {
398+ List_each (ImageBuffer *, it, buffers) {
399+ ImageBuffer *next = (*it);
400+ if (next->_filename != nullptr && strcmp (next->_filename , filep->name ) == 0 ) {
401+ result = next;
402+ break ;
403+ }
404+ }
405+ }
310406 if (result == nullptr ) {
311407 unsigned w, h;
312- unsigned char *image ;
408+ unsigned char *imageData ;
313409 unsigned error = 0 ;
314410 unsigned network_error = 0 ;
315411 var_t *var_p;
@@ -322,13 +418,13 @@ ImageBuffer *load_image(dev_file_t *filep) {
322418 } else {
323419 var_p = v_new ();
324420 http_read (filep, var_p);
325- error = decode_png (&image , &w, &h, (unsigned char *)var_p->v .p .ptr , var_p->v .p .length );
421+ error = decode_png (&imageData , &w, &h, (unsigned char *)var_p->v .p .ptr , var_p->v .p .length );
326422 v_free (var_p);
327423 v_detach (var_p);
328424 }
329425 break ;
330426 case ft_stream:
331- error = decode_png_file (&image , &w, &h, filep->name );
427+ error = decode_png_file (&imageData , &w, &h, filep->name );
332428 break ;
333429 default :
334430 error = 1 ;
@@ -344,25 +440,37 @@ ImageBuffer *load_image(dev_file_t *filep) {
344440 result->_width = w;
345441 result->_height = h;
346442 result->_filename = strdup (filep->name );
347- result->_image = image;
443+ result->_image = imageData;
444+ scaleImage (result, scaling);
348445 buffers.add (result);
349446 }
350447 }
351448 return result;
352449}
353450
451+ //
452+ // Create from XPM data
453+ //
354454ImageBuffer *load_xpm_image (char **data) {
355455 unsigned w, h;
356456 unsigned char *image;
357457 unsigned error = xpm_decode32 (&image, &w, &h, data);
358458 ImageBuffer *result = nullptr ;
459+ var_num_t scaling = 1.0 ;
460+
461+ if (code_peek () == kwTYPE_SEP) {
462+ code_skipsep ();
463+ scaling = par_getnum ();
464+ }
465+
359466 if (!error) {
360467 result = new ImageBuffer ();
361468 result->_bid = ++nextId;
362469 result->_width = w;
363470 result->_height = h;
364471 result->_filename = nullptr ;
365472 result->_image = image;
473+ scaleImage (result, scaling);
366474 buffers.add (result);
367475 } else {
368476 err_throw (ERR_IMAGE_LOAD, ERR_XPM_IMAGE);
@@ -480,7 +588,7 @@ void cmd_image_save(var_s *self, var_s *) {
480588 if (!prog_error &&
481589 !encode_png_file (str.v .p .ptr , image->_image , w, h)) {
482590 saved = true ;
483- }
591+ }
484592 v_free (&str);
485593 break ;
486594 default :
@@ -493,7 +601,7 @@ void cmd_image_save(var_s *self, var_s *) {
493601 uint32_t offsetTop = map_get_int (self, IMG_OFFSET_TOP, 0 );
494602 uint32_t wClip = map_get_int (self, IMG_WIDTH, w);
495603 uint32_t hClip = map_get_int (self, IMG_HEIGHT, h);
496-
604+
497605 if (offsetTop < h && offsetLeft < w) {
498606 if (offsetTop + hClip > h) {
499607 hClip = h - offsetTop;
@@ -512,15 +620,15 @@ void cmd_image_save(var_s *self, var_s *) {
512620 uint8_t a, r, g, b;
513621 GET_IMAGE_ARGB (image->_image , yoffs + (x * 4 ), a, r, g, b);
514622 pixel_t px = v_get_argb_px (a, r, g, b);
515- unsigned pos = (y - offsetTop ) * wClip + (x - offsetLeft);
623+ unsigned pos = (y - offsetTop ) * wClip + (x - offsetLeft);
516624 v_setint (v_elem (var, pos), px);
517625 }
518626 }
519627 } else {
520628 v_tomatrix (var, hClip, wClip);
521629 }
522630 saved = true ;
523- }
631+ }
524632 }
525633 }
526634 if (!saved) {
@@ -646,6 +754,16 @@ void screen_dump() {
646754 }
647755}
648756
757+ /*
758+ * I = Image(file [,scale])
759+ * I = Image(image [,scale])
760+ * I = Image(x1,y1,x2,y2 [,scale])
761+ * I = Image(pixmap [,scale])
762+ * I = Image(array [,scale])
763+ * scale > 1: upscale
764+ * scale < 1: downscale
765+ * scale <=0: don't scale
766+ */
649767extern " C" void v_create_image (var_p_t var) {
650768 var_t arg;
651769 ImageBuffer *image = nullptr ;
@@ -659,22 +777,23 @@ extern "C" void v_create_image(var_p_t var) {
659777 image = load_image (filep);
660778 }
661779 break ;
662-
663780 case kwTYPE_LINE:
664781 case kwTYPE_EOC:
665782 break ;
666-
667783 default :
668784 v_init (&arg);
669785 eval (&arg);
786+
670787 if (arg.type == V_STR && !prog_error) {
788+ // Img = Image(FileName)
671789 dev_file_t file;
672790 strlcpy (file.name , arg.v .p .ptr , sizeof (file.name ));
673791 file.type = ft_stream;
674792 image = load_image (&file);
675793 } else if (arg.type == V_ARRAY && v_asize (&arg) > 0 && !prog_error) {
676794 var_p_t elem0 = v_elem (&arg, 0 );
677795 if (elem0->type == V_STR) {
796+ // Img = Image(PixmapData)
678797 char **data = new char *[v_asize (&arg)];
679798 for (unsigned i = 0 ; i < v_asize (&arg); i++) {
680799 var_p_t elem = v_elem (&arg, i);
@@ -683,9 +802,10 @@ extern "C" void v_create_image(var_p_t var) {
683802 image = load_xpm_image (data);
684803 delete [] data;
685804 } else if (v_maxdim (&arg) == 2 ) {
686- // load from 2d array
805+ // Img = Image(Array2D)
687806 image = load_image (&arg);
688807 } else if (elem0->type == V_INT) {
808+ // Create from buffer?
689809 auto *data = new unsigned char [v_asize (&arg)];
690810 for (unsigned i = 0 ; i < v_asize (&arg); i++) {
691811 var_p_t elem = v_elem (&arg, i);
@@ -695,8 +815,10 @@ extern "C" void v_create_image(var_p_t var) {
695815 delete [] data;
696816 }
697817 } else if (arg.type == V_INT && !prog_error) {
818+ // Copy from screen
698819 image = load_image (arg.v .i );
699820 } else {
821+ // Img2 = image(Img1) -> Img2 is pointer to existing buffer Img1
700822 image = load_image (&arg);
701823 }
702824 v_free (&arg);
0 commit comments