#include #include "gdk_imlib.h" #define id _gdk_imlib_data #include "gdk_imlib_private.h" #ifdef HAVE_LIBPNG #include unsigned char * loader_png (FILE * f, int *w, int *h, int *t) { png_structp png_ptr; png_infop info_ptr; unsigned char *data, *ptr, **lines, *ptr2, r, g, b, a; int i, x, y, transp, bit_depth, color_type, interlace_type; png_uint_32 ww, hh; /* Init PNG Reader */ transp = 0; #if 0 /* *Corrupting images on load is better than no image at all */ if (!strcmp("1.0.2", png_libpng_ver)) { fprintf(stderr, "WARNING! You have libpng 1.0.2\n" "It has a known bug that corrupts images on load.\n" "please use 1.0.1. PNG support is disabled.\n"); return NULL; } #endif png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return NULL; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } png_init_io(png_ptr, f); /* Read Header */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &ww, &hh, &bit_depth, &color_type, &interlace_type, NULL, NULL); *w = ww; *h = hh; /* Setup Translators */ if ((color_type == PNG_COLOR_TYPE_PALETTE) || (color_type == PNG_COLOR_TYPE_GRAY)) png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); data = _gdk_malloc_image(*w, *h); if (!data) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } /* SAFE - the malloc_image will fail first */ lines = (unsigned char **)malloc(*h * sizeof(unsigned char *)); if (lines == NULL) { free(data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } for (i = 0; i < *h; i++) { /* SAFE - the malloc_image will fail first */ if ((lines[i] = malloc(*w * (sizeof(unsigned char) * 4))) == NULL) { int n; free(data); for (n = 0; n < i; n++) free(lines[n]); free(lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } } png_read_image(png_ptr, lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ptr = data; if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { r = *ptr2++; a = *ptr2++; if (a < 128) { *ptr++ = 255; *ptr++ = 0; *ptr++ = 255; transp = 1; } else { *ptr++ = r; *ptr++ = r; *ptr++ = r; } } } } else if (color_type == PNG_COLOR_TYPE_GRAY) { for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { r = *ptr2++; ptr2++; *ptr++ = r; *ptr++ = r; *ptr++ = r; } } } else { for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { r = *ptr2++; g = *ptr2++; b = *ptr2++; a = *ptr2++; if (a < 128) { *ptr++ = 255; *ptr++ = 0; *ptr++ = 255; transp = 1; } else { if ((r == 255) && (g == 0) && (b == 255)) r = 254; *ptr++ = r; *ptr++ = g; *ptr++ = b; } } } } for (i = 0; i < *h; i++) free(lines[i]); free(lines); *t = transp; return data; } struct _io_info { unsigned char *data; unsigned char *ptr; unsigned char *end; }; static void _gdk_imlib_png_io_read(png_structp png_ptr, png_bytep data, png_uint_32 size) { struct _io_info *io_ptr; int bytes; io_ptr = (struct _io_info *)png_get_io_ptr(png_ptr); if ((io_ptr->end - io_ptr->ptr) >= size) { memcpy(data, io_ptr->ptr, size); io_ptr->ptr += size; return; } bytes = io_ptr->end - io_ptr->ptr; memcpy(data, io_ptr->ptr, bytes); io_ptr->ptr = io_ptr->end; return; } GdkImlibImage * inline_png(unsigned char *data, int data_size) { GdkImlibImage *im; png_structp png_ptr; png_infop info_ptr; unsigned char *ptr, **lines, *ptr2, r, g, b, a; int i, x, y, transp, bit_depth, color_type, interlace_type; png_uint_32 ww, hh; struct _io_info io_info; char s [64]; #if 0 /* *Corrupting images on load is better than no image at all */ if (!strcmp("1.0.2", png_libpng_ver)) { fprintf(stderr, "WARNING! You have libpng 1.0.2\n" "It has a known bug that corrupts images on load.\n" "please use 1.0.1.\n"); return NULL; } #endif im = malloc(sizeof(GdkImlibImage)); if (!im) return NULL; im->map = NULL; im->rgb_width = 0; im->rgb_height = 0; im->rgb_data = NULL; im->alpha_data = NULL; g_snprintf (s, sizeof (s), "creat_%x_%x", (int)time(NULL), (int)rand()); im->filename = strdup (s); im->width = 0; im->height = 0; im->border.left = 0; im->border.right = 0; im->border.top = 0; im->border.bottom = 0; im->pixmap = 0; im->shape_mask = 0; im->cache = 1; im->mod.gamma = id->mod.gamma; im->mod.brightness = id->mod.brightness; im->mod.contrast = id->mod.contrast; im->rmod.gamma = id->rmod.gamma; im->rmod.brightness = id->rmod.brightness; im->rmod.contrast = id->rmod.contrast; im->gmod.gamma = id->gmod.gamma; im->gmod.brightness = id->gmod.brightness; im->gmod.contrast = id->gmod.contrast; im->bmod.gamma = id->bmod.gamma; im->bmod.brightness = id->bmod.brightness; im->bmod.contrast = id->bmod.contrast; im->shape_color.r = -1; im->shape_color.g = -1; im->shape_color.b = -1; /* Init PNG Reader */ transp = 0; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return NULL; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } io_info.data = data; io_info.ptr = data; io_info.end = data + data_size; png_set_read_fn(png_ptr, (void *)(&io_info), (png_rw_ptr)_gdk_imlib_png_io_read); /* Read Header */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &ww, &hh, &bit_depth, &color_type, &interlace_type, NULL, NULL); im->rgb_width = ww; im->rgb_height = hh; /* Setup Translators */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); im->rgb_data = _gdk_malloc_image(ww, hh); if (!(im->rgb_data)) { free(im->filename); free(im); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } lines = (unsigned char **)malloc(hh * sizeof(unsigned char *)); if (lines == NULL) { free(im->filename); free(im); free(im->rgb_data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } for (i = 0; i < hh; i++) { if ((lines[i] = malloc(ww * (sizeof(unsigned char) * 4))) == NULL) { int n; free(im->filename); free(im); free(im->rgb_data); for (n = 0; n < i; n++) free(lines[n]); free(lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } } png_read_image(png_ptr, lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ptr = im->rgb_data; if ((color_type == PNG_COLOR_TYPE_GRAY) || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) { for (y = 0; y < hh; y++) { ptr2 = lines[y]; for (x = 0; x < ww; x++) { r = *ptr2++; a = *ptr2++; if (a < 128) { *ptr++ = 255; *ptr++ = 0; *ptr++ = 255; transp = 1; } else { *ptr++ = r; *ptr++ = r; *ptr++ = r; } } } } else { for (y = 0; y < hh; y++) { ptr2 = lines[y]; for (x = 0; x < ww; x++) { r = *ptr2++; g = *ptr2++; b = *ptr2++; a = *ptr2++; if (a < 128) { *ptr++ = 255; *ptr++ = 0; *ptr++ = 255; transp = 1; } else { if ((r == 255) && (g == 0) && (b == 255)) r = 254; *ptr++ = r; *ptr++ = g; *ptr++ = b; } } } } for (i = 0; i < hh; i++) free(lines[i]); free(lines); if (transp) { im->shape_color.r = 255; im->shape_color.g = 0; im->shape_color.b = 255; } #if 0 /* Generated data... We can't cache this! */ if (id->cache.on_image) _gdk_imlib_add_image(im, im->filename); #endif _gdk_imlib_calc_map_tables(im); return im; } static unsigned char * _loader_alpha_png (FILE * f, int *w, int *h, int *t, unsigned char **alpha) { png_structp png_ptr; png_infop info_ptr; unsigned char *data, *ptr, **lines, *ptr2, *aptr; int i, x, y, transp, bit_depth, color_type, interlace_type; png_uint_32 ww, hh; /* Init PNG Reader */ transp = 0; png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return NULL; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); return NULL; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } png_init_io(png_ptr, f); /* Read Header */ png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &ww, &hh, &bit_depth, &color_type, &interlace_type, NULL, NULL); *w = ww; *h = hh; /* Setup Translators */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); png_set_strip_16(png_ptr); png_set_packing(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); data = _gdk_malloc_image(*w, *h); if (!data) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } if (color_type != PNG_COLOR_TYPE_GRAY){ *alpha = malloc(*w * *h); if (!*alpha) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } transp = 1; } else { *alpha = NULL; transp = 0; } lines = (unsigned char **)malloc(*h * sizeof(unsigned char *)); if (lines == NULL) { free(data); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } for (i = 0; i < *h; i++) { if ((lines[i] = malloc(*w * (sizeof(unsigned char) * 4))) == NULL) { int n; free(data); free(*alpha); for (n = 0; n < i; n++) free(lines[n]); free(lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } } png_read_image(png_ptr, lines); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ptr = data; aptr = *alpha; if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { unsigned char r; for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { r = *ptr2++; *aptr++ = *ptr2++; *ptr++ = r; *ptr++ = r; *ptr++ = r; } } } else if (color_type == PNG_COLOR_TYPE_GRAY) { unsigned char r; for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { r = *ptr2++; *ptr++ = r; *ptr++ = r; *ptr++ = r; } } } else { for (y = 0; y < *h; y++) { ptr2 = lines[y]; for (x = 0; x < *w; x++) { *ptr++ = *ptr2++; *ptr++ = *ptr2++; *ptr++ = *ptr2++; *aptr++ = *ptr2++; } } } for (i = 0; i < *h; i++) free(lines[i]); free(lines); *t = transp; return data; } GdkImlibImage * loader_alpha_png (char *file) { FILE *f; int w, h, trans; GdkImlibImage *im; unsigned char *data, *alpha; g_return_val_if_fail (file != NULL, NULL); f = fopen (file, "rb"); if (!f) return NULL; data = _loader_alpha_png (f, &w, &h, &trans, &alpha); fclose (f); if (!data) return NULL; im = (GdkImlibImage *) malloc (sizeof (GdkImlibImage)); if (!im){ free (data); if (alpha) free (alpha); return NULL; } memset (im, 0, sizeof (GdkImlibImage)); im->alpha_data = alpha; im->shape_color.r = -1; im->shape_color.g = -1; im->shape_color.b = -1; im->rgb_data = data; im->rgb_width = w; im->rgb_height = h; return im; } gint saver_png (GdkImlibImage *im, char *file, GdkImlibSaveInfo *info) { png_structp png_ptr; png_infop info_ptr; unsigned char *data, *ptr; int x, y; png_bytep row_ptr; png_color_8 sig_bit; FILE *f; f = fopen(file, "wb"); if (f) { png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { fclose(f); return 0; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { fclose(f); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return 0; } if (setjmp(png_ptr->jmpbuf)) { fclose(f); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return 0; } png_init_io(png_ptr, f); png_set_IHDR(png_ptr, info_ptr, im->rgb_width, im->rgb_height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); sig_bit.red = 8; sig_bit.green = 8; sig_bit.blue = 8; sig_bit.alpha = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); png_write_info(png_ptr, info_ptr); png_set_shift(png_ptr, &sig_bit); png_set_packing(png_ptr); if(im->rgb_width >= 0x40000000) { fclose(f); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return 0; } data = malloc(im->rgb_width * 4); if (!data) { fclose(f); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return 0; } for (y = 0; y < im->rgb_height; y++) { ptr = im->rgb_data + (y * im->rgb_width * 3); for (x = 0; x < im->rgb_width; x++) { data[(x << 2) + 0] = *ptr++; data[(x << 2) + 1] = *ptr++; data[(x << 2) + 2] = *ptr++; if ((data[(x << 2) + 0] == im->shape_color.r) && (data[(x << 2) + 1] == im->shape_color.g) && (data[(x << 2) + 2] == im->shape_color.b)) data[(x << 2) + 3] = 0; else data[(x << 2) + 3] = 255; } row_ptr = data; png_write_rows(png_ptr, &row_ptr, 1); } free(data); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, (png_infopp) NULL); fclose(f); return 1; } return 0; } #else unsigned char * loader_png (FILE * f, int *w, int *h, int *t) { return NULL; } gint saver_png (GdkImlibImage *im, char *file, GdkImlibSaveInfo *info) { return 0; } GdkImlibImage * inline_png (unsigned char *data, int data_size) { return NULL; } GdkImlibImage * loader_alpha_png (char *file) { return NULL; } #endif