JPEG.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #if SUPPORT_JPG
  4. #include "../../../../ThirdPartyLibs/begin.h"
  5. #include <setjmp.h>
  6. #if 1 // JpegTurbo
  7. #include "../../../../ThirdPartyLibs/JpegTurbo/lib/jpeglib.h"
  8. #else // Jpeg
  9. #include "../../../../ThirdPartyLibs/Jpeg/jpeglib.h"
  10. #endif
  11. #include "../../../../ThirdPartyLibs/end.h"
  12. #endif
  13. namespace EE{
  14. /******************************************************************************/
  15. #if SUPPORT_JPG
  16. struct jpeg_error_mgr_ex : jpeg_error_mgr
  17. {
  18. jmp_buf jump_buffer;
  19. };
  20. static void my_error_exit(j_common_ptr cinfo)
  21. {
  22. jpeg_error_mgr_ex &err=*(jpeg_error_mgr_ex*)cinfo->err;
  23. //(*cinfo->err->output_message)(cinfo);
  24. longjmp(err.jump_buffer, 1);
  25. }
  26. #endif
  27. /******************************************************************************/
  28. Bool Image::ImportJPG(File &f)
  29. {
  30. #if SUPPORT_JPG
  31. struct JPGReader : jpeg_source_mgr
  32. {
  33. File &f;
  34. Byte data[4096];
  35. Bool start_of_file;
  36. Long start_pos;
  37. static void InitSource(j_decompress_ptr cinfo)
  38. {
  39. JPGReader &src=*(JPGReader*)cinfo->src;
  40. src.start_of_file=true;
  41. }
  42. static boolean FillInputBuffer(j_decompress_ptr cinfo)
  43. {
  44. JPGReader &src =*(JPGReader*)cinfo->src;
  45. Int nbytes=src.f.getReturnSize(src.data, SIZE(src.data));
  46. if(nbytes<=0) // if no more data available
  47. {
  48. if(src.start_of_file)return false; // if just started reading then fail
  49. // otherwise insert a fake EOI marker, and allowing reading incomplete JPG files
  50. src.data[0]=(JOCTET)0xFF;
  51. src.data[1]=(JOCTET)JPEG_EOI;
  52. nbytes=2;
  53. }
  54. src.next_input_byte=src.data;
  55. src.bytes_in_buffer=nbytes;
  56. src.start_of_file =false;
  57. return true;
  58. }
  59. static void SkipInputData(j_decompress_ptr cinfo, long num_bytes)
  60. {
  61. JPGReader &src=*(JPGReader*)cinfo->src;
  62. if(num_bytes>0)
  63. {
  64. while(num_bytes>src.bytes_in_buffer)
  65. {
  66. num_bytes-=(long)src.bytes_in_buffer;
  67. FillInputBuffer(cinfo);
  68. }
  69. src.next_input_byte+=num_bytes;
  70. src.bytes_in_buffer-=num_bytes;
  71. }
  72. }
  73. static void TermSource(j_decompress_ptr cinfo) {}
  74. JPGReader(File &f) : f(f)
  75. {
  76. init_source =InitSource;
  77. fill_input_buffer=FillInputBuffer;
  78. skip_input_data =SkipInputData;
  79. resync_to_restart=jpeg_resync_to_restart; // use libJpeg method
  80. term_source =TermSource;
  81. bytes_in_buffer =0;
  82. next_input_byte =null;
  83. start_pos =f.pos();
  84. }
  85. ~JPGReader()
  86. {
  87. f.pos(Max(start_pos, f.pos()-(Int)bytes_in_buffer)); // go back with any unprocessed data left, to be able to read them after reading the JPEG (this is needed because 'FillInputBuffer' reads ahead of what's needed)
  88. }
  89. };
  90. Bool ok=false, created=false;
  91. JPGReader jpg(f);
  92. jpeg_error_mgr_ex jerr ;
  93. jpeg_decompress_struct cinfo; cinfo.err=jpeg_std_error(&jerr); jerr.error_exit=my_error_exit; if(setjmp(jerr.jump_buffer))goto error; // setup jump position that will be reached upon jpeg error
  94. jpeg_create_decompress(&cinfo); cinfo.src=&jpg;
  95. if(jpeg_read_header (&cinfo, true))
  96. {
  97. jpeg_start_decompress(&cinfo);
  98. if(cinfo.output_components==1 && cinfo.out_color_space==JCS_GRAYSCALE
  99. || cinfo.output_components==3 && cinfo.out_color_space==JCS_RGB)
  100. if(createSoftTry(cinfo.output_width, cinfo.output_height, 1, (cinfo.output_components==1) ? IMAGE_L8 : IMAGE_R8G8B8))
  101. {
  102. created=true;
  103. for(; cinfo.output_scanline<cinfo.output_height; ){JSAMPROW row=T.data()+cinfo.output_scanline*pitch(); jpeg_read_scanlines(&cinfo, &row, 1);}
  104. ok=true;
  105. }
  106. jpeg_finish_decompress(&cinfo);
  107. }
  108. error:
  109. jpeg_destroy_decompress(&cinfo);
  110. if(!ok && !created)del(); return ok; // if failed but the image was created, then it's possible that some data was read, keep that in case user wants to preview what was read
  111. #else
  112. del(); return false;
  113. #endif
  114. }
  115. /******************************************************************************/
  116. Bool Image::ExportJPG(File &f, Flt quality, Int sub_sample)C
  117. {
  118. #if SUPPORT_JPG
  119. struct JPGWriter : jpeg_destination_mgr
  120. {
  121. File &f;
  122. Byte data[4096];
  123. static void InitDestination(j_compress_ptr cinfo)
  124. {
  125. JPGWriter &dest=*(JPGWriter*)cinfo->dest;
  126. dest.next_output_byte=dest.data;
  127. dest.free_in_buffer =SIZE(dest.data);
  128. }
  129. static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
  130. {
  131. JPGWriter &dest=*(JPGWriter*)cinfo->dest;
  132. dest.f<<dest.data;
  133. dest.next_output_byte=dest.data;
  134. dest.free_in_buffer =SIZE(dest.data);
  135. return true;
  136. }
  137. static void TermDestination(j_compress_ptr cinfo)
  138. {
  139. JPGWriter &dest=*(JPGWriter*)cinfo->dest;
  140. dest.f.put(dest.data, SIZE(dest.data)-(Int)dest.free_in_buffer);
  141. }
  142. JPGWriter(File &f) : f(f)
  143. {
  144. next_output_byte =null;
  145. free_in_buffer =0;
  146. init_destination =InitDestination;
  147. empty_output_buffer=EmptyOutputBuffer;
  148. term_destination =TermDestination;
  149. }
  150. };
  151. Int q=RoundPos(quality*100);
  152. if( q< 0)q= 80;else // default to 80
  153. if( q== 0)q= 1;else // min quality for jpeg is actually 1
  154. if( q> 100)q=100; // max quality is 100
  155. C Image *src=this;
  156. Image temp;
  157. if(!src->is ())return false;
  158. if( src->cube())if(temp.fromCube(*src, ImageTI[src->type()].compressed ? IMAGE_R8G8B8 : -1, IMAGE_SOFT))src=&temp;else return false;
  159. if(src->hwType()!=IMAGE_L8 && src->hwType()!=IMAGE_A8 && src->hwType()!=IMAGE_I8
  160. && src->hwType()!=IMAGE_R8G8B8
  161. #if JCS_EXTENSIONS
  162. && src->hwType()!=IMAGE_R8G8B8A8
  163. && src->hwType()!=IMAGE_R8G8B8X8
  164. && src->hwType()!=IMAGE_B8G8R8
  165. && src->hwType()!=IMAGE_B8G8R8A8
  166. && src->hwType()!=IMAGE_B8G8R8X8
  167. #endif
  168. )
  169. if(src->copyTry(temp, -1, -1, -1, (src->type()==IMAGE_I16) ? IMAGE_L8 : IMAGE_R8G8B8, IMAGE_SOFT, 1))src=&temp;else return false;
  170. if(src->lockRead())
  171. {
  172. JPGWriter jpg(f);
  173. jpeg_error_mgr_ex jerr ;
  174. jpeg_compress_struct cinfo; cinfo.err=jpeg_std_error(&jerr); jerr.error_exit=my_error_exit; if(setjmp(jerr.jump_buffer)){jpeg_destroy_compress(&cinfo); return false;} // setup jump position that will be reached upon jpeg error
  175. jpeg_create_compress(&cinfo);
  176. switch(src->hwType())
  177. {
  178. case IMAGE_L8 :
  179. case IMAGE_A8 :
  180. case IMAGE_I8 : cinfo.in_color_space=JCS_GRAYSCALE; cinfo.input_components=1; break;
  181. case IMAGE_R8G8B8: cinfo.in_color_space=JCS_RGB ; cinfo.input_components=3; break;
  182. #if JCS_EXTENSIONS
  183. case IMAGE_R8G8B8A8:
  184. case IMAGE_R8G8B8X8: cinfo.in_color_space=JCS_EXT_RGBX; cinfo.input_components=4; break;
  185. case IMAGE_B8G8R8 : cinfo.in_color_space=JCS_EXT_BGR ; cinfo.input_components=3; break;
  186. case IMAGE_B8G8R8A8:
  187. case IMAGE_B8G8R8X8: cinfo.in_color_space=JCS_EXT_BGRX; cinfo.input_components=4; break;
  188. #endif
  189. }
  190. cinfo.image_width =src->w();
  191. cinfo.image_height=src->h();
  192. cinfo.dest =&jpg;
  193. jpeg_set_defaults(&cinfo);
  194. if(cinfo.comp_info && cinfo.in_color_space!=JCS_GRAYSCALE)switch(sub_sample)
  195. {
  196. case 0: cinfo.comp_info[0].h_samp_factor=1; cinfo.comp_info[0].v_samp_factor=1; break;
  197. case 1: cinfo.comp_info[0].h_samp_factor=2; cinfo.comp_info[0].v_samp_factor=1; break;
  198. default: case 2: cinfo.comp_info[0].h_samp_factor=2; cinfo.comp_info[0].v_samp_factor=2; break;
  199. }
  200. jpeg_set_quality (&cinfo, q, true);
  201. jpeg_start_compress (&cinfo, true); for(; cinfo.next_scanline<cinfo.image_height; ){JSAMPROW data=ConstCast(src->data()+cinfo.next_scanline*src->pitch()); jpeg_write_scanlines(&cinfo, &data, 1);}
  202. jpeg_finish_compress (&cinfo);
  203. jpeg_destroy_compress(&cinfo);
  204. src->unlock();
  205. return f.ok();
  206. }
  207. #endif
  208. return false;
  209. }
  210. /******************************************************************************/
  211. Bool Image::ExportJPG(C Str &name, Flt quality, Int sub_sample)C
  212. {
  213. #if SUPPORT_JPG
  214. File f; if(f.writeTry(name)){if(ExportJPG(f, quality, sub_sample) && f.flush())return true; f.del(); FDelFile(name);}
  215. #endif
  216. return false;
  217. }
  218. Bool Image::ImportJPG(C Str &name)
  219. {
  220. #if SUPPORT_JPG
  221. File f; if(f.readTry(name))return ImportJPG(f);
  222. #endif
  223. del(); return false;
  224. }
  225. /******************************************************************************/
  226. }
  227. /******************************************************************************/