diff --git a/common/utils/T/tracer/Makefile.remote b/common/utils/T/tracer/Makefile.remote index c539a2c3886d2cdf72a69c87559c51cde2aaf210..be8a77250cd7328137f05411b2f6ba68cf91c9ba 100644 --- a/common/utils/T/tracer/Makefile.remote +++ b/common/utils/T/tracer/Makefile.remote @@ -3,7 +3,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. #CFLAGS += -O3 -ffast-math -fomit-frame-pointer -LIBS=-lX11 -lm +LIBS=-lX11 -lm -lpng tracer_remote: remote_old.o plot.o database.o gui.o utils.o gui/gui.a $(CC) $(CFLAGS) -o tracer_remote $^ $(LIBS) diff --git a/common/utils/T/tracer/gui/Makefile b/common/utils/T/tracer/gui/Makefile index fb3a9486d832355c2508755c0c4abd21c1e6992e..370020a8b56a3634931ba8d170974b8893361c13 100644 --- a/common/utils/T/tracer/gui/Makefile +++ b/common/utils/T/tracer/gui/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -g -pthread OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \ gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o \ - timeline.o space.o + timeline.o space.o image.o gui.a: $(OBJS) ar cr gui.a $(OBJS) diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index 208a3c2a5474c81fe61b7a90bdc9693bed44df0f..8ab0f063739d543c8b5f35e084f2ca4205d2ae5c 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -34,6 +34,7 @@ widget *new_textlist(gui *gui, int width, int nlines, int background_color); widget *new_timeline(gui *gui, int width, int number_of_sublines, int subline_height); widget *new_space(gui *gui, int width, int height); +widget *new_image(gui *gui, unsigned char *data, int length); void label_set_clickable(gui *gui, widget *label, int clickable); diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h index dc3559c82c7e14ac685bcfaf93e9e47d39832a8a..ec72bb0e2bb14e8951f8bf7e5d3acda960109de8 100644 --- a/common/utils/T/tracer/gui/gui_defs.h +++ b/common/utils/T/tracer/gui/gui_defs.h @@ -31,7 +31,7 @@ extern int volatile gui_logd; enum widget_type { TOPLEVEL_WINDOW, CONTAINER, POSITIONER, TEXT_LIST, XY_PLOT, BUTTON, LABEL, - TIMELINE, SPACE + TIMELINE, SPACE, IMAGE }; struct widget_list; @@ -154,6 +154,13 @@ struct space_widget { int wanted_height; }; +struct image_widget { + struct widget common; + int width; + int height; + void *x; /* opaque X data (type x_image), used in x.c */ +}; + /*************************************************************************/ /* events */ /*************************************************************************/ diff --git a/common/utils/T/tracer/gui/image.c b/common/utils/T/tracer/gui/image.c new file mode 100644 index 0000000000000000000000000000000000000000..70618239aa66800b64bbd669e7740b4654aec4da --- /dev/null +++ b/common/utils/T/tracer/gui/image.c @@ -0,0 +1,112 @@ +#include "gui.h" +#include "gui_defs.h" +#include "x.h" +#include <stdio.h> +#include <stdlib.h> +#include <png.h> + +static void paint(gui *_gui, widget *_w) +{ + struct gui *g = _gui; + struct image_widget *w = _w; + x_draw_image(g->x, g->xwin, w->x, w->common.x, w->common.y); +} + +static void hints(gui *_gui, widget *_w, int *width, int *height) +{ + struct image_widget *w = _w; + LOGD("HINTS image %p\n", w); + *width = w->width; + *height = w->height; +} + +struct png_reader { + unsigned char *data; + int size; + int pos; +}; + +static void png_readfn(png_structp png_ptr, png_bytep data, png_size_t length) +{ + struct png_reader *r = png_get_io_ptr(png_ptr); + if (length > r->size - r->pos) png_error(png_ptr, "bad png image"); + memcpy(data, r->data + r->pos, length); + r->pos += length; +} + +static void load_image(struct gui *g, struct image_widget *w, + unsigned char *data, int length) +{ + png_structp png_ptr; + png_infop info_ptr; + png_bytepp image; + int width, height, bit_depth, color_type, channels; + unsigned char *img_data; + struct png_reader r; + int i; + + /* unpack PNG data */ + + r.data = data; + r.size = length; + r.pos = 0; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) abort(); + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) abort(); + + if (setjmp(png_jmpbuf(png_ptr))) abort(); + + png_set_read_fn(png_ptr, &r, png_readfn); + + png_read_png(png_ptr, info_ptr, + PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING | + PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_BGR, NULL); + + image = png_get_rows(png_ptr, info_ptr); + + width = png_get_image_width(png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + color_type = png_get_color_type(png_ptr, info_ptr); + channels = png_get_channels(png_ptr, info_ptr); + + if (width < 1 || width > 1000 || height < 1 || height > 1000 || + bit_depth != 8 || color_type != PNG_COLOR_TYPE_RGBA || channels != 4) + { printf("bad image\n"); abort(); } + + img_data = malloc(4 * width * height); if (img_data == NULL) abort(); + for (i = 0; i < height; i++) + memcpy(img_data+i*4*width, image[i], width*4); + + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + /* create the X image */ + w->x = x_create_image(g->x, img_data, width, height); + + free(img_data); + + w->width = width; + w->height = height; +} + +widget *new_image(gui *_gui, unsigned char *data, int length) +{ + struct gui *g = _gui; + struct image_widget *w; + + glock(g); + + w = new_widget(g, IMAGE, sizeof(struct image_widget)); + + load_image(g, w, data, length); + + w->common.paint = paint; + w->common.hints = hints; + + gunlock(g); + + return w; +} diff --git a/common/utils/T/tracer/gui/widget.c b/common/utils/T/tracer/gui/widget.c index 149f4be7f593d2e5ce5eac32499416af4c4361bb..362d2e1e4898c39960033fe206518d902a3ba897 100644 --- a/common/utils/T/tracer/gui/widget.c +++ b/common/utils/T/tracer/gui/widget.c @@ -265,7 +265,7 @@ void widget_dirty(gui *_gui, widget *_this) static const char *names[] = { "TOPLEVEL_WINDOW", "CONTAINER", "POSITIONER", "TEXT_LIST", - "XY_PLOT", "BUTTON", "LABEL", "TIMELINE", "SPACE" + "XY_PLOT", "BUTTON", "LABEL", "TIMELINE", "SPACE", "IMAGE" }; const char *widget_name(enum widget_type type) { @@ -279,6 +279,7 @@ const char *widget_name(enum widget_type type) case LABEL: case TIMELINE: case SPACE: + case IMAGE: return names[type]; } return "UNKNOWN (error)"; diff --git a/common/utils/T/tracer/gui/x.c b/common/utils/T/tracer/gui/x.c index 0a2d1450398ac58220026e96b5c13ee97dc766f2..5fb41b4f9249d55f1bb81c277c7969a31ab358c6 100644 --- a/common/utils/T/tracer/gui/x.c +++ b/common/utils/T/tracer/gui/x.c @@ -2,6 +2,7 @@ #include "x_defs.h" #include "gui_defs.h" #include <X11/Xlib.h> +#include <X11/Xutil.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -111,6 +112,52 @@ x_window *x_create_window(x_connection *_x, int width, int height, return ret; } +x_image *x_create_image(x_connection *_x, unsigned char *data, + int width, int height) +{ + struct x_connection *x = _x; + struct x_image *ret; + XImage *ximage; + XVisualInfo *vs; + XVisualInfo template; + int nvs; + Visual *v; + + ret = calloc(1, sizeof(struct x_image)); if (ret == NULL) OOM; + + template.class = TrueColor; + template.depth = 24; + template.red_mask = 0xff0000; + template.green_mask = 0x00ff00; + template.blue_mask = 0x0000ff; + template.bits_per_rgb = 8; + + vs = XGetVisualInfo(x->d, VisualDepthMask | VisualClassMask | + VisualRedMaskMask | VisualGreenMaskMask | VisualBlueMaskMask | + VisualBitsPerRGBMask, &template, &nvs); + if (vs == NULL || nvs == 0) ERR("no good visual found\n"); + v = vs[0].visual; + XFree(vs); + + ximage = XCreateImage(x->d, v, 24, ZPixmap, 0, + (char*)data, width, height, 32, 0); + if (ximage == NULL) ERR("image creation failed\n"); + + ret->p = XCreatePixmap(x->d, DefaultRootWindow(x->d), width, height, 24); + + XPutImage(x->d, ret->p, DefaultGC(x->d, DefaultScreen(x->d)), + ximage, 0, 0, 0, 0, width, height); + + /* TODO: be sure it's fine to set data to NULL */ + ximage->data = NULL; + XDestroyImage(ximage); + + ret->width = width; + ret->height = height; + + return ret; +} + static struct toplevel_window_widget *find_x_window(struct gui *g, Window id) { struct widget_list *cur; @@ -312,6 +359,16 @@ void x_draw_clipped_string(x_connection *_c, x_window *_w, int color, XSetClipMask(c->d, c->colors[color], None); } +void x_draw_image(x_connection *_c, x_window *_w, x_image *_img, int x, int y) +{ + struct x_connection *c = _c; + struct x_window *w = _w; + struct x_image *img = _img; + + XCopyArea(c->d, img->p, w->p, DefaultGC(c->d, DefaultScreen(c->d)), + 0, 0, img->width, img->height, x, y); +} + void x_draw(x_connection *_c, x_window *_w) { struct x_connection *c = _c; diff --git a/common/utils/T/tracer/gui/x.h b/common/utils/T/tracer/gui/x.h index c1f8d33d89e8831c8a1882ecbf737763c02191fb..aca9868ae0ed568b41ee065a0eb8696774c2c8ca 100644 --- a/common/utils/T/tracer/gui/x.h +++ b/common/utils/T/tracer/gui/x.h @@ -5,12 +5,16 @@ typedef void x_connection; typedef void x_window; +typedef void x_image; x_connection *x_open(void); x_window *x_create_window(x_connection *x, int width, int height, char *title); +x_image *x_create_image(x_connection *x, unsigned char *data, + int width, int height); + int x_connection_fd(x_connection *x); void x_flush(x_connection *x); @@ -42,6 +46,8 @@ void x_draw_clipped_string(x_connection *_c, x_window *_w, int color, int x, int y, const char *t, int clipx, int clipy, int clipwidth, int clipheight); +void x_draw_image(x_connection *c, x_window *w, x_image *img, int x, int y); + /* specials functions to plot many points * you call several times x_add_point() then x_plot_points() */ diff --git a/common/utils/T/tracer/gui/x_defs.h b/common/utils/T/tracer/gui/x_defs.h index 41817d06ceb95ebb1dc1ec6ad11dcd1c0ad72fbf..e5874a1a3bc53ee0d21f064c34566bb5704b6bb4 100644 --- a/common/utils/T/tracer/gui/x_defs.h +++ b/common/utils/T/tracer/gui/x_defs.h @@ -23,4 +23,10 @@ struct x_window { int resize, new_width, new_height; }; +struct x_image { + Pixmap p; + int width; + int height; +}; + #endif /* _X_DEFS_H_ */