Skip to content

Commit a5fe11b

Browse files
committed
FLTK: Implemented image opacity handling
1 parent dec2440 commit a5fe11b

File tree

3 files changed

+97
-43
lines changed

3 files changed

+97
-43
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2021-06-23 (12.22)
2+
FLTK: Implemented image opacity handling
3+
14
2021-06-12 (12.22)
25
UI: Fix potential memory leak using IMAGE
36
UI: Fix RGB handling with IMAGE

src/platform/fltk/display.cxx

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ struct DrawData {
116116
uint8_t *_image;
117117
uint8_t *_screen;
118118
int _opacity;
119+
int _stride;
120+
int _left;
121+
int _top;
119122
};
120123

121124
// x, y, w are position and width of scan line in image.
@@ -125,35 +128,36 @@ void drawImage(void *data, int x, int y, int w, uchar *out) {
125128
uint8_t *image = drawData->_image;
126129
uint8_t *screen = drawData->_screen;
127130
int opacity = drawData->_opacity;
128-
int scanLine = w * 3;
129-
int offs = y * w * 4;
131+
int scanLine = w * 4;
132+
int i_offs = (drawData->_left + ((y + drawData->_top) * drawData->_stride)) * 4;
133+
int s_offs = y * w * 4;
130134
float op = opacity / 100.0f;
131135

132-
for (int sx = 0; sx < scanLine; sx += 3, offs += 4) {
133-
uint8_t a = image[offs + 3];
134-
uint8_t r = image[offs + 2];
135-
uint8_t g = image[offs + 1];
136-
uint8_t b = image[offs + 0];
137-
uint8_t dR = screen[offs + 2];
138-
uint8_t dG = screen[offs + 1];
139-
uint8_t dB = screen[offs + 0];
136+
for (int sx = 0; sx < scanLine; sx += 4, i_offs += 4, s_offs += 4) {
137+
uint8_t a = image[i_offs + 3];
138+
uint8_t r = image[i_offs + 2];
139+
uint8_t g = image[i_offs + 1];
140+
uint8_t b = image[i_offs + 0];
141+
uint8_t sR = screen[s_offs + 2];
142+
uint8_t sG = screen[s_offs + 1];
143+
uint8_t sB = screen[s_offs + 0];
140144
if (opacity > 0 && opacity < 100 && a > 64) {
141-
dR = (op * r) + ((1 - op) * dR);
142-
dG = (op * g) + ((1 - op) * dG);
143-
dB = (op * b) + ((1 - op) * dB);
145+
sR = (op * r) + ((1 - op) * sR);
146+
sG = (op * g) + ((1 - op) * sG);
147+
sB = (op * b) + ((1 - op) * sB);
144148
} else {
145-
dR = dR + ((r - dR) * a / 255);
146-
dG = dG + ((g - dG) * a / 255);
147-
dB = dB + ((b - dB) * a / 255);
149+
sR = sR + ((r - sR) * a / 255);
150+
sG = sG + ((g - sG) * a / 255);
151+
sB = sB + ((b - sB) * a / 255);
148152
}
149153
out[sx + 3] = a;
150-
out[sx + 2] = dR;
151-
out[sx + 1] = dG;
152-
out[sx + 0] = dB;
154+
out[sx + 2] = sR;
155+
out[sx + 1] = sG;
156+
out[sx + 0] = sB;
153157
}
154158
}
155159

156-
void Canvas::drawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *srcRect, int opacity, int bytesPerLine) {
160+
void Canvas::drawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *srcRect, int opacity, int stride) {
157161
int x = dstPoint->x;
158162
int y = dstPoint->y;
159163
int w = srcRect->width;
@@ -162,10 +166,13 @@ void Canvas::drawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *s
162166
data._image = (uint8_t *)src;
163167
data._opacity = opacity;
164168
data._screen = (uint8_t *)calloc(w * h * 4, 1);
169+
data._stride = stride;
170+
data._left = srcRect->left;
171+
data._top = srcRect->top;
165172

166173
fl_begin_offscreen(_offscreen);
167174
fl_read_image(data._screen, x, y, w, h, 1);
168-
fl_draw_image(drawImage, (void *)&data, x, y, w, h, 3);
175+
fl_draw_image(drawImage, (void *)&data, x, y, w, h, 4);
169176
fl_end_offscreen();
170177
free(data._screen);
171178
}
@@ -199,7 +206,7 @@ void Canvas::fillRect(int left, int top, int width, int height, Fl_Color color)
199206
fl_end_offscreen();
200207
}
201208

