Back to index

plt-scheme  4.2.1
wx_bmp.cc
Go to the documentation of this file.
00001 /*
00002  * xvbmp.c - i/o routines for .BMP files (MS Windows 3.x)
00003  *
00004  * LoadBMP(fname, numcols)
00005  * WriteBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
00006  */
00007 
00008 /* Copyright Notice
00009  * ================
00010  * Copyright 1989, 1990, 1991, 1992, 1993 by John Bradley
00011  * 
00012  * Permission to use, copy, and distribute XV in its entirety, for 
00013  * non-commercial purposes, is hereby granted without fee, provided that
00014  * this license information and copyright notice appear in all copies.
00015  * 
00016  * Note that distributing XV 'bundled' in with ANY product is considered
00017  * to be a 'commercial purpose'.
00018  *
00019  * Also note that any copies of XV that are distributed MUST be built
00020  * and/or configured to be in their 'unregistered copy' mode, so that it
00021  * is made obvious to the user that XV is shareware, and that they should
00022  * consider donating, or at least reading this License Info.
00023  * 
00024  * The software may be modified for your own purposes, but modified
00025  * versions may NOT be distributed without prior consent of the author.
00026  * 
00027  * This software is provided 'as-is', without any express or implied
00028  * warranty.  In no event will the author be held liable for any damages
00029  * arising from the use of this software.
00030  * 
00031  * If you would like to do something with XV that this copyright
00032  * prohibits (such as distributing it with a commercial product, 
00033  * using portions of the source in some other program, etc.), please
00034  * contact the author (preferably via email).  Arrangements can
00035  * probably be worked out.
00036  *
00037  * XV is shareware for PERSONAL USE only.  You may use XV for your own
00038  * amusement, and if you find it nifty, useful, generally cool, or of
00039  * some value to you, your non-deductable donation would be greatly
00040  * appreciated.  $25 is the suggested donation, though, of course,
00041  * larger donations are quite welcome.  Folks who donate $25 or more
00042  * can receive a Real Nice bound copy of the XV manual for no extra
00043  * charge.
00044  * 
00045  * Commercial, government, and institutional users MUST register their
00046  * copies of XV, for the exceedingly REASONABLE price of just $25 per
00047  * workstation/X terminal.  Site licenses are available for those who
00048  * wish to run XV on a large number of machines.  Contact the author
00049  * for more details.
00050  *
00051  * The author may be contacted via:
00052  *    US Mail:  John Bradley
00053  *              1053 Floyd Terrace
00054  *              Bryn Mawr, PA  19010
00055  *
00056  *    Phone:    (215) 898-8813
00057  *    EMail:    bradley@cis.upenn.edu
00058  */
00059 
00060 
00061 #include <stdlib.h>
00062 #include "wx_image.h"
00063 
00064 #ifdef MZ_PRECISE_GC
00065 END_XFORM_ARITH;
00066 #endif
00067 
00068 /* comments on error handling:
00069    a truncated file is not considered a Major Error.  The file is loaded, the
00070    rest of the pic is filled with 0's.
00071 
00072    a file with garbage characters in it is an unloadable file.  All allocated
00073    stuff is tossed, and LoadPBM returns non-zero
00074 
00075    not being able to malloc is a Fatal Error.  The program is aborted. */
00076 
00077 
00078 #define BI_RGB  0
00079 #define BI_RLE8 1
00080 #define BI_RLE4 2
00081 
00082 
00083 static long filesize;
00084 
00085   static int  loadBMP1(FILE *, byte *, int, int);
00086   static int  loadBMP4(FILE *, byte *, int, int, int);
00087   static int  loadBMP8(FILE *, byte *, int, int, int);
00088   static int  loadBMP24(FILE *, byte *, int, int);
00089   static unsigned int getshort(FILE *);
00090   static unsigned int getint(FILE *);
00091   static void putshort(FILE *, int);
00092   static void putint(FILE *, int);
00093   static void writeBMP1(FILE *, byte *, int, int);
00094   static void writeBMP4(FILE *, byte *, int, int);
00095   static void writeBMP8(FILE *, byte *, int, int);
00096   static void writeBMP24(FILE *, byte *, int, int);
00097   static int  bmpError(char *, char *);
00098 
00099 
00100 /*******************************************/
00101 int wxImage::LoadBMP(char *fname, PICINFO *pinfo)
00102 /*******************************************/
00103 {
00104   FILE         *fp;
00105   int          i, c, c1, rv;
00106   unsigned int bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
00107   unsigned int biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
00108   unsigned int biYPelsPerMeter, biClrUsed, biClrImportant;
00109   char         *cmpstr;
00110   byte         *_pic24, *pic8;
00111   char          buf[512];
00112 
00113   /* returns '1' on success */
00114 
00115   pic8 = _pic24 = (byte *) NULL;
00116 
00117   fp=fopen(fname,"r");
00118   if (!fp) return (bmpError(fname, "couldn't open file"));
00119   
00120   fseek(fp, 0L, 2);      /* figure out the file size */
00121   filesize = ftell(fp);
00122   fseek(fp, 0L, 0);
00123 
00124 
00125   /* read the file type (first two bytes) */
00126   c = getc(fp);  c1 = getc(fp);
00127   if (c!='B' || c1!='M') { bmpError(fname,"file type != 'BM'"); goto ERROR; }
00128 
00129   bfSize = getint(fp);
00130   getshort(fp);         /* reserved and ignored */
00131   getshort(fp);
00132   bfOffBits = getint(fp);
00133 
00134   biSize          = getint(fp);
00135   biWidth         = getint(fp);
00136   biHeight        = getint(fp);
00137   biPlanes        = getshort(fp);
00138   biBitCount      = getshort(fp);
00139   biCompression   = getint(fp);
00140   biSizeImage     = getint(fp);
00141   biXPelsPerMeter = getint(fp);
00142   biYPelsPerMeter = getint(fp);
00143   biClrUsed       = getint(fp);
00144   biClrImportant  = getint(fp);
00145   
00146 
00147   if (imgDEBUG>1) {
00148     fprintf(stderr,"\nLoadBMP:\tbfSize=%d, bfOffBits=%d\n",bfSize,bfOffBits);
00149     fprintf(stderr,"\t\tbiSize=%d, biWidth=%d, biHeight=%d, biPlanes=%d\n",
00150            biSize, biWidth, biHeight, biPlanes);
00151     fprintf(stderr,"\t\tbiBitCount=%d, biCompression=%d, biSizeImage=%d\n",
00152            biBitCount, biCompression, biSizeImage);
00153     fprintf(stderr,"\t\tbiX,YPelsPerMeter=%d,%d  biClrUsed=%d, biClrImp=%d\n",
00154            biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant);
00155   }
00156 
00157   if (ferror(fp)) { bmpError(fname,"EOF reached in file header"); goto ERROR; }
00158 
00159 
00160   /* error checking */
00161   if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 && biBitCount!=24) || 
00162       biPlanes!=1 || biCompression>BI_RLE4) {
00163 
00164     sprintf(buf,"Bogus BMP File!  (bitCount=%d, Planes=%d, Compression=%d)",
00165            biBitCount, biPlanes, biCompression);
00166 
00167     bmpError(fname, buf);
00168     goto ERROR;
00169   }
00170 
00171   if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) ||
00172       (biBitCount==4 && biCompression==BI_RLE8) ||
00173       (biBitCount==8 && biCompression==BI_RLE4)) {
00174 
00175     sprintf(buf,"Bogus BMP File!  (bitCount=%d, Compression=%d)",
00176            biBitCount, biCompression);
00177 
00178     bmpError(fname, buf);
00179     goto ERROR;
00180   }
00181 
00182 
00183   
00184   /* skip ahead to colormap, using biSize */
00185   c = biSize - 40;    /* 40 bytes read from biSize to biClrImportant */
00186   for (i=0; i<c; i++) { getc(fp); }
00187 
00188 
00189   /* load up colormap, if any */
00190   if (biBitCount!=24) {
00191     int i, cmaplen;
00192 
00193     if ((biBitCount < 16) && biClrUsed)
00194       cmaplen = biClrUsed;
00195     else
00196       cmaplen = 1 << biBitCount;
00197     numcols = cmaplen;
00198     for (i=0; i<cmaplen; i++) {
00199       int ac;
00200       ac = getc(fp);
00201       pinfo->b[i] = ac;
00202       ac = getc(fp);
00203       pinfo->g[i] = ac;
00204       ac = getc(fp);
00205       pinfo->r[i] = ac;
00206       // JACS code to fit in with old xv
00207       r[i] = rorg[i] = pinfo->r[i];
00208       b[i] = borg[i] = pinfo->b[i];
00209       g[i] = gorg[i] = pinfo->g[i];
00210 
00211       getc(fp);         /* unused */
00212     }
00213 
00214     if (ferror(fp)) 
00215       { bmpError(fname,"EOF reached in BMP colormap"); goto ERROR; }
00216 
00217     if (imgDEBUG>1) {
00218       fprintf(stderr,"LoadBMP:  BMP colormap:  (RGB order)\n");
00219       for (i=0; i<cmaplen; i++) {
00220        fprintf(stderr,"%02x%02x%02x  ", pinfo->r[i],pinfo->g[i],pinfo->b[i]);
00221       }
00222       fprintf(stderr,"\n\n");
00223     }
00224   }
00225 
00226 
00227   /* create pic8 or pic24 */
00228 
00229   if (biBitCount==24) {
00230     _pic24 = (byte *) calloc(biWidth * biHeight * 3, 1);
00231     if (!_pic24) {
00232       fclose(fp);
00233       return (bmpError(fname, "couldn't malloc 'pic24'"));
00234     }
00235   }
00236   else {
00237     pic8 = (byte *) calloc(biWidth * biHeight, 1);
00238     if (!pic8) {
00239       fclose(fp);
00240       return(bmpError(fname, "couldn't malloc 'pic8'"));
00241     }
00242   }
00243 
00244   /* load up the image */
00245   if      (biBitCount == 1) rv = loadBMP1(fp,pic8,biWidth,biHeight);
00246   else if (biBitCount == 4) rv = loadBMP4(fp,pic8,biWidth,biHeight,
00247                                      biCompression);
00248   else if (biBitCount == 8) rv = loadBMP8(fp,pic8,biWidth,biHeight,
00249                                      biCompression);
00250   else                      rv = loadBMP24(fp,_pic24,biWidth,biHeight);
00251 
00252   if (rv) bmpError(fname, "File appears truncated.  Winging it.\n");
00253 
00254   fclose(fp);
00255 
00256 
00257   if (biBitCount == 24) {
00258     pinfo->pic  = _pic24;
00259     pinfo->type = PIC24;
00260   }
00261   else {
00262     pinfo->pic  = pic8;
00263     pinfo->type = PIC8;
00264   }
00265 
00266   cmpstr = "";
00267   if      (biCompression == BI_RLE4) cmpstr = ", RLE4 compressed";
00268   else if (biCompression == BI_RLE8) cmpstr = ", RLE8 compressed";
00269 
00270   pinfo->w = biWidth;  pinfo->h = biHeight;
00271   pinfo->frmType = F_BMP;
00272   pinfo->colType = F_FULLCOLOR;
00273 
00274   sprintf(pinfo->fullInfo, "BMP, %d bit%s per pixel%s.  (%ld bytes)",
00275          biBitCount,  (biBitCount == 1) ? "" : "s",
00276          cmpstr, filesize);
00277   sprintf(pinfo->shrtInfo, "%dx%d BMP.", biWidth, biHeight);
00278   pinfo->comment = (char *) NULL;
00279 //  cout << pinfo->fullInfo << "\n";
00280 
00281   return 1;
00282 
00283 
00284  ERROR:
00285   fclose(fp);
00286   return 0;
00287 }  
00288 
00289 
00290 /*******************************************/
00291 static int loadBMP1(FILE *fp, byte *pic8, int w, int h)
00292 {
00293   int   i,j,c,bitnum,padw;
00294   byte *pp;
00295 
00296   c = 0;
00297   padw = ((w + 31)/32) * 32;  /* 'w', padded to be a multiple of 32 */
00298 
00299   for (i=h-1; i>=0; i--) {
00300     pp = pic8 + (i * w);
00301     for (j=bitnum=0; j<padw; j++,bitnum++) {
00302       if ((bitnum&7) == 0) { /* read the next byte */
00303        c = getc(fp);
00304        bitnum = 0;
00305       }
00306       
00307       if (j<w) {
00308        *pp++ = (c & 0x80) ? 1 : 0;
00309        c <<= 1;
00310       }
00311     }
00312     if (ferror(fp)) break;
00313   }
00314 
00315   return (ferror(fp));
00316 }  
00317 
00318 
00319 
00320 /*******************************************/
00321 static int loadBMP4(FILE *fp, byte *pic8, int w, int h, int comp)
00322 {
00323   int   i,j,c,c1,x,y,nybnum,padw,rv;
00324   byte *pp;
00325 
00326 
00327   rv = 0;
00328   c = c1 = 0;
00329 
00330   if (comp == BI_RGB) {   /* read uncompressed data */
00331     padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
00332 
00333     for (i=h-1; i>=0; i--) {
00334       pp = pic8 + (i * w);
00335       for (j=nybnum=0; j<padw; j++,nybnum++) {
00336        if ((nybnum & 1) == 0) { /* read next byte */
00337          c = getc(fp);
00338          nybnum = 0;
00339        }
00340 
00341        if (j<w) {
00342          *pp++ = (c & 0xf0) >> 4;
00343          c <<= 4;
00344        }
00345       }
00346       if (ferror(fp)) break;
00347     }
00348   }
00349 
00350   else if (comp == BI_RLE4) {  /* read RLE4 compressed data */
00351     x = y = 0;  
00352     pp = pic8 + x + (h-y-1)*w;
00353 
00354     while (y<h) {
00355       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
00356 
00357       if (c) {                                   /* encoded mode */
00358        c1 = getc(fp);
00359        for (i=0; i<c; i++,x++,pp++) {
00360          *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
00361        }
00362       }
00363 
00364       else {    /* c==0x00  :  escape codes */
00365        c = getc(fp);  if (c == EOF) { rv = 1;  break; }
00366 
00367        if      (c == 0x00) {                    /* end of line */
00368          x=0;  y++;  pp = pic8 + x + (h-y-1)*w;
00369        } 
00370 
00371        else if (c == 0x01) break;               /* end of pic8 */
00372 
00373        else if (c == 0x02) {                    /* delta */
00374          c = getc(fp);  x += c;
00375          c = getc(fp);  y += c;
00376          pp = pic8 + x + (h-y-1)*w;
00377        }
00378 
00379        else {                                   /* absolute mode */
00380          for (i=0; i<c; i++, x++, pp++) {
00381            if ((i&1) == 0) c1 = getc(fp);
00382            *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
00383          }
00384          
00385          if (((c&3)==1) || ((c&3)==2)) getc(fp);  /* read pad byte */
00386        }
00387       }  /* escape processing */
00388       if (ferror(fp)) break;
00389     }  /* while */
00390   }
00391   
00392   else {
00393     fprintf(stderr,"unknown BMP compression type 0x%0x\n", comp);
00394   }
00395 
00396   if (ferror(fp)) rv = 1;
00397   return rv;
00398 }  
00399 
00400 
00401 
00402 /*******************************************/
00403 static int loadBMP8(FILE *fp, byte *pic8, int w, int h, int comp)
00404 {
00405   int   i,j,c,c1,padw,x,y,rv;
00406   byte *pp;
00407 
00408   rv = 0;
00409 
00410   if (comp == BI_RGB) {   /* read uncompressed data */
00411     padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
00412 
00413     for (i=h-1; i>=0; i--) {
00414       pp = pic8 + (i * w);
00415 
00416       for (j=0; j<padw; j++) {
00417        c = getc(fp);  if (c==EOF) rv = 1;
00418        if (j<w) *pp++ = c;
00419       }
00420       if (ferror(fp)) break;
00421     }
00422   }
00423 
00424   else if (comp == BI_RLE8) {  /* read RLE8 compressed data */
00425     x = y = 0;  
00426     pp = pic8 + x + (h-y-1)*w;
00427 
00428     while (y<h) {
00429       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
00430 
00431       if (c) {                                   /* encoded mode */
00432        c1 = getc(fp);
00433        for (i=0; i<c; i++,x++,pp++) { *pp = c1; }
00434       }
00435 
00436       else {    /* c==0x00  :  escape codes */
00437        c = getc(fp);  if (c == EOF) { rv = 1;  break; }
00438 
00439        if      (c == 0x00) {                    /* end of line */
00440          x=0;  y++;  pp = pic8 + x + (h-y-1)*w;
00441        } 
00442 
00443        else if (c == 0x01) break;               /* end of pic8 */
00444 
00445        else if (c == 0x02) {                    /* delta */
00446          c = getc(fp);  x += c;
00447          c = getc(fp);  y += c;
00448          pp = pic8 + x + (h-y-1)*w;
00449        }
00450 
00451        else {                                   /* absolute mode */
00452          for (i=0; i<c; i++, x++, pp++) {
00453            c1 = getc(fp);
00454            *pp = c1;
00455          }
00456          
00457          if (c & 1) getc(fp);  /* odd length run: read an extra pad byte */
00458        }
00459       }  /* escape processing */
00460       if (ferror(fp)) break;
00461     }  /* while */
00462   }
00463   
00464   else {
00465     fprintf(stderr,"unknown BMP compression type 0x%0x\n", comp);
00466   }
00467 
00468   if (ferror(fp)) rv = 1;
00469   return rv;
00470 }  
00471 
00472 typedef unsigned char uchar;
00473 
00474 /*******************************************/
00475 static int loadBMP24(FILE *fp, byte *pic24, int w, int h)
00476 {
00477   int   i,j,padb,k;
00478   byte *pp;
00479   uchar *line;
00480 
00481   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to read at EOscanline */
00482 
00483   line = new WXGC_ATOMIC uchar[(w * 3) + padb];
00484 
00485   for (i=h-1; i>=0; i--) {
00486     pp = pic24 + (i * w * 3);
00487 
00488     fread(line, (w * 3) + padb, 1, fp);
00489     k = 0;
00490     
00491     for (j=0; j<w; j++) {
00492       int rc, grc, bc;
00493       /* BMP data is ordered backward: BGR */
00494       bc = line[k++];
00495       grc = line[k++];
00496       rc = line[k++];
00497       *pp++ = rc;
00498       *pp++ = grc;
00499       *pp++ = bc;
00500     }
00501 
00502     if (ferror(fp)) break;
00503   }
00504 
00505   return (ferror(fp));
00506 }  
00507 
00508 
00509 
00510 /*******************************************/
00511 static unsigned int getshort(FILE *fp)
00512 {
00513   int c, c1;
00514   c = getc(fp);  c1 = getc(fp);
00515   return ((unsigned int) c) + (((unsigned int) c1) << 8);
00516 }
00517 
00518 
00519 /*******************************************/
00520 static unsigned int getint(FILE *fp)
00521 {
00522   int c, c1, c2, c3;
00523   c = getc(fp);  c1 = getc(fp);  c2 = getc(fp);  c3 = getc(fp);
00524   return ((unsigned int) c) +
00525          (((unsigned int) c1) << 8) + 
00526         (((unsigned int) c2) << 16) +
00527         (((unsigned int) c3) << 24);
00528 }
00529 
00530 
00531 /*******************************************/
00532 static void putshort(FILE *fp, int i)
00533 {
00534   int c, c1;
00535 
00536   c = ((unsigned int ) i) & 0xff;  c1 = (((unsigned int) i)>>8) & 0xff;
00537   putc(c, fp);   putc(c1,fp);
00538 }
00539 
00540 
00541 /*******************************************/
00542 static void putint(FILE *fp, int i)
00543 {
00544   int c, c1, c2, c3;
00545   c  = ((unsigned int ) i)      & 0xff;  
00546   c1 = (((unsigned int) i)>>8)  & 0xff;
00547   c2 = (((unsigned int) i)>>16) & 0xff;
00548   c3 = (((unsigned int) i)>>24) & 0xff;
00549 
00550   putc(c, fp);   putc(c1,fp);  putc(c2,fp);  putc(c3,fp);
00551 }
00552 
00553 
00554 
00555 
00556 static byte pc2nc[256],r1[256],g1[256],b1[256];
00557 
00558 
00559 /*******************************************/
00560 int wxImage::WriteBMP(FILE *fp, byte *pic824, int ptype, int w, int h, byte *rmap, byte *gmap, byte *bmap, int numcols, int colorstyle)
00561 {
00562   /*
00563    * if PIC8, and colorstyle == F_FULLCOLOR, F_GREYSCALE, or F_REDUCED,
00564    * the program writes an uncompressed 4- or 8-bit image (depending on
00565    * the value of numcols)
00566    *
00567    * if PIC24, and colorstyle == F_FULLCOLOR, program writes an uncompressed
00568    *    24-bit image
00569    * if PIC24 and colorstyle = F_GREYSCALE, program writes an uncompressed
00570    *    8-bit image
00571    * note that PIC24 and F_BWDITHER/F_REDUCED won't happen
00572    *
00573    * if colorstyle == F_BWDITHER, it writes a 1-bit image 
00574    *
00575    */
00576 
00577   int i,j, nc, nbits, bperlin, cmaplen;
00578   byte *graypic, *sp, *dp, graymap[256];
00579 
00580   nc = nbits = cmaplen = 0;
00581   graypic = NULL;
00582 
00583   if (ptype == PIC24 && colorstyle == F_GREYSCALE) {
00584     /* generate a faked 8-bit per pixel image with a grayscale cmap,
00585        so that it can just fall through existing 8-bit code */
00586 
00587     graypic = (byte *) malloc(w*h);
00588     if (!graypic) FatalError("unable to malloc in WriteBMP()");
00589 
00590     for (i=0,sp=pic824,dp=graypic; i<w*h; i++,sp+=3, dp++) {
00591       *dp = MONO(sp[0],sp[1],sp[2]);
00592     }
00593 
00594     for (i=0; i<256; i++) { graymap[i] = i; }
00595     rmap = gmap = bmap = graymap;
00596     numcols = 256;
00597     ptype = PIC8;
00598 
00599     pic824 = graypic;
00600   }
00601 
00602 
00603   if (ptype == PIC24) {  /* is F_FULLCOLOR */
00604     nbits = 24;
00605     cmaplen = 0;
00606     nc = 0;
00607   }
00608 
00609   else if (ptype == PIC8) {
00610     /* we may have duplicate colors in the colormap, and we'd prefer not to.
00611      * build r1,g1,b1 (a contiguous, minimum set colormap), and pc2nc[], a
00612      * array that maps 'pic8' values (0-numcols) into corresponding values
00613      * in the r1,g1,b1 colormaps (0-nc)
00614      */
00615 
00616     for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; }
00617 
00618     nc = 0;
00619     for (i=0; i<numcols; i++) {
00620       /* see if color #i is a duplicate */
00621       for (j=0; j<i; j++) {
00622        if (rmap[i] == rmap[j] && gmap[i] == gmap[j] && 
00623            bmap[i] == bmap[j]) break;
00624       }
00625 
00626       if (j==i) {  /* wasn't found */
00627        pc2nc[i] = nc;
00628        r1[nc] = rmap[i];
00629        g1[nc] = gmap[i];
00630        b1[nc] = bmap[i];
00631        nc++;
00632       }
00633       else pc2nc[i] = pc2nc[j];
00634     }
00635 
00636     /* determine how many bits per pixel we'll be writing */
00637     if (colorstyle == F_BWDITHER || nc <= 2) nbits = 1;
00638     else if (nc<=16) nbits = 4;
00639     else nbits = 8;
00640 
00641     cmaplen = 1<<nbits;                      /* # of entries in cmap */
00642   }
00643 
00644 
00645   bperlin = ((w * nbits + 31) / 32) * 4;   /* # bytes written per line */
00646 
00647   putc('B', fp);  putc('M', fp);           /* BMP file magic number */
00648 
00649   /* compute filesize and write it */
00650   i = 14 +                /* size of bitmap file header */
00651       40 +                /* size of bitmap info header */
00652       (cmaplen * 4) +     /* size of colormap */
00653       bperlin * h;        /* size of image data */
00654 
00655   putint(fp, i);
00656   putshort(fp, 0);        /* reserved1 */
00657   putshort(fp, 0);        /* reserved2 */
00658   putint(fp, 14 + 40 + (cmaplen * 4));  /* offset from BOfile to BObitmap */
00659 
00660   putint(fp, 40);         /* biSize: size of bitmap info header */
00661   putint(fp, w);          /* biWidth */
00662   putint(fp, h);          /* biHeight */
00663   putshort(fp, 1);        /* biPlanes:  must be '1' */
00664   putshort(fp, nbits);    /* biBitCount: 1,4,8, or 24 */
00665   putint(fp, BI_RGB);     /* biCompression:  BI_RGB, BI_RLE8 or BI_RLE4 */
00666   putint(fp, bperlin*h);  /* biSizeImage:  size of raw image data */
00667   putint(fp, 75 * 39);    /* biXPelsPerMeter: (75dpi * 39" per meter) */
00668   putint(fp, 75 * 39);    /* biYPelsPerMeter: (75dpi * 39" per meter) */
00669   putint(fp, nc);         /* biClrUsed: # of colors used in cmap */
00670   putint(fp, nc);         /* biClrImportant: same as above */
00671 
00672 
00673   /* write out the colormap */
00674   for (i=0; i<cmaplen; i++) {
00675     if (colorstyle == F_GREYSCALE) {
00676       j = MONO(r1[i],g1[i],b1[i]);
00677       putc(j,fp);  putc(j,fp);  putc(j,fp);  putc(0,fp);
00678     }
00679     else {
00680       putc(b1[i],fp);
00681       putc(g1[i],fp);
00682       putc(r1[i],fp);
00683       putc(0,fp);
00684     }
00685   }
00686 
00687   /* write out the image */
00688   if      (nbits ==  1) writeBMP1 (fp, pic824, w, h);
00689   else if (nbits ==  4) writeBMP4 (fp, pic824, w, h);
00690   else if (nbits ==  8) writeBMP8 (fp, pic824, w, h);
00691   else if (nbits == 24) writeBMP24(fp, pic824, w, h);
00692 
00693   if (graypic) free(graypic);
00694 
00695   if (ferror(fp)) return -1;
00696   
00697   return 0;
00698 }
00699 
00700 
00701          
00702          
00703 /*******************************************/
00704 static void writeBMP1(FILE *fp, byte *pic8, int w, int h)
00705 {
00706   int   i,j,c,bitnum,padw;
00707   byte *pp;
00708 
00709   padw = ((w + 31)/32) * 32;  /* 'w', padded to be a multiple of 32 */
00710 
00711   for (i=h-1; i>=0; i--) {
00712     pp = pic8 + (i * w);  
00713 
00714     for (j=bitnum=c=0; j<=padw; j++,bitnum++) {
00715       if (bitnum == 8) { /* write the next byte */
00716        putc(c,fp);
00717        bitnum = c = 0;
00718       }
00719       
00720       c <<= 1;
00721 
00722       if (j<w) {
00723        c |= (pc2nc[*pp++] & 0x01);
00724       }
00725     }
00726   }
00727 }  
00728 
00729 
00730 
00731 /*******************************************/
00732 static void writeBMP4(FILE *fp, byte *pic8, int w, int h)
00733 {
00734   int   i,j,c,nybnum,padw;
00735   byte *pp;
00736 
00737 
00738   padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
00739 
00740   for (i=h-1; i>=0; i--) {
00741     pp = pic8 + (i * w);
00742 
00743     for (j=nybnum=c=0; j<=padw; j++,nybnum++) {
00744       if (nybnum == 2) { /* write next byte */
00745        putc((c&0xff), fp);
00746        nybnum = c = 0;
00747       }
00748 
00749       c <<= 4;
00750 
00751       if (j<w) {
00752        c |= (pc2nc[*pp] & 0x0f);
00753        pp++;
00754       }
00755     }
00756   }
00757 }  
00758 
00759 
00760 
00761 /*******************************************/
00762 static void writeBMP8(FILE *fp, byte *pic8, int w, int h)
00763 {
00764   int   i,j,padw;
00765   byte *pp;
00766 
00767   padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
00768 
00769   for (i=h-1; i>=0; i--) {
00770     pp = pic8 + (i * w);
00771 
00772     for (j=0; j<w; j++) { putc(pc2nc[*pp++], fp); }
00773     for ( ; j<padw; j++) { putc(0, fp); }
00774   }
00775 }  
00776 
00777 
00778 /*******************************************/
00779 static void writeBMP24(FILE *fp, byte *pic24, int w, int h)
00780 {
00781   int   i,j,padb;
00782   byte *pp;
00783 
00784   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to write at EOscanline */
00785 
00786   for (i=h-1; i>=0; i--) {
00787     pp = pic24 + (i * w * 3);
00788 
00789     for (j=0; j<w; j++) {
00790       putc(*pp++, fp);
00791       putc(*pp++, fp);
00792       putc(*pp++, fp);
00793     }
00794 
00795     for (j=0; j<padb; j++) { putc(0, fp); }
00796   }
00797 }  
00798 
00799 
00800 
00801 
00802 
00803 
00804 /*******************************************/
00805 static int bmpError(char *fname, char *st)
00806 {
00807   fprintf(stderr, "wxImage: %s: %s\n", fname, st);
00808   return 0;
00809 }
00810 
00811 
00812