1 /* -copyright-
2 #-#
3 #-# xsnow: let it snow on your desktop
4 #-# Copyright (C) 1984,1988,1990,1993-1995,2000-2001 Rick Jansen
5 #-# 2019,2020,2021 Willem Vermin
6 #-#
7 #-# This program is free software: you can redistribute it and/or modify
8 #-# it under the terms of the GNU General Public License as published by
9 #-# the Free Software Foundation, either version 3 of the License, or
10 #-# (at your option) any later version.
11 #-#
12 #-# This program is distributed in the hope that it will be useful,
13 #-# but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 #-# GNU General Public License for more details.
16 #-#
17 #-# You should have received a copy of the GNU General Public License
18 #-# along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #-#
20 */
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include "ixpm.h"
26 #include "debug.h"
27 #include "utils.h"
28 // from the xpm package:
xpmCreatePixmapFromImage(Display * display,Drawable d,XImage * ximage,Pixmap * pixmap_return)29 static void xpmCreatePixmapFromImage(
30 Display *display,
31 Drawable d,
32 XImage *ximage,
33 Pixmap *pixmap_return)
34 {
35 GC gc;
36 XGCValues values;
37
38 *pixmap_return = XCreatePixmap(display, d, ximage->width,
39 ximage->height, ximage->depth);
40 /* set fg and bg in case we have an XYBitmap */
41 values.foreground = 1;
42 values.background = 0;
43 gc = XCreateGC(display, *pixmap_return,
44 GCForeground | GCBackground, &values);
45
46 XPutImage(display, *pixmap_return, gc, ximage, 0, 0, 0, 0,
47 ximage->width, ximage->height);
48
49 XFreeGC(display, gc);
50 }
51
paintit(XImage * img,long int color)52 void paintit(XImage *img, long int color)
53 {
54 int x,y;
55 for (y=0; y<img->height; y++)
56 for (x=0; x<img->width; x++)
57 {
58 XPutPixel(img, x,y,color);
59 }
60 }
61
62
63 // reverse characters in string, characters taken in chunks of l
64 // if you know what I mean
strrevert(char * s,size_t l)65 static void strrevert(char*s, size_t l)
66 {
67 assert(l>0);
68 size_t n = strlen(s)/l;
69 size_t i;
70 char *c = (char *)malloc(l*sizeof(*c));
71 char *a = s;
72 char *b = s+strlen(s)-l;
73 for (i=0; i<n/2; i++)
74 {
75 strncpy(c,a,l);
76 strncpy(a,b,l);
77 strncpy(b,c,l);
78 a+=l;
79 b-=l;
80 }
81 free(c);
82 }
83
84 //
85 // equal to XpmCreatePixmapFromData, with extra flags:
86 // flop: if 1, reverse the data horizontally
87 // Extra: 0xff000000 is added to the pixmap data
88 //
iXpmCreatePixmapFromData(Display * display,Drawable d,const char * data[],Pixmap * p,Pixmap * s,XpmAttributes * attr,int flop)89 int iXpmCreatePixmapFromData(Display *display, Drawable d,
90 const char *data[], Pixmap *p, Pixmap *s, XpmAttributes *attr, int flop)
91 {
92 int rc, lines, i, ncolors, height, w;
93 char **idata;
94
95 sscanf(data[0],"%*s %d %d %d", &height, &ncolors, &w);
96 lines = height+ncolors+1;
97 assert(lines>0);
98 idata = (char **)malloc(lines*sizeof(*idata));
99 for (i=0; i<lines; i++)
100 idata[i] = strdup(data[i]);
101 if(flop)
102 // flop the image data
103 for (i=1+ncolors; i<lines; i++)
104 strrevert(idata[i],w);
105
106 XImage *ximage,*shapeimage;
107 rc = XpmCreateImageFromData(display,idata,&ximage,&shapeimage,attr);
108 if (rc != 0)
109 {
110 I("rc from XpmCreateImageFromData: ");
111 switch (rc)
112 {
113 case 1:
114 printf("XpmColorError\n");
115 for (i=0; i<lines; i++)
116 printf("\"%s\",\n",idata[i]);
117 break;
118 case -1:
119 printf("XpmOpenFailed\n");
120 break;
121 case -2:
122 printf("XpmFileInvalid\n");
123 break;
124 case -3:
125 printf("XpmNoMemory: maybe issue with width of data: w=%d\n",w);
126 break;
127 case -4:
128 printf("XpmColorFailed\n");
129 for (i=0; i<lines; i++)
130 printf("\"%s\",\n",idata[i]);
131 break;
132 default:
133 printf("%d\n",rc);
134 break;
135 }
136 printf("exiting\n");
137 fflush(NULL);
138 abort();
139 }
140 XAddPixel(ximage,0xff000000);
141 if(p)
142 xpmCreatePixmapFromImage(display, d, ximage, p);
143 if(s)
144 xpmCreatePixmapFromImage(display, d, shapeimage, s);
145 XDestroyImage(ximage);
146 XDestroyImage(shapeimage);
147 for(i=0; i<lines; i++) free(idata[i]);
148 free(idata);
149 return rc;
150 }
151
152 // given xpmdata **data, add the non-transparent pixels to Region r
regionfromxpm(const char ** data,int flop,float scale)153 Region regionfromxpm(const char **data, int flop, float scale)
154 {
155 (void) scale; // todo gdk_cairo_region_create_from_surface kan worden gebruikt
156 int w,h,nc,n;
157 Region r = XCreateRegion();
158 // width, height, #colors, $chars to code color
159 sscanf(*data,"%d %d %d %d",&w,&h,&nc,&n);
160 // find color "None":
161 int i;
162 char *code = (char *)"";
163 int offset = nc + 1;
164 for(i=1; i<=nc; i++)
165 {
166 char s[100];
167 P("%s\n",data[i]);
168 sscanf(data[i]+n,"%*s %100s",s);
169 P("%s\n",s);
170 if(!strcasecmp(s,"None"))
171 {
172 code = strndup(data[i],n);
173 break;
174 }
175 }
176 XRectangle rect;
177 rect.width = 1;
178 rect.height = 1;
179 int y;
180 for (y=0; y<h; y++)
181 {
182 int x;
183 char*s = strdup(data[y+offset]);
184 if(flop)
185 strrevert(s,n);
186 for(x=0; x<w; x++)
187 {
188 if (strncmp(s+n*x,code,n))
189 {
190 rect.x = x;
191 rect.y = y;
192 XUnionRectWithRegion(&rect,r,r);
193 }
194 }
195 free(s);
196 }
197 free(code);
198 return r;
199 }
200
gregionfromxpm(const char ** data,int flop,float scale)201 cairo_region_t *gregionfromxpm(const char **data, int flop, float scale)
202 {
203 int w,h;
204 sscanf(data[0],"%d %d",&w,&h);
205 P("gregionfromxpm: w:%d h:%d\n",w,h);
206
207 GdkPixbuf *pixbuf;
208 GdkPixbuf *pixbuf1 = gdk_pixbuf_new_from_xpm_data(data);
209 if (flop)
210 {
211 pixbuf = gdk_pixbuf_flip(pixbuf1,1);
212 g_clear_object(&pixbuf1);
213 }
214 else
215 pixbuf = pixbuf1;
216
217 int iw = w*scale; if(iw < 1) iw = 1;
218 int ih = h*scale; if(ih < 1) ih = 1;
219 if (iw == 1 && ih == 1) ih = 2;
220 GdkPixbuf *pixbufscaled = gdk_pixbuf_scale_simple(pixbuf,iw,ih,GDK_INTERP_HYPER);
221 cairo_surface_t *surface = gdk_cairo_surface_create_from_pixbuf (pixbufscaled, 0, NULL);
222 g_clear_object(&pixbuf);
223 g_clear_object(&pixbufscaled);
224
225 cairo_region_t *region = gdk_cairo_region_create_from_surface(surface);
226 cairo_surface_destroy(surface);
227 return region;
228 }
229
230 /*
231 * converts xpm data to bitmap
232 * xpm: input xpm data
233 * bitsreturn: output bitmap, allocated by this function
234 * wreturn: width of bitmap
235 * hreturn: height of bitmap
236 * lreturn: length of bitmap
237 *
238 * Return value: 1: OK, 0: not OK.
239 * BUGS: this code has not been tested on a big endian system
240 */
xpmtobits(char * xpm[],unsigned char ** bitsreturn,int * wreturn,int * hreturn,int * lreturn)241 int xpmtobits(char *xpm[],unsigned char **bitsreturn, int *wreturn, int *hreturn, int *lreturn)
242 {
243 int nc,cpp,w,h;
244
245 unsigned char *bits = (unsigned char*) malloc(sizeof(unsigned char)*1);
246 if (sscanf(xpm[0],"%d %d %d %d",&w,&h,&nc,&cpp)!=4)
247 return 0;
248 if(cpp <=0 || w<0 || h<0 || nc<0)
249 return 0;
250 *wreturn = w;
251 *hreturn = h;
252 int l = ((int)w + 7)/8; // # chars needed for this w
253 *lreturn = l*h;
254 // l*h+1: we do not want allocate 0 bytes
255 bits = (unsigned char*) realloc(bits,sizeof(unsigned char)*(l*h+1));
256 *bitsreturn = bits;
257 int i;
258 for(i=0; i<l*h; i++)
259 bits[i] = 0;
260
261 char *code = (char *)malloc(sizeof(char)*cpp);
262 for (i=0; i<cpp; i++)
263 code[i] = ' ';
264
265 int offset = nc + 1;
266 for(i=1; i<=nc; i++)
267 {
268 char s[100];
269 if (strlen(xpm[i]) > (size_t)cpp + 6)
270 {
271 sscanf(xpm[i]+cpp,"%*s %100s",s);
272 if(!strcasecmp(s,"none"))
273 {
274 free(code);
275 code = strndup(xpm[i],cpp);
276 break;
277 }
278 }
279 }
280 int y;
281 unsigned char c = 0;
282 int j = 0;
283 if (is_little_endian())
284 for (y=0; y<h; y++) // little endian
285 {
286 int x,k=0;
287 const char *s = xpm[y+offset];
288 int l = strlen(s);
289 for(x=0; x<w; x++)
290 {
291 c >>= 1;
292 if (cpp*x + cpp <= l)
293 {
294 if (strncmp(s+cpp*x,code,cpp))
295 c |= 0x80;
296 }
297 k++;
298 if (k == 8)
299 {
300 bits[j++] = c;
301 k = 0;
302 }
303 }
304 if (k)
305 bits[j++] = c>>(8-k);
306 }
307 else
308 for (y=0; y<h; y++) // big endian NOT tested
309 {
310 int x,k=0;
311 const char *s = xpm[y+offset];
312 int l = strlen(s);
313 for(x=0; x<w; x++)
314 {
315 c <<= 1;
316 if (cpp*x + cpp <= l)
317 {
318 if (strncmp(s+cpp*x,code,cpp))
319 c |= 0x01;
320 }
321 k++;
322 if (k == 8)
323 {
324 bits[j++] = c;
325 k = 0;
326 }
327 }
328 if (k)
329 bits[j++] = c<<(8-k);
330 }
331
332 free(code);
333 return 1;
334 }
335
336
337 // given color and xmpdata **data of a monocolored picture like:
338 //
339 //XPM_TYPE *snow06_xpm[] = {
340 ///* columns rows colors chars-per-pixel */
341 //"3 3 2 1 ",
342 //" c none",
343 //". c black",
344 ///* pixels */
345 //". .",
346 //" . ",
347 //". ."
348 //};
349 // change the second color to color and put the result in out.
350 // lines will become the number of lines in out, comes in handy
351 // when wanteing to free out.
xpm_set_color(char ** data,char *** out,int * lines,const char * color)352 void xpm_set_color(char **data, char ***out, int *lines, const char *color)
353 {
354 int n;
355 sscanf(data[0],"%*d %d",&n);
356 assert(n+3>0);
357 *out = (char**)malloc(sizeof(char *)*(n+3));
358 char **x = *out;
359 int j;
360 for (j=0; j<2; j++)
361 x[j] = strdup(data[j]);
362 x[2] = (char *)malloc(5+strlen(color));
363 x[2][0] = '\0';
364 strcat(x[2],". c ");
365 strcat(x[2],color);
366 P("c: [%s]\n",x[2]);
367
368 for (j=3; j<n+3; j++)
369 {
370 x[j] = strdup(data[j]);
371 P("%d %s\n",j,x[j]);
372 }
373 *lines = n+3;
374 }
375
xpm_destroy(char ** data)376 void xpm_destroy(char **data)
377 {
378 int h,nc;
379 sscanf(data[0],"%*d %d %d",&h,&nc);
380 int i;
381 for (i=0; i<h+nc+1; i++)
382 free(data[i]);
383 free(data);
384 }
385
xpm_print(char ** xpm)386 void xpm_print(char **xpm)
387 {
388 int w,h,nc;
389 sscanf(xpm[0],"%d %d %d",&w,&h,&nc);
390 int i,j;
391 printf("%s\n",xpm[0]);
392 for (i=1; i<1+nc; i++)
393 printf("%s\n",xpm[i]);
394 for (i=0; i<2*w+2; i++)
395 printf("_");
396 printf("\n");
397 for (i=0; i<h; i++)
398 {
399 printf("|");
400 for (j=0; j<w; j++)
401 printf("%2c",xpm[i+nc+1][j]);
402 printf("|");
403 printf("\n");
404 }
405 for (i=0; i<2*w+2; i++)
406 printf("-");
407 printf("\n");
408 }
409
410