rdpng.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
  2. #ifdef PNG_SUPPORTED
  3. #include <png.h> /* if this fails, you need to install libpng-devel */
  4. typedef struct png_source_struct {
  5. struct cjpeg_source_struct pub;
  6. png_structp png_ptr;
  7. png_infop info_ptr;
  8. JDIMENSION current_row;
  9. } png_source_struct;
  10. METHODDEF(void)
  11. finish_input_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo);
  12. METHODDEF(JDIMENSION)
  13. get_pixel_rows_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo);
  14. METHODDEF(void)
  15. start_input_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo);
  16. GLOBAL(cjpeg_source_ptr)
  17. jinit_read_png(j_compress_ptr cinfo)
  18. {
  19. png_source_struct *source = (*cinfo->mem->alloc_small)((j_common_ptr) cinfo, JPOOL_IMAGE, sizeof(png_source_struct));
  20. memset(source, 0, sizeof(*source));
  21. /* Fill in method ptrs, except get_pixel_rows which start_input sets */
  22. source->pub.start_input = start_input_png;
  23. source->pub.finish_input = finish_input_png;
  24. return &source->pub;
  25. }
  26. METHODDEF(void) error_input_png(png_structp png_ptr, png_const_charp msg) {
  27. j_compress_ptr cinfo = png_get_error_ptr(png_ptr);
  28. ERREXITS(cinfo, JERR_PNG_ERROR, msg);
  29. }
  30. /* This is a small ICC profile for sRGB */
  31. static unsigned char tiny_srgb[] = {0,0,2,24,108,99,109,115,2,16,0,0,109,110,
  32. 116,114,82,71,66,32,88,89,90,32,7,220,0,1,0,25,0,3,0,41,0,57,97,99,115,112,65,
  33. 80,80,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,246,214,0,1,0,0,0,
  34. 0,211,45,108,99,109,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  35. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,100,101,115,99,0,0,0,252,0,0,0,106,
  36. 99,112,114,116,0,0,1,104,0,0,0,11,119,116,112,116,0,0,1,116,0,0,0,20,98,107,
  37. 112,116,0,0,1,136,0,0,0,20,114,88,89,90,0,0,1,156,0,0,0,20,103,88,89,90,0,0,1,
  38. 176,0,0,0,20,98,88,89,90,0,0,1,196,0,0,0,20,114,84,82,67,0,0,1,216,0,0,0,64,98,
  39. 84,82,67,0,0,1,216,0,0,0,64,103,84,82,67,0,0,1,216,0,0,0,64,100,101,115,99,0,0,
  40. 0,0,0,0,0,13,115,82,71,66,32,77,111,122,74,80,69,71,0,0,0,0,0,0,0,0,1,0,0,0,0,
  41. 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  42. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,116,101,120,
  43. 116,0,0,0,0,80,68,0,0,88,89,90,32,0,0,0,0,0,0,246,214,0,1,0,0,0,0,211,45,88,89,
  44. 90,32,0,0,0,0,0,0,3,22,0,0,3,51,0,0,2,164,88,89,90,32,0,0,0,0,0,0,111,162,0,0,
  45. 56,245,0,0,3,144,88,89,90,32,0,0,0,0,0,0,98,153,0,0,183,133,0,0,24,218,88,89,
  46. 90,32,0,0,0,0,0,0,36,160,0,0,15,132,0,0,182,207,99,117,114,118,0,0,0,0,0,0,0,
  47. 26,0,0,0,203,1,201,3,99,5,146,8,107,11,246,16,63,21,81,27,52,33,241,41,144,50,
  48. 24,59,146,70,5,81,119,93,237,107,112,122,5,137,177,154,124,172,105,191,125,211,
  49. 195,233,48,255,255,};
  50. METHODDEF(void)
  51. start_input_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  52. {
  53. png_source_struct *source = (png_source_struct *)sinfo;
  54. png_uint_32 width, height;
  55. int bit_depth, color_type;
  56. int has_srgb_chunk;
  57. double gamma;
  58. png_bytep profile;
  59. png_charp unused1;
  60. int unused2;
  61. png_uint_32 proflen;
  62. int has_profile;
  63. size_t datalen;
  64. JOCTET *dataptr;
  65. struct jpeg_marker_struct *marker;
  66. png_size_t rowbytes;
  67. source->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, cinfo, error_input_png, NULL);
  68. source->info_ptr = png_create_info_struct(source->png_ptr);
  69. if (!source->png_ptr || !source->info_ptr) {
  70. ERREXITS(cinfo, JERR_PNG_ERROR, "Can't create read/info_struct");
  71. return;
  72. }
  73. png_set_palette_to_rgb(source->png_ptr);
  74. png_set_expand_gray_1_2_4_to_8(source->png_ptr);
  75. png_set_strip_alpha(source->png_ptr);
  76. png_set_interlace_handling(source->png_ptr);
  77. png_init_io(source->png_ptr, source->pub.input_file);
  78. png_read_info(source->png_ptr, source->info_ptr);
  79. png_get_IHDR(source->png_ptr, source->info_ptr, &width, &height,
  80. &bit_depth, &color_type, NULL, NULL, NULL);
  81. if (width > 65535 || height > 65535) {
  82. ERREXITS(cinfo, JERR_PNG_ERROR, "Image too large");
  83. return;
  84. }
  85. if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
  86. cinfo->in_color_space = JCS_GRAYSCALE;
  87. cinfo->input_components = 1;
  88. } else {
  89. cinfo->in_color_space = JCS_RGB;
  90. cinfo->input_components = 3;
  91. }
  92. if (bit_depth == 16) {
  93. png_set_strip_16(source->png_ptr);
  94. }
  95. cinfo->data_precision = 8;
  96. cinfo->image_width = width;
  97. cinfo->image_height = height;
  98. has_srgb_chunk = png_get_valid(source->png_ptr, source->info_ptr, PNG_INFO_sRGB);
  99. gamma = 0.45455;
  100. if (!has_srgb_chunk) {
  101. png_get_gAMA(source->png_ptr, source->info_ptr, &gamma);
  102. }
  103. cinfo->input_gamma = gamma;
  104. sinfo->get_pixel_rows = get_pixel_rows_png;
  105. source->pub.marker_list = NULL;
  106. profile = NULL;
  107. unused1 = NULL;
  108. unused2 = 0;
  109. proflen = 0;
  110. has_profile = 0;
  111. if (has_srgb_chunk) {
  112. /* PNG can declare use of an sRGB profile without embedding an ICC file, but JPEG doesn't have such feature */
  113. has_profile = 1;
  114. profile = tiny_srgb;
  115. proflen = sizeof(tiny_srgb);
  116. } else {
  117. has_profile = png_get_iCCP(source->png_ptr, source->info_ptr, &unused1, &unused2, &profile, &proflen); /* your libpng is out of date if you get a warning here */
  118. }
  119. if (has_profile && profile && proflen) {
  120. if (proflen < 65535-14) {
  121. datalen = proflen + 14;
  122. dataptr = (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE, datalen);
  123. memcpy(dataptr, "ICC_PROFILE\0\x01\x01", 14);
  124. memcpy(dataptr + 14, profile, proflen);
  125. marker = (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(struct jpeg_marker_struct));
  126. marker->next = NULL;
  127. marker->marker = JPEG_APP0+2;
  128. marker->original_length = 0;
  129. marker->data_length = datalen;
  130. marker->data = dataptr;
  131. source->pub.marker_list = marker;
  132. } else {
  133. WARNMS(cinfo, JERR_PNG_PROFILETOOLARGE);
  134. }
  135. }
  136. png_read_update_info(source->png_ptr, source->info_ptr);
  137. rowbytes = png_get_rowbytes(source->png_ptr, source->info_ptr);
  138. source->pub.buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)rowbytes, 1);
  139. source->pub.buffer_height = 1;
  140. }
  141. METHODDEF(JDIMENSION)
  142. get_pixel_rows_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  143. {
  144. png_source_struct *source = (png_source_struct *)sinfo;
  145. png_read_row(source->png_ptr, source->pub.buffer[0], NULL);
  146. return 1;
  147. }
  148. METHODDEF(void)
  149. finish_input_png (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  150. {
  151. png_source_struct *source = (png_source_struct *)sinfo;
  152. png_read_end(source->png_ptr, source->info_ptr);
  153. png_destroy_read_struct(&source->png_ptr, &source->info_ptr, NULL);
  154. }
  155. #endif