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