Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
    IMGLIB:  An example image loading library for use with SDL
3
    Copyright (C) 1999  Sam Lantinga
4
 
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Library General Public
7
    License as published by the Free Software Foundation; either
8
    version 2 of the License, or (at your option) any later version.
9
 
10
    This library is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
    Library General Public License for more details.
14
 
15
    You should have received a copy of the GNU Library General Public
16
    License along with this library; if not, write to the Free
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
19
    Sam Lantinga
20
    5635-34 Springhouse Dr.
21
    Pleasanton, CA 94588 (USA)
22
    slouken@devolution.com
23
*/
24
 
25
/* This is a JPEG image file loading framework */
26
 
27
#include 
28
#include 
29
 
30
#include "SDL_image.h"
31
 
32
#ifdef LOAD_JPG
33
 
34
#include 
35
 
36
/* Define this for fast loading and not as good image quality */
37
/*#define FAST_JPEG*/
38
 
39
/* See if an image is contained in a data source */
40
int IMG_isJPG(SDL_RWops *src)
41
{
42
	int is_JPG;
43
	Uint8 magic[4];
44
 
45
	is_JPG = 0;
46
	if ( SDL_RWread(src, magic, 2, 1) ) {
47
		if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
48
			SDL_RWread(src, magic, 4, 1);
49
			SDL_RWread(src, magic, 4, 1);
50
			if ( memcmp((char *)magic, "JFIF", 4) == 0 ) {
51
				is_JPG = 1;
52
			}
53
		}
54
	}
55
	return(is_JPG);
56
}
57
 
58
#define INPUT_BUFFER_SIZE	4096
59
typedef struct {
60
	struct jpeg_source_mgr pub;
61
 
62
	SDL_RWops *ctx;
63
	Uint8 buffer[INPUT_BUFFER_SIZE];
64
} my_source_mgr;
65
 
66
/*
67
 * Initialize source --- called by jpeg_read_header
68
 * before any data is actually read.
69
 */
70
static void init_source (j_decompress_ptr cinfo)
71
{
72
	/* We don't actually need to do anything */
73
	return;
74
}
75
 
76
/*
77
 * Fill the input buffer --- called whenever buffer is emptied.
78
 */
79
static int fill_input_buffer (j_decompress_ptr cinfo)
80
{
81
	my_source_mgr * src = (my_source_mgr *) cinfo->src;
82
	int nbytes;
83
 
84
	nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE);
85
	if (nbytes <= 0) {
86
		/* Insert a fake EOI marker */
87
		src->buffer[0] = (Uint8) 0xFF;
88
		src->buffer[1] = (Uint8) JPEG_EOI;
89
		nbytes = 2;
90
	}
91
	src->pub.next_input_byte = src->buffer;
92
	src->pub.bytes_in_buffer = nbytes;
93
 
94
	return TRUE;
95
}
96
 
97
 
98
/*
99
 * Skip data --- used to skip over a potentially large amount of
100
 * uninteresting data (such as an APPn marker).
101
 *
102
 * Writers of suspendable-input applications must note that skip_input_data
103
 * is not granted the right to give a suspension return.  If the skip extends
104
 * beyond the data currently in the buffer, the buffer can be marked empty so
105
 * that the next read will cause a fill_input_buffer call that can suspend.
106
 * Arranging for additional bytes to be discarded before reloading the input
107
 * buffer is the application writer's problem.
108
 */
109
static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
110
{
111
	my_source_mgr * src = (my_source_mgr *) cinfo->src;
112
 
113
	/* Just a dumb implementation for now.	Could use fseek() except
114
	 * it doesn't work on pipes.  Not clear that being smart is worth
115
	 * any trouble anyway --- large skips are infrequent.
116
	 */
117
	if (num_bytes > 0) {
118
		while (num_bytes > (long) src->pub.bytes_in_buffer) {
119
			num_bytes -= (long) src->pub.bytes_in_buffer;
120
			(void) src->pub.fill_input_buffer(cinfo);
121
			/* note we assume that fill_input_buffer will never
122
			 * return FALSE, so suspension need not be handled.
123
			 */
124
		}
125
		src->pub.next_input_byte += (size_t) num_bytes;
126
		src->pub.bytes_in_buffer -= (size_t) num_bytes;
127
	}
128
}
129
 
