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.
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.
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).
21 * This code contributed by James Arthur Boucher.
24 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
29 /* Macros to deal with unsigned chars as efficiently as compiler allows */
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
37 #define UCH(x) ((int) (x))
40 #define UCH(x) ((int) (x) & 0xFF)
42 #endif /* HAVE_UNSIGNED_CHAR */
45 #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
48 /* Private version of data source object */
50 typedef struct _bmp_source_struct
* bmp_source_ptr
;
52 typedef struct _bmp_source_struct
{
53 struct cjpeg_source_struct pub
; /* public fields */
55 j_compress_ptr cinfo
; /* back link saves passing separate parm */
57 JSAMPARRAY colormap
; /* BMP colormap (converted to my format) */
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 */
63 int bits_per_pixel
; /* remembers 8- or 24-bit format */
68 read_byte (bmp_source_ptr sinfo
)
69 /* Read next byte from BMP file */
71 register FILE *infile
= sinfo
->pub
.input_file
;
74 if ((c
= getc(infile
)) == EOF
)
75 ERREXIT(sinfo
->cinfo
, JERR_INPUT_EOF
);
81 read_colormap (bmp_source_ptr sinfo
, int cmaplen
, int mapentrysize
)
82 /* Read the colormap from a BMP file */
86 switch (mapentrysize
) {
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
);
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
);
105 ERREXIT(sinfo
->cinfo
, JERR_BMP_BADCMAP
);
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.
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 */
122 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
123 register JSAMPARRAY colormap
= source
->colormap
;
124 JSAMPARRAY image_ptr
;
126 register JSAMPROW inptr
, outptr
;
127 register JDIMENSION col
;
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
);
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
];
149 METHODDEF(JDIMENSION
)
150 get_24bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
151 /* This version is for reading 24-bit pixels */
153 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
154 JSAMPARRAY image_ptr
;
155 register JSAMPROW inptr
, outptr
;
156 register JDIMENSION col
;
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
);
164 /* Transfer data. Note source values are in BGR order
165 * (even though Microsoft's own documents say the opposite).
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
++;
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.
186 METHODDEF(JDIMENSION
)
187 preload_image (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
189 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
190 register FILE *infile
= source
->pub
.input_file
;
192 register JSAMPROW out_ptr
;
193 JSAMPARRAY image_ptr
;
195 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
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
);
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
;
215 if (progress
!= NULL
)
216 progress
->completed_extra_passes
++;
218 /* Set up to read from the virtual array in top-to-bottom order */
219 switch (source
->bits_per_pixel
) {
221 source
->pub
.get_pixel_rows
= get_8bit_row
;
224 source
->pub
.get_pixel_rows
= get_24bit_row
;
227 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
229 source
->source_row
= cinfo
->image_height
;
231 /* And read the first row */
232 return (*source
->pub
.get_pixel_rows
) (cinfo
, sinfo
);
237 * Read the file header; return image size and component count.
241 start_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
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))
254 INT32 biWidth
= 0; /* initialize to avoid compiler warning */
256 unsigned int biPlanes
;
258 INT32 biXPelsPerMeter
,biYPelsPerMeter
;
260 int mapentrysize
= 0; /* 0 indicates no colormap */
262 JDIMENSION row_width
;
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 */
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.
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
);
283 switch ((int) headerSize
) {
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);
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
);
296 case 24: /* RGB image */
297 TRACEMS2(cinfo
, 1, JTRC_BMP_OS2
, (int) biWidth
, (int) biHeight
);
300 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
304 ERREXIT(cinfo
, JERR_BMP_BADPLANES
);
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 */
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
);
325 case 24: /* RGB image */
326 TRACEMS2(cinfo
, 1, JTRC_BMP
, (int) biWidth
, (int) biHeight
);
329 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
333 ERREXIT(cinfo
, JERR_BMP_BADPLANES
);
334 if (biCompression
!= 0)
335 ERREXIT(cinfo
, JERR_BMP_COMPRESSED
);
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 */
345 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
349 /* Compute distance to bitmap data --- will adjust for colormap below */
350 bPad
= bfOffBits
- (headerSize
+ 14);
352 /* Read the colormap, if any */
353 if (mapentrysize
> 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
;
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
);
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);
379 row_width
= (JDIMENSION
) biWidth
;
380 while ((row_width
& 3) != 0) row_width
++;
381 source
->row_width
= row_width
;
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 */
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;
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
;
408 * Finish up at the end of the file.
412 finish_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
419 * The module selection routine for BMP format input.
422 GLOBAL(cjpeg_source_ptr
)
423 jinit_read_bmp (j_compress_ptr cinfo
)
425 bmp_source_ptr source
;
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
;
436 return (cjpeg_source_ptr
) source
;
439 #endif /* BMP_SUPPORTED */