1 //-----------------------------------------------------------------------------
2 //
3 // ImageLib Sources
4 // Copyright (C) 2000-2009 by Denton Woods
5 // Last modified: 02/14/2009
6 //
7 // Filename: src-IL/src/il_jpeg.c
8 //
9 // Description: Jpeg (.jpg) functions
10 //
11 //-----------------------------------------------------------------------------
12 //
13 // Most of the comments here are sufficient, as we're just using libjpeg.
14 // I have left most of the libjpeg example's comments intact, though.
15 //
16
17 #include "il_internal.h"
18
19 #ifndef IL_NO_JPG
20 #ifndef IL_USE_IJL
21 #ifdef RGB_RED
22 #undef RGB_RED
23 #undef RGB_GREEN
24 #undef RGB_BLUE
25 #endif
26 #define RGB_RED 0
27 #define RGB_GREEN 1
28 #define RGB_BLUE 2
29
30 #if defined(_MSC_VER)
31 #pragma warning(push)
32 #pragma warning(disable : 4005) // Redefinitions in
33 #pragma warning(disable : 4142) // jmorecfg.h
34 #endif
35
36 #include "jpeglib.h"
37
38 #if JPEG_LIB_VERSION < 62
39 #warning DevIL was designed with libjpeg 6b or higher in mind. Consider upgrading at www.ijg.org
40 #endif
41 #else
42 #include <ijl.h>
43 #include <limits.h>
44 #endif
45
46 #include "il_jpeg.h"
47 #include "il_manip.h"
48 #include <setjmp.h>
49
50
51 #if (defined(_WIN32) || defined(_WIN64)) && defined(IL_USE_PRAGMA_LIBS)
52 #if defined(_MSC_VER) || defined(__BORLANDC__)
53 #ifdef IL_USE_IJL
54 //pragma comment(lib, "ijl15.lib")
55 #else
56 #ifndef _DEBUG
57 #pragma comment(lib, "libjpeg.lib")
58 #else
59 #pragma comment(lib, "libjpeg-d.lib")
60 #endif
61 #endif//IL_USE_IJL
62 #endif
63 #endif
64
65
66 static ILboolean jpgErrorOccured = IL_FALSE;
67
68 // define a protype of ilLoadFromJpegStruct
69 ILboolean ilLoadFromJpegStruct(void *_JpegInfo);
70
71 // Internal function used to get the .jpg header from the current file.
iGetJpgHead(ILubyte * Header)72 void iGetJpgHead(ILubyte *Header)
73 {
74 Header[0] = igetc();
75 Header[1] = igetc();
76 return;
77 }
78
79
80 // Internal function used to check if the HEADER is a valid .Jpg header.
iCheckJpg(ILubyte Header[2])81 ILboolean iCheckJpg(ILubyte Header[2])
82 {
83 if (Header[0] != 0xFF || Header[1] != 0xD8)
84 return IL_FALSE;
85 return IL_TRUE;
86 }
87
88
89 // Internal function to get the header and check it.
iIsValidJpeg()90 ILboolean iIsValidJpeg()
91 {
92 ILubyte Head[2];
93
94 iGetJpgHead(Head);
95 iseek(-2, IL_SEEK_CUR); // Go ahead and restore to previous state
96
97 return iCheckJpg(Head);
98 }
99
100
101 //! Checks if the file specified in FileName is a valid .jpg file.
ilIsValidJpeg(ILconst_string FileName)102 ILboolean ilIsValidJpeg(ILconst_string FileName)
103 {
104 ILHANDLE JpegFile;
105 ILboolean bJpeg = IL_FALSE;
106
107 if (!iCheckExtension(FileName, IL_TEXT("jpg")) &&
108 !iCheckExtension(FileName, IL_TEXT("jpe")) &&
109 !iCheckExtension(FileName, IL_TEXT("jpeg")) &&
110 !iCheckExtension(FileName, IL_TEXT("jif")) &&
111 !iCheckExtension(FileName, IL_TEXT("jfif")))
112 {
113 ilSetError(IL_INVALID_EXTENSION);
114 return bJpeg;
115 }
116
117 JpegFile = iopenr(FileName);
118 if (JpegFile == NULL) {
119 ilSetError(IL_COULD_NOT_OPEN_FILE);
120 return bJpeg;
121 }
122
123 bJpeg = ilIsValidJpegF(JpegFile);
124 icloser(JpegFile);
125
126 return bJpeg;
127 }
128
129
130 //! Checks if the ILHANDLE contains a valid .jpg file at the current position.
ilIsValidJpegF(ILHANDLE File)131 ILboolean ilIsValidJpegF(ILHANDLE File)
132 {
133 ILuint FirstPos;
134 ILboolean bRet;
135
136 iSetInputFile(File);
137 FirstPos = itell();
138 bRet = iIsValidJpeg();
139 iseek(FirstPos, IL_SEEK_SET);
140
141 return bRet;
142 }
143
144
ilIsValidJpegL(const void * Lump,ILuint Size)145 ILboolean ilIsValidJpegL(const void *Lump, ILuint Size)
146 {
147 iSetInputLump(Lump, Size);
148 return iIsValidJpeg();
149 }
150
151
152 #ifndef IL_USE_IJL // Use libjpeg instead of the IJL.
153
154 // Overrides libjpeg's stupid error/warning handlers. =P
ExitErrorHandle(struct jpeg_common_struct * JpegInfo)155 void ExitErrorHandle (struct jpeg_common_struct *JpegInfo)
156 {
157 ilSetError(IL_LIB_JPEG_ERROR);
158 jpgErrorOccured = IL_TRUE;
159 return;
160 }
OutputMsg(struct jpeg_common_struct * JpegInfo)161 void OutputMsg(struct jpeg_common_struct *JpegInfo)
162 {
163 return;
164 }
165
166
167 //! Reads a jpeg file
ilLoadJpeg(ILconst_string FileName)168 ILboolean ilLoadJpeg(ILconst_string FileName)
169 {
170 ILHANDLE JpegFile;
171 ILboolean bJpeg = IL_FALSE;
172
173 JpegFile = iopenr(FileName);
174 if (JpegFile == NULL) {
175 ilSetError(IL_COULD_NOT_OPEN_FILE);
176 return bJpeg;
177 }
178
179 bJpeg = ilLoadJpegF(JpegFile);
180 icloser(JpegFile);
181
182 return bJpeg;
183 }
184
185
186 //! Reads an already-opened jpeg file
ilLoadJpegF(ILHANDLE File)187 ILboolean ilLoadJpegF(ILHANDLE File)
188 {
189 ILboolean bRet;
190 ILuint FirstPos;
191
192 iSetInputFile(File);
193 FirstPos = itell();
194 bRet = iLoadJpegInternal();
195 iseek(FirstPos, IL_SEEK_SET);
196
197 return bRet;
198 }
199
200
201 // Reads from a memory "lump" containing a jpeg
ilLoadJpegL(const void * Lump,ILuint Size)202 ILboolean ilLoadJpegL(const void *Lump, ILuint Size)
203 {
204 iSetInputLump(Lump, Size);
205 return iLoadJpegInternal();
206 }
207
208
209 typedef struct {
210 struct jpeg_source_mgr pub; /* public fields */
211
212 JOCTET * buffer; /* start of buffer */
213 boolean start_of_file; /* have we gotten any data yet? */
214 } iread_mgr;
215
216 typedef iread_mgr * iread_ptr;
217
218 #define INPUT_BUF_SIZE 4096 // choose an efficiently iread'able size
219
220
221 METHODDEF(void)
init_source(j_decompress_ptr cinfo)222 init_source (j_decompress_ptr cinfo)
223 {
224 iread_ptr src = (iread_ptr) cinfo->src;
225 src->start_of_file = TRUE;
226 }
227
228
229 METHODDEF(boolean)
fill_input_buffer(j_decompress_ptr cinfo)230 fill_input_buffer (j_decompress_ptr cinfo)
231 {
232 iread_ptr src = (iread_ptr) cinfo->src;
233 ILint nbytes;
234
235 nbytes = iread(src->buffer, 1, INPUT_BUF_SIZE);
236
237 if (nbytes <= 0) {
238 if (src->start_of_file) { // Treat empty input file as fatal error
239 //ERREXIT(cinfo, JERR_INPUT_EMPTY);
240 jpgErrorOccured = IL_TRUE;
241 }
242 //WARNMS(cinfo, JWRN_JPEG_EOF);
243 // Insert a fake EOI marker
244 src->buffer[0] = (JOCTET) 0xFF;
245 src->buffer[1] = (JOCTET) JPEG_EOI;
246 nbytes = 2;
247 return IL_FALSE;
248 }
249 if (nbytes < INPUT_BUF_SIZE) {
250 ilGetError(); // Gets rid of the IL_FILE_READ_ERROR.
251 }
252
253 src->pub.next_input_byte = src->buffer;
254 src->pub.bytes_in_buffer = nbytes;
255 src->start_of_file = IL_FALSE;
256
257 return IL_TRUE;
258 }
259
260
261 METHODDEF(void)
skip_input_data(j_decompress_ptr cinfo,long num_bytes)262 skip_input_data (j_decompress_ptr cinfo, long num_bytes)
263 {
264 iread_ptr src = (iread_ptr) cinfo->src;
265
266 if (num_bytes > 0) {
267 while (num_bytes > (long) src->pub.bytes_in_buffer) {
268 num_bytes -= (long) src->pub.bytes_in_buffer;
269 (void) fill_input_buffer(cinfo);
270 }
271 src->pub.next_input_byte += (size_t) num_bytes;
272 src->pub.bytes_in_buffer -= (size_t) num_bytes;
273 }
274 }
275
276
277 METHODDEF(void)
term_source(j_decompress_ptr cinfo)278 term_source (j_decompress_ptr cinfo)
279 {
280 // no work necessary here
281 }
282
283
284 GLOBAL(void)
devil_jpeg_read_init(j_decompress_ptr cinfo)285 devil_jpeg_read_init (j_decompress_ptr cinfo)
286 {
287 iread_ptr src;
288
289 if ( cinfo->src == NULL ) { // first time for this JPEG object?
290 cinfo->src = (struct jpeg_source_mgr *)
291 (*cinfo->mem->alloc_small)( (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(iread_mgr) );
292 src = (iread_ptr) cinfo->src;
293 src->buffer = (JOCTET *)
294 (*cinfo->mem->alloc_small)( (j_common_ptr)cinfo, JPOOL_PERMANENT,
295 INPUT_BUF_SIZE * sizeof(JOCTET) );
296 }
297
298 src = (iread_ptr) cinfo->src;
299 src->pub.init_source = init_source;
300 src->pub.fill_input_buffer = fill_input_buffer;
301 src->pub.skip_input_data = skip_input_data;
302 src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method
303 src->pub.term_source = term_source;
304 src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
305 src->pub.next_input_byte = NULL; // until buffer loaded
306 }
307
308
309 jmp_buf JpegJumpBuffer;
310
iJpegErrorExit(j_common_ptr cinfo)311 static void iJpegErrorExit( j_common_ptr cinfo )
312 {
313 ilSetError( IL_LIB_JPEG_ERROR );
314 jpeg_destroy( cinfo );
315 longjmp( JpegJumpBuffer, 1 );
316 }
317
318 // Internal function used to load the jpeg.
iLoadJpegInternal()319 ILboolean iLoadJpegInternal()
320 {
321 struct jpeg_error_mgr Error;
322 struct jpeg_decompress_struct JpegInfo;
323 ILboolean result;
324
325 if (iCurImage == NULL) {
326 ilSetError(IL_ILLEGAL_OPERATION);
327 return IL_FALSE;
328 }
329
330 JpegInfo.err = jpeg_std_error(&Error); // init standard error handlers
331 Error.error_exit = iJpegErrorExit; // add our exit handler
332 Error.output_message = OutputMsg;
333
334 if ((result = setjmp(JpegJumpBuffer) == 0) != IL_FALSE) {
335 jpeg_create_decompress(&JpegInfo);
336 JpegInfo.do_block_smoothing = IL_TRUE;
337 JpegInfo.do_fancy_upsampling = IL_TRUE;
338
339 //jpeg_stdio_src(&JpegInfo, iGetFile());
340
341 devil_jpeg_read_init(&JpegInfo);
342 jpeg_read_header(&JpegInfo, IL_TRUE);
343
344 result = ilLoadFromJpegStruct(&JpegInfo);
345
346 jpeg_finish_decompress(&JpegInfo);
347 jpeg_destroy_decompress(&JpegInfo);
348
349 }
350 else
351 {
352 jpeg_destroy_decompress(&JpegInfo);
353 }
354
355 //return ilFixImage(); // No need to call it again (called first in ilLoadFromJpegStruct).
356 return result;
357 }
358
359
360
361 typedef struct
362 {
363 struct jpeg_destination_mgr pub;
364 JOCTET *buffer;
365 ILboolean bah;
366 } iwrite_mgr;
367
368 typedef iwrite_mgr *iwrite_ptr;
369
370 #define OUTPUT_BUF_SIZE 4096
371
372
373 METHODDEF(void)
init_destination(j_compress_ptr cinfo)374 init_destination(j_compress_ptr cinfo)
375 {
376 iwrite_ptr dest = (iwrite_ptr)cinfo->dest;
377 dest->buffer = (JOCTET *)
378 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
379 OUTPUT_BUF_SIZE * sizeof(JOCTET));
380
381 dest->pub.next_output_byte = dest->buffer;
382 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
383 return;
384 }
385
386 METHODDEF(boolean)
empty_output_buffer(j_compress_ptr cinfo)387 empty_output_buffer (j_compress_ptr cinfo)
388 {
389 iwrite_ptr dest = (iwrite_ptr)cinfo->dest;
390 iwrite(dest->buffer, 1, OUTPUT_BUF_SIZE);
391 dest->pub.next_output_byte = dest->buffer;
392 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
393 return IL_TRUE;
394 }
395
396 METHODDEF(void)
term_destination(j_compress_ptr cinfo)397 term_destination (j_compress_ptr cinfo)
398 {
399 iwrite_ptr dest = (iwrite_ptr)cinfo->dest;
400 iwrite(dest->buffer, 1, OUTPUT_BUF_SIZE - (ILuint)dest->pub.free_in_buffer);
401 return;
402 }
403
404
405 GLOBAL(void)
devil_jpeg_write_init(j_compress_ptr cinfo)406 devil_jpeg_write_init(j_compress_ptr cinfo)
407 {
408 iwrite_ptr dest;
409
410 if (cinfo->dest == NULL) { // first time for this JPEG object?
411 cinfo->dest = (struct jpeg_destination_mgr *)
412 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
413 sizeof(iwrite_mgr));
414 dest = (iwrite_ptr)cinfo->dest;
415 }
416
417 dest = (iwrite_ptr)cinfo->dest;
418 dest->pub.init_destination = init_destination;
419 dest->pub.empty_output_buffer = empty_output_buffer;
420 dest->pub.term_destination = term_destination;
421
422 return;
423 }
424
425
426 //! Writes a Jpeg file
ilSaveJpeg(const ILstring FileName)427 ILboolean ilSaveJpeg(const ILstring FileName)
428 {
429 ILHANDLE JpegFile;
430 ILuint JpegSize;
431
432 if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
433 if (iFileExists(FileName)) {
434 ilSetError(IL_FILE_ALREADY_EXISTS);
435 return IL_FALSE;
436 }
437 }
438
439 JpegFile = iopenw(FileName);
440 if (JpegFile == NULL) {
441 ilSetError(IL_COULD_NOT_OPEN_FILE);
442 return IL_FALSE;
443 }
444
445 JpegSize = ilSaveJpegF(JpegFile);
446 iclosew(JpegFile);
447
448 if (JpegSize == 0)
449 return IL_FALSE;
450 return IL_TRUE;
451 }
452
453
454 //! Writes a Jpeg to an already-opened file
ilSaveJpegF(ILHANDLE File)455 ILuint ilSaveJpegF(ILHANDLE File)
456 {
457 ILuint Pos;
458 iSetOutputFile(File);
459 Pos = itellw();
460 if (iSaveJpegInternal() == IL_FALSE)
461 return 0; // Error occurred
462 return itellw() - Pos; // Return the number of bytes written.
463 }
464
465
466 //! Writes a Jpeg to a memory "lump"
ilSaveJpegL(void * Lump,ILuint Size)467 ILuint ilSaveJpegL(void *Lump, ILuint Size)
468 {
469 ILuint Pos;
470 iSetOutputLump(Lump, Size);
471 Pos = itellw();
472 if (iSaveJpegInternal() == IL_FALSE)
473 return 0; // Error occurred
474 return itellw() - Pos; // Return the number of bytes written.
475 }
476
477
478 // Internal function used to save the Jpeg.
iSaveJpegInternal()479 ILboolean iSaveJpegInternal()
480 {
481 struct jpeg_compress_struct JpegInfo;
482 struct jpeg_error_mgr Error;
483 JSAMPROW row_pointer[1];
484 ILimage *TempImage;
485 ILubyte *TempData;
486 ILenum Type = 0;
487
488 if (iCurImage == NULL) {
489 ilSetError(IL_ILLEGAL_OPERATION);
490 return IL_FALSE;
491 }
492
493 /*if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION)
494 Quality = 85; // Not sure how low we should dare go...
495 else
496 Quality = 99;*/
497
498 if ((iCurImage->Format != IL_RGB && iCurImage->Format != IL_LUMINANCE) || iCurImage->Bpc != 1) {
499 TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
500 if (TempImage == NULL) {
501 return IL_FALSE;
502 }
503 }
504 else {
505 TempImage = iCurImage;
506 }
507
508 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) {
509 TempData = iGetFlipped(TempImage);
510 if (TempData == NULL) {
511 if (TempImage != iCurImage)
512 ilCloseImage(TempImage);
513 return IL_FALSE;
514 }
515 }
516 else {
517 TempData = TempImage->Data;
518 }
519
520
521 JpegInfo.err = jpeg_std_error(&Error);
522 // Now we can initialize the JPEG compression object.
523 jpeg_create_compress(&JpegInfo);
524
525 //jpeg_stdio_dest(&JpegInfo, JpegFile);
526 devil_jpeg_write_init(&JpegInfo);
527
528 JpegInfo.image_width = TempImage->Width; // image width and height, in pixels
529 JpegInfo.image_height = TempImage->Height;
530 JpegInfo.input_components = TempImage->Bpp; // # of color components per pixel
531
532 // John Villar's addition
533 if (TempImage->Bpp == 1)
534 JpegInfo.in_color_space = JCS_GRAYSCALE;
535 else
536 JpegInfo.in_color_space = JCS_RGB;
537
538 jpeg_set_defaults(&JpegInfo);
539
540 /*#ifndef IL_USE_JPEGLIB_UNMODIFIED
541 Type = iGetInt(IL_JPG_SAVE_FORMAT);
542 if (Type == IL_EXIF) {
543 JpegInfo.write_JFIF_header = FALSE;
544 JpegInfo.write_EXIF_header = TRUE;
545 }
546 else if (Type == IL_JFIF) {
547 JpegInfo.write_JFIF_header = TRUE;
548 JpegInfo.write_EXIF_header = FALSE;
549 } //EXIF not present in libjpeg...
550 #else*/
551 Type = Type;
552 JpegInfo.write_JFIF_header = TRUE;
553 //#endif//IL_USE_JPEGLIB_UNMODIFIED
554
555 // Set the quality output
556 jpeg_set_quality(&JpegInfo, iGetInt(IL_JPG_QUALITY), IL_TRUE);
557 // Sets progressive saving here
558 if (ilGetBoolean(IL_JPG_PROGRESSIVE))
559 jpeg_simple_progression(&JpegInfo);
560
561 jpeg_start_compress(&JpegInfo, IL_TRUE);
562
563 //row_stride = image_width * 3; // JSAMPLEs per row in image_buffer
564
565 while (JpegInfo.next_scanline < JpegInfo.image_height) {
566 // jpeg_write_scanlines expects an array of pointers to scanlines.
567 // Here the array is only one element long, but you could pass
568 // more than one scanline at a time if that's more convenient.
569 row_pointer[0] = &TempData[JpegInfo.next_scanline * TempImage->Bps];
570 (void) jpeg_write_scanlines(&JpegInfo, row_pointer, 1);
571 }
572
573 // Step 6: Finish compression
574 jpeg_finish_compress(&JpegInfo);
575
576 // Step 7: release JPEG compression object
577
578 // This is an important step since it will release a good deal of memory.
579 jpeg_destroy_compress(&JpegInfo);
580
581 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
582 ifree(TempData);
583 if (TempImage != iCurImage)
584 ilCloseImage(TempImage);
585
586 return IL_TRUE;
587 }
588
589
590
591 #else // Use the IJL instead of libjpeg.
592
593
594
595 //! Reads a jpeg file
ilLoadJpeg(ILconst_string FileName)596 ILboolean ilLoadJpeg(ILconst_string FileName)
597 {
598 if (!iFileExists(FileName)) {
599 ilSetError(IL_COULD_NOT_OPEN_FILE);
600 return IL_FALSE;
601 }
602 return iLoadJpegInternal(FileName, NULL, 0);
603 }
604
605
606 // Reads from a memory "lump" containing a jpeg
ilLoadJpegL(void * Lump,ILuint Size)607 ILboolean ilLoadJpegL(void *Lump, ILuint Size)
608 {
609 return iLoadJpegInternal(NULL, Lump, Size);
610 }
611
612
613 // Internal function used to load the jpeg.
iLoadJpegInternal(ILstring FileName,void * Lump,ILuint Size)614 ILboolean iLoadJpegInternal(ILstring FileName, void *Lump, ILuint Size)
615 {
616 JPEG_CORE_PROPERTIES Image;
617
618 if (iCurImage == NULL) {
619 ilSetError(IL_ILLEGAL_OPERATION);
620 return IL_FALSE;
621 }
622
623 if (ijlInit(&Image) != IJL_OK) {
624 ilSetError(IL_LIB_JPEG_ERROR);
625 return IL_FALSE;
626 }
627
628 if (FileName != NULL) {
629 Image.JPGFile = FileName;
630 if (ijlRead(&Image, IJL_JFILE_READPARAMS) != IJL_OK) {
631 ilSetError(IL_LIB_JPEG_ERROR);
632 return IL_FALSE;
633 }
634 }
635 else {
636 Image.JPGBytes = Lump;
637 Image.JPGSizeBytes = Size > 0 ? Size : UINT_MAX;
638 if (ijlRead(&Image, IJL_JBUFF_READPARAMS) != IJL_OK) {
639 ilSetError(IL_LIB_JPEG_ERROR);
640 return IL_FALSE;
641 }
642 }
643
644 switch (Image.JPGChannels)
645 {
646 case 1:
647 Image.JPGColor = IJL_G;
648 Image.DIBChannels = 1;
649 Image.DIBColor = IJL_G;
650 iCurImage->Format = IL_LUMINANCE;
651 break;
652
653 case 3:
654 Image.JPGColor = IJL_YCBCR;
655 Image.DIBChannels = 3;
656 Image.DIBColor = IJL_RGB;
657 iCurImage->Format = IL_RGB;
658 break;
659
660 case 4:
661 Image.JPGColor = IJL_YCBCRA_FPX;
662 Image.DIBChannels = 4;
663 Image.DIBColor = IJL_RGBA_FPX;
664 iCurImage->Format = IL_RGBA;
665 break;
666
667 default:
668 // This catches everything else, but no
669 // color twist will be performed by the IJL.
670 /*Image.DIBColor = (IJL_COLOR)IJL_OTHER;
671 Image.JPGColor = (IJL_COLOR)IJL_OTHER;
672 Image.DIBChannels = Image.JPGChannels;
673 break;*/
674 ijlFree(&Image);
675 ilSetError(IL_LIB_JPEG_ERROR);
676 return IL_FALSE;
677 }
678
679 if (!ilTexImage(Image.JPGWidth, Image.JPGHeight, 1, (ILubyte)Image.DIBChannels, iCurImage->Format, IL_UNSIGNED_BYTE, NULL)) {
680 ijlFree(&Image);
681 return IL_FALSE;
682 }
683 iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
684
685 Image.DIBWidth = Image.JPGWidth;
686 Image.DIBHeight = Image.JPGHeight;
687 Image.DIBPadBytes = 0;
688 Image.DIBBytes = iCurImage->Data;
689
690 if (FileName != NULL) {
691 if (ijlRead(&Image, IJL_JFILE_READWHOLEIMAGE) != IJL_OK) {
692 ijlFree(&Image);
693 ilSetError(IL_LIB_JPEG_ERROR);
694 return IL_FALSE;
695 }
696 }
697 else {
698 if (ijlRead(&Image, IJL_JBUFF_READWHOLEIMAGE) != IJL_OK) {
699 ijlFree(&Image);
700 ilSetError(IL_LIB_JPEG_ERROR);
701 return IL_FALSE;
702 }
703 }
704
705 ijlFree(&Image);
706 return ilFixImage();
707 }
708
709
710 //! Writes a Jpeg file
ilSaveJpeg(ILconst_string FileName)711 ILboolean ilSaveJpeg(ILconst_string FileName)
712 {
713 if (ilGetBoolean(IL_FILE_MODE) == IL_FALSE) {
714 if (iFileExists(FileName)) {
715 ilSetError(IL_FILE_ALREADY_EXISTS);
716 return IL_FALSE;
717 }
718 }
719
720 return iSaveJpegInternal(FileName, NULL, 0);
721 }
722
723
724 //! Writes a Jpeg to a memory "lump"
ilSaveJpegL(void * Lump,ILuint Size)725 ILboolean ilSaveJpegL(void *Lump, ILuint Size)
726 {
727 return iSaveJpegInternal(NULL, Lump, Size);
728 }
729
730
731 // Internal function used to save the Jpeg.
iSaveJpegInternal(ILstring FileName,void * Lump,ILuint Size)732 ILboolean iSaveJpegInternal(ILstring FileName, void *Lump, ILuint Size)
733 {
734 JPEG_CORE_PROPERTIES Image;
735 ILuint Quality;
736 ILimage *TempImage;
737 ILubyte *TempData;
738
739 imemclear(&Image, sizeof(JPEG_CORE_PROPERTIES));
740
741 if (iCurImage == NULL) {
742 ilSetError(IL_ILLEGAL_OPERATION);
743 return IL_FALSE;
744 }
745 if (FileName == NULL && Lump == NULL) {
746 ilSetError(IL_INVALID_PARAM);
747 return IL_FALSE;
748 }
749
750 if (iGetHint(IL_COMPRESSION_HINT) == IL_USE_COMPRESSION)
751 Quality = 85; // Not sure how low we should dare go...
752 else
753 Quality = 99;
754
755 if (ijlInit(&Image) != IJL_OK) {
756 ilSetError(IL_LIB_JPEG_ERROR);
757 return IL_FALSE;
758 }
759
760 if ((iCurImage->Format != IL_RGB && iCurImage->Format != IL_RGBA && iCurImage->Format != IL_LUMINANCE)
761 || iCurImage->Bpc != 1) {
762 if (iCurImage->Format == IL_BGRA)
763 Temp = iConvertImage(iCurImage, IL_RGBA, IL_UNSIGNED_BYTE);
764 else
765 Temp = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
766 if (Temp == NULL) {
767 return IL_FALSE;
768 }
769 }
770 else {
771 Temp = iCurImage;
772 }
773
774 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) {
775 TempData = iGetFlipped(TempImage);
776 if (TempData == NULL) {
777 if (TempImage != iCurImage)
778 ilCloseImage(TempImage);
779 return IL_FALSE;
780 }
781 }
782 else {
783 TempData = TempImage->Data;
784 }
785
786 // Setup DIB
787 Image.DIBWidth = TempImage->Width;
788 Image.DIBHeight = TempImage->Height;
789 Image.DIBChannels = TempImage->Bpp;
790 Image.DIBBytes = TempData;
791 Image.DIBPadBytes = 0;
792
793 // Setup JPEG
794 Image.JPGWidth = TempImage->Width;
795 Image.JPGHeight = TempImage->Height;
796 Image.JPGChannels = TempImage->Bpp;
797
798 switch (Temp->Bpp)
799 {
800 case 1:
801 Image.DIBColor = IJL_G;
802 Image.JPGColor = IJL_G;
803 Image.JPGSubsampling = IJL_NONE;
804 break;
805 case 3:
806 Image.DIBColor = IJL_RGB;
807 Image.JPGColor = IJL_YCBCR;
808 Image.JPGSubsampling = IJL_411;
809 break;
810 case 4:
811 Image.DIBColor = IJL_RGBA_FPX;
812 Image.JPGColor = IJL_YCBCRA_FPX;
813 Image.JPGSubsampling = IJL_4114;
814 break;
815 }
816
817 if (FileName != NULL) {
818 Image.JPGFile = FileName;
819 if (ijlWrite(&Image, IJL_JFILE_WRITEWHOLEIMAGE) != IJL_OK) {
820 if (TempImage != iCurImage)
821 ilCloseImage(TempImage);
822 ilSetError(IL_LIB_JPEG_ERROR);
823 return IL_FALSE;
824 }
825 }
826 else {
827 Image.JPGBytes = Lump;
828 Image.JPGSizeBytes = Size;
829 if (ijlWrite(&Image, IJL_JBUFF_WRITEWHOLEIMAGE) != IJL_OK) {
830 if (TempImage != iCurImage)
831 ilCloseImage(TempImage);
832 ilSetError(IL_LIB_JPEG_ERROR);
833 return IL_FALSE;
834 }
835 }
836
837 ijlFree(&Image);
838
839 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
840 ifree(TempData);
841 if (Temp != iCurImage)
842 ilCloseImage(Temp);
843
844 return IL_TRUE;
845 }
846
847 #endif//IL_USE_IJL
848
849
850 // Access point for applications wishing to use the jpeg library directly in
851 // conjunction with DevIL.
852 //
853 // The decompressor must be set up with an input source and all desired parameters
854 // this function is called. The caller must call jpeg_finish_decompress because
855 // the caller may still need decompressor after calling this for e.g. examining
856 // saved markers.
ilLoadFromJpegStruct(void * _JpegInfo)857 ILboolean ilLoadFromJpegStruct(void *_JpegInfo)
858 {
859 #ifndef IL_NO_JPG
860 #ifndef IL_USE_IJL
861 // sam. void (*errorHandler)(j_common_ptr);
862 ILubyte *TempPtr[1];
863 ILuint Returned;
864 j_decompress_ptr JpegInfo = (j_decompress_ptr)_JpegInfo;
865
866 //added on 2003-08-31 as explained in sf bug 596793
867 jpgErrorOccured = IL_FALSE;
868
869 // sam. errorHandler = JpegInfo->err->error_exit;
870 // sam. JpegInfo->err->error_exit = ExitErrorHandle;
871 jpeg_start_decompress((j_decompress_ptr)JpegInfo);
872
873 if (!ilTexImage(JpegInfo->output_width, JpegInfo->output_height, 1, (ILubyte)JpegInfo->output_components, 0, IL_UNSIGNED_BYTE, NULL)) {
874 return IL_FALSE;
875 }
876 iCurImage->Origin = IL_ORIGIN_UPPER_LEFT;
877
878 switch (iCurImage->Bpp)
879 {
880 case 1:
881 iCurImage->Format = IL_LUMINANCE;
882 break;
883 case 3:
884 iCurImage->Format = IL_RGB;
885 break;
886 case 4:
887 iCurImage->Format = IL_RGBA;
888 break;
889 default:
890 //@TODO: Anyway to get here? Need to error out or something...
891 break;
892 }
893
894 TempPtr[0] = iCurImage->Data;
895 while (JpegInfo->output_scanline < JpegInfo->output_height) {
896 Returned = jpeg_read_scanlines(JpegInfo, TempPtr, 1); // anyway to make it read all at once?
897 TempPtr[0] += iCurImage->Bps;
898 if (Returned == 0)
899 break;
900 }
901
902 // sam. JpegInfo->err->error_exit = errorHandler;
903
904 if (jpgErrorOccured)
905 return IL_FALSE;
906
907 return ilFixImage();
908 #endif
909 #endif
910 return IL_FALSE;
911 }
912
913
914
915 // Access point for applications wishing to use the jpeg library directly in
916 // conjunction with DevIL.
917 //
918 // The caller must set up the desired parameters by e.g. calling
919 // jpeg_set_defaults and overriding the parameters the caller wishes
920 // to change, such as quality, before calling this function. The caller
921 // is also responsible for calling jpeg_finish_compress in case the
922 // caller still needs to compressor for something.
923 //
ilSaveFromJpegStruct(void * _JpegInfo)924 ILboolean ilSaveFromJpegStruct(void *_JpegInfo)
925 {
926 #ifndef IL_NO_JPG
927 #ifndef IL_USE_IJL
928 void (*errorHandler)();
929 JSAMPROW row_pointer[1];
930 ILimage *TempImage;
931 ILubyte *TempData;
932 j_compress_ptr JpegInfo = (j_compress_ptr)_JpegInfo;
933
934 if (iCurImage == NULL) {
935 ilSetError(IL_ILLEGAL_OPERATION);
936 return IL_FALSE;
937 }
938
939 //added on 2003-08-31 as explained in SF bug 596793
940 jpgErrorOccured = IL_FALSE;
941
942 errorHandler = JpegInfo->err->error_exit;
943 JpegInfo->err->error_exit = ExitErrorHandle;
944
945
946 if ((iCurImage->Format != IL_RGB && iCurImage->Format != IL_LUMINANCE) || iCurImage->Bpc != 1) {
947 TempImage = iConvertImage(iCurImage, IL_RGB, IL_UNSIGNED_BYTE);
948 if (TempImage == NULL) {
949 return IL_FALSE;
950 }
951 }
952 else {
953 TempImage = iCurImage;
954 }
955
956 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT) {
957 TempData = iGetFlipped(TempImage);
958 if (TempData == NULL) {
959 if (TempImage != iCurImage)
960 ilCloseImage(TempImage);
961 return IL_FALSE;
962 }
963 }
964 else {
965 TempData = TempImage->Data;
966 }
967
968 JpegInfo->image_width = TempImage->Width; // image width and height, in pixels
969 JpegInfo->image_height = TempImage->Height;
970 JpegInfo->input_components = TempImage->Bpp; // # of color components per pixel
971
972 jpeg_start_compress(JpegInfo, IL_TRUE);
973
974 //row_stride = image_width * 3; // JSAMPLEs per row in image_buffer
975
976 while (JpegInfo->next_scanline < JpegInfo->image_height) {
977 // jpeg_write_scanlines expects an array of pointers to scanlines.
978 // Here the array is only one element long, but you could pass
979 // more than one scanline at a time if that's more convenient.
980 row_pointer[0] = &TempData[JpegInfo->next_scanline * TempImage->Bps];
981 (void) jpeg_write_scanlines(JpegInfo, row_pointer, 1);
982 }
983
984 if (TempImage->Origin == IL_ORIGIN_LOWER_LEFT)
985 ifree(TempData);
986 if (TempImage != iCurImage)
987 ilCloseImage(TempImage);
988
989 return (!jpgErrorOccured);
990 #endif//IL_USE_IJL
991 #endif//IL_NO_JPG
992 return IL_FALSE;
993 }
994
995
996 #if defined(_MSC_VER)
997 #pragma warning(pop)
998 //#pragma warning(disable : 4756) // Disables 'named type definition in parentheses' warning
999 #endif
1000
1001 #endif//IL_NO_JPG
1002