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