1 /*
2  * xvbmp.c - I/O routines for .BMP files (MS Windows 3.x and later; OS/2)
3  *
4  * LoadBMP(fname, numcols)
5  * WriteBMP(fp, pic, ptype, w, h, r, g, b, numcols, style);
6  */
7 
8 #include "copyright.h"
9 
10 #include "xv.h"
11 
12 /* Comments on error-handling:
13    A truncated file is not considered a Major Error.  The file is loaded,
14    and the rest of the pic is filled with 0's.
15 
16    A file with garbage characters in it is an unloadable file.  All allocated
17    stuff is tossed, and LoadBMP returns non-zero.
18 
19    Not being able to malloc is a Fatal Error.  The program is aborted. */
20 
21 
22 #define BI_RGB       0   /* a.k.a. uncompressed */
23 #define BI_RLE8      1
24 #define BI_RLE4      2
25 #define BI_BITFIELDS 3   /* BMP version 4 */
26 #define BI_JPEG      4   /* BMP version 5 (not yet supported) */
27 #define BI_PNG       5   /* BMP version 5 (not yet supported) */
28 
29 #define WIN_OS2_OLD 12
30 #define WIN_NEW     40
31 #define OS2_NEW     64
32 
33 #if (defined(UINT_MAX) && UINT_MAX != 0xffffffffU)
34 #  error XV's BMP code requires 32-bit unsigned integer type, but u_int isn't
35 #endif
36 
37 static long filesize;
38 
39 static int   loadBMP1   PARM((FILE *, byte *, u_int, u_int));
40 static int   loadBMP4   PARM((FILE *, byte *, u_int, u_int, u_int));
41 static int   loadBMP8   PARM((FILE *, byte *, u_int, u_int, u_int));
42 static int   loadBMP16  PARM((FILE *, byte *, u_int, u_int, u_int *));
43 static int   loadBMP24  PARM((FILE *, byte *, u_int, u_int, u_int));
44 static int   loadBMP32  PARM((FILE *, byte *, u_int, u_int, u_int *));
45 static u_int getshort   PARM((FILE *));
46 static u_int getint     PARM((FILE *));
47 static void  putshort   PARM((FILE *, int));
48 static void  putint     PARM((FILE *, int));
49 static void  writeBMP1  PARM((FILE *, byte *, int, int));
50 static void  writeBMP4  PARM((FILE *, byte *, int, int));
51 static void  writeBMP8  PARM((FILE *, byte *, int, int));
52 static void  writeBMP24 PARM((FILE *, byte *, int, int));
53 static int   bmpError   PARM((const char *, const char *));
54 
55 
56 #define FERROR(fp) (ferror(fp) || feof(fp))
57 
58 /*******************************************/
LoadBMP(fname,pinfo)59 int LoadBMP(fname, pinfo)
60      char    *fname;
61      PICINFO *pinfo;
62 /*******************************************/
63 {
64   FILE       *fp;
65   int        i, c, c1, rv, bPad;
66   u_int      bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
67   u_int      biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
68   u_int      biYPelsPerMeter, biClrUsed, biClrImportant;
69   u_int      colormask[3];
70   char       buf[512], rgb_bits[16];
71   const char *cmpstr, *bname;
72   byte       *pic24, *pic8;
73 
74   /* returns '1' on success */
75 
76   pic8 = pic24 = (byte *) NULL;
77   bname = BaseName(fname);
78 
79   fp = xv_fopen(fname,"r");
80   if (!fp) return (bmpError(bname, "couldn't open file"));
81 
82   fseek(fp, 0L, 2);      /* figure out the file size */
83   filesize = ftell(fp);
84   fseek(fp, 0L, 0);
85 
86 
87   /* read the file type (first two bytes) */
88   c = getc(fp);  c1 = getc(fp);
89   if (c!='B' || c1!='M') { bmpError(bname,"file type != 'BM'"); goto ERROR; }
90 
91   bfSize = getint(fp);
92   getshort(fp);         /* reserved and ignored */
93   getshort(fp);
94   bfOffBits = getint(fp);
95 
96   biSize          = getint(fp);
97 
98   if (biSize == WIN_NEW || biSize == OS2_NEW) {
99     biWidth         = getint(fp);
100     biHeight        = getint(fp);
101     biPlanes        = getshort(fp);
102     biBitCount      = getshort(fp);
103     biCompression   = getint(fp);
104     biSizeImage     = getint(fp);
105     biXPelsPerMeter = getint(fp);
106     biYPelsPerMeter = getint(fp);
107     biClrUsed       = getint(fp);
108     biClrImportant  = getint(fp);
109   }
110   else {    /* old bitmap format */
111     biWidth         = getshort(fp);          /* Types have changed ! */
112     biHeight        = getshort(fp);
113     biPlanes        = getshort(fp);
114     biBitCount      = getshort(fp);
115 
116     /* not in old versions, so have to compute them */
117     biSizeImage = (((biPlanes * biBitCount*biWidth)+31)/32)*4*biHeight;
118 
119     biCompression   = BI_RGB;
120     biXPelsPerMeter = biYPelsPerMeter = 0;
121     biClrUsed       = biClrImportant  = 0;
122   }
123 
124   if (DEBUG>1) {
125     fprintf(stderr,"\nLoadBMP:\tbfSize=%d, bfOffBits=%d\n",bfSize,bfOffBits);
126     fprintf(stderr,"\t\tbiSize=%d, biWidth=%d, biHeight=%d, biPlanes=%d\n",
127 	    biSize, biWidth, biHeight, biPlanes);
128     fprintf(stderr,"\t\tbiBitCount=%d, biCompression=%d, biSizeImage=%d\n",
129 	    biBitCount, biCompression, biSizeImage);
130     fprintf(stderr,"\t\tbiX,YPelsPerMeter=%d,%d  biClrUsed=%d, biClrImp=%d\n",
131 	    biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant);
132   }
133 
134   if (FERROR(fp)) { bmpError(bname,"EOF reached in file header"); goto ERROR; }
135 
136 
137   /* error-checking */
138   if ((biBitCount!=1 && biBitCount!=4 && biBitCount!=8 &&
139        biBitCount!=16 && biBitCount!=24 && biBitCount!=32) ||
140       biPlanes!=1 || biCompression>BI_PNG ||
141       biWidth<=0 || biHeight<=0 ||
142       (biClrUsed && biClrUsed > (1 << biBitCount))) {
143 
144     sprintf(buf,
145 	    "Unsupported BMP type (%dx%d, Bits=%d, Colors=%d, Planes=%d, "
146 	    "Compr=%d)",
147 	    biWidth, biHeight, biBitCount, biClrUsed, biPlanes, biCompression);
148 
149     bmpError(bname, buf);
150     goto ERROR;
151   }
152 
153   if (biCompression>BI_BITFIELDS) {
154     sprintf(buf, "Unsupported BMP compression method (%s)",
155 	    biCompression == BI_JPEG? "JPEG" :
156 	    biCompression == BI_PNG? "PNG" :
157 	    "unknown/newer than v5");
158 
159     bmpError(bname, buf);
160     goto ERROR;
161   }
162 
163   if (((biBitCount==1 || biBitCount==24) && biCompression != BI_RGB) ||
164       (biBitCount==4 && biCompression!=BI_RGB && biCompression!=BI_RLE4) ||
165       (biBitCount==8 && biCompression!=BI_RGB && biCompression!=BI_RLE8) ||
166       ((biBitCount==16 || biBitCount==32) &&
167        biCompression!=BI_RGB && biCompression!=BI_BITFIELDS)) {
168 
169     sprintf(buf,"Unsupported BMP type (bitCount=%d, Compression=%d)",
170 	    biBitCount, biCompression);
171 
172     bmpError(bname, buf);
173     goto ERROR;
174   }
175 
176 
177   bPad = 0;
178   if (biSize != WIN_OS2_OLD) {
179     /* skip ahead to colormap, using biSize */
180     c = biSize - 40;    /* 40 bytes read from biSize to biClrImportant */
181     for (i=0; i<c; i++)
182       getc(fp);
183     bPad = bfOffBits - (biSize + 14);
184   }
185 
186   /* 16-bit or 32-bit color mask */
187   if (biCompression==BI_BITFIELDS) {
188     colormask[0] = getint(fp);
189     colormask[1] = getint(fp);
190     colormask[2] = getint(fp);
191     bPad -= 12;
192   }
193 
194   /* load up colormap, if any */
195   if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8) {
196     int i, cmaplen;
197 
198     cmaplen = (biClrUsed) ? biClrUsed : 1 << biBitCount;
199     for (i=0; i<cmaplen; i++) {
200       pinfo->b[i] = getc(fp);
201       pinfo->g[i] = getc(fp);
202       pinfo->r[i] = getc(fp);
203       if (biSize != WIN_OS2_OLD) {
204 	getc(fp);
205 	bPad -= 4;
206       }
207     }
208 
209     if (FERROR(fp))
210       { bmpError(bname,"EOF reached in BMP colormap"); goto ERROR; }
211 
212     if (DEBUG>1) {
213       fprintf(stderr,"LoadBMP:  BMP colormap:  (RGB order)\n");
214       for (i=0; i<cmaplen; i++) {
215 	fprintf(stderr,"%02x%02x%02x  ", pinfo->r[i],pinfo->g[i],pinfo->b[i]);
216       }
217       fprintf(stderr,"\n\n");
218     }
219   }
220 
221   if (biSize != WIN_OS2_OLD) {
222     /* Waste any unused bytes between the colour map (if present)
223        and the start of the actual bitmap data. */
224 
225     while (bPad > 0) {
226       (void) getc(fp);
227       bPad--;
228     }
229   }
230 
231   /* create pic8 or pic24 */
232 
233   if (biBitCount==16 || biBitCount==24 || biBitCount==32) {
234     u_int npixels = biWidth * biHeight;
235     u_int count = 3 * npixels;
236 
237     if (biWidth == 0 || biHeight == 0 || npixels/biWidth != biHeight ||
238         count/3 != npixels)
239       return (bmpError(bname, "image dimensions too large"));
240     pic24 = (byte *) calloc((size_t) count, (size_t) 1);
241     if (!pic24) return (bmpError(bname, "couldn't malloc 'pic24'"));
242   }
243   else {
244     u_int npixels = biWidth * biHeight;
245 
246     if (biWidth == 0 || biHeight == 0 || npixels/biWidth != biHeight)
247       return (bmpError(bname, "image dimensions too large"));
248     pic8 = (byte *) calloc((size_t) npixels, (size_t) 1);
249     if (!pic8) return(bmpError(bname, "couldn't malloc 'pic8'"));
250   }
251 
252   WaitCursor();
253 
254   /* load up the image */
255   switch (biBitCount) {
256   case 1:
257     rv = loadBMP1(fp, pic8, biWidth, biHeight);
258     break;
259   case 4:
260     rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression);
261     break;
262   case 8:
263     rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression);
264     break;
265   case 16:
266     rv = loadBMP16(fp, pic24, biWidth, biHeight,           /*  v-- BI_RGB */
267                    biCompression == BI_BITFIELDS? colormask : NULL);
268     break;
269   default:
270     if (biBitCount == 32 && biCompression == BI_BITFIELDS)
271       rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask);
272     else /* 24 or (32 and BI_RGB) */
273       rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount);
274     break;
275   }
276 
277   if (rv) bmpError(bname, "File appears truncated.  Winging it.");
278 
279 
280   fclose(fp);
281 
282 
283   if (biBitCount > 8) {
284     pinfo->pic  = pic24;
285     pinfo->type = PIC24;
286   }
287   else {
288     pinfo->pic  = pic8;
289     pinfo->type = PIC8;
290   }
291 
292   cmpstr = "";
293   if      (biCompression == BI_RLE4) cmpstr = ", RLE4 compressed";
294   else if (biCompression == BI_RLE8) cmpstr = ", RLE8 compressed";
295   else if (biCompression == BI_BITFIELDS) {
296     int    bit, c[3], i;
297     u_int  mask;
298 
299     for (i = 0; i < 3; ++i) {
300       mask = colormask[i];
301       c[i] = 0;
302       for (bit = 0; bit < 32; ++bit) {
303         if (mask & 1)
304           ++c[i];
305         mask >>= 1;
306       }
307     }
308     sprintf(rgb_bits, ", RGB%d%d%d", c[0], c[1], c[2]);
309     cmpstr = rgb_bits;
310   }
311 
312   pinfo->w = biWidth;  pinfo->h = biHeight;
313   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
314   pinfo->frmType = F_BMP;
315   pinfo->colType = F_FULLCOLOR;
316 
317   sprintf(pinfo->fullInfo, "%sBMP, %d bit%s per pixel%s.  (%ld bytes)",
318 	  ((biSize==WIN_OS2_OLD) ? "Old OS/2 " :
319 	   (biSize==WIN_NEW)     ? "Windows "  : ""),
320 	  biBitCount,  (biBitCount == 1) ? "" : "s",
321 	  cmpstr, filesize);
322 
323   sprintf(pinfo->shrtInfo, "%dx%d BMP.", biWidth, biHeight);
324   pinfo->comment = (char *) NULL;
325 
326   return 1;
327 
328 
329  ERROR:
330   fclose(fp);
331   return 0;
332 }
333 
334 
335 /*******************************************/
loadBMP1(fp,pic8,w,h)336 static int loadBMP1(fp, pic8, w, h)
337      FILE *fp;
338      byte *pic8;
339      u_int  w,h;
340 {
341   int   i,j,c,bitnum,padw;
342   byte *pp = pic8 + ((h - 1) * w);
343   size_t l = w*h;
344 
345   c = 0;
346   padw = ((w + 31)/32) * 32;  /* 'w', padded to be a multiple of 32 */
347 
348   for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
349     pp = pic8 + (i * w);
350     if ((i&0x3f)==0) WaitCursor();
351     for (j=bitnum=0; j<padw; j++,bitnum++) {
352       if ((bitnum&7) == 0) { /* read the next byte */
353 	c = getc(fp);
354 	bitnum = 0;
355       }
356 
357       if (j<w) {
358 	*pp++ = (c & 0x80) ? 1 : 0;
359 	c <<= 1;
360       }
361     }
362     if (FERROR(fp)) break;
363   }
364 
365   return (FERROR(fp));
366 }
367 
368 
369 
370 /*******************************************/
loadBMP4(fp,pic8,w,h,comp)371 static int loadBMP4(fp, pic8, w, h, comp)
372      FILE *fp;
373      byte *pic8;
374      u_int  w,h,comp;
375 {
376   int   i,j,c,c1,x,y,nybnum,padw,rv;
377   byte *pp = pic8 + ((h - 1) * w);
378   size_t l = w*h;
379 
380   rv = 0;
381   c = c1 = 0;
382 
383   if (comp == BI_RGB) {   /* read uncompressed data */
384     padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
385 
386     for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
387       pp = pic8 + (i * w);
388       if ((i&0x3f)==0) WaitCursor();
389 
390       for (j=nybnum=0; j<padw; j++,nybnum++) {
391 	if ((nybnum & 1) == 0) { /* read next byte */
392 	  c = getc(fp);
393 	  nybnum = 0;
394 	}
395 
396 	if (j<w) {
397 	  *pp++ = (c & 0xf0) >> 4;
398 	  c <<= 4;
399 	}
400       }
401       if (FERROR(fp)) break;
402     }
403   }
404 
405   else if (comp == BI_RLE4) {  /* read RLE4 compressed data */
406     x = y = 0;
407     pp = pic8 + x + (h-y-1)*w;
408 
409     while (y<h) {
410       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
411 
412       if (c) {                                   /* encoded mode */
413 	c1 = getc(fp);
414 	for (i=0; i<c && (pp - pic8 <= l); i++,x++,pp++)
415 	  *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
416       }
417 
418       else {    /* c==0x00  :  escape codes */
419 	c = getc(fp);  if (c == EOF) { rv = 1;  break; }
420 
421 	if      (c == 0x00) {                    /* end of line */
422 	  x=0;  y++;  pp = pic8 + x + (h-y-1)*w;
423 	}
424 
425 	else if (c == 0x01) break;               /* end of pic8 */
426 
427 	else if (c == 0x02) {                    /* delta */
428 	  c = getc(fp);  x += c;
429 	  c = getc(fp);  y += c;
430 	  pp = pic8 + x + (h-y-1)*w;
431 	}
432 
433 	else {                                   /* absolute mode */
434 	  for (i=0; i<c && (pp - pic8 <= l); i++, x++, pp++) {
435 	    if ((i&1) == 0) c1 = getc(fp);
436 	    *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f);
437 	  }
438 
439 	  if (((c&3)==1) || ((c&3)==2)) getc(fp);  /* read pad byte */
440 	}
441       }  /* escape processing */
442       if (FERROR(fp)) break;
443     }  /* while */
444   }
445 
446   else {
447     fprintf(stderr,"unknown BMP compression type 0x%0x\n", comp);
448   }
449 
450   if (FERROR(fp)) rv = 1;
451   return rv;
452 }
453 
454 
455 
456 /*******************************************/
loadBMP8(fp,pic8,w,h,comp)457 static int loadBMP8(fp, pic8, w, h, comp)
458      FILE *fp;
459      byte *pic8;
460      u_int  w,h,comp;
461 {
462   int   i,j,c,c1,padw,x,y,rv;
463   byte *pp = pic8 + ((h - 1) * w);
464   size_t l = w*h;
465   byte *pend;
466 
467   rv = 0;
468 
469   pend = pic8 + w * h;
470 
471   if (comp == BI_RGB) {   /* read uncompressed data */
472     padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
473 
474     for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
475       pp = pic8 + (i * w);
476       if ((i&0x3f)==0) WaitCursor();
477 
478       for (j=0; j<padw; j++) {
479 	c = getc(fp);  if (c==EOF) rv = 1;
480 	if (j<w) *pp++ = c;
481       }
482       if (FERROR(fp)) break;
483     }
484   }
485 
486   else if (comp == BI_RLE8) {  /* read RLE8 compressed data */
487     x = y = 0;
488     pp = pic8 + x + (h-y-1)*w;
489 
490     while (y<h && pp<=pend) {
491       c = getc(fp);  if (c == EOF) { rv = 1;  break; }
492 
493       if (c) {                                   /* encoded mode */
494 	c1 = getc(fp);
495 	for (i=0; i<c && pp<=pend; i++,x++,pp++) *pp = c1;
496       }
497 
498       else {    /* c==0x00  :  escape codes */
499 	c = getc(fp);  if (c == EOF) { rv = 1;  break; }
500 
501 	if      (c == 0x00) {                    /* end of line */
502 	  x=0;  y++;  pp = pic8 + x + (h-y-1)*w;
503 	}
504 
505 	else if (c == 0x01) break;               /* end of pic8 */
506 
507 	else if (c == 0x02) {                    /* delta */
508 	  c = getc(fp);  x += c;
509 	  c = getc(fp);  y += c;
510 	  pp = pic8 + x + (h-y-1)*w;
511 	}
512 
513 	else {                                   /* absolute mode */
514 	  for (i=0; i<c && pp<=pend; i++, x++, pp++) {
515 	    c1 = getc(fp);
516 	    *pp = c1;
517 	  }
518 
519 	  if (c & 1) getc(fp);  /* odd length run: read an extra pad byte */
520 	}
521       }  /* escape processing */
522       if (FERROR(fp)) break;
523     }  /* while */
524   }
525 
526   else {
527     fprintf(stderr,"unknown BMP compression type 0x%0x\n", comp);
528   }
529 
530   if (FERROR(fp)) rv = 1;
531   return rv;
532 }
533 
534 
535 
536 /*******************************************/
loadBMP16(fp,pic24,w,h,mask)537 static int loadBMP16(fp, pic24, w, h, mask)
538      FILE  *fp;
539      byte  *pic24;
540      u_int w, h, *mask;
541 {
542   int	 x, y;
543   byte	*pp = pic24 + ((h - 1) * w * 3);
544   size_t l = w*h*3;
545   u_int	 buf, colormask[6];
546   int	 i, bit, bitshift[6], colorbits[6], bitshift2[6];
547 
548   if (mask == NULL) {  /* RGB555 */
549     colormask[0] = 0x00007c00;
550     colormask[1] = 0x000003e0;
551     colormask[2] = 0x0000001f;
552     colormask[3] = 0x7c000000;
553     colormask[4] = 0x03e00000;
554     colormask[5] = 0x001f0000;
555     bitshift[0] =  7;	bitshift2[0] = 0;
556     bitshift[1] =  2;	bitshift2[1] = 0;
557     bitshift[2] =  0;	bitshift2[2] = 3;
558     bitshift[3] = 23;	bitshift2[3] = 0;
559     bitshift[4] = 18;	bitshift2[4] = 0;
560     bitshift[5] = 13;	bitshift2[5] = 0;
561   } else {
562     colormask[0] = mask[0];
563     colormask[1] = mask[1];
564     colormask[2] = mask[2];
565     colormask[3] = (mask[0] & 0xffff) << 16;
566     colormask[4] = (mask[1] & 0xffff) << 16;
567     colormask[5] = (mask[2] & 0xffff) << 16;
568 
569     for (i = 0; i < 3; ++i) {
570       buf = colormask[i];
571 
572       bitshift[i] = 0;
573       for (bit = 0; bit < 32; ++bit) {
574 	if (buf & 1)
575 	  break;
576 	else
577 	  ++bitshift[i];
578 	buf >>= 1;
579       }
580       bitshift[i+3] = bitshift[i] + 16;
581 
582       colorbits[i] = 0;
583       for (; bit < 32; ++bit) {
584 	if (buf & 1)
585 	  ++colorbits[i];
586 	else
587 	  break;
588 	buf >>= 1;
589       }
590       if (colorbits[i] > 8) { /* over 8-bit depth */
591 	bitshift[i] += (colorbits[i] - 8);
592 	bitshift[i+3] = bitshift[i] + 16;
593 	bitshift2[i] = bitshift2[i+3] = 0;
594       } else
595 	bitshift2[i] = bitshift2[i+3] = 8 - colorbits[i];
596     }
597   }
598 
599   if (DEBUG > 1)
600     fprintf(stderr, "loadBMP16: bitfields\n"
601 	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
602 	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
603 	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
604 	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n"
605 	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
606 	    "\t             (mask = %08x, shift >>%2d, <<%2d)\n",
607 	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
608 	    colormask[3], bitshift[3], bitshift2[3],
609 	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
610 	    colormask[4], bitshift[4], bitshift2[4],
611 	    colorbits[2], colormask[2], bitshift[2], bitshift2[2],
612 	    colormask[5], bitshift[5], bitshift2[5]);
613 
614   for (y = h-1; y >= 0 && (pp - pic24 <= l); y--) {
615     pp = pic24 + (3 * w * y);
616     if ((y&0x3f)==0) WaitCursor();
617 
618     for (x = w; x > 1; x -= 2) {
619       buf = getint(fp);
620       *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
621       *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
622       *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
623       *(pp++) = (buf & colormask[3]) >> bitshift[3] << bitshift2[3];
624       *(pp++) = (buf & colormask[4]) >> bitshift[4] << bitshift2[4];
625       *(pp++) = (buf & colormask[5]) >> bitshift[5] << bitshift2[5];
626     }
627     if (w & 1) { /* padded to 2 pix */
628       buf = getint(fp);
629       *(pp++) = (buf & colormask[0]) >> bitshift[0];
630       *(pp++) = (buf & colormask[1]) >> bitshift[1];
631       *(pp++) = (buf & colormask[2]) >> bitshift[2];
632     }
633   }
634 
635   return FERROR(fp)? 1 : 0;
636 }
637 
638 
639 
640 /*******************************************/
loadBMP24(fp,pic24,w,h,bits)641 static int loadBMP24(fp, pic24, w, h, bits)   /* also handles 32-bit BI_RGB */
642      FILE *fp;
643      byte *pic24;
644      u_int  w,h, bits;
645 {
646   int   i,j,padb,rv;
647   byte *pp = pic24 + ((h - 1) * w * 3);
648   size_t l = w*h*3;
649 
650   rv = 0;
651 
652   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to read at EOscanline */
653   if (bits==32) padb = 0;
654 
655   for (i=h-1; i>=0; i--) {
656     pp = pic24 + (i * w * 3);
657     if ((i&0x3f)==0) WaitCursor();
658 
659     for (j=0; j<w && (pp - pic24 <= l); j++) {
660       pp[2] = getc(fp);   /* blue */
661       pp[1] = getc(fp);   /* green */
662       pp[0] = getc(fp);   /* red */
663       if (bits==32) getc(fp);
664       pp += 3;
665     }
666 
667     for (j=0; j<padb; j++) getc(fp);
668 
669     rv = (FERROR(fp));
670     if (rv) break;
671   }
672 
673   return rv;
674 }
675 
676 
677 
678 /*******************************************/
loadBMP32(fp,pic24,w,h,colormask)679 static int loadBMP32(fp, pic24, w, h, colormask) /* 32-bit BI_BITFIELDS only */
680      FILE  *fp;
681      byte  *pic24;
682      u_int w, h, *colormask;
683 {
684   int	 x, y;
685   byte	*pp;
686   u_int	 buf;
687   int	 i, bit, bitshift[3], colorbits[3], bitshift2[3];
688 
689   for (i = 0; i < 3; ++i) {
690     buf = colormask[i];
691 
692     bitshift[i] = 0;
693     for (bit = 0; bit < 32; ++bit) {
694       if (buf & 1)
695 	break;
696       else
697 	++bitshift[i];
698       buf >>= 1;
699     }
700 
701     colorbits[i] = 0;
702     for (; bit < 32; ++bit) {
703       if (buf & 1)
704 	++colorbits[i];
705       else
706 	break;
707       buf >>= 1;
708     }
709     if (colorbits[i] > 8) {  /* over 8-bit depth */
710       bitshift[i] += (colorbits[i] - 8);
711       bitshift2[i] = 0;
712     } else
713       bitshift2[i] = 8 - colorbits[i];
714   }
715 
716   if (DEBUG > 1)
717     fprintf(stderr, "loadBMP32: bitfields\n"
718 	    "\tR: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
719 	    "\tG: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n"
720 	    "\tB: bits = %2d, mask = %08x, shift >>%2d, <<%2d\n",
721 	    colorbits[0], colormask[0], bitshift[0], bitshift2[0],
722 	    colorbits[1], colormask[1], bitshift[1], bitshift2[1],
723 	    colorbits[2], colormask[2], bitshift[2], bitshift2[2]);
724 
725   for (y = h-1; y >= 0; y--) {
726     pp = pic24 + (3 * w * y);
727     if ((y&0x3f)==0) WaitCursor();
728 
729     for(x = w; x > 0; x --) {
730       buf = getint(fp);
731       *(pp++) = (buf & colormask[0]) >> bitshift[0] << bitshift2[0];
732       *(pp++) = (buf & colormask[1]) >> bitshift[1] << bitshift2[1];
733       *(pp++) = (buf & colormask[2]) >> bitshift[2] << bitshift2[2];
734     }
735   }
736 
737   return FERROR(fp)? 1 : 0;
738 }
739 
740 
741 
742 /*******************************************/
getshort(fp)743 static u_int getshort(fp)
744      FILE *fp;
745 {
746   int c, c1;
747   c = getc(fp);  c1 = getc(fp);
748   return ((u_int) c) + (((u_int) c1) << 8);
749 }
750 
751 
752 /*******************************************/
getint(fp)753 static u_int getint(fp)
754      FILE *fp;
755 {
756   int c, c1, c2, c3;
757   c = getc(fp);  c1 = getc(fp);  c2 = getc(fp);  c3 = getc(fp);
758   return  ((u_int) c) +
759 	 (((u_int) c1) << 8) +
760 	 (((u_int) c2) << 16) +
761 	 (((u_int) c3) << 24);
762 }
763 
764 
765 /*******************************************/
putshort(fp,i)766 static void putshort(fp, i)
767      FILE *fp;
768      int i;
769 {
770   int c, c1;
771 
772   c = ((u_int) i) & 0xff;  c1 = (((u_int) i)>>8) & 0xff;
773   putc(c, fp);   putc(c1,fp);
774 }
775 
776 
777 /*******************************************/
putint(fp,i)778 static void putint(fp, i)
779      FILE *fp;
780      int i;
781 {
782   int c, c1, c2, c3;
783   c  =  ((u_int) i)      & 0xff;
784   c1 = (((u_int) i)>>8)  & 0xff;
785   c2 = (((u_int) i)>>16) & 0xff;
786   c3 = (((u_int) i)>>24) & 0xff;
787 
788   putc(c, fp);   putc(c1,fp);  putc(c2,fp);  putc(c3,fp);
789 }
790 
791 
792 
793 
794 static byte pc2nc[256],r1[256],g1[256],b1[256];
795 
796 
797 /*******************************************/
WriteBMP(fp,pic824,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle)798 int WriteBMP(fp,pic824,ptype,w,h,rmap,gmap,bmap,numcols,colorstyle)
799      FILE *fp;
800      byte *pic824;
801      int   ptype,w,h;
802      byte *rmap, *gmap, *bmap;
803      int   numcols, colorstyle;
804 {
805   /*
806    * if PIC8, and colorstyle == F_FULLCOLOR, F_GREYSCALE, or F_REDUCED,
807    * the program writes an uncompressed 4- or 8-bit image (depending on
808    * the value of numcols)
809    *
810    * if PIC24, and colorstyle == F_FULLCOLOR, program writes an uncompressed
811    *    24-bit image
812    * if PIC24 and colorstyle = F_GREYSCALE, program writes an uncompressed
813    *    8-bit image
814    * note that PIC24 and F_BWDITHER/F_REDUCED won't happen
815    *
816    * if colorstyle == F_BWDITHER, it writes a 1-bit image
817    *
818    */
819 
820   int i,j, nc, nbits, bperlin, cmaplen, npixels;
821   byte *graypic, *sp, *dp, graymap[256];
822 
823   nc = nbits = cmaplen = 0;
824   graypic = NULL;
825 
826   if (ptype == PIC24 && colorstyle == F_GREYSCALE) {
827     /* generate a faked 8-bit per pixel image with a grayscale cmap,
828        so that it can just fall through existing 8-bit code */
829 
830     npixels = w * h;
831     if (w <= 0 || h <= 0 || npixels/w != h) {
832       SetISTR(ISTR_WARNING, "image dimensions too large");
833       return -1;
834     }
835 
836     graypic = (byte *) malloc((size_t) npixels);
837     if (!graypic) FatalError("unable to malloc in WriteBMP()");
838 
839     for (i=0,sp=pic824,dp=graypic; i<npixels; i++,sp+=3, dp++) {
840       *dp = MONO(sp[0],sp[1],sp[2]);
841     }
842 
843     for (i=0; i<256; i++) graymap[i] = i;
844     rmap = gmap = bmap = graymap;
845     numcols = 256;
846     ptype = PIC8;
847 
848     pic824 = graypic;
849   }
850 
851 
852   if (ptype == PIC24) {  /* is F_FULLCOLOR */
853     nbits = 24;
854     cmaplen = 0;
855     nc = 0;
856   }
857 
858   else if (ptype == PIC8) {
859     /* we may have duplicate colors in the colormap, and we'd prefer not to.
860      * build r1,g1,b1 (a contiguous, minimum set colormap), and pc2nc[], a
861      * array that maps 'pic8' values (0-numcols) into corresponding values
862      * in the r1,g1,b1 colormaps (0-nc)
863      */
864 
865     for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; }
866 
867     nc = 0;
868     for (i=0; i<numcols; i++) {
869       /* see if color #i is a duplicate */
870       for (j=0; j<i; j++) {
871 	if (rmap[i] == rmap[j] && gmap[i] == gmap[j] &&
872 	    bmap[i] == bmap[j]) break;
873       }
874 
875       if (j==i) {  /* wasn't found */
876 	pc2nc[i] = nc;
877 	r1[nc] = rmap[i];
878 	g1[nc] = gmap[i];
879 	b1[nc] = bmap[i];
880 	nc++;
881       }
882       else pc2nc[i] = pc2nc[j];
883     }
884 
885     /* determine how many bits per pixel we'll be writing */
886     if (colorstyle == F_BWDITHER || nc <= 2) nbits = 1;
887     else if (nc<=16) nbits = 4;
888     else nbits = 8;
889 
890     cmaplen = 1<<nbits;                      /* # of entries in cmap */
891   }
892 
893 
894   bperlin = ((w * nbits + 31) / 32) * 4;   /* # bytes written per line */
895 
896   putc('B', fp);  putc('M', fp);           /* BMP file magic number */
897 
898   /* compute filesize and write it */
899   i = 14 +                /* size of bitmap file header */
900       40 +                /* size of bitmap info header */
901       (nc * 4) +          /* size of colormap */
902       bperlin * h;        /* size of image data */
903 
904   putint(fp, i);
905   putshort(fp, 0);        /* reserved1 */
906   putshort(fp, 0);        /* reserved2 */
907   putint(fp, 14 + 40 + (nc * 4));  /* offset from BOfile to BObitmap */
908 
909   putint(fp, 40);         /* biSize: size of bitmap info header */
910   putint(fp, w);          /* biWidth */
911   putint(fp, h);          /* biHeight */
912   putshort(fp, 1);        /* biPlanes:  must be '1' */
913   putshort(fp, nbits);    /* biBitCount: 1,4,8, or 24 */
914   putint(fp, BI_RGB);     /* biCompression:  BI_RGB, BI_RLE8 or BI_RLE4 */
915   putint(fp, bperlin*h);  /* biSizeImage:  size of raw image data */
916   putint(fp, 75 * 39);    /* biXPelsPerMeter: (75dpi * 39" per meter) */
917   putint(fp, 75 * 39);    /* biYPelsPerMeter: (75dpi * 39" per meter) */
918   putint(fp, nc);         /* biClrUsed: # of colors used in cmap */
919   putint(fp, nc);         /* biClrImportant: same as above */
920 
921 
922   /* write out the colormap */
923   for (i=0; i<nc; i++) {
924     if (colorstyle == F_GREYSCALE) {
925       j = MONO(r1[i],g1[i],b1[i]);
926       putc(j,fp);  putc(j,fp);  putc(j,fp);  putc(0,fp);
927     }
928     else {
929       putc(b1[i],fp);
930       putc(g1[i],fp);
931       putc(r1[i],fp);
932       putc(0,fp);
933     }
934   }
935 
936   /* write out the image */
937   if      (nbits ==  1) writeBMP1 (fp, pic824, w, h);
938   else if (nbits ==  4) writeBMP4 (fp, pic824, w, h);
939   else if (nbits ==  8) writeBMP8 (fp, pic824, w, h);
940   else if (nbits == 24) writeBMP24(fp, pic824, w, h);
941 
942   if (graypic) free(graypic);
943 
944 #ifndef VMS
945   if (FERROR(fp)) return -1;
946 #else
947   if (!FERROR(fp)) return -1;
948 #endif
949 
950   return 0;
951 }
952 
953 
954 
955 
956 /*******************************************/
writeBMP1(fp,pic8,w,h)957 static void writeBMP1(fp, pic8, w, h)
958      FILE *fp;
959      byte *pic8;
960      int  w,h;
961 {
962   int   i,j,c,bitnum,padw;
963   byte *pp;
964 
965   padw = ((w + 31)/32) * 32;  /* 'w', padded to be a multiple of 32 */
966 
967   for (i=h-1; i>=0; i--) {
968     pp = pic8 + (i * w);
969     if ((i&0x3f)==0) WaitCursor();
970 
971     for (j=bitnum=c=0; j<=padw; j++,bitnum++) {
972       if (bitnum == 8) { /* write the next byte */
973 	putc(c,fp);
974 	bitnum = c = 0;
975       }
976 
977       c <<= 1;
978 
979       if (j<w) {
980 	c |= (pc2nc[*pp++] & 0x01);
981       }
982     }
983   }
984 }
985 
986 
987 
988 /*******************************************/
writeBMP4(fp,pic8,w,h)989 static void writeBMP4(fp, pic8, w, h)
990      FILE *fp;
991      byte *pic8;
992      int  w,h;
993 {
994   int   i,j,c,nybnum,padw;
995   byte *pp;
996 
997 
998   padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
999 
1000   for (i=h-1; i>=0; i--) {
1001     pp = pic8 + (i * w);
1002     if ((i&0x3f)==0) WaitCursor();
1003 
1004     for (j=nybnum=c=0; j<=padw; j++,nybnum++) {
1005       if (nybnum == 2) { /* write next byte */
1006 	putc((c&0xff), fp);
1007 	nybnum = c = 0;
1008       }
1009 
1010       c <<= 4;
1011 
1012       if (j<w) {
1013 	c |= (pc2nc[*pp] & 0x0f);
1014 	pp++;
1015       }
1016     }
1017   }
1018 }
1019 
1020 
1021 
1022 /*******************************************/
writeBMP8(fp,pic8,w,h)1023 static void writeBMP8(fp, pic8, w, h)
1024      FILE *fp;
1025      byte *pic8;
1026      int  w,h;
1027 {
1028   int   i,j,padw;
1029   byte *pp;
1030 
1031   padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
1032 
1033   for (i=h-1; i>=0; i--) {
1034     pp = pic8 + (i * w);
1035     if ((i&0x3f)==0) WaitCursor();
1036 
1037     for (j=0; j<w; j++) putc(pc2nc[*pp++], fp);
1038     for ( ; j<padw; j++) putc(0, fp);
1039   }
1040 }
1041 
1042 
1043 /*******************************************/
writeBMP24(fp,pic24,w,h)1044 static void writeBMP24(fp, pic24, w, h)
1045      FILE *fp;
1046      byte *pic24;
1047      int  w,h;
1048 {
1049   int   i,j,padb;
1050   byte *pp;
1051 
1052   padb = (4 - ((w*3) % 4)) & 0x03;  /* # of pad bytes to write at EOscanline */
1053 
1054   for (i=h-1; i>=0; i--) {
1055     pp = pic24 + (i * w * 3);
1056     if ((i&0x3f)==0) WaitCursor();
1057 
1058     for (j=0; j<w; j++) {
1059       putc(pp[2], fp);
1060       putc(pp[1], fp);
1061       putc(pp[0], fp);
1062       pp += 3;
1063     }
1064 
1065     for (j=0; j<padb; j++) putc(0, fp);
1066   }
1067 }
1068 
1069 
1070 
1071 
1072 
1073 
1074 /*******************************************/
bmpError(fname,st)1075 static int bmpError(fname, st)
1076      const char *fname, *st;
1077 {
1078   SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
1079   return 0;
1080 }
1081 
1082 
1083 
1084