bitmapJpeg.cpp

Engine/source/gfx/bitmap/loaders/bitmapJpeg.cpp

More...

Classes:

Public Defines

define
MAX_HEIGHT() 4096

Public Variables

struct _privateRegisterJPG

Public Functions

jpegErrorFn(void * client_data)
jpegReadDataFn(void * client_data, U8 * data, S32 length)
jpegWriteDataFn(void * client_data, U8 * data, S32 length)
bool
sReadJPG(Stream & stream, GBitmap * bitmap)
bool
sWriteJPG(GBitmap * bitmap, Stream & stream, U32 compressionLevel)

Detailed Description

Public Defines

MAX_HEIGHT() 4096

Public Variables

struct _privateRegisterJPG sStaticRegisterJPG 

Public Functions

jpegErrorFn(void * client_data)

jpegFlushDataFn(void * )

jpegReadDataFn(void * client_data, U8 * data, S32 length)

jpegWriteDataFn(void * client_data, U8 * data, S32 length)

sReadJPG(Stream & stream, GBitmap * bitmap)

sWriteJPG(GBitmap * bitmap, Stream & stream, U32 compressionLevel)

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