bitmapJpeg.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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 "io/stream.h"
  23. #include "io/fileStream.h"
  24. #include "io/memstream.h"
  25. #include "graphics/gPalette.h"
  26. #include "graphics/gBitmap.h"
  27. #include "jpeglib.h"
  28. U32 gJpegQuality = 90;
  29. //-------------------------------------- Replacement I/O for standard LIBjpeg
  30. // functions. we don't wanna use
  31. // FILE*'s...
  32. static int jpegReadDataFn(void *client_data, unsigned char *data, int length)
  33. {
  34. Stream *stream = (Stream*)client_data;
  35. AssertFatal(stream != NULL, "jpegReadDataFn::No stream.");
  36. int pos = stream->getPosition();
  37. if (stream->read(length, data))
  38. return length;
  39. if (stream->getStatus() == Stream::EOS)
  40. return (stream->getPosition()-pos);
  41. else
  42. return 0;
  43. }
  44. //--------------------------------------
  45. static int jpegWriteDataFn(void *client_data, unsigned char *data, int length)
  46. {
  47. Stream *stream = (Stream*)client_data;
  48. AssertFatal(stream != NULL, "jpegWriteDataFn::No stream.");
  49. if (stream->write(length, data))
  50. return length;
  51. else
  52. return 0;
  53. }
  54. //--------------------------------------
  55. static int jpegFlushDataFn(void *)
  56. {
  57. // do nothing since we can't flush the stream object
  58. return 0;
  59. }
  60. //--------------------------------------
  61. static int jpegErrorFn(void *client_data)
  62. {
  63. Stream *stream = (Stream*)client_data;
  64. AssertFatal(stream != NULL, "jpegErrorFn::No stream.");
  65. return (stream->getStatus() != Stream::Ok);
  66. }
  67. //--------------------------------------
  68. bool GBitmap::readJPEG(Stream &stream)
  69. {
  70. JFREAD = jpegReadDataFn;
  71. JFERROR = jpegErrorFn;
  72. jpeg_decompress_struct cinfo;
  73. jpeg_error_mgr jerr;
  74. // We set up the normal JPEG error routines, then override error_exit.
  75. //cinfo.err = jpeg_std_error(&jerr.pub);
  76. //jerr.pub.error_exit = my_error_exit;
  77. // if (setjmp(jerr.setjmp_buffer))
  78. // {
  79. // // If we get here, the JPEG code has signaled an error.
  80. // // We need to clean up the JPEG object, close the input file, and return.
  81. // jpeg_destroy_decompress(&cinfo);
  82. // return false;
  83. // }
  84. cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
  85. cinfo.client_data = (void*)&stream; // set the stream into the client_data
  86. // Now we can initialize the JPEG decompression object.
  87. jpeg_create_decompress(&cinfo);
  88. jpeg_stdio_src(&cinfo);
  89. // Read file header, set default decompression parameters
  90. jpeg_read_header(&cinfo, true);
  91. BitmapFormat format;
  92. switch (cinfo.out_color_space)
  93. {
  94. case JCS_GRAYSCALE: format = Alpha; break;
  95. case JCS_RGB: format = RGB; break;
  96. default:
  97. jpeg_destroy_decompress(&cinfo);
  98. return false;
  99. }
  100. // Start decompressor
  101. jpeg_start_decompress(&cinfo);
  102. // allocate the bitmap space and init internal variables...
  103. allocateBitmap(cinfo.output_width, cinfo.output_height, false, format);
  104. // Set up the row pointers...
  105. U32 rowBytes = cinfo.output_width * cinfo.output_components;
  106. U8* pBase = (U8*)getBits();
  107. for (U32 i = 0; i < height; i++)
  108. {
  109. JSAMPROW rowPointer = pBase + (i * rowBytes);
  110. jpeg_read_scanlines(&cinfo, &rowPointer, 1);
  111. }
  112. // Finish decompression
  113. jpeg_finish_decompress(&cinfo);
  114. // Release JPEG decompression object
  115. // This is an important step since it will release a good deal of memory.
  116. jpeg_destroy_decompress(&cinfo);
  117. return true;
  118. }
  119. //--------------------------------------------------------------------------
  120. bool GBitmap::writeJPEG(Stream& stream) const
  121. {
  122. // JPEG format has no support for transparancy so any image
  123. // in Alpha format should be saved as a grayscale which coincides
  124. // with how the readJPEG function will read-in a JPEG. So the
  125. // only formats supported are RGB and Alpha, not RGBA.
  126. AssertFatal(getFormat() == RGB || getFormat() == Alpha,
  127. "GBitmap::writeJPEG: ONLY RGB bitmap writing supported at this time.");
  128. if (internalFormat != RGB && internalFormat != Alpha)
  129. return false;
  130. // maximum image size allowed
  131. #define MAX_HEIGHT 4096
  132. if (height >= MAX_HEIGHT)
  133. return false;
  134. // Bind our own stream writing, error, and memory flush functions
  135. // to the jpeg library interface
  136. JFWRITE = jpegWriteDataFn;
  137. JFFLUSH = jpegFlushDataFn;
  138. JFERROR = jpegErrorFn;
  139. // Allocate and initialize our jpeg compression structure and error manager
  140. jpeg_compress_struct cinfo;
  141. jpeg_error_mgr jerr;
  142. cinfo.err = jpeg_std_error(&jerr); // set up the normal JPEG error routines.
  143. cinfo.client_data = (void*)&stream; // set the stream into the client_data
  144. jpeg_create_compress(&cinfo); // allocates a small amount of memory
  145. // specify the destination for the compressed data(our stream)
  146. jpeg_stdio_dest(&cinfo);
  147. // set the image properties
  148. cinfo.image_width = getWidth(); // image width
  149. cinfo.image_height = getHeight(); // image height
  150. cinfo.input_components = bytesPerPixel; // samples per pixel(RGB:3, Alpha:1)
  151. switch (internalFormat)
  152. {
  153. case Alpha: // no alpha support in JPEG format, so turn it into a grayscale
  154. cinfo.in_color_space = JCS_GRAYSCALE;
  155. break;
  156. case RGB: // otherwise we are writing in RGB format
  157. cinfo.in_color_space = JCS_RGB;
  158. break;
  159. case Palettized:
  160. case Intensity:
  161. case RGBA:
  162. case RGB565:
  163. case RGB5551:
  164. case Luminance:
  165. case LuminanceAlpha:
  166. #ifdef TORQUE_OS_IOS
  167. case PVR2:
  168. case PVR2A:
  169. case PVR4:
  170. case PVR4A:
  171. #endif
  172. {
  173. // error, unhandled case
  174. }
  175. }
  176. // use default compression params(75% compression)
  177. jpeg_set_defaults(&cinfo);
  178. jpeg_set_quality(&cinfo, gJpegQuality, false);
  179. // begin JPEG compression cycle
  180. jpeg_start_compress(&cinfo, true);
  181. // Set up the row pointers...
  182. U32 rowBytes = cinfo.image_width * cinfo.input_components;
  183. U8* pBase = (U8*)getBits();
  184. for (U32 i = 0; i < height; i++)
  185. {
  186. // write the image data
  187. JSAMPROW rowPointer = pBase + (i * rowBytes);
  188. jpeg_write_scanlines(&cinfo, &rowPointer, 1);
  189. }
  190. // complete the compression cycle
  191. jpeg_finish_compress(&cinfo);
  192. // release the JPEG compression object
  193. jpeg_destroy_compress(&cinfo);
  194. // return success
  195. return true;
  196. }