Skip to content

Commit 298a1d4

Browse files
authored
Merge pull request #241 from Joe7M/master
Image rescaling for IMAGE()
2 parents bd314e9 + f1336f3 commit 298a1d4

File tree

1 file changed

+144
-22
lines changed

1 file changed

+144
-22
lines changed

src/ui/image.cpp

Lines changed: 144 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
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+
//
214254
ImageBuffer *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+
//
248292
ImageBuffer *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+
//
280358
ImageBuffer *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+
//
300388
ImageBuffer *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+
//
354454
ImageBuffer *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+
*/
649767
extern "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

Comments
 (0)