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