00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 #include "cdjpeg.h"             
00021 
00022 #ifdef BMP_SUPPORTED
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #if BITS_IN_JSAMPLE != 8
00031   Sorry, this code only copes with 8-bit JSAMPLEs. 
00032 #endif
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 typedef struct {
00045   struct djpeg_dest_struct pub; 
00046 
00047   boolean is_os2;               
00048 
00049   jvirt_sarray_ptr whole_image; 
00050   JDIMENSION data_width;        
00051   JDIMENSION row_width;         
00052   int pad_bytes;                
00053   JDIMENSION cur_output_row;    
00054 } bmp_dest_struct;
00055 
00056 typedef bmp_dest_struct * bmp_dest_ptr;
00057 
00058 
00059 
00060 LOCAL(void) write_colormap
00061         JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
00062              int map_colors, int map_entry_size));
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 METHODDEF(void)
00071 put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
00072                 JDIMENSION rows_supplied)
00073 
00074 {
00075   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
00076   JSAMPARRAY image_ptr;
00077   register JSAMPROW inptr, outptr;
00078   register JDIMENSION col;
00079   int pad;
00080 
00081   
00082   image_ptr = (*cinfo->mem->access_virt_sarray)
00083     ((j_common_ptr) cinfo, dest->whole_image,
00084      dest->cur_output_row, (JDIMENSION) 1, TRUE);
00085   dest->cur_output_row++;
00086 
00087   
00088 
00089 
00090   inptr = dest->pub.buffer[0];
00091   outptr = image_ptr[0];
00092   for (col = cinfo->output_width; col > 0; col--) {
00093     outptr[2] = *inptr++;       
00094     outptr[1] = *inptr++;
00095     outptr[0] = *inptr++;
00096     outptr += 3;
00097   }
00098 
00099   
00100   pad = dest->pad_bytes;
00101   while (--pad >= 0)
00102     *outptr++ = 0;
00103 }
00104 
00105 METHODDEF(void)
00106 put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
00107                JDIMENSION rows_supplied)
00108 
00109 {
00110   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
00111   JSAMPARRAY image_ptr;
00112   register JSAMPROW inptr, outptr;
00113   register JDIMENSION col;
00114   int pad;
00115 
00116   
00117   image_ptr = (*cinfo->mem->access_virt_sarray)
00118     ((j_common_ptr) cinfo, dest->whole_image,
00119      dest->cur_output_row, (JDIMENSION) 1, TRUE);
00120   dest->cur_output_row++;
00121 
00122   
00123   inptr = dest->pub.buffer[0];
00124   outptr = image_ptr[0];
00125   for (col = cinfo->output_width; col > 0; col--) {
00126     *outptr++ = *inptr++;       
00127   }
00128 
00129   
00130   pad = dest->pad_bytes;
00131   while (--pad >= 0)
00132     *outptr++ = 0;
00133 }
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 METHODDEF(void)
00142 start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
00143 {
00144   
00145 }
00146 
00147 
00148 
00149 
00150 
00151 
00152 
00153 
00154 
00155 
00156 LOCAL(void)
00157 write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
00158 
00159 {
00160   char bmpfileheader[14];
00161   char bmpinfoheader[40];
00162 #define PUT_2B(array,offset,value)  \
00163         (array[offset] = (char) ((value) & 0xFF), \
00164          array[offset+1] = (char) (((value) >> 8) & 0xFF))
00165 #define PUT_4B(array,offset,value)  \
00166         (array[offset] = (char) ((value) & 0xFF), \
00167          array[offset+1] = (char) (((value) >> 8) & 0xFF), \
00168          array[offset+2] = (char) (((value) >> 16) & 0xFF), \
00169          array[offset+3] = (char) (((value) >> 24) & 0xFF))
00170   INT32 headersize, bfSize;
00171   int bits_per_pixel, cmap_entries;
00172 
00173   
00174   if (cinfo->out_color_space == JCS_RGB) {
00175     if (cinfo->quantize_colors) {
00176       
00177       bits_per_pixel = 8;
00178       cmap_entries = 256;
00179     } else {
00180       
00181       bits_per_pixel = 24;
00182       cmap_entries = 0;
00183     }
00184   } else {
00185     
00186     bits_per_pixel = 8;
00187     cmap_entries = 256;
00188   }
00189   
00190   headersize = 14 + 40 + cmap_entries * 4; 
00191   bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
00192   
00193   
00194   MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
00195   MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
00196 
00197   
00198   bmpfileheader[0] = 0x42;      
00199   bmpfileheader[1] = 0x4D;
00200   PUT_4B(bmpfileheader, 2, bfSize); 
00201   
00202   PUT_4B(bmpfileheader, 10, headersize); 
00203 
00204   
00205   PUT_2B(bmpinfoheader, 0, 40); 
00206   PUT_4B(bmpinfoheader, 4, cinfo->output_width); 
00207   PUT_4B(bmpinfoheader, 8, cinfo->output_height); 
00208   PUT_2B(bmpinfoheader, 12, 1); 
00209   PUT_2B(bmpinfoheader, 14, bits_per_pixel); 
00210   
00211   
00212   if (cinfo->density_unit == 2) { 
00213     PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); 
00214     PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); 
00215   }
00216   PUT_2B(bmpinfoheader, 32, cmap_entries); 
00217   
00218 
00219   if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
00220     ERREXIT(cinfo, JERR_FILE_WRITE);
00221   if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
00222     ERREXIT(cinfo, JERR_FILE_WRITE);
00223 
00224   if (cmap_entries > 0)
00225     write_colormap(cinfo, dest, cmap_entries, 4);
00226 }
00227 
00228 
00229 LOCAL(void)
00230 write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
00231 
00232 {
00233   char bmpfileheader[14];
00234   char bmpcoreheader[12];
00235   INT32 headersize, bfSize;
00236   int bits_per_pixel, cmap_entries;
00237 
00238   
00239   if (cinfo->out_color_space == JCS_RGB) {
00240     if (cinfo->quantize_colors) {
00241       
00242       bits_per_pixel = 8;
00243       cmap_entries = 256;
00244     } else {
00245       
00246       bits_per_pixel = 24;
00247       cmap_entries = 0;
00248     }
00249   } else {
00250     
00251     bits_per_pixel = 8;
00252     cmap_entries = 256;
00253   }
00254   
00255   headersize = 14 + 12 + cmap_entries * 3; 
00256   bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
00257   
00258   
00259   MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
00260   MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
00261 
00262   
00263   bmpfileheader[0] = 0x42;      
00264   bmpfileheader[1] = 0x4D;
00265   PUT_4B(bmpfileheader, 2, bfSize); 
00266   
00267   PUT_4B(bmpfileheader, 10, headersize); 
00268 
00269   
00270   PUT_2B(bmpcoreheader, 0, 12); 
00271   PUT_2B(bmpcoreheader, 4, cinfo->output_width); 
00272   PUT_2B(bmpcoreheader, 6, cinfo->output_height); 
00273   PUT_2B(bmpcoreheader, 8, 1);  
00274   PUT_2B(bmpcoreheader, 10, bits_per_pixel); 
00275 
00276   if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
00277     ERREXIT(cinfo, JERR_FILE_WRITE);
00278   if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
00279     ERREXIT(cinfo, JERR_FILE_WRITE);
00280 
00281   if (cmap_entries > 0)
00282     write_colormap(cinfo, dest, cmap_entries, 3);
00283 }
00284 
00285 
00286 
00287 
00288 
00289 
00290 
00291 LOCAL(void)
00292 write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
00293                 int map_colors, int map_entry_size)
00294 {
00295   JSAMPARRAY colormap = cinfo->colormap;
00296   int num_colors = cinfo->actual_number_of_colors;
00297   FILE * outfile = dest->pub.output_file;
00298   int i;
00299 
00300   if (colormap != NULL) {
00301     if (cinfo->out_color_components == 3) {
00302       
00303       for (i = 0; i < num_colors; i++) {
00304         putc(GETJSAMPLE(colormap[2][i]), outfile);
00305         putc(GETJSAMPLE(colormap[1][i]), outfile);
00306         putc(GETJSAMPLE(colormap[0][i]), outfile);
00307         if (map_entry_size == 4)
00308           putc(0, outfile);
00309       }
00310     } else {
00311       
00312       for (i = 0; i < num_colors; i++) {
00313         putc(GETJSAMPLE(colormap[0][i]), outfile);
00314         putc(GETJSAMPLE(colormap[0][i]), outfile);
00315         putc(GETJSAMPLE(colormap[0][i]), outfile);
00316         if (map_entry_size == 4)
00317           putc(0, outfile);
00318       }
00319     }
00320   } else {
00321     
00322     for (i = 0; i < 256; i++) {
00323       putc(i, outfile);
00324       putc(i, outfile);
00325       putc(i, outfile);
00326       if (map_entry_size == 4)
00327         putc(0, outfile);
00328     }
00329   }
00330    
00331   if (i > map_colors)
00332     ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
00333   for (; i < map_colors; i++) {
00334     putc(0, outfile);
00335     putc(0, outfile);
00336     putc(0, outfile);
00337     if (map_entry_size == 4)
00338       putc(0, outfile);
00339   }
00340 }
00341 
00342 
00343 METHODDEF(void)
00344 finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
00345 {
00346   bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
00347   register FILE * outfile = dest->pub.output_file;
00348   JSAMPARRAY image_ptr;
00349   register JSAMPROW data_ptr;
00350   JDIMENSION row;
00351   register JDIMENSION col;
00352   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
00353 
00354   
00355   if (dest->is_os2)
00356     write_os2_header(cinfo, dest);
00357   else
00358     write_bmp_header(cinfo, dest);
00359 
00360   
00361   for (row = cinfo->output_height; row > 0; row--) {
00362     if (progress != NULL) {
00363       progress->pub.pass_counter = (long) (cinfo->output_height - row);
00364       progress->pub.pass_limit = (long) cinfo->output_height;
00365       (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
00366     }
00367     image_ptr = (*cinfo->mem->access_virt_sarray)
00368       ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
00369     data_ptr = image_ptr[0];
00370     for (col = dest->row_width; col > 0; col--) {
00371       putc(GETJSAMPLE(*data_ptr), outfile);
00372       data_ptr++;
00373     }
00374   }
00375   if (progress != NULL)
00376     progress->completed_extra_passes++;
00377 
00378   
00379   fflush(outfile);
00380   if (ferror(outfile))
00381     ERREXIT(cinfo, JERR_FILE_WRITE);
00382 }
00383 
00384 
00385 
00386 
00387 
00388 
00389 GLOBAL(djpeg_dest_ptr)
00390 jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
00391 {
00392   bmp_dest_ptr dest;
00393   JDIMENSION row_width;
00394 
00395   
00396   dest = (bmp_dest_ptr)
00397       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
00398                                   SIZEOF(bmp_dest_struct));
00399   dest->pub.start_output = start_output_bmp;
00400   dest->pub.finish_output = finish_output_bmp;
00401   dest->is_os2 = is_os2;
00402 
00403   if (cinfo->out_color_space == JCS_GRAYSCALE) {
00404     dest->pub.put_pixel_rows = put_gray_rows;
00405   } else if (cinfo->out_color_space == JCS_RGB) {
00406     if (cinfo->quantize_colors)
00407       dest->pub.put_pixel_rows = put_gray_rows;
00408     else
00409       dest->pub.put_pixel_rows = put_pixel_rows;
00410   } else {
00411     ERREXIT(cinfo, JERR_BMP_COLORSPACE);
00412   }
00413 
00414   
00415   jpeg_calc_output_dimensions(cinfo);
00416 
00417   
00418   row_width = cinfo->output_width * cinfo->output_components;
00419   dest->data_width = row_width;
00420   while ((row_width & 3) != 0) row_width++;
00421   dest->row_width = row_width;
00422   dest->pad_bytes = (int) (row_width - dest->data_width);
00423 
00424   
00425   dest->whole_image = (*cinfo->mem->request_virt_sarray)
00426     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
00427      row_width, cinfo->output_height, (JDIMENSION) 1);
00428   dest->cur_output_row = 0;
00429   if (cinfo->progress != NULL) {
00430     cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
00431     progress->total_extra_passes++; 
00432   }
00433 
00434   
00435   dest->pub.buffer = (*cinfo->mem->alloc_sarray)
00436     ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
00437   dest->pub.buffer_height = 1;
00438 
00439   return (djpeg_dest_ptr) dest;
00440 }
00441 
00442 #endif