130
/*
131
 * Terminate source --- called by jpeg_finish_decompress
132
 * after all data has been read.
133
 */
134
static void term_source (j_decompress_ptr cinfo)
135
{
136
	/* We don't actually need to do anything */
137
	return;
138
}
139
 
140
/*
141
 * Prepare for input from a stdio stream.
142
 * The caller must have already opened the stream, and is responsible
143
 * for closing it after finishing decompression.
144
 */
145
static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx)
146
{
147
  my_source_mgr *src;
148
 
149
  /* The source object and input buffer are made permanent so that a series
150
   * of JPEG images can be read from the same file by calling jpeg_stdio_src
151
   * only before the first one.  (If we discarded the buffer at the end of
152
   * one image, we'd likely lose the start of the next one.)
153
   * This makes it unsafe to use this manager and a different source
154
   * manager serially with the same JPEG object.  Caveat programmer.
155
   */
156
  if (cinfo->src == NULL) {	/* first time for this JPEG object? */
157
    cinfo->src = (struct jpeg_source_mgr *)
158
      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
159
				  sizeof(my_source_mgr));
160
    src = (my_source_mgr *) cinfo->src;
161
  }
162
 
163
  src = (my_source_mgr *) cinfo->src;
164
  src->pub.init_source = init_source;
165
  src->pub.fill_input_buffer = fill_input_buffer;
166
  src->pub.skip_input_data = skip_input_data;
167
  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
168
  src->pub.term_source = term_source;
169
  src->ctx = ctx;
170
  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
171
  src->pub.next_input_byte = NULL; /* until buffer loaded */
172
}
173
 
174
/* Load a JPEG type image from an SDL datasource */
175
SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
176
{
177
	struct jpeg_error_mgr errmgr;
178
	struct jpeg_decompress_struct cinfo;
179
	JSAMPROW rowptr[1];
180
	SDL_Surface *surface;
181
 
182
	/* Create a decompression structure and load the JPEG header */
183
	cinfo.err = jpeg_std_error(&errmgr);
184
	jpeg_create_decompress(&cinfo);
185
	jpeg_SDL_RW_src(&cinfo, src);
186
	jpeg_read_header(&cinfo, TRUE);
187
 
188
	/* Set 24-bit RGB output */
189
	cinfo.out_color_space = JCS_RGB;
190
	cinfo.quantize_colors = FALSE;
191
#ifdef FAST_JPEG
192
	cinfo.scale_num   = 1;
193
	cinfo.scale_denom = 1;
194
	cinfo.dct_method = JDCT_FASTEST;
195
	cinfo.do_fancy_upsampling = FALSE;
196
#endif
197
	jpeg_calc_output_dimensions(&cinfo);
198
 
199
	/* Allocate an output surface to hold the image */
200
	surface = SDL_AllocSurface(SDL_SWSURFACE,
201
	               cinfo.output_width, cinfo.output_height, 24,
202
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
203
	                           0x0000FF, 0x00FF00, 0xFF0000,
204
#else
205
	                           0xFF0000, 0x00FF00, 0x0000FF,
206
#endif
207
				   0);
208
	if ( surface == NULL ) {
209
		IMG_SetError("Out of memory");
210
		goto done;
211
	}
212
 
213
	/* Decompress the image */
214
	jpeg_start_decompress(&cinfo);
215
	while ( cinfo.output_scanline < cinfo.output_height ) {
216
		rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
217
		                    cinfo.output_scanline * surface->pitch;
218
		jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
219
	}
220
	jpeg_finish_decompress(&cinfo);
221
 
222
	/* Clean up and return */
223
done:
224
	jpeg_destroy_decompress(&cinfo);
225
	return(surface);
226
}
227
 
228
#else
229
 
230
/* See if an image is contained in a data source */
231
int IMG_isJPG(SDL_RWops *src)
232
{
233
	return(0);
234
}
235
 
236
/* Load a JPEG type image from an SDL datasource */
237
SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
238
{
239
	return(NULL);
240
}
241
 
242
#endif /* LOAD_JPG */