diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderJPG.cpp | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderJPG.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderJPG.cpp new file mode 100644 index 0000000..8fc5222 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CImageLoaderJPG.cpp | |||
@@ -0,0 +1,306 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "CImageLoaderJPG.h" | ||
6 | |||
7 | #ifdef _IRR_COMPILE_WITH_JPG_LOADER_ | ||
8 | |||
9 | #include "IReadFile.h" | ||
10 | #include "CImage.h" | ||
11 | #include "os.h" | ||
12 | #include "irrString.h" | ||
13 | |||
14 | namespace irr | ||
15 | { | ||
16 | namespace video | ||
17 | { | ||
18 | |||
19 | // Static members | ||
20 | io::path CImageLoaderJPG::Filename; | ||
21 | |||
22 | //! constructor | ||
23 | CImageLoaderJPG::CImageLoaderJPG() | ||
24 | { | ||
25 | #ifdef _DEBUG | ||
26 | setDebugName("CImageLoaderJPG"); | ||
27 | #endif | ||
28 | } | ||
29 | |||
30 | |||
31 | |||
32 | //! destructor | ||
33 | CImageLoaderJPG::~CImageLoaderJPG() | ||
34 | { | ||
35 | } | ||
36 | |||
37 | |||
38 | |||
39 | //! returns true if the file maybe is able to be loaded by this class | ||
40 | //! based on the file extension (e.g. ".tga") | ||
41 | bool CImageLoaderJPG::isALoadableFileExtension(const io::path& filename) const | ||
42 | { | ||
43 | return core::hasFileExtension ( filename, "jpg", "jpeg" ); | ||
44 | } | ||
45 | |||
46 | |||
47 | #ifdef _IRR_COMPILE_WITH_LIBJPEG_ | ||
48 | |||
49 | // struct for handling jpeg errors | ||
50 | struct irr_jpeg_error_mgr | ||
51 | { | ||
52 | // public jpeg error fields | ||
53 | struct jpeg_error_mgr pub; | ||
54 | |||
55 | // for longjmp, to return to caller on a fatal error | ||
56 | jmp_buf setjmp_buffer; | ||
57 | }; | ||
58 | |||
59 | void CImageLoaderJPG::init_source (j_decompress_ptr cinfo) | ||
60 | { | ||
61 | // DO NOTHING | ||
62 | } | ||
63 | |||
64 | |||
65 | |||
66 | boolean CImageLoaderJPG::fill_input_buffer (j_decompress_ptr cinfo) | ||
67 | { | ||
68 | // DO NOTHING | ||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | |||
73 | |||
74 | void CImageLoaderJPG::skip_input_data (j_decompress_ptr cinfo, long count) | ||
75 | { | ||
76 | jpeg_source_mgr * src = cinfo->src; | ||
77 | if(count > 0) | ||
78 | { | ||
79 | src->bytes_in_buffer -= count; | ||
80 | src->next_input_byte += count; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | |||
85 | |||
86 | void CImageLoaderJPG::term_source (j_decompress_ptr cinfo) | ||
87 | { | ||
88 | // DO NOTHING | ||
89 | } | ||
90 | |||
91 | |||
92 | void CImageLoaderJPG::error_exit (j_common_ptr cinfo) | ||
93 | { | ||
94 | // unfortunately we need to use a goto rather than throwing an exception | ||
95 | // as gcc crashes under linux crashes when using throw from within | ||
96 | // extern c code | ||
97 | |||
98 | // Always display the message | ||
99 | (*cinfo->err->output_message) (cinfo); | ||
100 | |||
101 | // cinfo->err really points to a irr_error_mgr struct | ||
102 | irr_jpeg_error_mgr *myerr = (irr_jpeg_error_mgr*) cinfo->err; | ||
103 | |||
104 | longjmp(myerr->setjmp_buffer, 1); | ||
105 | } | ||
106 | |||
107 | |||
108 | void CImageLoaderJPG::output_message(j_common_ptr cinfo) | ||
109 | { | ||
110 | // display the error message. | ||
111 | c8 temp1[JMSG_LENGTH_MAX]; | ||
112 | (*cinfo->err->format_message)(cinfo, temp1); | ||
113 | core::stringc errMsg("JPEG FATAL ERROR in "); | ||
114 | errMsg += core::stringc(Filename); | ||
115 | os::Printer::log(errMsg.c_str(),temp1, ELL_ERROR); | ||
116 | } | ||
117 | #endif // _IRR_COMPILE_WITH_LIBJPEG_ | ||
118 | |||
119 | //! returns true if the file maybe is able to be loaded by this class | ||
120 | bool CImageLoaderJPG::isALoadableFileFormat(io::IReadFile* file) const | ||
121 | { | ||
122 | #ifndef _IRR_COMPILE_WITH_LIBJPEG_ | ||
123 | return false; | ||
124 | #else | ||
125 | |||
126 | if (!file) | ||
127 | return false; | ||
128 | |||
129 | s32 jfif = 0; | ||
130 | file->seek(6); | ||
131 | file->read(&jfif, sizeof(s32)); | ||
132 | return (jfif == 0x4a464946 || jfif == 0x4649464a); | ||
133 | |||
134 | #endif | ||
135 | } | ||
136 | |||
137 | //! creates a surface from the file | ||
138 | IImage* CImageLoaderJPG::loadImage(io::IReadFile* file) const | ||
139 | { | ||
140 | #ifndef _IRR_COMPILE_WITH_LIBJPEG_ | ||
141 | os::Printer::log("Can't load as not compiled with _IRR_COMPILE_WITH_LIBJPEG_:", file->getFileName(), ELL_DEBUG); | ||
142 | return 0; | ||
143 | #else | ||
144 | |||
145 | if (!file) | ||
146 | return 0; | ||
147 | |||
148 | Filename = file->getFileName(); | ||
149 | |||
150 | u8 **rowPtr=0; | ||
151 | u8* input = new u8[file->getSize()]; | ||
152 | file->read(input, file->getSize()); | ||
153 | |||
154 | // allocate and initialize JPEG decompression object | ||
155 | struct jpeg_decompress_struct cinfo; | ||
156 | struct irr_jpeg_error_mgr jerr; | ||
157 | |||
158 | //We have to set up the error handler first, in case the initialization | ||
159 | //step fails. (Unlikely, but it could happen if you are out of memory.) | ||
160 | //This routine fills in the contents of struct jerr, and returns jerr's | ||
161 | //address which we place into the link field in cinfo. | ||
162 | |||
163 | cinfo.err = jpeg_std_error(&jerr.pub); | ||
164 | cinfo.err->error_exit = error_exit; | ||
165 | cinfo.err->output_message = output_message; | ||
166 | |||
167 | // compatibility fudge: | ||
168 | // we need to use setjmp/longjmp for error handling as gcc-linux | ||
169 | // crashes when throwing within external c code | ||
170 | if (setjmp(jerr.setjmp_buffer)) | ||
171 | { | ||
172 | // If we get here, the JPEG code has signaled an error. | ||
173 | // We need to clean up the JPEG object and return. | ||
174 | |||
175 | jpeg_destroy_decompress(&cinfo); | ||
176 | |||
177 | delete [] input; | ||
178 | // if the row pointer was created, we delete it. | ||
179 | if (rowPtr) | ||
180 | delete [] rowPtr; | ||
181 | |||
182 | // return null pointer | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | // Now we can initialize the JPEG decompression object. | ||
187 | jpeg_create_decompress(&cinfo); | ||
188 | |||
189 | // specify data source | ||
190 | jpeg_source_mgr jsrc; | ||
191 | |||
192 | // Set up data pointer | ||
193 | jsrc.bytes_in_buffer = file->getSize(); | ||
194 | jsrc.next_input_byte = (JOCTET*)input; | ||
195 | cinfo.src = &jsrc; | ||
196 | |||
197 | jsrc.init_source = init_source; | ||
198 | jsrc.fill_input_buffer = fill_input_buffer; | ||
199 | jsrc.skip_input_data = skip_input_data; | ||
200 | jsrc.resync_to_restart = jpeg_resync_to_restart; | ||
201 | jsrc.term_source = term_source; | ||
202 | |||
203 | // Decodes JPG input from whatever source | ||
204 | // Does everything AFTER jpeg_create_decompress | ||
205 | // and BEFORE jpeg_destroy_decompress | ||
206 | // Caller is responsible for arranging these + setting up cinfo | ||
207 | |||
208 | // read file parameters with jpeg_read_header() | ||
209 | jpeg_read_header(&cinfo, TRUE); | ||
210 | |||
211 | bool useCMYK=false; | ||
212 | if (cinfo.jpeg_color_space==JCS_CMYK) | ||
213 | { | ||
214 | cinfo.out_color_space=JCS_CMYK; | ||
215 | cinfo.out_color_components=4; | ||
216 | useCMYK=true; | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | cinfo.out_color_space=JCS_RGB; | ||
221 | cinfo.out_color_components=3; | ||
222 | } | ||
223 | cinfo.output_gamma=2.2; | ||
224 | cinfo.do_fancy_upsampling=FALSE; | ||
225 | |||
226 | // Start decompressor | ||
227 | jpeg_start_decompress(&cinfo); | ||
228 | |||
229 | // Get image data | ||
230 | u16 rowspan = cinfo.image_width * cinfo.out_color_components; | ||
231 | u32 width = cinfo.image_width; | ||
232 | u32 height = cinfo.image_height; | ||
233 | |||
234 | // Allocate memory for buffer | ||
235 | u8* output = new u8[rowspan * height]; | ||
236 | |||
237 | // Here we use the library's state variable cinfo.output_scanline as the | ||
238 | // loop counter, so that we don't have to keep track ourselves. | ||
239 | // Create array of row pointers for lib | ||
240 | rowPtr = new u8* [height]; | ||
241 | |||
242 | for( u32 i = 0; i < height; i++ ) | ||
243 | rowPtr[i] = &output[ i * rowspan ]; | ||
244 | |||
245 | u32 rowsRead = 0; | ||
246 | |||
247 | while( cinfo.output_scanline < cinfo.output_height ) | ||
248 | rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead ); | ||
249 | |||
250 | delete [] rowPtr; | ||
251 | // Finish decompression | ||
252 | |||
253 | jpeg_finish_decompress(&cinfo); | ||
254 | |||
255 | // Release JPEG decompression object | ||
256 | // This is an important step since it will release a good deal of memory. | ||
257 | jpeg_destroy_decompress(&cinfo); | ||
258 | |||
259 | // convert image | ||
260 | IImage* image = 0; | ||
261 | if (useCMYK) | ||
262 | { | ||
263 | image = new CImage(ECF_R8G8B8, | ||
264 | core::dimension2d<u32>(width, height)); | ||
265 | const u32 size = 3*width*height; | ||
266 | u8* data = (u8*)image->lock(); | ||
267 | if (data) | ||
268 | { | ||
269 | for (u32 i=0,j=0; i<size; i+=3, j+=4) | ||
270 | { | ||
271 | // Also works without K, but has more contrast with K multiplied in | ||
272 | // data[i+0] = output[j+2]; | ||
273 | // data[i+1] = output[j+1]; | ||
274 | // data[i+2] = output[j+0]; | ||
275 | data[i+0] = (char)(output[j+2]*(output[j+3]/255.f)); | ||
276 | data[i+1] = (char)(output[j+1]*(output[j+3]/255.f)); | ||
277 | data[i+2] = (char)(output[j+0]*(output[j+3]/255.f)); | ||
278 | } | ||
279 | } | ||
280 | image->unlock(); | ||
281 | delete [] output; | ||
282 | } | ||
283 | else | ||
284 | image = new CImage(ECF_R8G8B8, | ||
285 | core::dimension2d<u32>(width, height), output); | ||
286 | |||
287 | delete [] input; | ||
288 | |||
289 | return image; | ||
290 | |||
291 | #endif | ||
292 | } | ||
293 | |||
294 | |||
295 | |||
296 | //! creates a loader which is able to load jpeg images | ||
297 | IImageLoader* createImageLoaderJPG() | ||
298 | { | ||
299 | return new CImageLoaderJPG(); | ||
300 | } | ||
301 | |||
302 | } // end namespace video | ||
303 | } // end namespace irr | ||
304 | |||
305 | #endif | ||
306 | |||