wrbmp.c
上传用户:wuyixingx
上传日期:2007-01-08
资源大小:745k
文件大小:14k
源码类别:

图形图象

开发平台:

C/C++

  1. /*
  2.  * wrbmp.c
  3.  *
  4.  * Copyright (C) 1994-1996, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains routines to write output images in Microsoft "BMP"
  9.  * format (MS Windows 3.x and OS/2 1.x flavors).
  10.  * Either 8-bit colormapped or 24-bit full-color format can be written.
  11.  * No compression is supported.
  12.  *
  13.  * These routines may need modification for non-Unix environments or
  14.  * specialized applications.  As they stand, they assume output to
  15.  * an ordinary stdio stream.
  16.  *
  17.  * This code contributed by James Arthur Boucher.
  18.  */
  19. #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
  20. #ifdef BMP_SUPPORTED
  21. /*
  22.  * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
  23.  * This is not yet implemented.
  24.  */
  25. #if BITS_IN_JSAMPLE != 8
  26.   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
  27. #endif
  28. /*
  29.  * Since BMP stores scanlines bottom-to-top, we have to invert the image
  30.  * from JPEG's top-to-bottom order.  To do this, we save the outgoing data
  31.  * in a virtual array during put_pixel_row calls, then actually emit the
  32.  * BMP file during finish_output.  The virtual array contains one JSAMPLE per
  33.  * pixel if the output is grayscale or colormapped, three if it is full color.
  34.  */
  35. /* Private version of data destination object */
  36. typedef struct {
  37.   struct djpeg_dest_struct pub; /* public fields */
  38.   boolean is_os2; /* saves the OS2 format request flag */
  39.   jvirt_sarray_ptr whole_image; /* needed to reverse row order */
  40.   JDIMENSION data_width; /* JSAMPLEs per row */
  41.   JDIMENSION row_width; /* physical width of one row in the BMP file */
  42.   int pad_bytes; /* number of padding bytes needed per row */
  43.   JDIMENSION cur_output_row; /* next row# to write to virtual array */
  44. } bmp_dest_struct;
  45. typedef bmp_dest_struct * bmp_dest_ptr;
  46. /* Forward declarations */
  47. LOCAL(void) write_colormap
  48. JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
  49.      int map_colors, int map_entry_size));
  50. /*
  51.  * Write some pixel data.
  52.  * In this module rows_supplied will always be 1.
  53.  */
  54. METHODDEF(void)
  55. put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  56. JDIMENSION rows_supplied)
  57. /* This version is for writing 24-bit pixels */
  58. {
  59.   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  60.   JSAMPARRAY image_ptr;
  61.   register JSAMPROW inptr, outptr;
  62.   register JDIMENSION col;
  63.   int pad;
  64.   /* Access next row in virtual array */
  65.   image_ptr = (*cinfo->mem->access_virt_sarray)
  66.     ((j_common_ptr) cinfo, dest->whole_image,
  67.      dest->cur_output_row, (JDIMENSION) 1, TRUE);
  68.   dest->cur_output_row++;
  69.   /* Transfer data.  Note destination values must be in BGR order
  70.    * (even though Microsoft's own documents say the opposite).
  71.    */
  72.   inptr = dest->pub.buffer[0];
  73.   outptr = image_ptr[0];
  74.   for (col = cinfo->output_width; col > 0; col--) {
  75.     outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
  76.     outptr[1] = *inptr++;
  77.     outptr[0] = *inptr++;
  78.     outptr += 3;
  79.   }
  80.   /* Zero out the pad bytes. */
  81.   pad = dest->pad_bytes;
  82.   while (--pad >= 0)
  83.     *outptr++ = 0;
  84. }
  85. METHODDEF(void)
  86. put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
  87.        JDIMENSION rows_supplied)
  88. /* This version is for grayscale OR quantized color output */
  89. {
  90.   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  91.   JSAMPARRAY image_ptr;
  92.   register JSAMPROW inptr, outptr;
  93.   register JDIMENSION col;
  94.   int pad;
  95.   /* Access next row in virtual array */
  96.   image_ptr = (*cinfo->mem->access_virt_sarray)
  97.     ((j_common_ptr) cinfo, dest->whole_image,
  98.      dest->cur_output_row, (JDIMENSION) 1, TRUE);
  99.   dest->cur_output_row++;
  100.   /* Transfer data. */
  101.   inptr = dest->pub.buffer[0];
  102.   outptr = image_ptr[0];
  103.   for (col = cinfo->output_width; col > 0; col--) {
  104.     *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
  105.   }
  106.   /* Zero out the pad bytes. */
  107.   pad = dest->pad_bytes;
  108.   while (--pad >= 0)
  109.     *outptr++ = 0;
  110. }
  111. /*
  112.  * Startup: normally writes the file header.
  113.  * In this module we may as well postpone everything until finish_output.
  114.  */
  115. METHODDEF(void)
  116. start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  117. {
  118.   /* no work here */
  119. }
  120. /*
  121.  * Finish up at the end of the file.
  122.  *
  123.  * Here is where we really output the BMP file.
  124.  *
  125.  * First, routines to write the Windows and OS/2 variants of the file header.
  126.  */
  127. LOCAL(void)
  128. write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
  129. /* Write a Windows-style BMP file header, including colormap if needed */
  130. {
  131.   char bmpfileheader[14];
  132.   char bmpinfoheader[40];
  133. #define PUT_2B(array,offset,value)  
  134. (array[offset] = (char) ((value) & 0xFF), 
  135.  array[offset+1] = (char) (((value) >> 8) & 0xFF))
  136. #define PUT_4B(array,offset,value)  
  137. (array[offset] = (char) ((value) & 0xFF), 
  138.  array[offset+1] = (char) (((value) >> 8) & 0xFF), 
  139.  array[offset+2] = (char) (((value) >> 16) & 0xFF), 
  140.  array[offset+3] = (char) (((value) >> 24) & 0xFF))
  141.   INT32 headersize, bfSize;
  142.   int bits_per_pixel, cmap_entries;
  143.   /* Compute colormap size and total file size */
  144.   if (cinfo->out_color_space == JCS_RGB) {
  145.     if (cinfo->quantize_colors) {
  146.       /* Colormapped RGB */
  147.       bits_per_pixel = 8;
  148.       cmap_entries = 256;
  149.     } else {
  150.       /* Unquantized, full color RGB */
  151.       bits_per_pixel = 24;
  152.       cmap_entries = 0;
  153.     }
  154.   } else {
  155.     /* Grayscale output.  We need to fake a 256-entry colormap. */
  156.     bits_per_pixel = 8;
  157.     cmap_entries = 256;
  158.   }
  159.   /* File size */
  160.   headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
  161.   bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
  162.   
  163.   /* Set unused fields of header to 0 */
  164.   MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
  165.   MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
  166.   /* Fill the file header */
  167.   bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
  168.   bmpfileheader[1] = 0x4D;
  169.   PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
  170.   /* we leave bfReserved1 & bfReserved2 = 0 */
  171.   PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
  172.   /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
  173.   PUT_2B(bmpinfoheader, 0, 40); /* biSize */
  174.   PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
  175.   PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
  176.   PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
  177.   PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
  178.   /* we leave biCompression = 0, for none */
  179.   /* we leave biSizeImage = 0; this is correct for uncompressed data */
  180.   if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
  181.     PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
  182.     PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
  183.   }
  184.   PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
  185.   /* we leave biClrImportant = 0 */
  186.   if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
  187.     ERREXIT(cinfo, JERR_FILE_WRITE);
  188.   if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
  189.     ERREXIT(cinfo, JERR_FILE_WRITE);
  190.   if (cmap_entries > 0)
  191.     write_colormap(cinfo, dest, cmap_entries, 4);
  192. }
  193. LOCAL(void)
  194. write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
  195. /* Write an OS2-style BMP file header, including colormap if needed */
  196. {
  197.   char bmpfileheader[14];
  198.   char bmpcoreheader[12];
  199.   INT32 headersize, bfSize;
  200.   int bits_per_pixel, cmap_entries;
  201.   /* Compute colormap size and total file size */
  202.   if (cinfo->out_color_space == JCS_RGB) {
  203.     if (cinfo->quantize_colors) {
  204.       /* Colormapped RGB */
  205.       bits_per_pixel = 8;
  206.       cmap_entries = 256;
  207.     } else {
  208.       /* Unquantized, full color RGB */
  209.       bits_per_pixel = 24;
  210.       cmap_entries = 0;
  211.     }
  212.   } else {
  213.     /* Grayscale output.  We need to fake a 256-entry colormap. */
  214.     bits_per_pixel = 8;
  215.     cmap_entries = 256;
  216.   }
  217.   /* File size */
  218.   headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
  219.   bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
  220.   
  221.   /* Set unused fields of header to 0 */
  222.   MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
  223.   MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
  224.   /* Fill the file header */
  225.   bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
  226.   bmpfileheader[1] = 0x4D;
  227.   PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
  228.   /* we leave bfReserved1 & bfReserved2 = 0 */
  229.   PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
  230.   /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
  231.   PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
  232.   PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
  233.   PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
  234.   PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
  235.   PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
  236.   if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
  237.     ERREXIT(cinfo, JERR_FILE_WRITE);
  238.   if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
  239.     ERREXIT(cinfo, JERR_FILE_WRITE);
  240.   if (cmap_entries > 0)
  241.     write_colormap(cinfo, dest, cmap_entries, 3);
  242. }
  243. /*
  244.  * Write the colormap.
  245.  * Windows uses BGR0 map entries; OS/2 uses BGR entries.
  246.  */
  247. LOCAL(void)
  248. write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
  249. int map_colors, int map_entry_size)
  250. {
  251.   JSAMPARRAY colormap = cinfo->colormap;
  252.   int num_colors = cinfo->actual_number_of_colors;
  253.   FILE * outfile = dest->pub.output_file;
  254.   int i;
  255.   if (colormap != NULL) {
  256.     if (cinfo->out_color_components == 3) {
  257.       /* Normal case with RGB colormap */
  258.       for (i = 0; i < num_colors; i++) {
  259. putc(GETJSAMPLE(colormap[2][i]), outfile);
  260. putc(GETJSAMPLE(colormap[1][i]), outfile);
  261. putc(GETJSAMPLE(colormap[0][i]), outfile);
  262. if (map_entry_size == 4)
  263.   putc(0, outfile);
  264.       }
  265.     } else {
  266.       /* Grayscale colormap (only happens with grayscale quantization) */
  267.       for (i = 0; i < num_colors; i++) {
  268. putc(GETJSAMPLE(colormap[0][i]), outfile);
  269. putc(GETJSAMPLE(colormap[0][i]), outfile);
  270. putc(GETJSAMPLE(colormap[0][i]), outfile);
  271. if (map_entry_size == 4)
  272.   putc(0, outfile);
  273.       }
  274.     }
  275.   } else {
  276.     /* If no colormap, must be grayscale data.  Generate a linear "map". */
  277.     for (i = 0; i < 256; i++) {
  278.       putc(i, outfile);
  279.       putc(i, outfile);
  280.       putc(i, outfile);
  281.       if (map_entry_size == 4)
  282. putc(0, outfile);
  283.     }
  284.   }
  285.   /* Pad colormap with zeros to ensure specified number of colormap entries */ 
  286.   if (i > map_colors)
  287.     ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
  288.   for (; i < map_colors; i++) {
  289.     putc(0, outfile);
  290.     putc(0, outfile);
  291.     putc(0, outfile);
  292.     if (map_entry_size == 4)
  293.       putc(0, outfile);
  294.   }
  295. }
  296. METHODDEF(void)
  297. finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  298. {
  299.   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
  300.   register FILE * outfile = dest->pub.output_file;
  301.   JSAMPARRAY image_ptr;
  302.   register JSAMPROW data_ptr;
  303.   JDIMENSION row;
  304.   register JDIMENSION col;
  305.   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  306.   /* Write the header and colormap */
  307.   if (dest->is_os2)
  308.     write_os2_header(cinfo, dest);
  309.   else
  310.     write_bmp_header(cinfo, dest);
  311.   /* Write the file body from our virtual array */
  312.   for (row = cinfo->output_height; row > 0; row--) {
  313.     if (progress != NULL) {
  314.       progress->pub.pass_counter = (long) (cinfo->output_height - row);
  315.       progress->pub.pass_limit = (long) cinfo->output_height;
  316.       (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
  317.     }
  318.     image_ptr = (*cinfo->mem->access_virt_sarray)
  319.       ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
  320.     data_ptr = image_ptr[0];
  321.     for (col = dest->row_width; col > 0; col--) {
  322.       putc(GETJSAMPLE(*data_ptr), outfile);
  323.       data_ptr++;
  324.     }
  325.   }
  326.   if (progress != NULL)
  327.     progress->completed_extra_passes++;
  328.   /* Make sure we wrote the output file OK */
  329.   fflush(outfile);
  330.   if (ferror(outfile))
  331.     ERREXIT(cinfo, JERR_FILE_WRITE);
  332. }
  333. /*
  334.  * The module selection routine for BMP format output.
  335.  */
  336. GLOBAL(djpeg_dest_ptr)
  337. jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
  338. {
  339.   bmp_dest_ptr dest;
  340.   JDIMENSION row_width;
  341.   /* Create module interface object, fill in method pointers */
  342.   dest = (bmp_dest_ptr)
  343.       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  344.   SIZEOF(bmp_dest_struct));
  345.   dest->pub.start_output = start_output_bmp;
  346.   dest->pub.finish_output = finish_output_bmp;
  347.   dest->is_os2 = is_os2;
  348.   if (cinfo->out_color_space == JCS_GRAYSCALE) {
  349.     dest->pub.put_pixel_rows = put_gray_rows;
  350.   } else if (cinfo->out_color_space == JCS_RGB) {
  351.     if (cinfo->quantize_colors)
  352.       dest->pub.put_pixel_rows = put_gray_rows;
  353.     else
  354.       dest->pub.put_pixel_rows = put_pixel_rows;
  355.   } else {
  356.     ERREXIT(cinfo, JERR_BMP_COLORSPACE);
  357.   }
  358.   /* Calculate output image dimensions so we can allocate space */
  359.   jpeg_calc_output_dimensions(cinfo);
  360.   /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
  361.   row_width = cinfo->output_width * cinfo->output_components;
  362.   dest->data_width = row_width;
  363.   while ((row_width & 3) != 0) row_width++;
  364.   dest->row_width = row_width;
  365.   dest->pad_bytes = (int) (row_width - dest->data_width);
  366.   /* Allocate space for inversion array, prepare for write pass */
  367.   dest->whole_image = (*cinfo->mem->request_virt_sarray)
  368.     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
  369.      row_width, cinfo->output_height, (JDIMENSION) 1);
  370.   dest->cur_output_row = 0;
  371.   if (cinfo->progress != NULL) {
  372.     cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
  373.     progress->total_extra_passes++; /* count file input as separate pass */
  374.   }
  375.   /* Create decompressor output buffer. */
  376.   dest->pub.buffer = (*cinfo->mem->alloc_sarray)
  377.     ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
  378.   dest->pub.buffer_height = 1;
  379.   return (djpeg_dest_ptr) dest;
  380. }
  381. #endif /* BMP_SUPPORTED */