1 /********************************************************************************
2 *                                                                               *
3 *                          X B M   I n p u t / O u t p u t                      *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2003,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: fxxbmio.cpp,v 1.14 2005/01/16 16:06:07 fox Exp $                         *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXHash.h"
28 #include "FXStream.h"
29 #include "fxpriv.h"
30 
31 
32 
33 /*
34   Notes:
35   - Support for black and white images.
36   - When writing image, dither output to bilevel.
37   - Hot spot allows using these routines for cursor images.
38   - Should we load (or save) image name?
39 */
40 
41 using namespace FX;
42 
43 
44 /*******************************************************************************/
45 
46 namespace FX {
47 
48 
49 extern FXAPI FXbool fxcheckXBM(FXStream& store);
50 extern FXAPI FXbool fxloadXBM(FXColor*& data,const FXuchar *pix,const FXuchar *msk,FXint width,FXint height);
51 extern FXAPI FXbool fxloadXBM(FXStream& store,FXColor*& data,FXint& width,FXint& height,FXint& hotx,FXint& hoty);
52 extern FXAPI FXbool fxsaveXBM(FXStream& store,const FXColor *data,FXint width,FXint height,FXint hotx=-1,FXint hoty=-1);
53 
54 
55 // Little helper
readline(FXStream & store,FXchar * buffer,FXuint size)56 static void readline(FXStream& store,FXchar* buffer,FXuint size){
57   register FXuint i=0;
58   while(!store.eof() && i<size){
59     store >> buffer[i];
60     if(buffer[i]=='\r') continue;
61     if(buffer[i]=='\n') break;
62     i++;
63     }
64   buffer[i]=0;
65   }
66 
67 
68 // Check if stream contains a XBM
fxcheckXBM(FXStream & store)69 FXbool fxcheckXBM(FXStream& store){
70   FXuchar signature[4];
71   store.load(signature,4);
72   store.position(-4,FXFromCurrent);
73   return signature[0]=='#' && signature[1]=='d' && signature[2]=='e' && signature[3]=='f';
74   }
75 
76 
77 // Load alpha XBM image from pixels and mask
fxloadXBM(FXColor * & data,const FXuchar * pixels,const FXuchar * mask,FXint width,FXint height)78 FXbool fxloadXBM(FXColor*& data,const FXuchar *pixels,const FXuchar *mask,FXint width,FXint height){
79   register FXint x,y,byt,bit,row;
80   data=NULL;
81   if(pixels && mask && 0<width && 0<height){
82     if(FXCALLOC(&data,FXColor,width*height)){
83       row=(width+7)>>3;
84       for(y=0; y<height; y++){
85         for(x=0; x<width; x++){
86           byt=y*row+(x>>3);
87           bit=1<<(x&7);
88           if(mask[byt]&bit){
89             data[y*width+x]|=FXRGBA(0,0,0,255);                                 // Opaque
90             if(!(pixels[byt]&bit)) data[y*width+x]|=FXRGBA(255,255,255,0);      // White
91             }
92           }
93         }
94       return TRUE;
95       }
96     }
97   return FALSE;
98   }
99 
100 
101 // Load image from stream
fxloadXBM(FXStream & store,FXColor * & data,FXint & width,FXint & height,FXint & hotx,FXint & hoty)102 FXbool fxloadXBM(FXStream& store,FXColor*& data,FXint& width,FXint& height,FXint& hotx,FXint& hoty){
103   const FXColor colormap[2]={FXRGB(255,255,255),FXRGB(0,0,0)};
104   FXchar buffer[1024],name[255],ch;
105   FXint  value,i,j;
106   FXColor *pp;
107 
108   // Null out
109   data=NULL;
110   width=0;
111   height=0;
112   hotx=-1;
113   hoty=-1;
114 
115   // Read header
116   while(!store.eof()){
117 
118     // Read buffer
119     readline(store,buffer,sizeof(buffer));
120     while(strstr(buffer,"/*") && !store.eof()){
121       readline(store,buffer,sizeof(buffer));
122       }
123 
124     // Recognize #define
125     if(sscanf(buffer,"#define %s %d",name,&value)==2){
126       if(strstr(name,"width")) width=value;
127       else if(strstr(name,"height")) height=value;
128       else if(strstr(name,"x_hot")) hotx=value;
129       else if(strstr(name,"y_hot")) hoty=value;
130       continue;
131       }
132 
133     // Recognize declaration
134     if(sscanf(buffer,"static unsigned char %s = {",name)==1) break;
135     if(sscanf(buffer,"static char %s = {", name)==1) break;
136     }
137 
138   // Test sensible width, height
139   if(width<=0 || height<=0) return FALSE;
140 
141   // Allocate image to return
142   if(!FXCALLOC(&data,FXColor,width*height)){
143     return FALSE;
144     }
145 
146   // Load image; note we will read a whole number of bytes
147   // for each line, the last byte may not be completely used
148   for(j=0,pp=data; j<height; j++){
149     for(i=0; i<width; i++){
150       if((i&7)==0){
151         value=0;
152         while(!store.eof()){
153           store >> ch;
154           if(ch!='0') continue;
155           store >> ch;
156           if(ch!='x' && ch!='X') continue;
157           break;
158           }
159         while(!store.eof()){
160           store >> ch;
161           if(!isxdigit((FXuchar)ch)) break;
162           value=value*16+(('a'<=ch) ? ch-'a'+10 : ('A'<=ch) ? ch-'A'+10 : ch-'0');
163           }
164         }
165       *pp++=colormap[value&1];
166       value>>=1;
167       }
168     }
169 
170   // We got the image, but we're not done yet; need to read few more bytes
171   // the number of bytes read here must match the number of bytes written
172   // by fxsaveXBM() so that the stream won't get out of sync
173   while(!store.eof()){
174     store >> ch;
175     if(ch=='\n') break;
176     }
177 
178   return TRUE;
179   }
180 
181 
182 /*******************************************************************************/
183 
184 
185 
186 // Save image to a stream
fxsaveXBM(FXStream & store,const FXColor * data,FXint width,FXint height,FXint hotx,FXint hoty)187 FXbool fxsaveXBM(FXStream& store,const FXColor *data,FXint width,FXint height,FXint hotx,FXint hoty){
188   static const FXint dither[4][4]={{0,32768, 8192,40960},{49152,16384,57344,24576},{12288,45056,4096,36864},{61440,28672,53248,20480}};
189   register const FXuchar *ptr=(const FXuchar*)data;
190   register FXint bit,code,count,x,y,n;
191   const char name[]="image";
192   FXchar buffer[128];
193 
194   // Write width
195   n=sprintf(buffer,"#define %s_width %d\n",name,width);
196   store.save(buffer,n);
197 
198   // Write height
199   n=sprintf(buffer,"#define %s_height %d\n",name,height);
200   store.save(buffer,n);
201 
202   // Write hot spot
203   if(0<=hotx && 0<=hoty){
204     n=sprintf(buffer,"#define %s_x_hot %d\n",name,hotx);
205     store.save(buffer,n);
206     n=sprintf(buffer,"#define %s_y_hot %d\n",name,hoty);
207     store.save(buffer,n);
208     }
209 
210   // Write declaration
211   n=sprintf(buffer,"static char %s_bits[] = {",name);
212   store.save(buffer,n);
213 
214   // Write pixels
215   for(y=count=0; y<height; y++){
216     for(x=code=0,bit=1; x<width; x++){
217       if((ptr[0]*77+ptr[1]*151+ptr[2]*29)<dither[y&3][x&3]) code|=bit;
218       bit<<=1;
219       if(bit==256 || x==width-1){
220         if(count){
221           store.save(",",1);
222           }
223         if(count%12==0){
224           store.save("\n   ",3);
225           }
226         n=sprintf(buffer," 0x%02x",code);
227         store.save(buffer,n);
228         bit=1;
229         code=0;
230         count++;
231         }
232       ptr+=4;
233       }
234     }
235 
236   // Wrap it up
237   store.save("};\n",3);
238 
239   return TRUE;
240   }
241 
242 }
243 
244