4 * Copyright (C) 1994-1996, Thomas G. Lane.
5 * Modified 2009-2010 by Guido Vollbeding.
6 * This file is part of the Independent JPEG Group's software.
7 * For conditions of distribution and use, see the accompanying README file.
9 * This file contains routines to read input images in Microsoft "BMP"
10 * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
11 * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
12 * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
13 * Also, we don't support RLE-compressed files.
15 * These routines may need modification for non-Unix environments or
16 * specialized applications. As they stand, they assume input from
17 * an ordinary stdio stream. They further assume that reading begins
18 * at the start of the file; start_input may need work if the
19 * user interface has already read some data (e.g., to determine that
20 * the file is indeed BMP format).
22 * This code contributed by James Arthur Boucher.
25 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
30 /* Macros to deal with unsigned chars as efficiently as compiler allows */
32 #ifdef HAVE_UNSIGNED_CHAR
33 typedef unsigned char U_CHAR
;
34 #define UCH(x) ((int) (x))
35 #else /* !HAVE_UNSIGNED_CHAR */
36 #ifdef CHAR_IS_UNSIGNED
38 #define UCH(x) ((int) (x))
41 #define UCH(x) ((int) (x) & 0xFF)
43 #endif /* HAVE_UNSIGNED_CHAR */
46 #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
49 /* Private version of data source object */
51 typedef struct _bmp_source_struct
* bmp_source_ptr
;
53 typedef struct _bmp_source_struct
{
54 struct cjpeg_source_struct pub
; /* public fields */
56 j_compress_ptr cinfo
; /* back link saves passing separate parm */
58 JSAMPARRAY colormap
; /* BMP colormap (converted to my format) */
60 jvirt_sarray_ptr whole_image
; /* Needed to reverse row order */
61 JDIMENSION source_row
; /* Current source row number */
62 JDIMENSION row_width
; /* Physical width of scanlines in file */
64 int bits_per_pixel
; /* remembers 8- or 24-bit format */
69 read_byte (bmp_source_ptr sinfo
)
70 /* Read next byte from BMP file */
72 register FILE *infile
= sinfo
->pub
.input_file
;
75 if ((c
= getc(infile
)) == EOF
)
76 ERREXIT(sinfo
->cinfo
, JERR_INPUT_EOF
);
82 read_colormap (bmp_source_ptr sinfo
, int cmaplen
, int mapentrysize
)
83 /* Read the colormap from a BMP file */
87 switch (mapentrysize
) {
89 /* BGR format (occurs in OS/2 files) */
90 for (i
= 0; i
< cmaplen
; i
++) {
91 sinfo
->colormap
[2][i
] = (JSAMPLE
) read_byte(sinfo
);
92 sinfo
->colormap
[1][i
] = (JSAMPLE
) read_byte(sinfo
);
93 sinfo
->colormap
[0][i
] = (JSAMPLE
) read_byte(sinfo
);
97 /* BGR0 format (occurs in MS Windows files) */
98 for (i
= 0; i
< cmaplen
; i
++) {
99 sinfo
->colormap
[2][i
] = (JSAMPLE
) read_byte(sinfo
);
100 sinfo
->colormap
[1][i
] = (JSAMPLE
) read_byte(sinfo
);
101 sinfo
->colormap
[0][i
] = (JSAMPLE
) read_byte(sinfo
);
102 (void) read_byte(sinfo
);
106 ERREXIT(sinfo
->cinfo
, JERR_BMP_BADCMAP
);
113 * Read one row of pixels.
114 * The image has been read into the whole_image array, but is otherwise
115 * unprocessed. We must read it out in top-to-bottom row order, and if
116 * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
119 METHODDEF(JDIMENSION
)
120 get_8bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
121 /* This version is for reading 8-bit colormap indexes */
123 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
124 register JSAMPARRAY colormap
= source
->colormap
;
125 JSAMPARRAY image_ptr
;
127 register JSAMPROW inptr
, outptr
;
128 register JDIMENSION col
;
130 /* Fetch next row from virtual array */
131 source
->source_row
--;
132 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
133 ((j_common_ptr
) cinfo
, source
->whole_image
,
134 source
->source_row
, (JDIMENSION
) 1, FALSE
);
136 /* Expand the colormap indexes to real data */
137 inptr
= image_ptr
[0];
138 outptr
= source
->pub
.buffer
[0];
139 for (col
= cinfo
->image_width
; col
> 0; col
--) {
140 t
= GETJSAMPLE(*inptr
++);
141 *outptr
++ = colormap
[0][t
]; /* can omit GETJSAMPLE() safely */
142 *outptr
++ = colormap
[1][t
];
143 *outptr
++ = colormap
[2][t
];
150 METHODDEF(JDIMENSION
)
151 get_24bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
152 /* This version is for reading 24-bit pixels */
154 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
155 JSAMPARRAY image_ptr
;
156 register JSAMPROW inptr
, outptr
;
157 register JDIMENSION col
;
159 /* Fetch next row from virtual array */
160 source
->source_row
--;
161 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
162 ((j_common_ptr
) cinfo
, source
->whole_image
,
163 source
->source_row
, (JDIMENSION
) 1, FALSE
);
165 /* Transfer data. Note source values are in BGR order
166 * (even though Microsoft's own documents say the opposite).
168 inptr
= image_ptr
[0];
169 outptr
= source
->pub
.buffer
[0];
170 for (col
= cinfo
->image_width
; col
> 0; col
--) {
171 outptr
[2] = *inptr
++; /* can omit GETJSAMPLE() safely */
172 outptr
[1] = *inptr
++;
173 outptr
[0] = *inptr
++;
181 METHODDEF(JDIMENSION
)
182 get_32bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
183 /* This version is for reading 32-bit pixels */
185 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
186 JSAMPARRAY image_ptr
;
187 register JSAMPROW inptr
, outptr
;
188 register JDIMENSION col
;
190 /* Fetch next row from virtual array */
191 source
->source_row
--;
192 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
193 ((j_common_ptr
) cinfo
, source
->whole_image
,
194 source
->source_row
, (JDIMENSION
) 1, FALSE
);
195 /* Transfer data. Note source values are in BGR order
196 * (even though Microsoft's own documents say the opposite).
198 inptr
= image_ptr
[0];
199 outptr
= source
->pub
.buffer
[0];
200 for (col
= cinfo
->image_width
; col
> 0; col
--) {
201 outptr
[2] = *inptr
++; /* can omit GETJSAMPLE() safely */
202 outptr
[1] = *inptr
++;
203 outptr
[0] = *inptr
++;
204 inptr
++; /* skip the 4th byte (Alpha channel) */
213 * This method loads the image into whole_image during the first call on
214 * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
215 * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
218 METHODDEF(JDIMENSION
)
219 preload_image (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
221 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
222 register FILE *infile
= source
->pub
.input_file
;
224 register JSAMPROW out_ptr
;
225 JSAMPARRAY image_ptr
;
227 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
229 /* Read the data into a virtual array in input-file row order. */
230 for (row
= 0; row
< cinfo
->image_height
; row
++) {
231 if (progress
!= NULL
) {
232 progress
->pub
.pass_counter
= (long) row
;
233 progress
->pub
.pass_limit
= (long) cinfo
->image_height
;
234 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
236 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
237 ((j_common_ptr
) cinfo
, source
->whole_image
,
238 row
, (JDIMENSION
) 1, TRUE
);
239 out_ptr
= image_ptr
[0];
240 for (col
= source
->row_width
; col
> 0; col
--) {
241 /* inline copy of read_byte() for speed */
242 if ((c
= getc(infile
)) == EOF
)
243 ERREXIT(cinfo
, JERR_INPUT_EOF
);
244 *out_ptr
++ = (JSAMPLE
) c
;
247 if (progress
!= NULL
)
248 progress
->completed_extra_passes
++;
250 /* Set up to read from the virtual array in top-to-bottom order */
251 switch (source
->bits_per_pixel
) {
253 source
->pub
.get_pixel_rows
= get_8bit_row
;
256 source
->pub
.get_pixel_rows
= get_24bit_row
;
259 source
->pub
.get_pixel_rows
= get_32bit_row
;
262 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
264 source
->source_row
= cinfo
->image_height
;
266 /* And read the first row */
267 return (*source
->pub
.get_pixel_rows
) (cinfo
, sinfo
);
272 * Read the file header; return image size and component count.
276 start_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
278 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
279 U_CHAR bmpfileheader
[14];
280 U_CHAR bmpinfoheader
[64];
281 #define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \
282 (((unsigned int) UCH(array[offset+1])) << 8))
283 #define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \
284 (((INT32) UCH(array[offset+1])) << 8) + \
285 (((INT32) UCH(array[offset+2])) << 16) + \
286 (((INT32) UCH(array[offset+3])) << 24))
291 unsigned int biPlanes
;
293 INT32 biXPelsPerMeter
,biYPelsPerMeter
;
295 int mapentrysize
= 0; /* 0 indicates no colormap */
297 JDIMENSION row_width
;
299 /* Read and verify the bitmap file header */
300 if (! ReadOK(source
->pub
.input_file
, bmpfileheader
, 14))
301 ERREXIT(cinfo
, JERR_INPUT_EOF
);
302 if (GET_2B(bmpfileheader
,0) != 0x4D42) /* 'BM' */
303 ERREXIT(cinfo
, JERR_BMP_NOT
);
304 bfOffBits
= (INT32
) GET_4B(bmpfileheader
,10);
305 /* We ignore the remaining fileheader fields */
307 /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
308 * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
310 if (! ReadOK(source
->pub
.input_file
, bmpinfoheader
, 4))
311 ERREXIT(cinfo
, JERR_INPUT_EOF
);
312 headerSize
= (INT32
) GET_4B(bmpinfoheader
,0);
313 if (headerSize
< 12 || headerSize
> 64)
314 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
315 if (! ReadOK(source
->pub
.input_file
, bmpinfoheader
+4, headerSize
-4))
316 ERREXIT(cinfo
, JERR_INPUT_EOF
);
318 switch ((int) headerSize
) {
320 /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
321 biWidth
= (INT32
) GET_2B(bmpinfoheader
,4);
322 biHeight
= (INT32
) GET_2B(bmpinfoheader
,6);
323 biPlanes
= GET_2B(bmpinfoheader
,8);
324 source
->bits_per_pixel
= (int) GET_2B(bmpinfoheader
,10);
326 switch (source
->bits_per_pixel
) {
327 case 8: /* colormapped image */
328 mapentrysize
= 3; /* OS/2 uses RGBTRIPLE colormap */
329 TRACEMS2(cinfo
, 1, JTRC_BMP_OS2_MAPPED
, (int) biWidth
, (int) biHeight
);
331 case 24: /* RGB image */
332 TRACEMS2(cinfo
, 1, JTRC_BMP_OS2
, (int) biWidth
, (int) biHeight
);
335 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
341 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
342 /* or OS/2 2.x header, which has additional fields that we ignore */
343 biWidth
= GET_4B(bmpinfoheader
,4);
344 biHeight
= GET_4B(bmpinfoheader
,8);
345 biPlanes
= GET_2B(bmpinfoheader
,12);
346 source
->bits_per_pixel
= (int) GET_2B(bmpinfoheader
,14);
347 biCompression
= GET_4B(bmpinfoheader
,16);
348 biXPelsPerMeter
= GET_4B(bmpinfoheader
,24);
349 biYPelsPerMeter
= GET_4B(bmpinfoheader
,28);
350 biClrUsed
= GET_4B(bmpinfoheader
,32);
351 /* biSizeImage, biClrImportant fields are ignored */
353 switch (source
->bits_per_pixel
) {
354 case 8: /* colormapped image */
355 mapentrysize
= 4; /* Windows uses RGBQUAD colormap */
356 TRACEMS2(cinfo
, 1, JTRC_BMP_MAPPED
, (int) biWidth
, (int) biHeight
);
358 case 24: /* RGB image */
359 TRACEMS2(cinfo
, 1, JTRC_BMP
, (int) biWidth
, (int) biHeight
);
361 case 32: /* RGB image + Alpha channel */
362 TRACEMS2(cinfo
, 1, JTRC_BMP
, (int) biWidth
, (int) biHeight
);
365 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
368 if (biCompression
!= 0)
369 ERREXIT(cinfo
, JERR_BMP_COMPRESSED
);
371 if (biXPelsPerMeter
> 0 && biYPelsPerMeter
> 0) {
372 /* Set JFIF density parameters from the BMP data */
373 cinfo
->X_density
= (UINT16
) (biXPelsPerMeter
/100); /* 100 cm per meter */
374 cinfo
->Y_density
= (UINT16
) (biYPelsPerMeter
/100);
375 cinfo
->density_unit
= 2; /* dots/cm */
379 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
383 if (biWidth
<= 0 || biHeight
<= 0)
384 ERREXIT(cinfo
, JERR_BMP_EMPTY
);
386 ERREXIT(cinfo
, JERR_BMP_BADPLANES
);
388 /* Compute distance to bitmap data --- will adjust for colormap below */
389 bPad
= bfOffBits
- (headerSize
+ 14);
391 /* Read the colormap, if any */
392 if (mapentrysize
> 0) {
394 biClrUsed
= 256; /* assume it's 256 */
395 else if (biClrUsed
> 256)
396 ERREXIT(cinfo
, JERR_BMP_BADCMAP
);
397 /* Allocate space to store the colormap */
398 source
->colormap
= (*cinfo
->mem
->alloc_sarray
)
399 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
400 (JDIMENSION
) biClrUsed
, (JDIMENSION
) 3);
401 /* and read it from the file */
402 read_colormap(source
, (int) biClrUsed
, mapentrysize
);
403 /* account for size of colormap */
404 bPad
-= biClrUsed
* mapentrysize
;
407 /* Skip any remaining pad bytes */
408 if (bPad
< 0) /* incorrect bfOffBits value? */
409 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
410 while (--bPad
>= 0) {
411 (void) read_byte(source
);
414 /* Compute row width in file, including padding to 4-byte boundary */
415 if (source
->bits_per_pixel
== 24)
416 row_width
= (JDIMENSION
) (biWidth
* 3);
417 else if (source
->bits_per_pixel
== 32)
418 row_width
= (JDIMENSION
) (biWidth
* 4);
420 row_width
= (JDIMENSION
) biWidth
;
421 while ((row_width
& 3) != 0) row_width
++;
422 source
->row_width
= row_width
;
424 /* Allocate space for inversion array, prepare for preload pass */
425 source
->whole_image
= (*cinfo
->mem
->request_virt_sarray
)
426 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
427 row_width
, (JDIMENSION
) biHeight
, (JDIMENSION
) 1);
428 source
->pub
.get_pixel_rows
= preload_image
;
429 if (cinfo
->progress
!= NULL
) {
430 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
431 progress
->total_extra_passes
++; /* count file input as separate pass */
434 /* Allocate one-row buffer for returned data */
435 source
->pub
.buffer
= (*cinfo
->mem
->alloc_sarray
)
436 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
437 (JDIMENSION
) (biWidth
* 3), (JDIMENSION
) 1);
438 source
->pub
.buffer_height
= 1;
440 cinfo
->in_color_space
= JCS_RGB
;
441 cinfo
->input_components
= 3;
442 cinfo
->data_precision
= 8;
443 cinfo
->image_width
= (JDIMENSION
) biWidth
;
444 cinfo
->image_height
= (JDIMENSION
) biHeight
;
449 * Finish up at the end of the file.
453 finish_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
460 * The module selection routine for BMP format input.
463 GLOBAL(cjpeg_source_ptr
)
464 jinit_read_bmp (j_compress_ptr cinfo
)
466 bmp_source_ptr source
;
468 /* Create module interface object */
469 source
= (bmp_source_ptr
)
470 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
471 SIZEOF(bmp_source_struct
));
472 source
->cinfo
= cinfo
; /* make back link for subroutines */
473 /* Fill in method ptrs, except get_pixel_rows which start_input sets */
474 source
->pub
.start_input
= start_input_bmp
;
475 source
->pub
.finish_input
= finish_input_bmp
;
477 return (cjpeg_source_ptr
) source
;
480 #endif /* BMP_SUPPORTED */