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