115 lines
2.7 KiB
C
115 lines
2.7 KiB
C
#include "gui.h"
|
|
#include "gui_defs.h"
|
|
#include "x.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <png.h>
|
|
|
|
static void paint(gui *_gui, widget *_w)
|
|
{
|
|
struct gui *g = _gui;
|
|
struct image_widget *w = _w;
|
|
LOGD("PAINT image %p\n", 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;
|
|
}
|