IMG_jpg.c
changeset 368 8a61842d00ce
parent 347 ad5034cad524
child 486 7bb8af91e887
equal deleted inserted replaced
367:b2aa197f6774 368:8a61842d00ce
    32 #ifdef LOAD_JPG
    32 #ifdef LOAD_JPG
    33 
    33 
    34 #include <jpeglib.h>
    34 #include <jpeglib.h>
    35 
    35 
    36 #ifdef JPEG_TRUE  /* MinGW version of jpeg-8.x renamed TRUE to JPEG_TRUE etc. */
    36 #ifdef JPEG_TRUE  /* MinGW version of jpeg-8.x renamed TRUE to JPEG_TRUE etc. */
    37 	typedef JPEG_boolean boolean;
    37     typedef JPEG_boolean boolean;
    38 	#define TRUE JPEG_TRUE
    38     #define TRUE JPEG_TRUE
    39 	#define FALSE JPEG_FALSE
    39     #define FALSE JPEG_FALSE
    40 #endif
    40 #endif
    41 
    41 
    42 /* Define this for fast loading and not as good image quality */
    42 /* Define this for fast loading and not as good image quality */
    43 /*#define FAST_JPEG*/
    43 /*#define FAST_JPEG*/
    44 
    44 
    45 /* Define this for quicker (but less perfect) JPEG identification */
    45 /* Define this for quicker (but less perfect) JPEG identification */
    46 #define FAST_IS_JPEG
    46 #define FAST_IS_JPEG
    47 
    47 
    48 static struct {
    48 static struct {
    49 	int loaded;
    49     int loaded;
    50 	void *handle;
    50     void *handle;
    51 	void (*jpeg_calc_output_dimensions) (j_decompress_ptr cinfo);
    51     void (*jpeg_calc_output_dimensions) (j_decompress_ptr cinfo);
    52 	void (*jpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize);
    52     void (*jpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize);
    53 	void (*jpeg_destroy_decompress) (j_decompress_ptr cinfo);
    53     void (*jpeg_destroy_decompress) (j_decompress_ptr cinfo);
    54 	boolean (*jpeg_finish_decompress) (j_decompress_ptr cinfo);
    54     boolean (*jpeg_finish_decompress) (j_decompress_ptr cinfo);
    55 	int (*jpeg_read_header) (j_decompress_ptr cinfo, boolean require_image);
    55     int (*jpeg_read_header) (j_decompress_ptr cinfo, boolean require_image);
    56 	JDIMENSION (*jpeg_read_scanlines) (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines);
    56     JDIMENSION (*jpeg_read_scanlines) (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines);
    57 	boolean (*jpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired);
    57     boolean (*jpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired);
    58 	boolean (*jpeg_start_decompress) (j_decompress_ptr cinfo);
    58     boolean (*jpeg_start_decompress) (j_decompress_ptr cinfo);
    59 	struct jpeg_error_mgr * (*jpeg_std_error) (struct jpeg_error_mgr * err);
    59     struct jpeg_error_mgr * (*jpeg_std_error) (struct jpeg_error_mgr * err);
    60 } lib;
    60 } lib;
    61 
    61 
    62 #ifdef LOAD_JPG_DYNAMIC
    62 #ifdef LOAD_JPG_DYNAMIC
    63 int IMG_InitJPG()
    63 int IMG_InitJPG()
    64 {
    64 {
    65 	if ( lib.loaded == 0 ) {
    65     if ( lib.loaded == 0 ) {
    66 		lib.handle = SDL_LoadObject(LOAD_JPG_DYNAMIC);
    66         lib.handle = SDL_LoadObject(LOAD_JPG_DYNAMIC);
    67 		if ( lib.handle == NULL ) {
    67         if ( lib.handle == NULL ) {
    68 			return -1;
    68             return -1;
    69 		}
    69         }
    70 		lib.jpeg_calc_output_dimensions =
    70         lib.jpeg_calc_output_dimensions =
    71 			(void (*) (j_decompress_ptr))
    71             (void (*) (j_decompress_ptr))
    72 			SDL_LoadFunction(lib.handle, "jpeg_calc_output_dimensions");
    72             SDL_LoadFunction(lib.handle, "jpeg_calc_output_dimensions");
    73 		if ( lib.jpeg_calc_output_dimensions == NULL ) {
    73         if ( lib.jpeg_calc_output_dimensions == NULL ) {
    74 			SDL_UnloadObject(lib.handle);
    74             SDL_UnloadObject(lib.handle);
    75 			return -1;
    75             return -1;
    76 		}
    76         }
    77 		lib.jpeg_CreateDecompress = 
    77         lib.jpeg_CreateDecompress =
    78 			(void (*) (j_decompress_ptr, int, size_t))
    78             (void (*) (j_decompress_ptr, int, size_t))
    79 			SDL_LoadFunction(lib.handle, "jpeg_CreateDecompress");
    79             SDL_LoadFunction(lib.handle, "jpeg_CreateDecompress");
    80 		if ( lib.jpeg_CreateDecompress == NULL ) {
    80         if ( lib.jpeg_CreateDecompress == NULL ) {
    81 			SDL_UnloadObject(lib.handle);
    81             SDL_UnloadObject(lib.handle);
    82 			return -1;
    82             return -1;
    83 		}
    83         }
    84 		lib.jpeg_destroy_decompress = 
    84         lib.jpeg_destroy_decompress =
    85 			(void (*) (j_decompress_ptr))
    85             (void (*) (j_decompress_ptr))
    86 			SDL_LoadFunction(lib.handle, "jpeg_destroy_decompress");
    86             SDL_LoadFunction(lib.handle, "jpeg_destroy_decompress");
    87 		if ( lib.jpeg_destroy_decompress == NULL ) {
    87         if ( lib.jpeg_destroy_decompress == NULL ) {
    88 			SDL_UnloadObject(lib.handle);
    88             SDL_UnloadObject(lib.handle);
    89 			return -1;
    89             return -1;
    90 		}
    90         }
    91 		lib.jpeg_finish_decompress = 
    91         lib.jpeg_finish_decompress =
    92 			(boolean (*) (j_decompress_ptr))
    92             (boolean (*) (j_decompress_ptr))
    93 			SDL_LoadFunction(lib.handle, "jpeg_finish_decompress");
    93             SDL_LoadFunction(lib.handle, "jpeg_finish_decompress");
    94 		if ( lib.jpeg_finish_decompress == NULL ) {
    94         if ( lib.jpeg_finish_decompress == NULL ) {
    95 			SDL_UnloadObject(lib.handle);
    95             SDL_UnloadObject(lib.handle);
    96 			return -1;
    96             return -1;
    97 		}
    97         }
    98 		lib.jpeg_read_header = 
    98         lib.jpeg_read_header =
    99 			(int (*) (j_decompress_ptr, boolean))
    99             (int (*) (j_decompress_ptr, boolean))
   100 			SDL_LoadFunction(lib.handle, "jpeg_read_header");
   100             SDL_LoadFunction(lib.handle, "jpeg_read_header");
   101 		if ( lib.jpeg_read_header == NULL ) {
   101         if ( lib.jpeg_read_header == NULL ) {
   102 			SDL_UnloadObject(lib.handle);
   102             SDL_UnloadObject(lib.handle);
   103 			return -1;
   103             return -1;
   104 		}
   104         }
   105 		lib.jpeg_read_scanlines = 
   105         lib.jpeg_read_scanlines =
   106 			(JDIMENSION (*) (j_decompress_ptr, JSAMPARRAY, JDIMENSION))
   106             (JDIMENSION (*) (j_decompress_ptr, JSAMPARRAY, JDIMENSION))
   107 			SDL_LoadFunction(lib.handle, "jpeg_read_scanlines");
   107             SDL_LoadFunction(lib.handle, "jpeg_read_scanlines");
   108 		if ( lib.jpeg_read_scanlines == NULL ) {
   108         if ( lib.jpeg_read_scanlines == NULL ) {
   109 			SDL_UnloadObject(lib.handle);
   109             SDL_UnloadObject(lib.handle);
   110 			return -1;
   110             return -1;
   111 		}
   111         }
   112 		lib.jpeg_resync_to_restart = 
   112         lib.jpeg_resync_to_restart =
   113 			(boolean (*) (j_decompress_ptr, int))
   113             (boolean (*) (j_decompress_ptr, int))
   114 			SDL_LoadFunction(lib.handle, "jpeg_resync_to_restart");
   114             SDL_LoadFunction(lib.handle, "jpeg_resync_to_restart");
   115 		if ( lib.jpeg_resync_to_restart == NULL ) {
   115         if ( lib.jpeg_resync_to_restart == NULL ) {
   116 			SDL_UnloadObject(lib.handle);
   116             SDL_UnloadObject(lib.handle);
   117 			return -1;
   117             return -1;
   118 		}
   118         }
   119 		lib.jpeg_start_decompress = 
   119         lib.jpeg_start_decompress =
   120 			(boolean (*) (j_decompress_ptr))
   120             (boolean (*) (j_decompress_ptr))
   121 			SDL_LoadFunction(lib.handle, "jpeg_start_decompress");
   121             SDL_LoadFunction(lib.handle, "jpeg_start_decompress");
   122 		if ( lib.jpeg_start_decompress == NULL ) {
   122         if ( lib.jpeg_start_decompress == NULL ) {
   123 			SDL_UnloadObject(lib.handle);
   123             SDL_UnloadObject(lib.handle);
   124 			return -1;
   124             return -1;
   125 		}
   125         }
   126 		lib.jpeg_std_error = 
   126         lib.jpeg_std_error =
   127 			(struct jpeg_error_mgr * (*) (struct jpeg_error_mgr *))
   127             (struct jpeg_error_mgr * (*) (struct jpeg_error_mgr *))
   128 			SDL_LoadFunction(lib.handle, "jpeg_std_error");
   128             SDL_LoadFunction(lib.handle, "jpeg_std_error");
   129 		if ( lib.jpeg_std_error == NULL ) {
   129         if ( lib.jpeg_std_error == NULL ) {
   130 			SDL_UnloadObject(lib.handle);
   130             SDL_UnloadObject(lib.handle);
   131 			return -1;
   131             return -1;
   132 		}
   132         }
   133 	}
   133     }
   134 	++lib.loaded;
   134     ++lib.loaded;
   135 
   135 
   136 	return 0;
   136     return 0;
   137 }
   137 }
   138 void IMG_QuitJPG()
   138 void IMG_QuitJPG()
   139 {
   139 {
   140 	if ( lib.loaded == 0 ) {
   140     if ( lib.loaded == 0 ) {
   141 		return;
   141         return;
   142 	}
   142     }
   143 	if ( lib.loaded == 1 ) {
   143     if ( lib.loaded == 1 ) {
   144 		SDL_UnloadObject(lib.handle);
   144         SDL_UnloadObject(lib.handle);
   145 	}
   145     }
   146 	--lib.loaded;
   146     --lib.loaded;
   147 }
   147 }
   148 #else
   148 #else
   149 int IMG_InitJPG()
   149 int IMG_InitJPG()
   150 {
   150 {
   151 	if ( lib.loaded == 0 ) {
   151     if ( lib.loaded == 0 ) {
   152 		lib.jpeg_calc_output_dimensions = jpeg_calc_output_dimensions;
   152         lib.jpeg_calc_output_dimensions = jpeg_calc_output_dimensions;
   153 		lib.jpeg_CreateDecompress = jpeg_CreateDecompress;
   153         lib.jpeg_CreateDecompress = jpeg_CreateDecompress;
   154 		lib.jpeg_destroy_decompress = jpeg_destroy_decompress;
   154         lib.jpeg_destroy_decompress = jpeg_destroy_decompress;
   155 		lib.jpeg_finish_decompress = jpeg_finish_decompress;
   155         lib.jpeg_finish_decompress = jpeg_finish_decompress;
   156 		lib.jpeg_read_header = jpeg_read_header;
   156         lib.jpeg_read_header = jpeg_read_header;
   157 		lib.jpeg_read_scanlines = jpeg_read_scanlines;
   157         lib.jpeg_read_scanlines = jpeg_read_scanlines;
   158 		lib.jpeg_resync_to_restart = jpeg_resync_to_restart;
   158         lib.jpeg_resync_to_restart = jpeg_resync_to_restart;
   159 		lib.jpeg_start_decompress = jpeg_start_decompress;
   159         lib.jpeg_start_decompress = jpeg_start_decompress;
   160 		lib.jpeg_std_error = jpeg_std_error;
   160         lib.jpeg_std_error = jpeg_std_error;
   161 	}
   161     }
   162 	++lib.loaded;
   162     ++lib.loaded;
   163 
   163 
   164 	return 0;
   164     return 0;
   165 }
   165 }
   166 void IMG_QuitJPG()
   166 void IMG_QuitJPG()
   167 {
   167 {
   168 	if ( lib.loaded == 0 ) {
   168     if ( lib.loaded == 0 ) {
   169 		return;
   169         return;
   170 	}
   170     }
   171 	if ( lib.loaded == 1 ) {
   171     if ( lib.loaded == 1 ) {
   172 	}
   172     }
   173 	--lib.loaded;
   173     --lib.loaded;
   174 }
   174 }
   175 #endif /* LOAD_JPG_DYNAMIC */
   175 #endif /* LOAD_JPG_DYNAMIC */
   176 
   176 
   177 /* See if an image is contained in a data source */
   177 /* See if an image is contained in a data source */
   178 int IMG_isJPG(SDL_RWops *src)
   178 int IMG_isJPG(SDL_RWops *src)
   179 {
   179 {
   180 	Sint64 start;
   180     Sint64 start;
   181 	int is_JPG;
   181     int is_JPG;
   182 	int in_scan;
   182     int in_scan;
   183 	Uint8 magic[4];
   183     Uint8 magic[4];
   184 
   184 
   185 	/* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
   185     /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
   186 	/* Blame me, not Sam, if this doesn't work right. */
   186     /* Blame me, not Sam, if this doesn't work right. */
   187 	/* And don't forget to report the problem to the the sdl list too! */
   187     /* And don't forget to report the problem to the the sdl list too! */
   188 
   188 
   189 	if ( !src )
   189     if ( !src )
   190 		return 0;
   190         return 0;
   191 	start = SDL_RWtell(src);
   191     start = SDL_RWtell(src);
   192 	is_JPG = 0;
   192     is_JPG = 0;
   193 	in_scan = 0;
   193     in_scan = 0;
   194 	if ( SDL_RWread(src, magic, 2, 1) ) {
   194     if ( SDL_RWread(src, magic, 2, 1) ) {
   195 		if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
   195         if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
   196 			is_JPG = 1;
   196             is_JPG = 1;
   197 			while (is_JPG == 1) {
   197             while (is_JPG == 1) {
   198 				if(SDL_RWread(src, magic, 1, 2) != 2) {
   198                 if(SDL_RWread(src, magic, 1, 2) != 2) {
   199 					is_JPG = 0;
   199                     is_JPG = 0;
   200 				} else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
   200                 } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
   201 					is_JPG = 0;
   201                     is_JPG = 0;
   202 				} else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
   202                 } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
   203 					/* Extra padding in JPEG (legal) */
   203                     /* Extra padding in JPEG (legal) */
   204 					/* or this is data and we are scanning */
   204                     /* or this is data and we are scanning */
   205 					SDL_RWseek(src, -1, RW_SEEK_CUR);
   205                     SDL_RWseek(src, -1, RW_SEEK_CUR);
   206 				} else if(magic[1] == 0xD9) {
   206                 } else if(magic[1] == 0xD9) {
   207 					/* Got to end of good JPEG */
   207                     /* Got to end of good JPEG */
   208 					break;
   208                     break;
   209 				} else if( (in_scan == 1) && (magic[1] == 0x00) ) {
   209                 } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
   210 					/* This is an encoded 0xFF within the data */
   210                     /* This is an encoded 0xFF within the data */
   211 				} else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
   211                 } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
   212 					/* These have nothing else */
   212                     /* These have nothing else */
   213 				} else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
   213                 } else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
   214 					is_JPG = 0;
   214                     is_JPG = 0;
   215 				} else {
   215                 } else {
   216 					/* Yes, it's big-endian */
   216                     /* Yes, it's big-endian */
   217 					Sint64 innerStart;
   217                     Sint64 innerStart;
   218 					Uint32 size;
   218                     Uint32 size;
   219 					Sint64 end;
   219                     Sint64 end;
   220 					innerStart = SDL_RWtell(src);
   220                     innerStart = SDL_RWtell(src);
   221 					size = (magic[2] << 8) + magic[3];
   221                     size = (magic[2] << 8) + magic[3];
   222 					end = SDL_RWseek(src, size-2, RW_SEEK_CUR);
   222                     end = SDL_RWseek(src, size-2, RW_SEEK_CUR);
   223 					if ( end != innerStart + size - 2 ) is_JPG = 0;
   223                     if ( end != innerStart + size - 2 ) is_JPG = 0;
   224 					if ( magic[1] == 0xDA ) {
   224                     if ( magic[1] == 0xDA ) {
   225 						/* Now comes the actual JPEG meat */
   225                         /* Now comes the actual JPEG meat */
   226 #ifdef	FAST_IS_JPEG
   226 #ifdef  FAST_IS_JPEG
   227 						/* Ok, I'm convinced.  It is a JPEG. */
   227                         /* Ok, I'm convinced.  It is a JPEG. */
   228 						break;
   228                         break;
   229 #else
   229 #else
   230 						/* I'm not convinced.  Prove it! */
   230                         /* I'm not convinced.  Prove it! */
   231 						in_scan = 1;
   231                         in_scan = 1;
   232 #endif
   232 #endif
   233 					}
   233                     }
   234 				}
   234                 }
   235 			}
   235             }
   236 		}
   236         }
   237 	}
   237     }
   238 	SDL_RWseek(src, start, RW_SEEK_SET);
   238     SDL_RWseek(src, start, RW_SEEK_SET);
   239 	return(is_JPG);
   239     return(is_JPG);
   240 }
   240 }
   241 
   241 
   242 #define INPUT_BUFFER_SIZE	4096
   242 #define INPUT_BUFFER_SIZE   4096
   243 typedef struct {
   243 typedef struct {
   244 	struct jpeg_source_mgr pub;
   244     struct jpeg_source_mgr pub;
   245 
   245 
   246 	SDL_RWops *ctx;
   246     SDL_RWops *ctx;
   247 	Uint8 buffer[INPUT_BUFFER_SIZE];
   247     Uint8 buffer[INPUT_BUFFER_SIZE];
   248 } my_source_mgr;
   248 } my_source_mgr;
   249 
   249 
   250 /*
   250 /*
   251  * Initialize source --- called by jpeg_read_header
   251  * Initialize source --- called by jpeg_read_header
   252  * before any data is actually read.
   252  * before any data is actually read.
   253  */
   253  */
   254 static void init_source (j_decompress_ptr cinfo)
   254 static void init_source (j_decompress_ptr cinfo)
   255 {
   255 {
   256 	/* We don't actually need to do anything */
   256     /* We don't actually need to do anything */
   257 	return;
   257     return;
   258 }
   258 }
   259 
   259 
   260 /*
   260 /*
   261  * Fill the input buffer --- called whenever buffer is emptied.
   261  * Fill the input buffer --- called whenever buffer is emptied.
   262  */
   262  */
   263 static boolean fill_input_buffer (j_decompress_ptr cinfo)
   263 static boolean fill_input_buffer (j_decompress_ptr cinfo)
   264 {
   264 {
   265 	my_source_mgr * src = (my_source_mgr *) cinfo->src;
   265     my_source_mgr * src = (my_source_mgr *) cinfo->src;
   266 	int nbytes;
   266     int nbytes;
   267 
   267 
   268 	nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE);
   268     nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE);
   269 	if (nbytes <= 0) {
   269     if (nbytes <= 0) {
   270 		/* Insert a fake EOI marker */
   270         /* Insert a fake EOI marker */
   271 		src->buffer[0] = (Uint8) 0xFF;
   271         src->buffer[0] = (Uint8) 0xFF;
   272 		src->buffer[1] = (Uint8) JPEG_EOI;
   272         src->buffer[1] = (Uint8) JPEG_EOI;
   273 		nbytes = 2;
   273         nbytes = 2;
   274 	}
   274     }
   275 	src->pub.next_input_byte = src->buffer;
   275     src->pub.next_input_byte = src->buffer;
   276 	src->pub.bytes_in_buffer = nbytes;
   276     src->pub.bytes_in_buffer = nbytes;
   277 
   277 
   278 	return TRUE;
   278     return TRUE;
   279 }
   279 }
   280 
   280 
   281 
   281 
   282 /*
   282 /*
   283  * Skip data --- used to skip over a potentially large amount of
   283  * Skip data --- used to skip over a potentially large amount of
   290  * Arranging for additional bytes to be discarded before reloading the input
   290  * Arranging for additional bytes to be discarded before reloading the input
   291  * buffer is the application writer's problem.
   291  * buffer is the application writer's problem.
   292  */
   292  */
   293 static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
   293 static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
   294 {
   294 {
   295 	my_source_mgr * src = (my_source_mgr *) cinfo->src;
   295     my_source_mgr * src = (my_source_mgr *) cinfo->src;
   296 
   296 
   297 	/* Just a dumb implementation for now.	Could use fseek() except
   297     /* Just a dumb implementation for now.  Could use fseek() except
   298 	 * it doesn't work on pipes.  Not clear that being smart is worth
   298      * it doesn't work on pipes.  Not clear that being smart is worth
   299 	 * any trouble anyway --- large skips are infrequent.
   299      * any trouble anyway --- large skips are infrequent.
   300 	 */
   300      */
   301 	if (num_bytes > 0) {
   301     if (num_bytes > 0) {
   302 		while (num_bytes > (long) src->pub.bytes_in_buffer) {
   302         while (num_bytes > (long) src->pub.bytes_in_buffer) {
   303 			num_bytes -= (long) src->pub.bytes_in_buffer;
   303             num_bytes -= (long) src->pub.bytes_in_buffer;
   304 			(void) src->pub.fill_input_buffer(cinfo);
   304             (void) src->pub.fill_input_buffer(cinfo);
   305 			/* note we assume that fill_input_buffer will never
   305             /* note we assume that fill_input_buffer will never
   306 			 * return FALSE, so suspension need not be handled.
   306              * return FALSE, so suspension need not be handled.
   307 			 */
   307              */
   308 		}
   308         }
   309 		src->pub.next_input_byte += (size_t) num_bytes;
   309         src->pub.next_input_byte += (size_t) num_bytes;
   310 		src->pub.bytes_in_buffer -= (size_t) num_bytes;
   310         src->pub.bytes_in_buffer -= (size_t) num_bytes;
   311 	}
   311     }
   312 }
   312 }
   313 
   313 
   314 /*
   314 /*
   315  * Terminate source --- called by jpeg_finish_decompress
   315  * Terminate source --- called by jpeg_finish_decompress
   316  * after all data has been read.
   316  * after all data has been read.
   317  */
   317  */
   318 static void term_source (j_decompress_ptr cinfo)
   318 static void term_source (j_decompress_ptr cinfo)
   319 {
   319 {
   320 	/* We don't actually need to do anything */
   320     /* We don't actually need to do anything */
   321 	return;
   321     return;
   322 }
   322 }
   323 
   323 
   324 /*
   324 /*
   325  * Prepare for input from a stdio stream.
   325  * Prepare for input from a stdio stream.
   326  * The caller must have already opened the stream, and is responsible
   326  * The caller must have already opened the stream, and is responsible
   335    * only before the first one.  (If we discarded the buffer at the end of
   335    * only before the first one.  (If we discarded the buffer at the end of
   336    * one image, we'd likely lose the start of the next one.)
   336    * one image, we'd likely lose the start of the next one.)
   337    * This makes it unsafe to use this manager and a different source
   337    * This makes it unsafe to use this manager and a different source
   338    * manager serially with the same JPEG object.  Caveat programmer.
   338    * manager serially with the same JPEG object.  Caveat programmer.
   339    */
   339    */
   340   if (cinfo->src == NULL) {	/* first time for this JPEG object? */
   340   if (cinfo->src == NULL) { /* first time for this JPEG object? */
   341     cinfo->src = (struct jpeg_source_mgr *)
   341     cinfo->src = (struct jpeg_source_mgr *)
   342       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
   342       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
   343 				  sizeof(my_source_mgr));
   343                   sizeof(my_source_mgr));
   344     src = (my_source_mgr *) cinfo->src;
   344     src = (my_source_mgr *) cinfo->src;
   345   }
   345   }
   346 
   346 
   347   src = (my_source_mgr *) cinfo->src;
   347   src = (my_source_mgr *) cinfo->src;
   348   src->pub.init_source = init_source;
   348   src->pub.init_source = init_source;
   354   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
   354   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
   355   src->pub.next_input_byte = NULL; /* until buffer loaded */
   355   src->pub.next_input_byte = NULL; /* until buffer loaded */
   356 }
   356 }
   357 
   357 
   358 struct my_error_mgr {
   358 struct my_error_mgr {
   359 	struct jpeg_error_mgr errmgr;
   359     struct jpeg_error_mgr errmgr;
   360 	jmp_buf escape;
   360     jmp_buf escape;
   361 };
   361 };
   362 
   362 
   363 static void my_error_exit(j_common_ptr cinfo)
   363 static void my_error_exit(j_common_ptr cinfo)
   364 {
   364 {
   365 	struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
   365     struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
   366 	longjmp(err->escape, 1);
   366     longjmp(err->escape, 1);
   367 }
   367 }
   368 
   368 
   369 static void output_no_message(j_common_ptr cinfo)
   369 static void output_no_message(j_common_ptr cinfo)
   370 {
   370 {
   371 	/* do nothing */
   371     /* do nothing */
   372 }
   372 }
   373 
   373 
   374 /* Load a JPEG type image from an SDL datasource */
   374 /* Load a JPEG type image from an SDL datasource */
   375 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
   375 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
   376 {
   376 {
   377 	Sint64 start;
   377     Sint64 start;
   378 	struct jpeg_decompress_struct cinfo;
   378     struct jpeg_decompress_struct cinfo;
   379 	JSAMPROW rowptr[1];
   379     JSAMPROW rowptr[1];
   380 	SDL_Surface *volatile surface = NULL;
   380     SDL_Surface *volatile surface = NULL;
   381 	struct my_error_mgr jerr;
   381     struct my_error_mgr jerr;
   382 
   382 
   383 	if ( !src ) {
   383     if ( !src ) {
   384 		/* The error message has been set in SDL_RWFromFile */
   384         /* The error message has been set in SDL_RWFromFile */
   385 		return NULL;
   385         return NULL;
   386 	}
   386     }
   387 	start = SDL_RWtell(src);
   387     start = SDL_RWtell(src);
   388 
   388 
   389 	if ( !IMG_Init(IMG_INIT_JPG) ) {
   389     if ( !IMG_Init(IMG_INIT_JPG) ) {
   390 		return NULL;
   390         return NULL;
   391 	}
   391     }
   392 
   392 
   393 	/* Create a decompression structure and load the JPEG header */
   393     /* Create a decompression structure and load the JPEG header */
   394 	cinfo.err = lib.jpeg_std_error(&jerr.errmgr);
   394     cinfo.err = lib.jpeg_std_error(&jerr.errmgr);
   395 	jerr.errmgr.error_exit = my_error_exit;
   395     jerr.errmgr.error_exit = my_error_exit;
   396 	jerr.errmgr.output_message = output_no_message;
   396     jerr.errmgr.output_message = output_no_message;
   397 	if(setjmp(jerr.escape)) {
   397     if(setjmp(jerr.escape)) {
   398 		/* If we get here, libjpeg found an error */
   398         /* If we get here, libjpeg found an error */
   399 		lib.jpeg_destroy_decompress(&cinfo);
   399         lib.jpeg_destroy_decompress(&cinfo);
   400 		if ( surface != NULL ) {
   400         if ( surface != NULL ) {
   401 			SDL_FreeSurface(surface);
   401             SDL_FreeSurface(surface);
   402 		}
   402         }
   403 		SDL_RWseek(src, start, RW_SEEK_SET);
   403         SDL_RWseek(src, start, RW_SEEK_SET);
   404 		IMG_SetError("JPEG loading error");
   404         IMG_SetError("JPEG loading error");
   405 		return NULL;
   405         return NULL;
   406 	}
   406     }
   407 
   407 
   408 	lib.jpeg_create_decompress(&cinfo);
   408     lib.jpeg_create_decompress(&cinfo);
   409 	jpeg_SDL_RW_src(&cinfo, src);
   409     jpeg_SDL_RW_src(&cinfo, src);
   410 	lib.jpeg_read_header(&cinfo, TRUE);
   410     lib.jpeg_read_header(&cinfo, TRUE);
   411 
   411 
   412 	if(cinfo.num_components == 4) {
   412     if(cinfo.num_components == 4) {
   413 		/* Set 32-bit Raw output */
   413         /* Set 32-bit Raw output */
   414 		cinfo.out_color_space = JCS_CMYK;
   414         cinfo.out_color_space = JCS_CMYK;
   415 		cinfo.quantize_colors = FALSE;
   415         cinfo.quantize_colors = FALSE;
   416 		lib.jpeg_calc_output_dimensions(&cinfo);
   416         lib.jpeg_calc_output_dimensions(&cinfo);
   417 
   417 
   418 		/* Allocate an output surface to hold the image */
   418         /* Allocate an output surface to hold the image */
   419 		surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   419         surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   420 		        cinfo.output_width, cinfo.output_height, 32,
   420                 cinfo.output_width, cinfo.output_height, 32,
   421 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   421 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   422 		                   0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
   422                            0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
   423 #else
   423 #else
   424 		                   0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF);
   424                            0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF);
   425 #endif
   425 #endif
   426 	} else {
   426     } else {
   427 		/* Set 24-bit RGB output */
   427         /* Set 24-bit RGB output */
   428 		cinfo.out_color_space = JCS_RGB;
   428         cinfo.out_color_space = JCS_RGB;
   429 		cinfo.quantize_colors = FALSE;
   429         cinfo.quantize_colors = FALSE;
   430 #ifdef FAST_JPEG
   430 #ifdef FAST_JPEG
   431 		cinfo.scale_num   = 1;
   431         cinfo.scale_num   = 1;
   432 		cinfo.scale_denom = 1;
   432         cinfo.scale_denom = 1;
   433 		cinfo.dct_method = JDCT_FASTEST;
   433         cinfo.dct_method = JDCT_FASTEST;
   434 		cinfo.do_fancy_upsampling = FALSE;
   434         cinfo.do_fancy_upsampling = FALSE;
   435 #endif
   435 #endif
   436 		lib.jpeg_calc_output_dimensions(&cinfo);
   436         lib.jpeg_calc_output_dimensions(&cinfo);
   437 
   437 
   438 		/* Allocate an output surface to hold the image */
   438         /* Allocate an output surface to hold the image */
   439 		surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   439         surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   440 		        cinfo.output_width, cinfo.output_height, 24,
   440                 cinfo.output_width, cinfo.output_height, 24,
   441 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   441 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   442 		                   0x0000FF, 0x00FF00, 0xFF0000,
   442                            0x0000FF, 0x00FF00, 0xFF0000,
   443 #else
   443 #else
   444 		                   0xFF0000, 0x00FF00, 0x0000FF,
   444                            0xFF0000, 0x00FF00, 0x0000FF,
   445 #endif
   445 #endif
   446 		                   0);
   446                            0);
   447 	}
   447     }
   448 
   448 
   449 	if ( surface == NULL ) {
   449     if ( surface == NULL ) {
   450 		lib.jpeg_destroy_decompress(&cinfo);
   450         lib.jpeg_destroy_decompress(&cinfo);
   451 		SDL_RWseek(src, start, RW_SEEK_SET);
   451         SDL_RWseek(src, start, RW_SEEK_SET);
   452 		IMG_SetError("Out of memory");
   452         IMG_SetError("Out of memory");
   453 		return NULL;
   453         return NULL;
   454 	}
   454     }
   455 
   455 
   456 	/* Decompress the image */
   456     /* Decompress the image */
   457 	lib.jpeg_start_decompress(&cinfo);
   457     lib.jpeg_start_decompress(&cinfo);
   458 	while ( cinfo.output_scanline < cinfo.output_height ) {
   458     while ( cinfo.output_scanline < cinfo.output_height ) {
   459 		rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
   459         rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
   460 		                    cinfo.output_scanline * surface->pitch;
   460                             cinfo.output_scanline * surface->pitch;
   461 		lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
   461         lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
   462 	}
   462     }
   463 	lib.jpeg_finish_decompress(&cinfo);
   463     lib.jpeg_finish_decompress(&cinfo);
   464 	lib.jpeg_destroy_decompress(&cinfo);
   464     lib.jpeg_destroy_decompress(&cinfo);
   465 
   465 
   466 	return(surface);
   466     return(surface);
   467 }
   467 }
   468 
   468 
   469 #else
   469 #else
   470 
   470 
   471 int IMG_InitJPG()
   471 int IMG_InitJPG()
   472 {
   472 {
   473 	IMG_SetError("JPEG images are not supported");
   473     IMG_SetError("JPEG images are not supported");
   474 	return(-1);
   474     return(-1);
   475 }
   475 }
   476 
   476 
   477 void IMG_QuitJPG()
   477 void IMG_QuitJPG()
   478 {
   478 {
   479 }
   479 }
   480 
   480 
   481 /* See if an image is contained in a data source */
   481 /* See if an image is contained in a data source */
   482 int IMG_isJPG(SDL_RWops *src)
   482 int IMG_isJPG(SDL_RWops *src)
   483 {
   483 {
   484 	return(0);
   484     return(0);
   485 }
   485 }
   486 
   486 
   487 /* Load a JPEG type image from an SDL datasource */
   487 /* Load a JPEG type image from an SDL datasource */
   488 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
   488 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
   489 {
   489 {
   490 	return(NULL);
   490     return(NULL);
   491 }
   491 }
   492 
   492 
   493 #endif /* LOAD_JPG */
   493 #endif /* LOAD_JPG */
   494 
   494 
   495 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */
   495 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */