FS2_Open
Open source remastering of the Freespace 2 engine
jpgutils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <setjmp.h>
15 
16 #include "jpeglib.h"
17 
18 #undef LOCAL // fix from a jpeg header, pstypes.h will define it again
19 
20 #include "globalincs/pstypes.h"
21 #include "jpgutils/jpgutils.h"
22 #include "cfile/cfile.h"
23 #include "bmpman/bmpman.h"
24 #include "palman/palman.h"
25 #include "graphics/2d.h"
26 
27 
28 // forward declarations
29 void jpeg_cfile_src(j_decompress_ptr cinfo, CFILE *cfp);
30 
31 // structs
32 typedef struct {
33  struct jpeg_source_mgr pub; // public fields
34 
35  CFILE *infile; // source stream
36  JOCTET *buffer; // start of buffer
37  boolean start_of_file; // have we gotten any data yet?
39 
41 struct jpeg_decompress_struct jpeg_info;
42 struct jpeg_error_mgr jpeg_err;
43 
44 #define INPUT_BUF_SIZE 4096 // choose an efficiently read'able size
45 
46 static int jpeg_error_code;
47 
48 // set current error
49 #define Jpeg_Set_Error(x) { jpeg_error_code = x; }
50 
51 // error handler stuff, rather than the default, which will screw us
52 //
53 jmp_buf FSJpegError;
54 
55 // error (exit) handler
56 void jpg_error_exit(j_common_ptr cinfo)
57 {
58  // give an error message that isn't just generic
59  (*cinfo->err->output_message) (cinfo);
60 
61  // do cleanup since we won't get the chance otherwise
62  jpeg_destroy(cinfo);
63 
64  // set the error code, pretty much always going to be a read error
66 
67  // bail
68  longjmp(FSJpegError, 1);
69 }
70 
71 // message handler for errors
72 void jpg_output_message(j_common_ptr cinfo)
73 {
74  // JMSG_LENGTH_MAX should be 200, DO NOT change from this define so
75  // that we don't risk overruns from the jpeg lib
76  char buffer[JMSG_LENGTH_MAX];
77 
78  // Create the message
79  (*cinfo->err->format_message) (cinfo, buffer);
80 
81  // don't actually output anything unless we are a debug build, let bmpman
82  // give any errors instead for release builds
83 #ifndef NDEBUG
84  Warning(LOCATION, "%s %s", "JPEG Error:", buffer);
85 #endif
86 }
87 
88 
89 
90 // Reads header information from the JPEG file into the bitmap pointer
91 //
92 // filename - name of the JPEG bitmap file
93 // w - (output) width of the bitmap
94 // h - (output) height of the bitmap
95 // bpp - (output) bits per pixel of the bitmap
96 //
97 // returns - JPEG_ERROR_NONE if successful, otherwise error code
98 //
99 int jpeg_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
100 {
101  CFILE *jpeg_file = NULL;
103 
104  if (img_cfp == NULL) {
105  strcpy_s( filename, real_filename );
106 
107  char *p = strchr( filename, '.' );
108 
109  if ( p )
110  *p = 0;
111 
112  strcat_s( filename, ".jpg" );
113 
114  jpeg_file = cfopen( filename , "rb" );
115 
116  if ( !jpeg_file ) {
117  return JPEG_ERROR_READING;
118  }
119  } else {
120  jpeg_file = img_cfp;
121  }
122 
123  Assert( jpeg_file != NULL );
124 
125  if (jpeg_file == NULL)
126  return JPEG_ERROR_READING;
127 
128  // set the basic/default error code
130 
131  // initialize error message handler and decompression struct
132  jpeg_info.err = jpeg_std_error(&jpeg_err);
133  jpeg_err.error_exit = jpg_error_exit;
134  jpeg_err.output_message = jpg_output_message;
135 
136  jpeg_create_decompress(&jpeg_info);
137 
138  // setup to read data via CFILE
139  jpeg_cfile_src(&jpeg_info, jpeg_file);
140 
142 
143  // send the info back out
144  if (w) *w = jpeg_info.image_width;
145  if (h) *h = jpeg_info.image_height;
146  if (bpp) *bpp = (jpeg_info.num_components * 8);
147 
148  // cleanup
149  jpeg_destroy_decompress(&jpeg_info);
150 
151  if (img_cfp == NULL) {
152  cfclose(jpeg_file);
153  jpeg_file = NULL;
154  }
155 
156  return jpeg_error_code;
157 }
158 
159 
160 // Loads a JPEG image
161 //
162 // filename - name of the targa file to load
163 // image_data - allocated storage for the bitmap
164 //
165 // returns - true if succesful, false otherwise
166 //
167 int jpeg_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *palette, int dest_size, int cf_type)
168 {
170  CFILE *img_cfp = NULL;
171  JSAMPARRAY buffer = NULL;
172 
173  strcpy_s( filename, real_filename );
174  char *p = strchr( filename, '.' );
175  if ( p ) *p = 0;
176  strcat_s( filename, ".jpg" );
177 
178 
179  img_cfp = cfopen(filename, "rb", CFILE_NORMAL, cf_type);
180 
181  if (img_cfp == NULL)
182  return JPEG_ERROR_READING;
183 
184  // set the basic error code
186 
187  // initialize error message handler
188  jpeg_info.err = jpeg_std_error(&jpeg_err);
189  jpeg_err.error_exit = jpg_error_exit;
190  jpeg_err.output_message = jpg_output_message;
191 
192  // SPECIAL NOTE: we've already allocated memory on the basis of original height, width and bpp
193  // of the image from the header. DO NOT change any settings that affect output variables here
194  // or we risk needed more memory than we have available in "image_data". The only exception is
195  // bpp since 'dest_size' should already indicate what we want to end up with.
196 
197  if ( setjmp( FSJpegError ) == 0) {
198  // initialize decompression struct
199  jpeg_create_decompress(&jpeg_info);
200 
201  // setup to read data via CFILE
202  jpeg_cfile_src(&jpeg_info, img_cfp);
203 
205 
206  // memory for the storage of each scanline
207  jpeg_calc_output_dimensions(&jpeg_info);
208 
209  // set the output components to be 'dest_size' (so we can support 16/24/32-bit images with this one function)
210  // NOTE: only 24-bit is actually supported right now, we don't currently up/down sample at all
211  jpeg_info.output_components = dest_size;
212  jpeg_info.out_color_components = dest_size; // may need/have to match above
213 
214  // multiplying by rec_outbuf_height isn't required but is more efficient
215  int size = jpeg_info.output_width * jpeg_info.output_components * jpeg_info.rec_outbuf_height;
216  // a standard malloc doesn't appear to work properly here (debug vm_malloc??), crashes in lib
217  buffer = (*jpeg_info.mem->alloc_sarray)((j_common_ptr) &jpeg_info, JPOOL_IMAGE, size, 1); // DON'T free() THIS! jpeg lib does it
218 
219  // begin decompression process --
220  jpeg_start_decompress(&jpeg_info);
221 
222  // read each scanline and output to previously allocated 'image_data'
223  while (jpeg_info.output_scanline < jpeg_info.output_height) {
224  jpeg_read_scanlines(&jpeg_info, buffer, 1);
225 
226  // niffiwan: swap some bytes (FSO uses BGR, not RGB) so that libjpeg
227  // code is used in its original state
228  // NOTE: assumes only one scanline is being read at a time. If
229  // multiple lines are read this needs updating
230  // also note that this doesn't deal with jpegs that are greyscale
231  JSAMPLE tmp;
232  for (int k = 2; k < size; k += 3) {
233  tmp = buffer[0][k - 2];
234  buffer[0][k - 2] = buffer[0][k];
235  buffer[0][k] = tmp;
236  }
237 
238  memcpy(image_data, *buffer, size);
239  image_data += size;
240  }
241 
242  // -- done with decompression process
243  jpeg_finish_decompress(&jpeg_info);
244 
245  // cleanup
246  jpeg_destroy_decompress(&jpeg_info);
247  }
248 
249  cfclose(img_cfp);
250 
251 
252  return jpeg_error_code;
253 }
254 
255 
256 
257 
258 // --------------------- handlers for reading of files -------------------------
259 // ---- basic copy of source from jdatasrc.c, originally:
260 // Copyright (C) 1994-1996, Thomas G. Lane.
261 
262 void jpeg_cf_init_source(j_decompress_ptr cinfo)
263 {
264  cfile_src_ptr src = (cfile_src_ptr) cinfo->src;
265 
266  // We reset the empty-input-file flag for each image,
267  // but we don't clear the input buffer.
268  // This is correct behavior for reading a series of images from one source.
269  src->start_of_file = TRUE;
270 }
271 
272 boolean jpeg_cf_fill_input_buffer(j_decompress_ptr cinfo)
273 {
274  cfile_src_ptr src = (cfile_src_ptr) cinfo->src;
275  size_t nbytes;
276 
277  nbytes = cfread(src->buffer, 1, INPUT_BUF_SIZE, src->infile);
278 
279  if (nbytes <= 0) {
280  if (src->start_of_file) { // Treat empty input file as fatal error
282  }
283 
284  // Insert a fake EOI marker
285  src->buffer[0] = (JOCTET) 0xFF;
286  src->buffer[1] = (JOCTET) JPEG_EOI;
287  nbytes = 2;
288 
289  return FALSE;
290  }
291 
292  src->pub.next_input_byte = src->buffer;
293  src->pub.bytes_in_buffer = nbytes;
294  src->start_of_file = FALSE;
295 
296  return TRUE;
297 }
298 
299 void jpeg_cf_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
300 {
301  cfile_src_ptr src = (cfile_src_ptr) cinfo->src;
302 
303  if (num_bytes > 0) {
304  while (num_bytes > (long) src->pub.bytes_in_buffer) {
305  num_bytes -= (long) src->pub.bytes_in_buffer;
306 
307  if (!jpeg_cf_fill_input_buffer(cinfo))
308  return;
309  }
310 
311  src->pub.next_input_byte += (size_t) num_bytes;
312  src->pub.bytes_in_buffer -= (size_t) num_bytes;
313  }
314 }
315 
316 void jpeg_cf_term_source(j_decompress_ptr cinfo)
317 {
318  // no work necessary here
319 }
320 
321 void jpeg_cfile_src(j_decompress_ptr cinfo, CFILE *cfp)
322 {
324 
325  if (cinfo->src == NULL) { // first time for this JPEG object?
326  cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(cfile_source_mgr));
327  src = (cfile_src_ptr) cinfo->src;
328  src->buffer = (JOCTET *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * sizeof(JOCTET));
329  }
330 
331  src = (cfile_src_ptr) cinfo->src;
332  src->pub.init_source = jpeg_cf_init_source;
333  src->pub.fill_input_buffer = jpeg_cf_fill_input_buffer;
334  src->pub.skip_input_data = jpeg_cf_skip_input_data;
335  src->pub.resync_to_restart = jpeg_resync_to_restart; // use default method
336  src->pub.term_source = jpeg_cf_term_source;
337  src->infile = cfp;
338  src->pub.bytes_in_buffer = 0; // forces fill_input_buffer on first read
339  src->pub.next_input_byte = NULL; // until buffer loaded
340 }
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
#define CFILE_NORMAL
Definition: cfile.h:89
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
#define Jpeg_Set_Error(x)
Definition: jpgutils.cpp:49
struct jpeg_error_mgr jpeg_err
Definition: jpgutils.cpp:42
void jpg_error_exit(j_common_ptr cinfo)
Definition: jpgutils.cpp:56
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
struct jpeg_decompress_struct jpeg_info
Definition: jpgutils.cpp:41
boolean start_of_file
Definition: jpgutils.cpp:37
struct jpeg_source_mgr pub
Definition: jpgutils.cpp:33
#define TRUE
Definition: pstypes.h:399
Definition: cfile.h:28
GLsizeiptr size
Definition: Glext.h:5496
void jpeg_cfile_src(j_decompress_ptr cinfo, CFILE *cfp)
Definition: jpgutils.cpp:321
int jpeg_read_bitmap(const char *real_filename, ubyte *image_data, ubyte *palette, int dest_size, int cf_type)
Definition: jpgutils.cpp:167
#define JPEG_ERROR_NONE
Definition: jpgutils.h:20
#define cfopen(...)
Definition: cfile.h:134
void jpeg_cf_init_source(j_decompress_ptr cinfo)
Definition: jpgutils.cpp:262
char * filename
JOCTET * buffer
Definition: jpgutils.cpp:36
void jpeg_cf_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
Definition: jpgutils.cpp:299
GLuint buffer
Definition: Glext.h:5492
cfp
Definition: cfile.cpp:1061
#define INPUT_BUF_SIZE
Definition: jpgutils.cpp:44
unsigned char ubyte
Definition: pstypes.h:62
boolean jpeg_cf_fill_input_buffer(j_decompress_ptr cinfo)
Definition: jpgutils.cpp:272
void jpg_output_message(j_common_ptr cinfo)
Definition: jpgutils.cpp:72
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
#define strcat_s(...)
Definition: safe_strings.h:68
GLubyte GLubyte GLubyte GLubyte w
Definition: Glext.h:5679
jmp_buf FSJpegError
Definition: jpgutils.cpp:53
GLfloat GLfloat p
Definition: Glext.h:8373
GLenum src
Definition: Glext.h:5917
#define LOCATION
Definition: pstypes.h:245
cfile_source_mgr * cfile_src_ptr
Definition: jpgutils.cpp:40
#define JPEG_ERROR_READING
Definition: jpgutils.h:21
void jpeg_cf_term_source(j_decompress_ptr cinfo)
Definition: jpgutils.cpp:316
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
int jpeg_read_header(const char *real_filename, CFILE *img_cfp, int *w, int *h, int *bpp, ubyte *palette)
Definition: jpgutils.cpp:99
CFILE * infile
Definition: jpgutils.cpp:35
#define FALSE
Definition: pstypes.h:400
#define strcpy_s(...)
Definition: safe_strings.h:67