]> icculus.org git repositories - divverent/darkplaces.git/blob - jpeg.c
moved all type-specific model fields to respective structures (alias, sprite, brush)
[divverent/darkplaces.git] / jpeg.c
1 /*
2         Copyright (C) 2002  Mathieu Olivier
3
4         This program is free software; you can redistribute it and/or
5         modify it under the terms of the GNU General Public License
6         as published by the Free Software Foundation; either version 2
7         of the License, or (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13         See the GNU General Public License for more details.
14
15         You should have received a copy of the GNU General Public License
16         along with this program; if not, write to:
17
18                 Free Software Foundation, Inc.
19                 59 Temple Place - Suite 330
20                 Boston, MA  02111-1307, USA
21
22 */
23
24
25 #include "quakedef.h"
26 #include "jpeg.h"
27
28
29 /*
30 =================================================================
31
32   Minimal set of definitions from the JPEG lib
33
34   WARNING: for a matter of simplicity, several pointer types are
35   casted to "void*", and most enumerated values are not included
36
37 =================================================================
38 */
39
40 // jboolean is qbyte instead of int on Win32
41 #ifdef WIN32
42 typedef qbyte jboolean;
43 #else
44 typedef int jboolean;
45 #endif
46
47 #define JPEG_LIB_VERSION  62  // Version 6b
48
49 typedef void *j_common_ptr;
50 typedef struct jpeg_compress_struct *j_compress_ptr;
51 typedef struct jpeg_decompress_struct *j_decompress_ptr;
52 typedef enum
53 {
54         JCS_UNKNOWN,
55         JCS_GRAYSCALE,
56         JCS_RGB,
57         JCS_YCbCr,
58         JCS_CMYK,
59         JCS_YCCK
60 } J_COLOR_SPACE;
61 typedef enum {JPEG_DUMMY1} J_DCT_METHOD;
62 typedef enum {JPEG_DUMMY2} J_DITHER_MODE;
63 typedef unsigned int JDIMENSION;
64
65 #define JPOOL_PERMANENT 0       // lasts until master record is destroyed
66 #define JPOOL_IMAGE             1       // lasts until done with image/datastream
67
68 #define JPEG_EOI        0xD9  // EOI marker code
69
70 #define JMSG_STR_PARM_MAX  80
71
72 #define DCTSIZE2 64
73 #define NUM_QUANT_TBLS 4
74 #define NUM_HUFF_TBLS 4
75 #define NUM_ARITH_TBLS 16
76 #define MAX_COMPS_IN_SCAN 4
77 #define C_MAX_BLOCKS_IN_MCU 10
78 #define D_MAX_BLOCKS_IN_MCU 10
79
80 struct jpeg_memory_mgr
81 {
82   void* (*alloc_small) (j_common_ptr cinfo, int pool_id, size_t sizeofobject);
83   void (*alloc_large) ();
84   void (*alloc_sarray) ();
85   void (*alloc_barray) ();
86   void (*request_virt_sarray) ();
87   void (*request_virt_barray) ();
88   void (*realize_virt_arrays) ();
89   void (*access_virt_sarray) ();
90   void (*access_virt_barray) ();
91   void (*free_pool) ();
92   void (*self_destruct) ();
93
94   long max_memory_to_use;
95   long max_alloc_chunk;
96 };
97
98 struct jpeg_error_mgr
99 {
100         void (*error_exit) (j_common_ptr cinfo);
101         void (*emit_message) (j_common_ptr cinfo, int msg_level);
102         void (*output_message) (j_common_ptr cinfo);
103         void (*format_message) (j_common_ptr cinfo, char * buffer);
104         void (*reset_error_mgr) (j_common_ptr cinfo);
105         int msg_code;
106         union {
107                 int i[8];
108                 char s[JMSG_STR_PARM_MAX];
109         } msg_parm;
110         int trace_level;
111         long num_warnings;
112         const char * const * jpeg_message_table;
113         int last_jpeg_message;
114         const char * const * addon_message_table;
115         int first_addon_message;
116         int last_addon_message;
117 };
118
119 struct jpeg_source_mgr
120 {
121         const qbyte *next_input_byte;
122         size_t bytes_in_buffer;
123
124         void (*init_source) (j_decompress_ptr cinfo);
125         jboolean (*fill_input_buffer) (j_decompress_ptr cinfo);
126         void (*skip_input_data) (j_decompress_ptr cinfo, long num_bytes);
127         jboolean (*resync_to_restart) (j_decompress_ptr cinfo, int desired);
128         void (*term_source) (j_decompress_ptr cinfo);
129 };
130
131 struct jpeg_decompress_struct
132 {
133         struct jpeg_error_mgr *err;             // USED
134         struct jpeg_memory_mgr *mem;    // USED
135
136         void *progress;
137         void *client_data;
138         jboolean is_decompressor;
139         int global_state;
140
141         struct jpeg_source_mgr *src;    // USED
142         JDIMENSION image_width;                 // USED
143         JDIMENSION image_height;                // USED
144
145         int num_components;
146         J_COLOR_SPACE jpeg_color_space;
147         J_COLOR_SPACE out_color_space;
148         unsigned int scale_num, scale_denom;
149         double output_gamma;
150         jboolean buffered_image;
151         jboolean raw_data_out;
152         J_DCT_METHOD dct_method;
153         jboolean do_fancy_upsampling;
154         jboolean do_block_smoothing;
155         jboolean quantize_colors;
156         J_DITHER_MODE dither_mode;
157         jboolean two_pass_quantize;
158         int desired_number_of_colors;
159         jboolean enable_1pass_quant;
160         jboolean enable_external_quant;
161         jboolean enable_2pass_quant;
162         JDIMENSION output_width;
163
164         JDIMENSION output_height;       // USED
165
166         int out_color_components;
167
168         int output_components;          // USED
169
170         int rec_outbuf_height;
171         int actual_number_of_colors;
172         void *colormap;
173
174         JDIMENSION output_scanline;     // USED
175
176         int input_scan_number;
177         JDIMENSION input_iMCU_row;
178         int output_scan_number;
179         JDIMENSION output_iMCU_row;
180         int (*coef_bits)[DCTSIZE2];
181         void *quant_tbl_ptrs[NUM_QUANT_TBLS];
182         void *dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
183         void *ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
184         int data_precision;
185         void *comp_info;
186         jboolean progressive_mode;
187         jboolean arith_code;
188         qbyte arith_dc_L[NUM_ARITH_TBLS];
189         qbyte arith_dc_U[NUM_ARITH_TBLS];
190         qbyte arith_ac_K[NUM_ARITH_TBLS];
191         unsigned int restart_interval;
192         jboolean saw_JFIF_marker;
193         qbyte JFIF_major_version;
194         qbyte JFIF_minor_version;
195         qbyte density_unit;
196         unsigned short X_density;
197         unsigned short Y_density;
198         jboolean saw_Adobe_marker;
199         qbyte Adobe_transform;
200         jboolean CCIR601_sampling;
201         void *marker_list;
202         int max_h_samp_factor;
203         int max_v_samp_factor;
204         int min_DCT_scaled_size;
205         JDIMENSION total_iMCU_rows;
206         void *sample_range_limit;
207         int comps_in_scan;
208         void *cur_comp_info[MAX_COMPS_IN_SCAN];
209         JDIMENSION MCUs_per_row;
210         JDIMENSION MCU_rows_in_scan;
211         int blocks_in_MCU;
212         int MCU_membership[D_MAX_BLOCKS_IN_MCU];
213         int Ss, Se, Ah, Al;
214         int unread_marker;
215         void *master;
216         void *main;
217         void *coef;
218         void *post;
219         void *inputctl;
220         void *marker;
221         void *entropy;
222         void *idct;
223         void *upsample;
224         void *cconvert;
225         void *cquantize;
226 };
227
228
229 struct jpeg_compress_struct
230 {
231         struct jpeg_error_mgr *err;
232         struct jpeg_memory_mgr *mem;
233         void *progress;
234         void *client_data;
235         jboolean is_decompressor;
236         int global_state;
237
238         void *dest;
239         JDIMENSION image_width;
240         JDIMENSION image_height;
241         int input_components;
242         J_COLOR_SPACE in_color_space;
243         double input_gamma;
244         int data_precision;
245
246         int num_components;
247         J_COLOR_SPACE jpeg_color_space;
248         void *comp_info;
249         void *quant_tbl_ptrs[NUM_QUANT_TBLS];
250         void *dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
251         void *ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
252         qbyte arith_dc_L[NUM_ARITH_TBLS];
253         qbyte arith_dc_U[NUM_ARITH_TBLS];
254         qbyte arith_ac_K[NUM_ARITH_TBLS];
255
256         int num_scans;
257         const void *scan_info;
258         jboolean raw_data_in;
259         jboolean arith_code;
260         jboolean optimize_coding;
261         jboolean CCIR601_sampling;
262         int smoothing_factor;
263         J_DCT_METHOD dct_method;
264
265         unsigned int restart_interval;
266         int restart_in_rows;
267
268         jboolean write_JFIF_header;
269         qbyte JFIF_major_version;
270         qbyte JFIF_minor_version;
271         qbyte density_unit;
272         unsigned short X_density;
273         unsigned short Y_density;
274         jboolean write_Adobe_marker;
275         JDIMENSION next_scanline;
276
277         jboolean progressive_mode;
278         int max_h_samp_factor;
279         int max_v_samp_factor;
280         JDIMENSION total_iMCU_rows;
281         int comps_in_scan;
282         void *cur_comp_info[MAX_COMPS_IN_SCAN];
283         JDIMENSION MCUs_per_row;
284         JDIMENSION MCU_rows_in_scan;
285         int blocks_in_MCU;
286         int MCU_membership[C_MAX_BLOCKS_IN_MCU];
287         int Ss, Se, Ah, Al;
288
289         void *master;
290         void *main;
291         void *prep;
292         void *coef;
293         void *marker;
294         void *cconvert;
295         void *downsample;
296         void *fdct;
297         void *entropy;
298         void *script_space;
299         int script_space_size;
300 };
301
302 struct jpeg_destination_mgr
303 {
304         qbyte* next_output_byte;
305         size_t free_in_buffer;
306
307         void (*init_destination) (j_compress_ptr cinfo);
308         jboolean (*empty_output_buffer) (j_compress_ptr cinfo);
309         void (*term_destination) (j_compress_ptr cinfo);
310 };
311
312
313 /*
314 =================================================================
315
316   DarkPlaces definitions
317
318 =================================================================
319 */
320
321 // Functions exported from libjpeg
322 #define qjpeg_create_compress(cinfo) \
323         qjpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_compress_struct))
324 #define qjpeg_create_decompress(cinfo) \
325         qjpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct))
326
327 static void (*qjpeg_CreateCompress) (j_compress_ptr cinfo, int version, size_t structsize);
328 static void (*qjpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize);
329 static void (*qjpeg_destroy_compress) (j_compress_ptr cinfo);
330 static void (*qjpeg_destroy_decompress) (j_decompress_ptr cinfo);
331 static void (*qjpeg_finish_compress) (j_compress_ptr cinfo);
332 static jboolean (*qjpeg_finish_decompress) (j_decompress_ptr cinfo);
333 static jboolean (*qjpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired);
334 static int (*qjpeg_read_header) (j_decompress_ptr cinfo, jboolean require_image);
335 static JDIMENSION (*qjpeg_read_scanlines) (j_decompress_ptr cinfo, qbyte** scanlines, JDIMENSION max_lines);
336 static void (*qjpeg_set_defaults) (j_compress_ptr cinfo);
337 static void (*qjpeg_set_quality) (j_compress_ptr cinfo, int quality, jboolean force_baseline);
338 static jboolean (*qjpeg_start_compress) (j_compress_ptr cinfo, jboolean write_all_tables);
339 static jboolean (*qjpeg_start_decompress) (j_decompress_ptr cinfo);
340 static struct jpeg_error_mgr* (*qjpeg_std_error) (struct jpeg_error_mgr *err);
341 static JDIMENSION (*qjpeg_write_scanlines) (j_compress_ptr cinfo, qbyte** scanlines, JDIMENSION num_lines);
342
343 static dllfunction_t jpegfuncs[] =
344 {
345         {"jpeg_CreateCompress",         (void **) &qjpeg_CreateCompress},
346         {"jpeg_CreateDecompress",       (void **) &qjpeg_CreateDecompress},
347         {"jpeg_destroy_compress",       (void **) &qjpeg_destroy_compress},
348         {"jpeg_destroy_decompress",     (void **) &qjpeg_destroy_decompress},
349         {"jpeg_finish_compress",        (void **) &qjpeg_finish_compress},
350         {"jpeg_finish_decompress",      (void **) &qjpeg_finish_decompress},
351         {"jpeg_resync_to_restart",      (void **) &qjpeg_resync_to_restart},
352         {"jpeg_read_header",            (void **) &qjpeg_read_header},
353         {"jpeg_read_scanlines",         (void **) &qjpeg_read_scanlines},
354         {"jpeg_set_defaults",           (void **) &qjpeg_set_defaults},
355         {"jpeg_set_quality",            (void **) &qjpeg_set_quality},
356         {"jpeg_start_compress",         (void **) &qjpeg_start_compress},
357         {"jpeg_start_decompress",       (void **) &qjpeg_start_decompress},
358         {"jpeg_std_error",                      (void **) &qjpeg_std_error},
359         {"jpeg_write_scanlines",        (void **) &qjpeg_write_scanlines},
360         {NULL, NULL}
361 };
362
363 // Handle for JPEG DLL
364 dllhandle_t jpeg_dll = NULL;
365
366 static qbyte jpeg_eoi_marker [2] = {0xFF, JPEG_EOI};
367 static qboolean error_in_jpeg;
368
369 // Our own output manager for JPEG compression
370 typedef struct
371 {
372         struct jpeg_destination_mgr pub;
373
374         qfile_t* outfile;
375         qbyte* buffer;
376 } my_destination_mgr;
377 typedef my_destination_mgr* my_dest_ptr;
378
379
380 /*
381 =================================================================
382
383   DLL load & unload
384
385 =================================================================
386 */
387
388 /*
389 ====================
390 JPEG_OpenLibrary
391
392 Try to load the JPEG DLL
393 ====================
394 */
395 qboolean JPEG_OpenLibrary (void)
396 {
397         const char* dllname;
398         const dllfunction_t *func;
399
400         // Already loaded?
401         if (jpeg_dll)
402                 return true;
403
404 #ifdef WIN32
405         dllname = "libjpeg.dll";
406 #else
407         dllname = "libjpeg.so.62";
408 #endif
409
410         // Initializations
411         for (func = jpegfuncs; func && func->name != NULL; func++)
412                 *func->funcvariable = NULL;
413
414         // Load the DLL
415         if (! (jpeg_dll = Sys_LoadLibrary (dllname)))
416         {
417                 Con_DPrintf("Can't find %s. JPEG support disabled\n", dllname);
418                 return false;
419         }
420
421         // Get the function adresses
422         for (func = jpegfuncs; func && func->name != NULL; func++)
423                 if (!(*func->funcvariable = (void *) Sys_GetProcAddress (jpeg_dll, func->name)))
424                 {
425                         Con_Printf("missing function \"%s\" - broken JPEG library!\n", func->name);
426                         JPEG_CloseLibrary ();
427                         return false;
428                 }
429
430         Con_DPrintf("%s loaded. JPEG support enabled\n", dllname);
431         return true;
432 }
433
434
435 /*
436 ====================
437 JPEG_CloseLibrary
438
439 Unload the JPEG DLL
440 ====================
441 */
442 void JPEG_CloseLibrary (void)
443 {
444         if (!jpeg_dll)
445                 return;
446
447         Sys_UnloadLibrary (jpeg_dll);
448         jpeg_dll = NULL;
449 }
450
451
452 /*
453 =================================================================
454
455         JPEG decompression
456
457 =================================================================
458 */
459
460 static void JPEG_Noop (j_decompress_ptr cinfo) {}
461
462 static jboolean JPEG_FillInputBuffer (j_decompress_ptr cinfo)
463 {
464     // Insert a fake EOI marker
465     cinfo->src->next_input_byte = jpeg_eoi_marker;
466     cinfo->src->bytes_in_buffer = 2;
467
468         return TRUE;
469 }
470
471 static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes)
472 {
473     if (cinfo->src->bytes_in_buffer <= (unsigned long)num_bytes)
474         {
475                 cinfo->src->bytes_in_buffer = 0;
476                 return;
477         }
478
479     cinfo->src->next_input_byte += num_bytes;
480     cinfo->src->bytes_in_buffer -= num_bytes;
481 }
482
483 static void JPEG_MemSrc (j_decompress_ptr cinfo, qbyte *buffer)
484 {
485         cinfo->src = cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof (struct jpeg_source_mgr));
486
487         cinfo->src->next_input_byte = buffer;
488         cinfo->src->bytes_in_buffer = fs_filesize;
489
490         cinfo->src->init_source = JPEG_Noop;
491         cinfo->src->fill_input_buffer = JPEG_FillInputBuffer;
492         cinfo->src->skip_input_data = JPEG_SkipInputData;
493         cinfo->src->resync_to_restart = qjpeg_resync_to_restart; // use the default method
494         cinfo->src->term_source = JPEG_Noop;
495 }
496
497 static void JPEG_ErrorExit (j_common_ptr cinfo)
498 {
499         ((struct jpeg_decompress_struct*)cinfo)->err->output_message (cinfo);
500         error_in_jpeg = true;
501 }
502
503
504 /*
505 ====================
506 JPEG_LoadImage
507
508 Load a JPEG image into a RGBA buffer
509 ====================
510 */
511 qbyte* JPEG_LoadImage (qbyte *f, int matchwidth, int matchheight)
512 {
513         struct jpeg_decompress_struct cinfo;
514         struct jpeg_error_mgr jerr;
515         qbyte *image_rgba, *scanline;
516         unsigned int line;
517
518         // No DLL = no JPEGs
519         if (!jpeg_dll)
520                 return NULL;
521
522         cinfo.err = qjpeg_std_error (&jerr);
523         qjpeg_create_decompress (&cinfo);
524         JPEG_MemSrc (&cinfo, f);
525         qjpeg_read_header (&cinfo, TRUE);
526         qjpeg_start_decompress (&cinfo);
527
528         image_width = cinfo.image_width;
529         image_height = cinfo.image_height;
530
531         if ((matchwidth && image_width != matchwidth) || (matchheight && image_height != matchheight))
532         {
533                 qjpeg_finish_decompress (&cinfo);
534                 qjpeg_destroy_decompress (&cinfo);
535                 return NULL;
536         }
537         if (image_width > 4096 || image_height > 4096 || image_width <= 0 || image_height <= 0)
538         {
539                 Con_Printf("JPEG_LoadImage: invalid image size %ix%i\n", image_width, image_height);
540                 return NULL;
541         }
542
543         image_rgba = Mem_Alloc(tempmempool, image_width * image_height * 4);
544         scanline = Mem_Alloc(tempmempool, image_width * cinfo.output_components);
545         if (!image_rgba || !scanline)
546         {
547                 if (!image_rgba)
548                         Mem_Free (image_rgba);
549
550                 Con_Printf("JPEG_LoadImage: not enough memory for %i by %i image\n", image_width, image_height);
551                 qjpeg_finish_decompress (&cinfo);
552                 qjpeg_destroy_decompress (&cinfo);
553                 return NULL;
554         }
555
556         // Decompress the image, line by line
557         line = 0;
558         while (cinfo.output_scanline < cinfo.output_height)
559         {
560                 qbyte *buffer_ptr;
561                 int ind;
562
563                 qjpeg_read_scanlines (&cinfo, &scanline, 1);
564
565                 // Convert the image to RGBA
566                 switch (cinfo.output_components)
567                 {
568                         // RGB images
569                         case 3:
570                                 buffer_ptr = &image_rgba[image_width * line * 4];
571                                 for (ind = 0; ind < image_width * 3; ind += 3, buffer_ptr += 4)
572                                 {
573                                         buffer_ptr[0] = scanline[ind];
574                                         buffer_ptr[1] = scanline[ind + 1];
575                                         buffer_ptr[2] = scanline[ind + 2];
576                                         buffer_ptr[3] = 255;
577                                 }
578                                 break;
579
580                         // Greyscale images (default to it, just in case)
581                         case 1:
582                         default:
583                                 buffer_ptr = &image_rgba[image_width * line * 4];
584                                 for (ind = 0; ind < image_width; ind++, buffer_ptr += 4)
585                                 {
586                                         buffer_ptr[0] = scanline[ind];
587                                         buffer_ptr[1] = scanline[ind];
588                                         buffer_ptr[2] = scanline[ind];
589                                         buffer_ptr[3] = 255;
590                                 }
591                 }
592
593                 line++;
594         }
595         Mem_Free (scanline);
596
597         qjpeg_finish_decompress (&cinfo);
598         qjpeg_destroy_decompress (&cinfo);
599
600         return image_rgba;
601 }
602
603
604 /*
605 =================================================================
606
607   JPEG compression
608
609 =================================================================
610 */
611
612 #define JPEG_OUTPUT_BUF_SIZE 4096
613 static void JPEG_InitDestination (j_compress_ptr cinfo)
614 {
615         my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
616         dest->buffer = (qbyte*)cinfo->mem->alloc_small ((j_common_ptr) cinfo, JPOOL_IMAGE, JPEG_OUTPUT_BUF_SIZE * sizeof(qbyte));
617         dest->pub.next_output_byte = dest->buffer;
618         dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE;
619 }
620
621 static jboolean JPEG_EmptyOutputBuffer (j_compress_ptr cinfo)
622 {
623         my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
624
625         if (FS_Write (dest->outfile, dest->buffer, JPEG_OUTPUT_BUF_SIZE) != (size_t) JPEG_OUTPUT_BUF_SIZE)
626         {
627                 error_in_jpeg = true;
628                 return false;
629         }
630
631         dest->pub.next_output_byte = dest->buffer;
632         dest->pub.free_in_buffer = JPEG_OUTPUT_BUF_SIZE;
633         return true;
634 }
635
636 static void JPEG_TermDestination (j_compress_ptr cinfo)
637 {
638         my_dest_ptr dest = (my_dest_ptr)cinfo->dest;
639         size_t datacount = JPEG_OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
640
641         // Write any data remaining in the buffer
642         if (datacount > 0)
643                 if (FS_Write (dest->outfile, dest->buffer, datacount) != datacount)
644                         error_in_jpeg = true;
645 }
646
647 static void JPEG_MemDest (j_compress_ptr cinfo, qfile_t* outfile)
648 {
649         my_dest_ptr dest;
650
651         // First time for this JPEG object?
652         if (cinfo->dest == NULL)
653                 cinfo->dest = (struct jpeg_destination_mgr *)(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_destination_mgr));
654
655         dest = (my_dest_ptr)cinfo->dest;
656         dest->pub.init_destination = JPEG_InitDestination;
657         dest->pub.empty_output_buffer = JPEG_EmptyOutputBuffer;
658         dest->pub.term_destination = JPEG_TermDestination;
659         dest->outfile = outfile;
660 }
661
662
663 /*
664 ====================
665 JPEG_SaveImage_preflipped
666
667 Save a preflipped JPEG image to a file
668 ====================
669 */
670 qboolean JPEG_SaveImage_preflipped (const char *filename, int width, int height, qbyte *data)
671 {
672         struct jpeg_compress_struct cinfo;
673         struct jpeg_error_mgr jerr;
674         qbyte *scanline;
675         unsigned int offset, linesize;
676         qfile_t* file;
677
678         // No DLL = no JPEGs
679         if (!jpeg_dll)
680         {
681                 Con_Printf ("You need the libjpeg library to save JPEG images\n");
682                 return false;
683         }
684
685         // Open the file
686         file = FS_Open (filename, "wb", true);
687         if (!file)
688                 return false;
689
690         cinfo.err = qjpeg_std_error (&jerr);
691         cinfo.err->error_exit = JPEG_ErrorExit;
692         error_in_jpeg = false;
693
694         qjpeg_create_compress (&cinfo);
695         JPEG_MemDest (&cinfo, file);
696
697         // Set the parameters for compression
698         cinfo.image_width = width;
699         cinfo.image_height = height;
700         cinfo.in_color_space = JCS_RGB;
701         cinfo.input_components = 3;
702         qjpeg_set_defaults (&cinfo);
703         qjpeg_set_quality (&cinfo, 90, TRUE);  // 90% quality; FIXME: use a cvar
704         qjpeg_start_compress (&cinfo, true);
705
706         // Compress each scanline
707         linesize = cinfo.image_width * 3;
708         offset = linesize * (cinfo.image_height - 1);
709         while (cinfo.next_scanline < cinfo.image_height)
710         {
711                 scanline = &data[offset - cinfo.next_scanline * linesize];
712
713                 qjpeg_write_scanlines (&cinfo, &scanline, 1);
714                 if (error_in_jpeg)
715                         break;
716         }
717
718         qjpeg_finish_compress (&cinfo);
719         qjpeg_destroy_compress (&cinfo);
720
721         FS_Close (file);
722         return true;
723 }