1 /* 2 * rdbmp.c 3 * 4 * Copyright (C) 1994-1996, Thomas G. Lane. 5 * Modified 2009-2019 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. 8 * 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-, 24-, and 32-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. 14 * 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). 21 * 22 * This code contributed by James Arthur Boucher. 23 */ 24 25 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ 26 27 #ifdef BMP_SUPPORTED 28 29 30 /* Macros to deal with unsigned chars as efficiently as compiler allows */ 31 32 #ifdef HAVE_UNSIGNED_CHAR 33 typedef unsigned char U_CHAR; 34 #define UCH(x) ((int) (x)) 35 #else /* !HAVE_UNSIGNED_CHAR */ 36 typedef char U_CHAR; 37 #ifdef CHAR_IS_UNSIGNED 38 #define UCH(x) ((int) (x)) 39 #else 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-, 24-, or 32-bit format */ 64 int cmap_length; /* colormap length */ 65 } bmp_source_struct; 66 67 68 LOCAL(int) 69 read_byte (bmp_source_ptr sinfo) 70 /* Read next byte from BMP file */ 71 { 72 register FILE *infile = sinfo->pub.input_file; 73 register int c; 74 75 if ((c = getc(infile)) == EOF) 76 ERREXIT(sinfo->cinfo, JERR_INPUT_EOF); 77 return c; 78 } 79 80 81 LOCAL(void) 82 read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize) 83 /* Read the colormap from a BMP file */ 84 { 85 int i; 86 87 switch (mapentrysize) { 88 case 3: 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); 94 } 95 break; 96 case 4: 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); 103 } 104 break; 105 default: 106 ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP); 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 JSAMPROW inptr, outptr; 124 register JSAMPARRAY colormap; 125 register JDIMENSION col; 126 register int t; 127 int cmaplen; 128 129 /* Fetch next row from virtual array */ 130 source->source_row--; 131 inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, 132 source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); 133 134 /* Expand the colormap indexes to real data */ 135 outptr = source->pub.buffer[0]; 136 colormap = source->colormap; 137 cmaplen = source->cmap_length; 138 for (col = cinfo->image_width; col > 0; col--) { 139 t = GETJSAMPLE(*inptr++); 140 if (t >= cmaplen) 141 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); 142 *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */ 143 *outptr++ = colormap[1][t]; 144 *outptr++ = colormap[2][t]; 145 } 146 147 return 1; 148 } 149 150 METHODDEF(JDIMENSION) 151 get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) 152 /* This version is for reading 24-bit pixels */ 153 { 154 bmp_source_ptr source = (bmp_source_ptr) sinfo; 155 register JSAMPROW inptr, outptr; 156 register JDIMENSION col; 157 158 /* Fetch next row from virtual array */ 159 source->source_row--; 160 inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, 161 source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); 162 163 /* Transfer data. Note source values are in BGR order 164 * (even though Microsoft's own documents say the opposite). 165 */ 166 outptr = source->pub.buffer[0]; 167 for (col = cinfo->image_width; col > 0; col--) { 168 outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ 169 outptr[1] = *inptr++; 170 outptr[0] = *inptr++; 171 outptr += 3; 172 } 173 174 return 1; 175 } 176 177 METHODDEF(JDIMENSION) 178 get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) 179 /* This version is for reading 32-bit pixels */ 180 { 181 bmp_source_ptr source = (bmp_source_ptr) sinfo; 182 register JSAMPROW inptr, outptr; 183 register JDIMENSION col; 184 185 /* Fetch next row from virtual array */ 186 source->source_row--; 187 inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, 188 source->whole_image, source->source_row, (JDIMENSION) 1, FALSE); 189 190 /* Transfer data. Note source values are in BGR order 191 * (even though Microsoft's own documents say the opposite). 192 */ 193 outptr = source->pub.buffer[0]; 194 for (col = cinfo->image_width; col > 0; col--) { 195 outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */ 196 outptr[1] = *inptr++; 197 outptr[0] = *inptr++; 198 inptr++; /* skip the 4th byte (Alpha channel) */ 199 outptr += 3; 200 } 201 202 return 1; 203 } 204 205 206 /* 207 * This method loads the image into whole_image during the first call on 208 * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call 209 * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls. 210 */ 211 212 METHODDEF(JDIMENSION) 213 preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) 214 { 215 bmp_source_ptr source = (bmp_source_ptr) sinfo; 216 register FILE *infile = source->pub.input_file; 217 register int c; 218 register JSAMPROW out_ptr; 219 JDIMENSION row, col; 220 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; 221 222 /* Read the data into a virtual array in input-file row order. */ 223 for (row = 0; row < cinfo->image_height; row++) { 224 if (progress != NULL) { 225 progress->pub.pass_counter = (long) row; 226 progress->pub.pass_limit = (long) cinfo->image_height; 227 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo); 228 } 229 out_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo, 230 source->whole_image, row, (JDIMENSION) 1, TRUE); 231 for (col = source->row_width; col > 0; col--) { 232 /* inline copy of read_byte() for speed */ 233 if ((c = getc(infile)) == EOF) 234 ERREXIT(cinfo, JERR_INPUT_EOF); 235 *out_ptr++ = (JSAMPLE) c; 236 } 237 } 238 if (progress != NULL) 239 progress->completed_extra_passes++; 240 241 /* Set up to read from the virtual array in top-to-bottom order */ 242 switch (source->bits_per_pixel) { 243 case 8: 244 source->pub.get_pixel_rows = get_8bit_row; 245 break; 246 case 24: 247 source->pub.get_pixel_rows = get_24bit_row; 248 break; 249 case 32: 250 source->pub.get_pixel_rows = get_32bit_row; 251 break; 252 default: 253 ERREXIT(cinfo, JERR_BMP_BADDEPTH); 254 } 255 source->source_row = cinfo->image_height; 256 257 /* And read the first row */ 258 return (*source->pub.get_pixel_rows) (cinfo, sinfo); 259 } 260 261 262 /* 263 * Read the file header; return image size and component count. 264 */ 265 266 METHODDEF(void) 267 start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) 268 { 269 bmp_source_ptr source = (bmp_source_ptr) sinfo; 270 U_CHAR bmpfileheader[14]; 271 U_CHAR bmpinfoheader[64]; 272 #define GET_2B(array, offset) ((unsigned int) UCH(array[offset]) + \ 273 (((unsigned int) UCH(array[offset+1])) << 8)) 274 #define GET_4B(array, offset) ((INT32) UCH(array[offset]) + \ 275 (((INT32) UCH(array[offset+1])) << 8) + \ 276 (((INT32) UCH(array[offset+2])) << 16) + \ 277 (((INT32) UCH(array[offset+3])) << 24)) 278 INT32 bfOffBits; 279 INT32 headerSize; 280 INT32 biWidth; 281 INT32 biHeight; 282 unsigned int biPlanes; 283 INT32 biCompression; 284 INT32 biXPelsPerMeter,biYPelsPerMeter; 285 INT32 biClrUsed = 0; 286 int mapentrysize = 0; /* 0 indicates no colormap */ 287 INT32 bPad; 288 JDIMENSION row_width; 289 290 /* Read and verify the bitmap file header */ 291 if (! ReadOK(source->pub.input_file, bmpfileheader, 14)) 292 ERREXIT(cinfo, JERR_INPUT_EOF); 293 if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */ 294 ERREXIT(cinfo, JERR_BMP_NOT); 295 bfOffBits = GET_4B(bmpfileheader, 10); 296 /* We ignore the remaining fileheader fields */ 297 298 /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows), 299 * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which. 300 */ 301 if (! ReadOK(source->pub.input_file, bmpinfoheader, 4)) 302 ERREXIT(cinfo, JERR_INPUT_EOF); 303 headerSize = GET_4B(bmpinfoheader, 0); 304 if (headerSize < 12 || headerSize > 64) 305 ERREXIT(cinfo, JERR_BMP_BADHEADER); 306 if (! ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4)) 307 ERREXIT(cinfo, JERR_INPUT_EOF); 308 309 switch ((int) headerSize) { 310 case 12: 311 /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */ 312 biWidth = (INT32) GET_2B(bmpinfoheader, 4); 313 biHeight = (INT32) GET_2B(bmpinfoheader, 6); 314 biPlanes = GET_2B(bmpinfoheader, 8); 315 source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 10); 316 317 switch (source->bits_per_pixel) { 318 case 8: /* colormapped image */ 319 mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */ 320 TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight); 321 break; 322 case 24: /* RGB image */ 323 case 32: /* RGB image + Alpha channel */ 324 TRACEMS3(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight, 325 source->bits_per_pixel); 326 break; 327 default: 328 ERREXIT(cinfo, JERR_BMP_BADDEPTH); 329 } 330 break; 331 case 40: 332 case 64: 333 /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */ 334 /* or OS/2 2.x header, which has additional fields that we ignore */ 335 biWidth = GET_4B(bmpinfoheader, 4); 336 biHeight = GET_4B(bmpinfoheader, 8); 337 biPlanes = GET_2B(bmpinfoheader, 12); 338 source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 14); 339 biCompression = GET_4B(bmpinfoheader, 16); 340 biXPelsPerMeter = GET_4B(bmpinfoheader, 24); 341 biYPelsPerMeter = GET_4B(bmpinfoheader, 28); 342 biClrUsed = GET_4B(bmpinfoheader, 32); 343 /* biSizeImage, biClrImportant fields are ignored */ 344 345 switch (source->bits_per_pixel) { 346 case 8: /* colormapped image */ 347 mapentrysize = 4; /* Windows uses RGBQUAD colormap */ 348 TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight); 349 break; 350 case 24: /* RGB image */ 351 case 32: /* RGB image + Alpha channel */ 352 TRACEMS3(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight, 353 source->bits_per_pixel); 354 break; 355 default: 356 ERREXIT(cinfo, JERR_BMP_BADDEPTH); 357 } 358 if (biCompression != 0) 359 ERREXIT(cinfo, JERR_BMP_COMPRESSED); 360 361 if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) { 362 /* Set JFIF density parameters from the BMP data */ 363 cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */ 364 cinfo->Y_density = (UINT16) (biYPelsPerMeter/100); 365 cinfo->density_unit = 2; /* dots/cm */ 366 } 367 break; 368 default: 369 ERREXIT(cinfo, JERR_BMP_BADHEADER); 370 return; /* avoid compiler warnings for uninitialized variables */ 371 } 372 373 if (biPlanes != 1) 374 ERREXIT(cinfo, JERR_BMP_BADPLANES); 375 /* Sanity check for buffer allocation below */ 376 if (biWidth <= 0 || biHeight <= 0 || (biWidth >> 24) || (biHeight >> 24)) 377 ERREXIT(cinfo, JERR_BMP_OUTOFRANGE); 378 379 /* Compute distance to bitmap data --- will adjust for colormap below */ 380 bPad = bfOffBits - (headerSize + 14); 381 382 /* Read the colormap, if any */ 383 if (mapentrysize > 0) { 384 if (biClrUsed <= 0) 385 biClrUsed = 256; /* assume it's 256 */ 386 else if (biClrUsed > 256) 387 ERREXIT(cinfo, JERR_BMP_BADCMAP); 388 /* Allocate space to store the colormap */ 389 source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, 390 JPOOL_IMAGE, (JDIMENSION) biClrUsed, (JDIMENSION) 3); 391 source->cmap_length = (int) biClrUsed; 392 /* and read it from the file */ 393 read_colormap(source, (int) biClrUsed, mapentrysize); 394 /* account for size of colormap */ 395 bPad -= biClrUsed * mapentrysize; 396 } 397 398 /* Skip any remaining pad bytes */ 399 if (bPad < 0) /* incorrect bfOffBits value? */ 400 ERREXIT(cinfo, JERR_BMP_BADHEADER); 401 while (--bPad >= 0) { 402 (void) read_byte(source); 403 } 404 405 /* Compute row width in file, including padding to 4-byte boundary */ 406 if (source->bits_per_pixel == 24) 407 row_width = (JDIMENSION) (biWidth * 3); 408 else if (source->bits_per_pixel == 32) 409 row_width = (JDIMENSION) (biWidth * 4); 410 else 411 row_width = (JDIMENSION) biWidth; 412 while ((row_width & 3) != 0) row_width++; 413 source->row_width = row_width; 414 415 /* Allocate space for inversion array, prepare for preload pass */ 416 source->whole_image = (*cinfo->mem->request_virt_sarray) 417 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, 418 row_width, (JDIMENSION) biHeight, (JDIMENSION) 1); 419 source->pub.get_pixel_rows = preload_image; 420 if (cinfo->progress != NULL) { 421 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress; 422 progress->total_extra_passes++; /* count file input as separate pass */ 423 } 424 425 /* Allocate one-row buffer for returned data */ 426 source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, 427 JPOOL_IMAGE, (JDIMENSION) (biWidth * 3), (JDIMENSION) 1); 428 source->pub.buffer_height = 1; 429 430 cinfo->in_color_space = JCS_RGB; 431 cinfo->input_components = 3; 432 cinfo->data_precision = 8; 433 cinfo->image_width = (JDIMENSION) biWidth; 434 cinfo->image_height = (JDIMENSION) biHeight; 435 } 436 437 438 /* 439 * Finish up at the end of the file. 440 */ 441 442 METHODDEF(void) 443 finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo) 444 { 445 /* no work */ 446 } 447 448 449 /* 450 * The module selection routine for BMP format input. 451 */ 452 453 GLOBAL(cjpeg_source_ptr) 454 jinit_read_bmp (j_compress_ptr cinfo) 455 { 456 bmp_source_ptr source; 457 458 /* Create module interface object */ 459 source = (bmp_source_ptr) (*cinfo->mem->alloc_small) 460 ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_source_struct)); 461 source->cinfo = cinfo; /* make back link for subroutines */ 462 /* Fill in method ptrs, except get_pixel_rows which start_input sets */ 463 source->pub.start_input = start_input_bmp; 464 source->pub.finish_input = finish_input_bmp; 465 466 return &source->pub; 467 } 468 469 #endif /* BMP_SUPPORTED */ 470