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