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