bitmapJpeg.cpp
Engine/source/gfx/bitmap/loaders/bitmapJpeg.cpp
Classes:
class
Public Defines
define
MAX_HEIGHT() 4096
Public Variables
struct _privateRegisterJPG
Public Functions
jpegErrorFn(void * client_data)
jpegFlushDataFn(void * )
jpegReadDataFn(void * client_data, U8 * data, S32 length)
jpegWriteDataFn(void * client_data, U8 * data, S32 length)
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