bitmapJpeg.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "ljpeg/jpeglib.h"
  23. #include "core/stream/stream.h"
  24. #include "gfx/bitmap/gBitmap.h"
  25. static bool sReadJPG(Stream &stream, GBitmap *bitmap);
  26. static bool sWriteJPG(GBitmap *bitmap, Stream &stream, U32 compressionLevel);
  27. static struct _privateRegisterJPG
  28. {
  29. _privateRegisterJPG()
  30. {
  31. GBitmap::Registration reg;
  32. reg.priority = 50;
  33. reg.extensions.push_back( "jpeg" );
  34. reg.extensions.push_back( "jpg" );
  35. reg.readFunc = sReadJPG;
  36. reg.writeFunc = sWriteJPG;
  37. GBitmap::sRegisterFormat( reg );
  38. }
  39. } sStaticRegisterJPG;
  40. //-------------------------------------- Replacement I/O for standard LIBjpeg
  41. // functions. we don't wanna use
  42. // FILE*'s...
  43. static S32 jpegReadDataFn(void *client_data, U8 *data, S32 length)
  44. {
  45. Stream *stream = (Stream*)client_data;
  46. AssertFatal(stream != NULL, "jpegReadDataFn::No stream.");
  47. S32 pos = stream->getPosition();
  48. if (stream->read(length, data))
  49. return length;
  50. if (stream->getStatus() == Stream::EOS)
  51. return (stream->getPosition()-pos);
  52. else
  53. return 0;
  54. }
  55. //--------------------------------------
  56. static S32 jpegWriteDataFn(void *client_data, U8 *data, S32 length)
  57. {
  58. Stream *stream = (Stream*)client_data;
  59. AssertFatal(stream != NULL, "jpegWriteDataFn::No stream.");
  60. if (stream->write(length, data))
  61. return length;
  62. else
  63. return 0;
  64. }
  65. //--------------------------------------
  66. static S32 jpegFlushDataFn(void *)
  67. {
  68. // do nothing since we can't flush the stream object
  69. return 0;
  70. }
  71. //--------------------------------------
  72. static S32 jpegErrorFn(void *client_data)
  73. {
  74. Stream *stream = (Stream*)client_data;
  75. AssertFatal(stream != NULL, "jpegErrorFn::No stream.");
  76. return (stream->getStatus() != Stream::Ok);
  77. }
  78. //--------------------------------------
  79. static bool sReadJPG(Stream &stream, GBitmap *bitmap)
  80. {
  81. PROFILE_SCOPE(sReadJPG);
  82. JFREAD = jpegReadDataFn;
  83. JFERROR = jpegErrorFn;
  84. jpeg_decompress_struct cinfo;
  85. jpeg_error_mgr jerr;
  86. // We set up the normal JPEG error routines, then override error_exit.
  87. //cinfo.err = jpeg_std_error(&jerr.pub);
  88. //jerr.pub.error_exit = my_error_exit;
  89. // if (setjmp(jerr.setjmp_buffer))
  90. // {
  91. // // If we get here, the JPEG code has signaled an error.
  92. // // We need to clean up the JPEG object, close the input file, and return.
  93. // jpeg_destroy_decompress(&cinfo);
  94. // return false;
  95. // }
  96. cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
  97. cinfo.client_data = (void*)&stream; // set the stream into the client_data
  98. // Now we can initialize the JPEG decompression object.
  99. jpeg_create_decompress(&cinfo);
  100. jpeg_stdio_src(&cinfo);
  101. // Read file header, set default decompression parameters
  102. jpeg_read_header(&cinfo, true);
  103. GFXFormat format;
  104. switch (cinfo.out_color_space)
  105. {
  106. case JCS_GRAYSCALE: format = GFXFormatA8; break;
  107. case JCS_RGB: format = GFXFormatR8G8B8; break;
  108. default:
  109. jpeg_destroy_decompress(&cinfo);
  110. return false;
  111. }
  112. // Start decompressor
  113. jpeg_start_decompress(&cinfo);
  114. // allocate the bitmap space and init internal variables...
  115. bitmap->allocateBitmap(cinfo.output_width, cinfo.output_height, false, format);
  116. // Set up the row pointers...
  117. U32 rowBytes = cinfo.output_width * cinfo.output_components;
  118. U8* pBase = (U8*)bitmap->getBits();
  119. for (U32 i = 0; i < bitmap->getHeight(); i++)
  120. {
  121. JSAMPROW rowPointer = pBase + (i * rowBytes);
  122. jpeg_read_scanlines(&cinfo, &rowPointer, 1);
  123. }
  124. // Finish decompression
  125. jpeg_finish_decompress(&cinfo);
  126. // Release JPEG decompression object
  127. // This is an important step since it will release a good deal of memory.
  128. jpeg_destroy_decompress(&cinfo);
  129. // We know JPEG's don't have any transparency
  130. bitmap->setHasTransparency(false);
  131. return true;
  132. }
  133. //--------------------------------------------------------------------------
  134. static bool sWriteJPG(GBitmap *bitmap, Stream &stream, U32 compressionLevel)
  135. {
  136. TORQUE_UNUSED(compressionLevel); // compression level not currently hooked up
  137. GFXFormat format = bitmap->getFormat();
  138. // JPEG format does not support transparency so any image
  139. // in Alpha format should be saved as a grayscale which coincides
  140. // with how the readJPEG function will read-in a JPEG. So the
  141. // only formats supported are RGB and Alpha, not RGBA.
  142. AssertFatal(format == GFXFormatR8G8B8 || format == GFXFormatA8,
  143. "GBitmap::writeJPEG: ONLY RGB bitmap writing supported at this time.");
  144. if (format != GFXFormatR8G8B8 && format != GFXFormatA8)
  145. return false;
  146. // maximum image size allowed
  147. #define MAX_HEIGHT 4096
  148. if (bitmap->getHeight() > MAX_HEIGHT)
  149. return false;
  150. // Bind our own stream writing, error, and memory flush functions
  151. // to the jpeg library interface
  152. JFWRITE = jpegWriteDataFn;
  153. JFFLUSH = jpegFlushDataFn;
  154. JFERROR = jpegErrorFn;
  155. // Allocate and initialize our jpeg compression structure and error manager
  156. jpeg_compress_struct cinfo;
  157. jpeg_error_mgr jerr;
  158. cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
  159. cinfo.client_data = (void*)&stream; // set the stream into the client_data
  160. jpeg_create_compress(&cinfo); // allocates a small amount of memory
  161. // specify the destination for the compressed data(our stream)
  162. jpeg_stdio_dest(&cinfo);
  163. // set the image properties
  164. cinfo.image_width = bitmap->getWidth(); // image width
  165. cinfo.image_height = bitmap->getHeight(); // image height
  166. cinfo.input_components = bitmap->getBytesPerPixel(); // samples per pixel(RGB:3, Alpha:1)
  167. switch (format)
  168. {
  169. case GFXFormatA8: // no alpha support in JPEG format, so turn it into a grayscale
  170. cinfo.in_color_space = JCS_GRAYSCALE;
  171. break;
  172. case GFXFormatR8G8B8: // otherwise we are writing in RGB format
  173. cinfo.in_color_space = JCS_RGB;
  174. break;
  175. default:
  176. AssertFatal( false, "Format not handled in GBitmap::writeJPEG() switch" );
  177. break;
  178. }
  179. // use default compression params(75% compression)
  180. jpeg_set_defaults(&cinfo);
  181. // begin JPEG compression cycle
  182. jpeg_start_compress(&cinfo, true);
  183. // Set up the row pointers...
  184. U32 rowBytes = cinfo.image_width * cinfo.input_components;
  185. U8* pBase = (U8*)bitmap->getBits();
  186. for (U32 i = 0; i < bitmap->getHeight(); i++)
  187. {
  188. // write the image data
  189. JSAMPROW rowPointer = pBase + (i * rowBytes);
  190. jpeg_write_scanlines(&cinfo, &rowPointer, 1);
  191. }
  192. // complete the compression cycle
  193. jpeg_finish_compress(&cinfo);
  194. // release the JPEG compression object
  195. jpeg_destroy_compress(&cinfo);
  196. // return success
  197. return true;
  198. }