Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 440 lines (376 sloc) 13.792 kb
9f5d49a auto import from //depot/cupcake/@135843
The Android Open Source Project authored
1 /*
2 * rdbmp.c
3 *
4 * Copyright (C) 1994-1996, Thomas G. Lane.
5 * This file is part of the Independent JPEG Group's software.
6 * For conditions of distribution and use, see the accompanying README file.
7 *
8 * This file contains routines to read input images in Microsoft "BMP"
9 * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
10 * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
11 * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
12 * Also, we don't support RLE-compressed files.
13 *
14 * These routines may need modification for non-Unix environments or
15 * specialized applications. As they stand, they assume input from
16 * an ordinary stdio stream. They further assume that reading begins
17 * at the start of the file; start_input may need work if the
18 * user interface has already read some data (e.g., to determine that
19 * the file is indeed BMP format).
20 *
21 * This code contributed by James Arthur Boucher.
22 */
23
24 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
25
26 #ifdef BMP_SUPPORTED
27
28
29 /* Macros to deal with unsigned chars as efficiently as compiler allows */
30
31 #ifdef HAVE_UNSIGNED_CHAR
32 typedef unsigned char U_CHAR;
33 #define UCH(x) ((int) (x))
34 #else /* !HAVE_UNSIGNED_CHAR */
35 #ifdef CHAR_IS_UNSIGNED
36 typedef char U_CHAR;
37 #define UCH(x) ((int) (x))
38 #else
39 typedef char U_CHAR;
40 #define UCH(x) ((int) (x) & 0xFF)
41 #endif
42 #endif /* HAVE_UNSIGNED_CHAR */
43
44
45 #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
46
47
48 /* Private version of data source object */
49
50 typedef struct _bmp_source_struct * bmp_source_ptr;
51
52 typedef struct _bmp_source_struct {
53 struct cjpeg_source_struct pub; /* public fields */
54
55 j_compress_ptr cinfo; /* back link saves passing separate parm */
56
57 JSAMPARRAY colormap; /* BMP colormap (converted to my format) */
58
59 jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
60 JDIMENSION source_row; /* Current source row number */
61 JDIMENSION row_width; /* Physical width of scanlines in file */
62
63 int bits_per_pixel; /* remembers 8- or 24-bit format */
64 } bmp_source_struct;
65
66
67 LOCAL(int)
68 read_byte (bmp_source_ptr sinfo)
69 /* Read next byte from BMP file */
70 {
71 register FILE *infile = sinfo->pub.input_file;
72 register int c;
73
74 if ((c = getc(infile)) == EOF)
75 ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
76 return c;
77 }
78
79
80 LOCAL(void)
81 read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
82 /* Read the colormap from a BMP file */
83 {
84 int i;
85
86 switch (mapentrysize) {
87 case 3:
88 /* BGR format (occurs in OS/2 files) */
89 for (i = 0; i < cmaplen; i++) {
90 sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
91 sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
92 sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
93 }
94 break;
95 case 4:
96 /* BGR0 format (occurs in MS Windows files) */
97 for (i = 0; i < cmaplen; i++) {
98 sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
99 sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
100 sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
101 (void) read_byte(sinfo);
102 }
103 break;
104 default:
105 ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
106 break;
107 }
108 }
109
110
111 /*
112 * Read one row of pixels.
113 * The image has been read into the whole_image array, but is otherwise
114 * unprocessed. We must read it out in top-to-bottom row order, and if
115 * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
116 */
117
118 METHODDEF(JDIMENSION)
119 get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
120 /* This version is for reading 8-bit colormap indexes */
121 {
122 bmp_source_ptr source = (bmp_source_ptr) sinfo;
123 register JSAMPARRAY colormap = source->colormap;
124 JSAMPARRAY image_ptr;
125 register int t;
126 register JSAMPROW inptr, outptr;
127 register JDIMENSION col;
128
129 /* Fetch next row from virtual array */
130 source->source_row--;
131 image_ptr = (*cinfo->mem->access_virt_sarray)
132 ((j_common_ptr) cinfo, source->whole_image,
133 source->source_row, (JDIMENSION) 1, FALSE);
134
135 /* Expand the colormap indexes to real data */
136 inptr = image_ptr[0];
137 outptr = source->pub.buffer[0];
138 for (col = cinfo->image_width; col > 0; col--) {
139 t = GETJSAMPLE(*inptr++);
140 *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
141 *outptr++ = colormap[1][t];
142 *outptr++ = colormap[2][t];
143 }
144
145 return 1;
146 }
147
148
149 METHODDEF(JDIMENSION)
150 get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
151 /* This version is for reading 24-bit pixels */
152 {
153 bmp_source_ptr source = (bmp_source_ptr) sinfo;
154 JSAMPARRAY image_ptr;
155 register JSAMPROW inptr, outptr;
156 register JDIMENSION col;
157
158 /* Fetch next row from virtual array */
159 source->source_row--;
160 image_ptr = (*cinfo->mem->access_virt_sarray)
161 ((j_common_ptr) cinfo, source->whole_image,
162 source->source_row, (JDIMENSION) 1, FALSE);
163
164 /* Transfer data. Note source values are in BGR order
165 * (even though Microsoft's own documents say the opposite).
166 */
167 inptr = image_ptr[0];
168 outptr = source->pub.buffer[0];
169 for (col = cinfo->image_width; col > 0; col--) {
170 outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
171 outptr[1] = *inptr++;
172 outptr[0] = *inptr++;
173 outptr += 3;
174 }
175
176 return 1;
177 }
178
179
180 /*
181 * This method loads the image into whole_image during the first call on
182 * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
183 * get_8bit_row or get_24bit_row on subsequent calls.
184 */
185
186 METHODDEF(JDIMENSION)
187 preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
188 {
189 bmp_source_ptr source = (bmp_source_ptr) sinfo;
190 register FILE *infile = source->pub.input_file;
191 register int c;
192 register JSAMPROW out_ptr;
193 JSAMPARRAY image_ptr;
194 JDIMENSION row, col;
195 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
196
197 /* Read the data into a virtual array in input-file row order. */
198 for (row = 0; row < cinfo->image_height; row++) {
199 if (progress != NULL) {
200 progress->pub.pass_counter = (long) row;
201 progress->pub.pass_limit = (long) cinfo->image_height;
202 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
203 }
204 image_ptr = (*cinfo->mem->access_virt_sarray)
205 ((j_common_ptr) cinfo, source->whole_image,
206 row, (JDIMENSION) 1, TRUE);
207 out_ptr = image_ptr[0];
208 for (col = source->row_width; col > 0; col--) {
209 /* inline copy of read_byte() for speed */
210 if ((c = getc(infile)) == EOF)
211 ERREXIT(cinfo, JERR_INPUT_EOF);
212 *out_ptr++ = (JSAMPLE) c;
213 }
214 }
215 if (progress != NULL)
216 progress->completed_extra_passes++;
217
218 /* Set up to read from the virtual array in top-to-bottom order */
219 switch (source->bits_per_pixel) {
220 case 8:
221 source->pub.get_pixel_rows = get_8bit_row;
222 break;
223 case 24:
224 source->pub.get_pixel_rows = get_24bit_row;
225 break;
226 default:
227 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
228 }
229 source->source_row = cinfo->image_height;
230
231 /* And read the first row */
232 return (*source->pub.get_pixel_rows) (cinfo, sinfo);
233 }
234
235
236 /*
237 * Read the file header; return image size and component count.
238 */
239
240 METHODDEF(void)
241 start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
242 {
243 bmp_source_ptr source = (bmp_source_ptr) sinfo;
244 U_CHAR bmpfileheader[14];
245 U_CHAR bmpinfoheader[64];
246 #define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \
247 (((unsigned int) UCH(array[offset+1])) << 8))
248 #define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \
249 (((INT32) UCH(array[offset+1])) << 8) + \
250 (((INT32) UCH(array[offset+2])) << 16) + \
251 (((INT32) UCH(array[offset+3])) << 24))
252 INT32 bfOffBits;
253 INT32 headerSize;
254 INT32 biWidth = 0; /* initialize to avoid compiler warning */
255 INT32 biHeight = 0;
256 unsigned int biPlanes;
257 INT32 biCompression;
258 INT32 biXPelsPerMeter,biYPelsPerMeter;
259 INT32 biClrUsed = 0;
260 int mapentrysize = 0; /* 0 indicates no colormap */
261 INT32 bPad;
262 JDIMENSION row_width;
263
264 /* Read and verify the bitmap file header */
265 if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
266 ERREXIT(cinfo, JERR_INPUT_EOF);
267 if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */
268 ERREXIT(cinfo, JERR_BMP_NOT);
269 bfOffBits = (INT32) GET_4B(bmpfileheader,10);
270 /* We ignore the remaining fileheader fields */
271
272 /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
273 * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
274 */
275 if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))
276 ERREXIT(cinfo, JERR_INPUT_EOF);
277 headerSize = (INT32) GET_4B(bmpinfoheader,0);
278 if (headerSize < 12 || headerSize > 64)
279 ERREXIT(cinfo, JERR_BMP_BADHEADER);
280 if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4))
281 ERREXIT(cinfo, JERR_INPUT_EOF);
282
283 switch ((int) headerSize) {
284 case 12:
285 /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
286 biWidth = (INT32) GET_2B(bmpinfoheader,4);
287 biHeight = (INT32) GET_2B(bmpinfoheader,6);
288 biPlanes = GET_2B(bmpinfoheader,8);
289 source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10);
290
291 switch (source->bits_per_pixel) {
292 case 8: /* colormapped image */
293 mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
294 TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
295 break;
296 case 24: /* RGB image */
297 TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight);
298 break;
299 default:
300 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
301 break;
302 }
303 if (biPlanes != 1)
304 ERREXIT(cinfo, JERR_BMP_BADPLANES);
305 break;
306 case 40:
307 case 64:
308 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
309 /* or OS/2 2.x header, which has additional fields that we ignore */
310 biWidth = GET_4B(bmpinfoheader,4);
311 biHeight = GET_4B(bmpinfoheader,8);
312 biPlanes = GET_2B(bmpinfoheader,12);
313 source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14);
314 biCompression = GET_4B(bmpinfoheader,16);
315 biXPelsPerMeter = GET_4B(bmpinfoheader,24);
316 biYPelsPerMeter = GET_4B(bmpinfoheader,28);
317 biClrUsed = GET_4B(bmpinfoheader,32);
318 /* biSizeImage, biClrImportant fields are ignored */
319
320 switch (source->bits_per_pixel) {
321 case 8: /* colormapped image */
322 mapentrysize = 4; /* Windows uses RGBQUAD colormap */
323 TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
324 break;
325 case 24: /* RGB image */
326 TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
327 break;
328 default:
329 ERREXIT(cinfo, JERR_BMP_BADDEPTH);
330 break;
331 }
332 if (biPlanes != 1)
333 ERREXIT(cinfo, JERR_BMP_BADPLANES);
334 if (biCompression != 0)
335 ERREXIT(cinfo, JERR_BMP_COMPRESSED);
336
337 if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
338 /* Set JFIF density parameters from the BMP data */
339 cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
340 cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
341 cinfo->density_unit = 2; /* dots/cm */
342 }
343 break;
344 default:
345 ERREXIT(cinfo, JERR_BMP_BADHEADER);
346 break;
347 }
348
349 /* Compute distance to bitmap data --- will adjust for colormap below */
350 bPad = bfOffBits - (headerSize + 14);
351
352 /* Read the colormap, if any */
353 if (mapentrysize > 0) {
354 if (biClrUsed <= 0)
355 biClrUsed = 256; /* assume it's 256 */
356 else if (biClrUsed > 256)
357 ERREXIT(cinfo, JERR_BMP_BADCMAP);
358 /* Allocate space to store the colormap */
359 source->colormap = (*cinfo->mem->alloc_sarray)
360 ((j_common_ptr) cinfo, JPOOL_IMAGE,
361 (JDIMENSION) biClrUsed, (JDIMENSION) 3);
362 /* and read it from the file */
363 read_colormap(source, (int) biClrUsed, mapentrysize);
364 /* account for size of colormap */
365 bPad -= biClrUsed * mapentrysize;
366 }
367
368 /* Skip any remaining pad bytes */
369 if (bPad < 0) /* incorrect bfOffBits value? */
370 ERREXIT(cinfo, JERR_BMP_BADHEADER);
371 while (--bPad >= 0) {
372 (void) read_byte(source);
373 }
374
375 /* Compute row width in file, including padding to 4-byte boundary */
376 if (source->bits_per_pixel == 24)
377 row_width = (JDIMENSION) (biWidth * 3);
378 else
379 row_width = (JDIMENSION) biWidth;
380 while ((row_width & 3) != 0) row_width++;
381 source->row_width = row_width;
382
383 /* Allocate space for inversion array, prepare for preload pass */
384 source->whole_image = (*cinfo->mem->request_virt_sarray)
385 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
386 row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
387 source->pub.get_pixel_rows = preload_image;
388 if (cinfo->progress != NULL) {
389 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
390 progress->total_extra_passes++; /* count file input as separate pass */
391 }
392
393 /* Allocate one-row buffer for returned data */
394 source->pub.buffer = (*cinfo->mem->alloc_sarray)
395 ((j_common_ptr) cinfo, JPOOL_IMAGE,
396 (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
397 source->pub.buffer_height = 1;
398
399 cinfo->in_color_space = JCS_RGB;
400 cinfo->input_components = 3;
401 cinfo->data_precision = 8;
402 cinfo->image_width = (JDIMENSION) biWidth;
403 cinfo->image_height = (JDIMENSION) biHeight;
404 }
405
406
407 /*
408 * Finish up at the end of the file.
409 */
410
411 METHODDEF(void)
412 finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
413 {
414 /* no work */
415 }
416
417
418 /*
419 * The module selection routine for BMP format input.
420 */
421
422 GLOBAL(cjpeg_source_ptr)
423 jinit_read_bmp (j_compress_ptr cinfo)
424 {
425 bmp_source_ptr source;
426
427 /* Create module interface object */
428 source = (bmp_source_ptr)
429 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
430 SIZEOF(bmp_source_struct));
431 source->cinfo = cinfo; /* make back link for subroutines */
432 /* Fill in method ptrs, except get_pixel_rows which start_input sets */
433 source->pub.start_input = start_input_bmp;
434 source->pub.finish_input = finish_input_bmp;
435
436 return (cjpeg_source_ptr) source;
437 }
438
439 #endif /* BMP_SUPPORTED */
Something went wrong with that request. Please try again.