diff options
Diffstat (limited to 'clients/cairo-util.c')
-rw-r--r-- | clients/cairo-util.c | 358 |
1 files changed, 14 insertions, 344 deletions
diff --git a/clients/cairo-util.c b/clients/cairo-util.c index 4257590..1f8d307 100644 --- a/clients/cairo-util.c +++ b/clients/cairo-util.c @@ -31,12 +31,7 @@ #include <cairo.h> #include "cairo-util.h" -#include <jpeglib.h> -#include <png.h> - -#ifdef HAVE_WEBP -#include <webp/decode.h> -#endif +#include "../shared/config-parser.h" #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -297,344 +292,19 @@ rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius) cairo_close_path(cr); } -static void -swizzle_row(JSAMPLE *row, JDIMENSION width) -{ - JSAMPLE *s; - uint32_t *d; - - s = row + (width - 1) * 3; - d = (uint32_t *) (row + (width - 1) * 4); - while (s >= row) { - *d = 0xff000000 | (s[0] << 16) | (s[1] << 8) | (s[2] << 0); - s -= 3; - d--; - } -} - -static void -error_exit(j_common_ptr cinfo) -{ - longjmp(cinfo->client_data, 1); -} - -static cairo_surface_t * -load_jpeg(FILE *fp) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - int stride, i, first; - JSAMPLE *data, *rows[4]; - jmp_buf env; - - cinfo.err = jpeg_std_error(&jerr); - jerr.error_exit = error_exit; - cinfo.client_data = env; - if (setjmp(env)) - return NULL; - - jpeg_create_decompress(&cinfo); - - jpeg_stdio_src(&cinfo, fp); - - jpeg_read_header(&cinfo, TRUE); - - cinfo.out_color_space = JCS_RGB; - jpeg_start_decompress(&cinfo); - - stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, - cinfo.output_width); - data = malloc(stride * cinfo.output_height); - if (data == NULL) { - fprintf(stderr, "couldn't allocate image data\n"); - return NULL; - } - - while (cinfo.output_scanline < cinfo.output_height) { - first = cinfo.output_scanline; - for (i = 0; i < ARRAY_LENGTH(rows); i++) - rows[i] = data + (first + i) * stride; - - jpeg_read_scanlines(&cinfo, rows, ARRAY_LENGTH(rows)); - for (i = 0; first + i < cinfo.output_scanline; i++) - swizzle_row(rows[i], cinfo.output_width); - } - - jpeg_finish_decompress(&cinfo); - - jpeg_destroy_decompress(&cinfo); - - return cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_RGB24, - cinfo.output_width, - cinfo.output_height, - stride); -} - -static inline int -multiply_alpha(int alpha, int color) -{ - int temp = (alpha * color) + 0x80; - - return ((temp + (temp >> 8)) >> 8); -} - -static void -premultiply_data(png_structp png, - png_row_infop row_info, - png_bytep data) -{ - unsigned int i; - png_bytep p; - - for (i = 0, p = data; i < row_info->rowbytes; i += 4, p += 4) { - png_byte alpha = p[3]; - uint32_t w; - - if (alpha == 0) { - w = 0; - } else { - png_byte red = p[0]; - png_byte green = p[1]; - png_byte blue = p[2]; - - if (alpha != 0xff) { - red = multiply_alpha(alpha, red); - green = multiply_alpha(alpha, green); - blue = multiply_alpha(alpha, blue); - } - w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); - } - - * (uint32_t *) p = w; - } -} - -static void -read_func(png_structp png, png_bytep data, png_size_t size) -{ - FILE *fp = png_get_io_ptr(png); - - if (fread(data, 1, size, fp) < 0) - png_error(png, NULL); -} - -static void -png_error_callback(png_structp png, png_const_charp error_msg) -{ - longjmp (png_jmpbuf (png), 1); -} - -static cairo_surface_t * -load_png(FILE *fp) -{ - png_struct *png; - png_info *info; - png_byte *data = NULL; - png_byte **row_pointers = NULL; - png_uint_32 width, height; - int depth, color_type, interlace, stride; - unsigned int i; - - png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, - png_error_callback, NULL); - if (!png) - return NULL; - - info = png_create_info_struct(png); - if (!info) { - png_destroy_read_struct(&png, &info, NULL); - return NULL; - } - - if (setjmp(png_jmpbuf(png))) { - if (data) - free(data); - if (row_pointers) - free(row_pointers); - png_destroy_read_struct(&png, &info, NULL); - return NULL; - } - - png_set_read_fn(png, fp, read_func); - png_read_info(png, info); - png_get_IHDR(png, info, - &width, &height, &depth, - &color_type, &interlace, NULL, NULL); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png); - - if (color_type == PNG_COLOR_TYPE_GRAY) - png_set_expand_gray_1_2_4_to_8(png); - - if (png_get_valid(png, info, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png); - - if (depth == 16) - png_set_strip_16(png); - - if (depth < 8) - png_set_packing(png); - - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png); - - if (interlace != PNG_INTERLACE_NONE) - png_set_interlace_handling(png); - - png_set_filler(png, 0xff, PNG_FILLER_AFTER); - png_set_read_user_transform_fn(png, premultiply_data); - png_read_update_info(png, info); - png_get_IHDR(png, info, - &width, &height, &depth, - &color_type, &interlace, NULL, NULL); - - - stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, width); - data = malloc(stride * height); - if (!data) { - png_destroy_read_struct(&png, &info, NULL); - return NULL; - } - - row_pointers = malloc(height * sizeof row_pointers[0]); - if (row_pointers == NULL) { - free(data); - png_destroy_read_struct(&png, &info, NULL); - return NULL; - } - - for (i = 0; i < height; i++) - row_pointers[i] = &data[i * stride]; - - png_read_image(png, row_pointers); - png_read_end(png, info); - - free(row_pointers); - png_destroy_read_struct(&png, &info, NULL); - - return cairo_image_surface_create_for_data (data, - CAIRO_FORMAT_RGB24, - width, height, stride); -} - -#ifdef HAVE_WEBP - -static cairo_surface_t * -load_webp(FILE *fp) -{ - WebPDecoderConfig config; - uint8_t buffer[16 * 1024]; - int len; - VP8StatusCode status; - WebPIDecoder *idec; - - if (!WebPInitDecoderConfig(&config)) { - fprintf(stderr, "Library version mismatch!\n"); - return NULL; - } - - /* webp decoding api doesn't seem to specify a min size that's - usable for GetFeatures, but 256 works... */ - len = fread(buffer, 1, 256, fp); - status = WebPGetFeatures(buffer, len, &config.input); - if (status != VP8_STATUS_OK) { - fprintf(stderr, "failed to parse webp header\n"); - WebPFreeDecBuffer(&config.output); - return NULL; - } - - config.output.colorspace = MODE_BGRA; - config.output.u.RGBA.stride = - cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, - config.input.width); - config.output.u.RGBA.size = - config.output.u.RGBA.stride * config.input.height; - config.output.u.RGBA.rgba = - malloc(config.output.u.RGBA.stride * config.input.height); - config.output.is_external_memory = 1; - if (!config.output.u.RGBA.rgba) { - WebPFreeDecBuffer(&config.output); - return NULL; - } - - rewind(fp); - idec = WebPINewDecoder(&config.output); - if (!idec) { - WebPFreeDecBuffer(&config.output); - return NULL; - } - - while (!feof(fp)) { - len = fread(buffer, 1, sizeof buffer, fp); - status = WebPIAppend(idec, buffer, len); - if (status != VP8_STATUS_OK) { - fprintf(stderr, "webp decode status %d\n", status); - WebPIDelete(idec); - WebPFreeDecBuffer(&config.output); - return NULL; - } - } - - WebPIDelete(idec); - WebPFreeDecBuffer(&config.output); - - return cairo_image_surface_create_for_data (config.output.u.RGBA.rgba, - CAIRO_FORMAT_RGB24, - config.input.width, - config.input.height, - config.output.u.RGBA.stride); -} - -#endif - - -struct image_loader { - char header[4]; - int header_size; - cairo_surface_t *(*load)(FILE *fp); -}; - -static const struct image_loader loaders[] = { - { { 0x89, 'P', 'N', 'G' }, 4, load_png }, - { { 0xff, 0xd8 }, 2, load_jpeg }, -#ifdef HAVE_WEBP - { { 'R', 'I', 'F', 'F' }, 4, load_webp } -#endif -}; - cairo_surface_t * -load_image(const char *filename) +load_cairo_surface(const char *filename) { - cairo_surface_t *surface; - unsigned char header[4]; - FILE *fp; - int i; - - fp = fopen(filename, "rb"); - if (fp == NULL) - return NULL; - - fread(header, sizeof header, 1, fp); - rewind(fp); - for (i = 0; i < ARRAY_LENGTH(loaders); i++) { - if (memcmp(header, loaders[i].header, - loaders[i].header_size) == 0) { - surface = loaders[i].load(fp); - break; - } - } - - fclose(fp); - - if (i == ARRAY_LENGTH(loaders)) { - fprintf(stderr, "unrecognized file header for %s: " - "0x%02x 0x%02x 0x%02x 0x%02x\n", - filename, header[0], header[1], header[2], header[3]); - surface = NULL; - } - - return surface; + pixman_image_t *image; + int width, height, stride; + void *data; + + image = load_image(filename); + data = pixman_image_get_data(image); + width = pixman_image_get_width(image); + height = pixman_image_get_height(image); + stride = pixman_image_get_stride(image); + + return cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, + width, height, stride); } |