202-
void Canvas::getImageData(uint8_t *image, const MARect *srcRect, int bytesPerLine) {
209+
void Canvas::getImageData(uint8_t *image, const MARect *srcRect, int stride) {
203210
fl_begin_offscreen(_offscreen);
204211
unsigned x = srcRect->left;
205212
unsigned y = srcRect->top;
@@ -391,10 +398,10 @@ void maDrawText(int left, int top, const char *str, int length) {
391398
}
392399
}
393400

394-
void maDrawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *srcRect, int opacity, int bytesPerLine) {
401+
void maDrawRGB(const MAPoint2d *dstPoint, const void *src, const MARect *srcRect, int opacity, int stride) {
395402
Canvas *canvas = graphics->getDrawTarget();
396403
if (canvas) {
397-
canvas->drawRGB(dstPoint, src, srcRect, opacity, bytesPerLine);
404+
canvas->drawRGB(dstPoint, src, srcRect, opacity, stride);
398405
}
399406
}
400407

@@ -443,12 +450,12 @@ void maDestroyPlaceholder(MAHandle maHandle) {
443450
delete canvas;
444451
}
445452

446-
void maGetImageData(MAHandle maHandle, void *dst, const MARect *srcRect, int bytesPerLine) {
453+
void maGetImageData(MAHandle maHandle, void *dst, const MARect *srcRect, int stride) {
447454
Canvas *canvas = (Canvas *)maHandle;
448455
if (canvas == HANDLE_SCREEN) {
449456
canvas = graphics->getScreen();
450457
}
451-
canvas->getImageData((uint8_t *)dst, srcRect, bytesPerLine);
458+
canvas->getImageData((uint8_t *)dst, srcRect, stride);
452459
}
453460

454461
MAHandle maSetDrawTarget(MAHandle maHandle) {

src/ui/image.cpp

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ uint8_t *get_image_data(int x, int y, int w, int h) {
191191
return result;
192192
}
193193

194+
195+
ImageBuffer *get_image(unsigned bid) {
196+
ImageBuffer *result = nullptr;
197+
List_each(ImageBuffer *, it, buffers) {
198+
ImageBuffer *next = (*it);
199+
if (next->_bid == (unsigned)bid) {
200+
result = next;
201+
break;
202+
}
203+
}
204+
return result;
205+
}
206+
194207
ImageBuffer *load_image(var_int_t x) {
195208
var_int_t y, w, h;
196209
int count = par_massget("iii", &y, &w, &h);
@@ -230,13 +243,7 @@ ImageBuffer *load_image(var_t *var) {
230243
if (var->type == V_MAP) {
231244
int bid = map_get_int(var, IMG_BID, -1);
232245
if (bid != -1) {
233-
List_each(ImageBuffer *, it, buffers) {
234-
ImageBuffer *next = (*it);
235-
if (next->_bid == (unsigned)bid) {
236-
result = next;
237-
break;
238-
}
239-
}
246+
result = get_image((unsigned)bid);
240247
}
241248
} else if (var->type == V_ARRAY && v_maxdim(var) == 2) {
242249
int w = ABS(v_lbound(var, 0) - v_ubound(var, 0)) + 1;
@@ -406,6 +413,9 @@ void get_image_display(var_s *self, ImageDisplay *image) {
406413
}
407414
}
408415

416+
//
417+
// png.show(x, y, zindex, opacity)
418+
//
409419
void cmd_image_show(var_s *self, var_s *) {
410420
ImageDisplay image;
411421
get_image_display(self, &image);
@@ -414,6 +424,9 @@ void cmd_image_show(var_s *self, var_s *) {
414424
}
415425
}
416426

427+
//
428+
// png.draw(x, y, opacity)
429+
//
417430
void cmd_image_draw(var_s *self, var_s *) {
418431
ImageDisplay image;
419432
get_image_display(self, &image);
@@ -423,22 +436,23 @@ void cmd_image_draw(var_s *self, var_s *) {
423436
}
424437
}
425438

439+
//
440+
// png.hide()
441+
//
426442
void cmd_image_hide(var_s *self, var_s *) {
427443
int id = map_get_int(self, IMG_ID, -1);
428444
g_system->getOutput()->removeImage(id);
429445
}
430446

447+
//
448+
// Output the image to a PNG file
449+
//
450+
// png.save("horse1.png")
451+
// png.save(#1)
452+
//
431453
void cmd_image_save(var_s *self, var_s *) {
432454
unsigned id = map_get_int(self, IMG_BID, -1);
433-
ImageBuffer *image = nullptr;
434-
List_each(ImageBuffer *, it, buffers) {
435-
ImageBuffer *next = (*it);
436-
if (next->_bid == id) {
437-
image = next;
438-
break;
439-
}
440-
}
441-
455+
ImageBuffer *image = get_image(id);
442456
var_t *array = nullptr;
443457
dev_file_t *file = nullptr;
444458
if (code_peek() == kwTYPE_SEP) {
@@ -481,13 +495,42 @@ void cmd_image_save(var_s *self, var_s *) {
481495
}
482496
}
483497

498+
499+
//
500+
// Reduces the size of the image
501+
// arguments: left, top, right, bottom
502+
//
503+
// png.clip(10, 10, 10, 10)
504+
//
505+
void cmd_image_clip(var_s *self, var_s *) {
506+
bool updated = false;
507+
if (self->type == V_MAP) {
508+
int bid = map_get_int(self, IMG_BID, -1);
509+
if (bid != -1) {
510+
ImageBuffer *image = get_image((unsigned)bid);
511+
var_int_t left, top, right, bottom;
512+
if (image != nullptr && par_massget("iiii", &left, &top, &right, &bottom) == 4 &&
513+
left >= 0 && left < image->_width && top >= 0 && top < image->_height) {
514+
map_set_int(self, IMG_OFFSET_LEFT, left);
515+
map_set_int(self, IMG_OFFSET_TOP, top);
516+
map_set_int(self, IMG_WIDTH, right);
517+
map_set_int(self, IMG_HEIGHT, bottom);
518+
updated = true;
519+
}
520+
}
521+
}
522+
if (!updated) {
523+
err_throw(ERR_PARAM);
524+
}
525+
}
526+
484527
void create_image(var_p_t var, ImageBuffer *image) {
485528
map_init(var);
486529
map_add_var(var, IMG_X, 0);
487530
map_add_var(var, IMG_Y, 0);
488531
map_add_var(var, IMG_OFFSET_TOP, 0);
489532
map_add_var(var, IMG_OFFSET_LEFT, 0);
490-
map_add_var(var, IMG_ZINDEX, 1);
533+
map_add_var(var, IMG_ZINDEX, 100);
491534
map_add_var(var, IMG_OPACITY, 0);
492535
map_add_var(var, IMG_ID, ++nextId);
493536
map_add_var(var, IMG_WIDTH, image->_width);
@@ -497,6 +540,7 @@ void create_image(var_p_t var, ImageBuffer *image) {
497540
v_create_func(var, "hide", cmd_image_hide);
498541
v_create_func(var, "save", cmd_image_save);
499542
v_create_func(var, "show", cmd_image_show);
543+
v_create_func(var, "clip", cmd_image_clip);
500544
}
501545

502546
// loads an image for the form image input type

0 commit comments

Comments
 (0)