1 /*
2  * xvxbm.c - load routine for X11 Bitmap format pictures
3  *
4  * LoadXBM(fname)  -  loads an X11 Bitmap file\
5  * WriteXBM(fp, pic, w, h)
6  */
7 
8 
9 #include "copyright.h"
10 
11 #include "xv.h"
12 
13 
14 
15 /*
16  * File Format:
17  *   (format identifier:  "#define" as first couple chars in file)
18  *
19  * looks for first line beginning with '#define'
20  *   reads "#define identifier width"  (identifier is ignored)
21  * looks for next line beginning with '#define'
22  *   reads "#define identifier height" (identifier is ignored)
23  * looks for next occurence of characters '0x'
24  *   read next two chars as two hex digits
25  *   move forward to next occurence of '0x'
26  *   repeat
27  */
28 
29 
30 static int xbmError PARM((const char *, const char *));
31 
32 
33 /*******************************************/
LoadXBM(fname,pinfo)34 int LoadXBM(fname, pinfo)
35      char    *fname;
36      PICINFO *pinfo;
37 {
38   /* returns '1' on success */
39 
40   FILE  *fp;
41   int    c, c1;
42   int    i, j, k, bit, w, h;
43   byte  *pix, *pic8;
44   long   filesize;
45   char   line[256], name[256];
46   byte   hex[256];
47   const char  *bname;
48 
49   k = 0;
50 
51   bname = BaseName(fname);
52   fp = xv_fopen(fname,"r");
53   if (!fp) return (xbmError(bname, "couldn't open file"));
54 
55   fseek(fp, 0L, 2);
56   filesize = ftell(fp);
57   fseek(fp, 0L, 0);
58 
59 
60   /* read width:  skip lines until we hit a #define */
61   while (1) {
62     if (!fgets(line,256,fp))
63       return(xbmError(bname, "EOF reached in header info."));
64 
65     if (strncmp(line,"#define",    (size_t) 7)==0 &&
66 	sscanf(line,"#define %s %d", name, &w)==2 &&
67 	xv_strstr(name, "_width") != NULL) break;
68   }
69 
70 
71   /* read height:  skip lines until we hit another #define */
72   while (1) {
73     if (!fgets(line,256,fp))
74       return(xbmError(bname, "EOF reached in header info."));
75 
76     if (strncmp(line,"#define",    (size_t) 7)==0 &&
77 	sscanf(line,"#define %s %d", name, &h)==2 &&
78 	xv_strstr(name, "_height") != NULL) break;
79   }
80 
81 
82 
83   /* scan forward until we see the first '0x' */
84   c = getc(fp);  c1 = getc(fp);
85   while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }
86 
87   if (c1==EOF)
88     return(xbmError(bname, "No bitmap data found"));
89 
90   if (w<1 || h<1 || w>10000 || h>10000)
91     return(xbmError(bname, "not an XBM file"));
92 
93   pic8 = (byte *) calloc((size_t) w*h, (size_t) 1);  /* safe (10^8 max) */
94   if (!pic8) return(xbmError(bname, "couldn't malloc 'pic8'"));
95 
96   /* load up the pinfo structure */
97   pinfo->pic = pic8;
98   pinfo->w = w;
99   pinfo->h = h;
100   pinfo->normw = pinfo->w;   pinfo->normh = pinfo->h;
101   pinfo->type = PIC8;
102   pinfo->frmType = F_XBM;
103   pinfo->colType = F_BWDITHER;
104   sprintf(pinfo->fullInfo, "X11 Bitmap  (%ld bytes)", filesize);
105   sprintf(pinfo->shrtInfo, "%dx%d X11 Bitmap.",w,h);
106   pinfo->comment = (char *) NULL;
107 
108   /* B/W bitmaps have a two entry colormap */
109   pinfo->r[0] = pinfo->g[0] = pinfo->b[0] = 255;     /* 0 = white */
110   pinfo->r[1] = pinfo->g[1] = pinfo->b[1] = 0;       /* 1 = black */
111 
112 
113   /* initialize the 'hex' array for zippy ASCII-hex -> int conversion */
114 
115   for (i=0; i<256; i++) hex[i] = 255;   /* flag 'undefined' chars */
116   for (i='0'; i<='9'; i++) hex[i] = i - '0';
117   for (i='a'; i<='f'; i++) hex[i] = i + 10 - 'a';
118   for (i='A'; i<='F'; i++) hex[i] = i + 10 - 'A';
119 
120   /* read/convert the image data */
121 
122   for (i=0, pix=pic8; i<h; i++)
123     for (j=0,bit=0; j<w; j++, pix++, bit = (bit+1)&7) {
124 
125       if (!bit) {
126 	/* get next byte from file.  we're already positioned at it */
127 	c = getc(fp);  c1 = getc(fp);
128 	if (c<0 || c1<0) {
129 	  /* EOF: break out of loop */
130 	  c=c1='0'; i=h; j=w;
131 	  xbmError(bname, "The file would appear to be truncated.");
132 	}
133 
134 	if (hex[c1] == 255) {
135 	  if (hex[c] == 255) k = 0;   /* no digits after the '0x' ... */
136 	  else k = hex[c];
137 	}
138 	else k = (hex[c] << 4) + hex[c1];
139 
140 	/* advance to next '0x' */
141 	c = getc(fp);  c1 = getc(fp);
142 	while (c1!=EOF && !(c=='0' && c1=='x') ) { c = c1;  c1 = getc(fp); }
143       }
144 
145       *pix = (k&1) ? 1 : 0;
146       k = k >> 1;
147     }
148 
149   fclose(fp);
150 
151   return 1;
152 }
153 
154 
155 
156 /*******************************************/
xbmError(fname,st)157 static int xbmError(fname, st)
158      const char *fname, *st;
159 {
160   SetISTR(ISTR_WARNING,"%s:  %s", fname, st);
161   return 0;
162 }
163 
164 
165 /*******************************************/
WriteXBM(fp,pic,w,h,rmap,gmap,bmap,fname)166 int WriteXBM(fp, pic, w, h, rmap, gmap, bmap, fname)
167      FILE *fp;
168      byte *pic;
169      int   w,h;
170      byte *rmap, *gmap, *bmap;
171      char *fname;
172 {
173   /* pic is expected to be an array of w*h bytes, each of which is either
174      '0' or '1'.
175      The 'darker' of {rmap,gmap,bmap}[0] and {rmap,gmap,bmap}[1] is
176      considered black, and the other one, white.
177      Some sort of stippling algorithm should've
178      been called already to produce pic, otherwise the output won't be at all
179      useful */
180 
181   int   i,j,k,bit,len,nbytes,flipbw;
182   byte *pix;
183   char name[256], *foo;
184 
185   strcpy(name, BaseName(fname));
186 
187   foo = (char *) index(name,'.');
188   if (foo) *foo='\0';                 /* truncated name at first '.' */
189 
190   fprintf(fp,"#define %s_width %d\n",name,w);
191   fprintf(fp,"#define %s_height %d\n",name,h);
192   fprintf(fp,"static char %s_bits[] = {\n",name);
193 
194   fprintf(fp," ");
195 
196   /* set flipbw if color#0 is black */
197   flipbw = (MONO(rmap[0],gmap[0],bmap[0]) < MONO(rmap[1],gmap[1],bmap[1]));
198 
199   nbytes = h * ((w+7)/8);   /* # of bytes to write */
200 
201   for (i=0, len=1, pix=pic; i<h; i++) {
202     for (j=bit=k=0; j<w; j++,pix++) {
203       k = (k>>1);
204       if (*pix) k |= 0x80;
205       bit++;
206       if (bit==8) {
207 	if (flipbw) k = ~k;
208 	fprintf(fp,"0x%02x",(byte) k&0xff);
209 	nbytes--;  len += 4;
210 	if (nbytes) { fprintf(fp,",");  len++; }
211 	if (len>72) { fprintf(fp,"\n ");  len=1; }
212 	bit = k = 0;
213       }
214     }
215 
216     if (bit) {
217       k = k >> (8-bit);
218       if (flipbw) k = ~k;
219       fprintf(fp,"0x%02x",(byte) k&0xff);
220       nbytes--;  len += 4;
221       if (nbytes) { fprintf(fp,",");  len++; }
222       if (len>72) { fprintf(fp,"\n ");  len=1; }
223     }
224   }
225 
226   fprintf(fp,"};\n");
227 
228   if (ferror(fp)) return -1;
229   return 0;
230 }
231 
232 
233 
234