/* * libpipi Pathetic image processing interface library * Copyright (c) 2004-2008 Sam Hocevar * 2008 Jean-Yves Lamoureux * All Rights Reserved * * $Id$ * * This library is free software. It comes without any warranty, to * the extent permitted by applicable law. You can redistribute it * and/or modify it under the terms of the Do What The Fuck You Want * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ /* * jpeg.c: libjpeg I/O functions */ #include "config.h" #include #include #include #include #include #include #include "pipi.h" #include "pipi_internals.h" static int pipi_free_jpeg(pipi_image_t *img); struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct my_error_mgr * my_error_ptr; static void format_msg(j_common_ptr cinfo, char *buf) { } static void emit_msg(j_common_ptr cinfo, int level) { } static void error_msg(j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; cinfo->client_data = (void*)0x1; longjmp(myerr->setjmp_buffer, 1); } static void output_msg(j_common_ptr cinfo) { } pipi_image_t *pipi_load_jpeg(const char *name) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; unsigned char *image = NULL, *scanline = NULL; pipi_image_t *img = NULL; unsigned int i, j, k = 0; FILE *fp; fp = fopen(name, "rb"); if(!fp) return NULL; if(setjmp(jerr.setjmp_buffer)) goto end; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = error_msg; jerr.pub.emit_message = emit_msg; jerr.pub.output_message = output_msg; jerr.pub.format_message = format_msg; /* Initialize libjpeg */ jpeg_create_decompress(&cinfo); cinfo.client_data = 0x0; jpeg_stdio_src(&cinfo, fp); if(cinfo.client_data == (void *)0x1) goto end; jpeg_read_header(&cinfo, TRUE); if(cinfo.client_data == (void *)0x1) goto end; jpeg_start_decompress(&cinfo); if(cinfo.client_data == (void *)0x1) goto end; /* One scanline */ image = malloc(cinfo.output_width * cinfo.output_height * 4); if(!image) goto end; scanline = malloc(cinfo.output_width * 3); for(i = 0; i < cinfo.output_height; i++) { jpeg_read_scanlines(&cinfo, &scanline, 1); if(cinfo.client_data == (void *)0x1) { free(img); img = NULL; goto end; } for(j = 0; j < cinfo.output_width * 3; j += 3) { image[k + 2] = scanline[j]; image[k + 1] = scanline[j + 1]; image[k] = scanline[j + 2]; image[k + 3] = 255; k += 4; } } img = pipi_new(cinfo.output_width, cinfo.output_height); img->p[PIPI_PIXELS_RGBA_U8].pixels = image; img->p[PIPI_PIXELS_RGBA_U8].w = cinfo.output_width; img->p[PIPI_PIXELS_RGBA_U8].h = cinfo.output_height; img->p[PIPI_PIXELS_RGBA_U8].pitch = cinfo.output_width * 4; img->p[PIPI_PIXELS_RGBA_U8].bpp = 24; img->p[PIPI_PIXELS_RGBA_U8].bytes = 4 * img->w * img->h; img->last_modified = PIPI_PIXELS_RGBA_U8; img->codec_priv = (void *)&cinfo; img->codec_format = PIPI_PIXELS_RGBA_U8; img->codec_free = pipi_free_jpeg; img->wrap = 0; img->u8 = 1; end: if(fp) fclose(fp); if(scanline) free(scanline); jpeg_destroy_decompress(&cinfo); return img; } int pipi_save_jpeg(pipi_image_t *img, const char *name) { struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; unsigned char *data; unsigned char *line; pipi_pixels_t *pixels; JSAMPROW *jbuf; uint32_t *ptr; FILE *fp; int i, j, y = 0; size_t len; int quality = 75; /* FIXME */ len = strlen(name); if(len < 4 || name[len - 4] != '.' || toupper(name[len - 3]) != 'J' || toupper(name[len - 2]) != 'P' || toupper(name[len - 1]) != 'G') { if(len < 5 || name[len - 5] != '.' || toupper(name[len - 4]) != 'J' || toupper(name[len - 3]) != 'P' || toupper(name[len - 2]) != 'E' || toupper(name[len - 1]) != 'G') return -1; } pixels = pipi_get_pixels(img, PIPI_PIXELS_RGBA_U8); if(!pixels) return -1; data = pixels->pixels; line = malloc(img->w * 3 * sizeof(unsigned char)); if(!line) return -1; fp = fopen(name, "wb"); if(!fp) { free(line); return -1; } if(setjmp(jerr.setjmp_buffer)) goto end; jerr.pub.error_exit = error_msg; jerr.pub.emit_message = emit_msg; jerr.pub.output_message = output_msg; cinfo.err = jpeg_std_error(&(jerr.pub)); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = img->w; cinfo.image_height = img->h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); ptr = (uint32_t*)data; while(cinfo.next_scanline < cinfo.image_height) { for (j = 0, i = 0; i < img->w; i++) { line[j++] = ((*ptr) >> 16) & 0xff; line[j++] = ((*ptr) >> 8) & 0xff; line[j++] = ((*ptr)) & 0xff; ptr++; } jbuf = (JSAMPROW *) (&line); jpeg_write_scanlines(&cinfo, jbuf, 1); y++; } jpeg_finish_compress(&cinfo); end: jpeg_destroy_compress(&cinfo); free(line); fclose(fp); pipi_release_pixels(img, pixels); return 0; } static int pipi_free_jpeg(pipi_image_t *img) { if(img->p[PIPI_PIXELS_RGBA_U8].pixels) free(img->p[PIPI_PIXELS_RGBA_U8].pixels); return 0; }