8 * Copyright (C) 1994-1996, Thomas G. Lane.
9 * This file is part of the Independent JPEG Group's software.
10 * For conditions of distribution and use, see the accompanying README file.
12 * This file contains routines to read input images in Microsoft "BMP"
13 * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
14 * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
15 * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
16 * Also, we don't support RLE-compressed files.
18 * These routines may need modification for non-Unix environments or
19 * specialized applications. As they stand, they assume input from
20 * an ordinary stdio stream. They further assume that reading begins
21 * at the start of the file; start_input may need work if the
22 * user interface has already read some data (e.g., to determine that
23 * the file is indeed BMP format).
25 * This code contributed by James Arthur Boucher.
28 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
33 /* Macros to deal with unsigned chars as efficiently as compiler allows */
35 #ifdef HAVE_UNSIGNED_CHAR
36 typedef unsigned char U_CHAR
;
37 #define UCH(x) ((int) (x))
38 #else /* !HAVE_UNSIGNED_CHAR */
39 #ifdef CHAR_IS_UNSIGNED
41 #define UCH(x) ((int) (x))
44 #define UCH(x) ((int) (x) & 0xFF)
46 #endif /* HAVE_UNSIGNED_CHAR */
49 #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
52 /* Private version of data source object */
54 typedef struct _bmp_source_struct
* bmp_source_ptr
;
56 typedef struct _bmp_source_struct
{
57 struct cjpeg_source_struct pub
; /* public fields */
59 j_compress_ptr cinfo
; /* back link saves passing separate parm */
61 JSAMPARRAY colormap
; /* BMP colormap (converted to my format) */
63 jvirt_sarray_ptr whole_image
; /* Needed to reverse row order */
64 JDIMENSION source_row
; /* Current source row number */
65 JDIMENSION row_width
; /* Physical width of scanlines in file */
67 int bits_per_pixel
; /* remembers 8- or 24-bit format */
72 read_byte (bmp_source_ptr sinfo
)
73 /* Read next byte from BMP file */
75 register FILE *infile
= sinfo
->pub
.input_file
;
78 if ((c
= getc(infile
)) == EOF
)
79 ERREXIT(sinfo
->cinfo
, JERR_INPUT_EOF
);
85 read_colormap (bmp_source_ptr sinfo
, int cmaplen
, int mapentrysize
)
86 /* Read the colormap from a BMP file */
90 switch (mapentrysize
) {
92 /* BGR format (occurs in OS/2 files) */
93 for (i
= 0; i
< cmaplen
; i
++) {
94 sinfo
->colormap
[2][i
] = (JSAMPLE
) read_byte(sinfo
);
95 sinfo
->colormap
[1][i
] = (JSAMPLE
) read_byte(sinfo
);
96 sinfo
->colormap
[0][i
] = (JSAMPLE
) read_byte(sinfo
);
100 /* BGR0 format (occurs in MS Windows files) */
101 for (i
= 0; i
< cmaplen
; i
++) {
102 sinfo
->colormap
[2][i
] = (JSAMPLE
) read_byte(sinfo
);
103 sinfo
->colormap
[1][i
] = (JSAMPLE
) read_byte(sinfo
);
104 sinfo
->colormap
[0][i
] = (JSAMPLE
) read_byte(sinfo
);
105 (void) read_byte(sinfo
);
109 ERREXIT(sinfo
->cinfo
, JERR_BMP_BADCMAP
);
116 * Read one row of pixels.
117 * The image has been read into the whole_image array, but is otherwise
118 * unprocessed. We must read it out in top-to-bottom row order, and if
119 * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
122 METHODDEF(JDIMENSION
)
123 get_8bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
124 /* This version is for reading 8-bit colormap indexes */
126 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
127 register JSAMPARRAY colormap
= source
->colormap
;
128 JSAMPARRAY image_ptr
;
130 register JSAMPROW inptr
, outptr
;
131 register JDIMENSION col
;
133 /* Fetch next row from virtual array */
134 source
->source_row
--;
135 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
136 ((j_common_ptr
) cinfo
, source
->whole_image
,
137 source
->source_row
, (JDIMENSION
) 1, FALSE
);
139 /* Expand the colormap indexes to real data */
140 inptr
= image_ptr
[0];
141 outptr
= source
->pub
.buffer
[0];
142 for (col
= cinfo
->image_width
; col
> 0; col
--) {
143 t
= GETJSAMPLE(*inptr
++);
144 *outptr
++ = colormap
[0][t
]; /* can omit GETJSAMPLE() safely */
145 *outptr
++ = colormap
[1][t
];
146 *outptr
++ = colormap
[2][t
];
153 METHODDEF(JDIMENSION
)
154 get_24bit_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
155 /* This version is for reading 24-bit pixels */
157 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
158 JSAMPARRAY image_ptr
;
159 register JSAMPROW inptr
, outptr
;
160 register JDIMENSION col
;
162 /* Fetch next row from virtual array */
163 source
->source_row
--;
164 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
165 ((j_common_ptr
) cinfo
, source
->whole_image
,
166 source
->source_row
, (JDIMENSION
) 1, FALSE
);
168 /* Transfer data. Note source values are in BGR order
169 * (even though Microsoft's own documents say the opposite).
171 inptr
= image_ptr
[0];
172 outptr
= source
->pub
.buffer
[0];
173 for (col
= cinfo
->image_width
; col
> 0; col
--) {
174 outptr
[2] = *inptr
++; /* can omit GETJSAMPLE() safely */
175 outptr
[1] = *inptr
++;
176 outptr
[0] = *inptr
++;
185 * This method loads the image into whole_image during the first call on
186 * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
187 * get_8bit_row or get_24bit_row on subsequent calls.
190 METHODDEF(JDIMENSION
)
191 preload_image (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
193 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
194 register FILE *infile
= source
->pub
.input_file
;
196 register JSAMPROW out_ptr
;
197 JSAMPARRAY image_ptr
;
199 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
201 /* Read the data into a virtual array in input-file row order. */
202 for (row
= 0; row
< cinfo
->image_height
; row
++) {
203 if (progress
!= NULL
) {
204 progress
->pub
.pass_counter
= (long) row
;
205 progress
->pub
.pass_limit
= (long) cinfo
->image_height
;
206 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
208 image_ptr
= (*cinfo
->mem
->access_virt_sarray
)
209 ((j_common_ptr
) cinfo
, source
->whole_image
,
210 row
, (JDIMENSION
) 1, TRUE
);
211 out_ptr
= image_ptr
[0];
212 for (col
= source
->row_width
; col
> 0; col
--) {
213 /* inline copy of read_byte() for speed */
214 if ((c
= getc(infile
)) == EOF
)
215 ERREXIT(cinfo
, JERR_INPUT_EOF
);
216 *out_ptr
++ = (JSAMPLE
) c
;
219 if (progress
!= NULL
)
220 progress
->completed_extra_passes
++;
222 /* Set up to read from the virtual array in top-to-bottom order */
223 switch (source
->bits_per_pixel
) {
225 source
->pub
.get_pixel_rows
= get_8bit_row
;
228 source
->pub
.get_pixel_rows
= get_24bit_row
;
231 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
233 source
->source_row
= cinfo
->image_height
;
235 /* And read the first row */
236 return (*source
->pub
.get_pixel_rows
) (cinfo
, sinfo
);
241 * Read the file header; return image size and component count.
245 start_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
247 bmp_source_ptr source
= (bmp_source_ptr
) sinfo
;
248 U_CHAR bmpfileheader
[14];
249 U_CHAR bmpinfoheader
[64];
250 #define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \
251 (((unsigned int) UCH(array[offset+1])) << 8))
252 #define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \
253 (((INT32) UCH(array[offset+1])) << 8) + \
254 (((INT32) UCH(array[offset+2])) << 16) + \
255 (((INT32) UCH(array[offset+3])) << 24))
258 INT32 biWidth
= 0; /* initialize to avoid compiler warning */
260 unsigned int biPlanes
;
262 INT32 biXPelsPerMeter
,biYPelsPerMeter
;
264 int mapentrysize
= 0; /* 0 indicates no colormap */
266 JDIMENSION row_width
;
268 /* Read and verify the bitmap file header */
269 if (! ReadOK(source
->pub
.input_file
, bmpfileheader
, 14))
270 ERREXIT(cinfo
, JERR_INPUT_EOF
);
271 if (GET_2B(bmpfileheader
,0) != 0x4D42) /* 'BM' */
272 ERREXIT(cinfo
, JERR_BMP_NOT
);
273 bfOffBits
= (INT32
) GET_4B(bmpfileheader
,10);
274 /* We ignore the remaining fileheader fields */
276 /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
277 * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
279 if (! ReadOK(source
->pub
.input_file
, bmpinfoheader
, 4))
280 ERREXIT(cinfo
, JERR_INPUT_EOF
);
281 headerSize
= (INT32
) GET_4B(bmpinfoheader
,0);
282 if (headerSize
< 12 || headerSize
> 64)
283 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
284 if (! ReadOK(source
->pub
.input_file
, bmpinfoheader
+4, headerSize
-4))
285 ERREXIT(cinfo
, JERR_INPUT_EOF
);
287 switch ((int) headerSize
) {
289 /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
290 biWidth
= (INT32
) GET_2B(bmpinfoheader
,4);
291 biHeight
= (INT32
) GET_2B(bmpinfoheader
,6);
292 biPlanes
= GET_2B(bmpinfoheader
,8);
293 source
->bits_per_pixel
= (int) GET_2B(bmpinfoheader
,10);
295 switch (source
->bits_per_pixel
) {
296 case 8: /* colormapped image */
297 mapentrysize
= 3; /* OS/2 uses RGBTRIPLE colormap */
298 TRACEMS2(cinfo
, 1, JTRC_BMP_OS2_MAPPED
, (int) biWidth
, (int) biHeight
);
300 case 24: /* RGB image */
301 TRACEMS2(cinfo
, 1, JTRC_BMP_OS2
, (int) biWidth
, (int) biHeight
);
304 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
308 ERREXIT(cinfo
, JERR_BMP_BADPLANES
);
312 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
313 /* or OS/2 2.x header, which has additional fields that we ignore */
314 biWidth
= GET_4B(bmpinfoheader
,4);
315 biHeight
= GET_4B(bmpinfoheader
,8);
316 biPlanes
= GET_2B(bmpinfoheader
,12);
317 source
->bits_per_pixel
= (int) GET_2B(bmpinfoheader
,14);
318 biCompression
= GET_4B(bmpinfoheader
,16);
319 biXPelsPerMeter
= GET_4B(bmpinfoheader
,24);
320 biYPelsPerMeter
= GET_4B(bmpinfoheader
,28);
321 biClrUsed
= GET_4B(bmpinfoheader
,32);
322 /* biSizeImage, biClrImportant fields are ignored */
324 switch (source
->bits_per_pixel
) {
325 case 8: /* colormapped image */
326 mapentrysize
= 4; /* Windows uses RGBQUAD colormap */
327 TRACEMS2(cinfo
, 1, JTRC_BMP_MAPPED
, (int) biWidth
, (int) biHeight
);
329 case 24: /* RGB image */
330 TRACEMS2(cinfo
, 1, JTRC_BMP
, (int) biWidth
, (int) biHeight
);
333 ERREXIT(cinfo
, JERR_BMP_BADDEPTH
);
337 ERREXIT(cinfo
, JERR_BMP_BADPLANES
);
338 if (biCompression
!= 0)
339 ERREXIT(cinfo
, JERR_BMP_COMPRESSED
);
341 if (biXPelsPerMeter
> 0 && biYPelsPerMeter
> 0) {
342 /* Set JFIF density parameters from the BMP data */
343 cinfo
->X_density
= (UINT16
) (biXPelsPerMeter
/100); /* 100 cm per meter */
344 cinfo
->Y_density
= (UINT16
) (biYPelsPerMeter
/100);
345 cinfo
->density_unit
= 2; /* dots/cm */
349 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
353 /* Compute distance to bitmap data --- will adjust for colormap below */
354 bPad
= bfOffBits
- (headerSize
+ 14);
356 /* Read the colormap, if any */
357 if (mapentrysize
> 0) {
359 biClrUsed
= 256; /* assume it's 256 */
360 else if (biClrUsed
> 256)
361 ERREXIT(cinfo
, JERR_BMP_BADCMAP
);
362 /* Allocate space to store the colormap */
363 source
->colormap
= (*cinfo
->mem
->alloc_sarray
)
364 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
365 (JDIMENSION
) biClrUsed
, (JDIMENSION
) 3);
366 /* and read it from the file */
367 read_colormap(source
, (int) biClrUsed
, mapentrysize
);
368 /* account for size of colormap */
369 bPad
-= biClrUsed
* mapentrysize
;
372 /* Skip any remaining pad bytes */
373 if (bPad
< 0) /* incorrect bfOffBits value? */
374 ERREXIT(cinfo
, JERR_BMP_BADHEADER
);
375 while (--bPad
>= 0) {
376 (void) read_byte(source
);
379 /* Compute row width in file, including padding to 4-byte boundary */
380 if (source
->bits_per_pixel
== 24)
381 row_width
= (JDIMENSION
) (biWidth
* 3);
383 row_width
= (JDIMENSION
) biWidth
;
384 while ((row_width
& 3) != 0) row_width
++;
385 source
->row_width
= row_width
;
387 /* Allocate space for inversion array, prepare for preload pass */
388 source
->whole_image
= (*cinfo
->mem
->request_virt_sarray
)
389 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
390 row_width
, (JDIMENSION
) biHeight
, (JDIMENSION
) 1);
391 source
->pub
.get_pixel_rows
= preload_image
;
392 if (cinfo
->progress
!= NULL
) {
393 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
394 progress
->total_extra_passes
++; /* count file input as separate pass */
397 /* Allocate one-row buffer for returned data */
398 source
->pub
.buffer
= (*cinfo
->mem
->alloc_sarray
)
399 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
400 (JDIMENSION
) (biWidth
* 3), (JDIMENSION
) 1);
401 source
->pub
.buffer_height
= 1;
403 cinfo
->in_color_space
= JCS_RGB
;
404 cinfo
->input_components
= 3;
405 cinfo
->data_precision
= 8;
406 cinfo
->image_width
= (JDIMENSION
) biWidth
;
407 cinfo
->image_height
= (JDIMENSION
) biHeight
;
412 * Finish up at the end of the file.
416 finish_input_bmp (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
423 * The module selection routine for BMP format input.
426 JGLOBAL(cjpeg_source_ptr
)
427 jinit_read_bmp (j_compress_ptr cinfo
)
429 bmp_source_ptr source
;
431 /* Create module interface object */
432 source
= (bmp_source_ptr
)
433 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
434 SIZEOF(bmp_source_struct
));
435 source
->cinfo
= cinfo
; /* make back link for subroutines */
436 /* Fill in method ptrs, except get_pixel_rows which start_input sets */
437 source
->pub
.start_input
= start_input_bmp
;
438 source
->pub
.finish_input
= finish_input_bmp
;
440 return (cjpeg_source_ptr
) source
;
443 #endif /* BMP_SUPPORTED */