You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

250 line
5.9 KiB

  1. /*
  2. * libpipi Pathetic image processing interface library
  3. * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
  4. * 2008 Jean-Yves Lamoureux <jylam@lnxscene.org>
  5. * All Rights Reserved
  6. *
  7. * $Id$
  8. *
  9. * This library is free software. It comes without any warranty, to
  10. * the extent permitted by applicable law. You can redistribute it
  11. * and/or modify it under the terms of the Do What The Fuck You Want
  12. * To Public License, Version 2, as published by Sam Hocevar. See
  13. * http://sam.zoy.org/wtfpl/COPYING for more details.
  14. */
  15. /*
  16. * jpeg.c: libjpeg I/O functions
  17. */
  18. #include "config.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <setjmp.h>
  24. #include <jpeglib.h>
  25. #include "pipi.h"
  26. #include "pipi_internals.h"
  27. static int pipi_free_jpeg(pipi_image_t *img);
  28. struct my_error_mgr
  29. {
  30. struct jpeg_error_mgr pub;
  31. jmp_buf setjmp_buffer;
  32. };
  33. typedef struct my_error_mgr * my_error_ptr;
  34. static void format_msg(j_common_ptr cinfo, char *buf)
  35. {
  36. }
  37. static void emit_msg(j_common_ptr cinfo, int level)
  38. {
  39. }
  40. static void error_msg(j_common_ptr cinfo)
  41. {
  42. my_error_ptr myerr = (my_error_ptr) cinfo->err;
  43. cinfo->client_data = (void*)0x1;
  44. longjmp(myerr->setjmp_buffer, 1);
  45. }
  46. static void output_msg(j_common_ptr cinfo)
  47. {
  48. }
  49. pipi_image_t *pipi_load_jpeg(const char *name)
  50. {
  51. struct jpeg_decompress_struct cinfo;
  52. struct my_error_mgr jerr;
  53. unsigned char *image = NULL, *scanline = NULL;
  54. pipi_image_t *img = NULL;
  55. unsigned int i, j, k = 0;
  56. FILE *fp;
  57. fp = fopen(name, "rb");
  58. if(!fp)
  59. return NULL;
  60. if(setjmp(jerr.setjmp_buffer))
  61. goto end;
  62. cinfo.err = jpeg_std_error(&jerr.pub);
  63. jerr.pub.error_exit = error_msg;
  64. jerr.pub.emit_message = emit_msg;
  65. jerr.pub.output_message = output_msg;
  66. jerr.pub.format_message = format_msg;
  67. /* Initialize libjpeg */
  68. jpeg_create_decompress(&cinfo);
  69. cinfo.client_data = 0x0;
  70. jpeg_stdio_src(&cinfo, fp);
  71. if(cinfo.client_data == (void *)0x1)
  72. goto end;
  73. jpeg_read_header(&cinfo, TRUE);
  74. if(cinfo.client_data == (void *)0x1)
  75. goto end;
  76. jpeg_start_decompress(&cinfo);
  77. if(cinfo.client_data == (void *)0x1)
  78. goto end;
  79. /* One scanline */
  80. image = malloc(cinfo.output_width * cinfo.output_height * 4);
  81. if(!image)
  82. goto end;
  83. scanline = malloc(cinfo.output_width * 3);
  84. for(i = 0; i < cinfo.output_height; i++)
  85. {
  86. jpeg_read_scanlines(&cinfo, &scanline, 1);
  87. if(cinfo.client_data == (void *)0x1)
  88. {
  89. free(img);
  90. img = NULL;
  91. goto end;
  92. }
  93. for(j = 0; j < cinfo.output_width * 3; j += 3)
  94. {
  95. image[k + 2] = scanline[j];
  96. image[k + 1] = scanline[j + 1];
  97. image[k] = scanline[j + 2];
  98. image[k + 3] = 255;
  99. k += 4;
  100. }
  101. }
  102. img = pipi_new(cinfo.output_width, cinfo.output_height);
  103. img->p[PIPI_PIXELS_RGBA_U8].pixels = image;
  104. img->p[PIPI_PIXELS_RGBA_U8].w = cinfo.output_width;
  105. img->p[PIPI_PIXELS_RGBA_U8].h = cinfo.output_height;
  106. img->p[PIPI_PIXELS_RGBA_U8].pitch = cinfo.output_width * 4;
  107. img->p[PIPI_PIXELS_RGBA_U8].bpp = 24;
  108. img->p[PIPI_PIXELS_RGBA_U8].bytes = 4 * img->w * img->h;
  109. img->last_modified = PIPI_PIXELS_RGBA_U8;
  110. img->codec_priv = (void *)&cinfo;
  111. img->codec_format = PIPI_PIXELS_RGBA_U8;
  112. img->codec_free = pipi_free_jpeg;
  113. img->wrap = 0;
  114. img->u8 = 1;
  115. end:
  116. if(fp)
  117. fclose(fp);
  118. if(scanline)
  119. free(scanline);
  120. jpeg_destroy_decompress(&cinfo);
  121. return img;
  122. }
  123. int pipi_save_jpeg(pipi_image_t *img, const char *name)
  124. {
  125. struct jpeg_compress_struct cinfo;
  126. struct my_error_mgr jerr;
  127. unsigned char *data;
  128. unsigned char *line;
  129. pipi_pixels_t *pixels;
  130. JSAMPROW *jbuf;
  131. uint32_t *ptr;
  132. FILE *fp;
  133. int i, j, y = 0;
  134. size_t len;
  135. int quality = 75; /* FIXME */
  136. len = strlen(name);
  137. if(len < 4 || name[len - 4] != '.'
  138. || toupper(name[len - 3]) != 'J'
  139. || toupper(name[len - 2]) != 'P'
  140. || toupper(name[len - 1]) != 'G')
  141. {
  142. if(len < 5 || name[len - 5] != '.'
  143. || toupper(name[len - 4]) != 'J'
  144. || toupper(name[len - 3]) != 'P'
  145. || toupper(name[len - 2]) != 'E'
  146. || toupper(name[len - 1]) != 'G')
  147. return -1;
  148. }
  149. pixels = pipi_get_pixels(img, PIPI_PIXELS_RGBA_U8);
  150. if(!pixels)
  151. return -1;
  152. data = pixels->pixels;
  153. line = malloc(img->w * 3 * sizeof(unsigned char));
  154. if(!line)
  155. return -1;
  156. fp = fopen(name, "wb");
  157. if(!fp)
  158. {
  159. free(line);
  160. return -1;
  161. }
  162. if(setjmp(jerr.setjmp_buffer))
  163. goto end;
  164. jerr.pub.error_exit = error_msg;
  165. jerr.pub.emit_message = emit_msg;
  166. jerr.pub.output_message = output_msg;
  167. cinfo.err = jpeg_std_error(&(jerr.pub));
  168. jpeg_create_compress(&cinfo);
  169. jpeg_stdio_dest(&cinfo, fp);
  170. cinfo.image_width = img->w;
  171. cinfo.image_height = img->h;
  172. cinfo.input_components = 3;
  173. cinfo.in_color_space = JCS_RGB;
  174. jpeg_set_defaults(&cinfo);
  175. jpeg_set_quality(&cinfo, quality, TRUE);
  176. jpeg_start_compress(&cinfo, TRUE);
  177. ptr = (uint32_t*)data;
  178. while(cinfo.next_scanline < cinfo.image_height)
  179. {
  180. for (j = 0, i = 0; i < img->w; i++)
  181. {
  182. line[j++] = ((*ptr) >> 16) & 0xff;
  183. line[j++] = ((*ptr) >> 8) & 0xff;
  184. line[j++] = ((*ptr)) & 0xff;
  185. ptr++;
  186. }
  187. jbuf = (JSAMPROW *) (&line);
  188. jpeg_write_scanlines(&cinfo, jbuf, 1);
  189. y++;
  190. }
  191. jpeg_finish_compress(&cinfo);
  192. end:
  193. jpeg_destroy_compress(&cinfo);
  194. free(line);
  195. fclose(fp);
  196. pipi_release_pixels(img, pixels);
  197. return 0;
  198. }
  199. static int pipi_free_jpeg(pipi_image_t *img)
  200. {
  201. if(img->p[PIPI_PIXELS_RGBA_U8].pixels)
  202. free(img->p[PIPI_PIXELS_RGBA_U8].pixels);
  203. return 0;
  204. }