1 /* xpm-ximage.c --- converts XPM data to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 1998-2016 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * Alpha channel support by Eric Lassauge <lassauge@users.sourceforge.net>
25 # include <X11/Xlib.h>
28 #include "xpm-ximage.h"
31 # include "grabscreen.h" /* for osx_load_image_file() */
34 extern char *progname;
37 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
41 union { int i; char c[sizeof(int)]; } u;
45 #endif /* HAVE_GDK_PIXBUF || HAVE_XPM */
48 #if defined(HAVE_GDK_PIXBUF)
50 # include <gdk-pixbuf/gdk-pixbuf.h>
53 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
54 # else /* !HAVE_GTK2 */
55 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
56 # endif /* !HAVE_GTK2 */
59 /* Returns an XImage structure containing the bits of the given XPM image.
60 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
61 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
63 The Display and Visual arguments are used only for creating the XImage;
64 no bits are pushed to the server.
66 The Colormap argument is used just for parsing color names; no colors
69 This is the gdk_pixbuf version of this function.
72 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
77 static int initted = 0;
85 #if !GLIB_CHECK_VERSION(2, 36 ,0)
89 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
90 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
96 ? gdk_pixbuf_new_from_file (filename, &gerr)
98 ? gdk_pixbuf_new_from_file (filename)
99 #endif /* HAVE_GTK2 */
100 : gdk_pixbuf_new_from_xpm_data ((const char **) xpm_data));
104 int w = gdk_pixbuf_get_width (pb);
105 int h = gdk_pixbuf_get_height (pb);
106 guchar *row = gdk_pixbuf_get_pixels (pb);
107 int stride = gdk_pixbuf_get_rowstride (pb);
108 int chan = gdk_pixbuf_get_n_channels (pb);
111 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
112 image->data = (char *) malloc(h * image->bytes_per_line);
114 /* Set the bit order in the XImage structure to whatever the
115 local host's native bit order is.
117 image->bitmap_bit_order =
119 (bigendian() ? MSBFirst : LSBFirst);
124 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
128 for (y = 0; y < h; y++)
130 int y2 = (h-1-y); /* Texture maps are upside down. */
133 for (x = 0; x < w; x++)
135 unsigned long rgba = 0;
138 rgba = ((0xFF << 24) |
145 rgba = ((0xFF << 24) |
152 rgba = ((i[3] << 24) |
162 XPutPixel (image, x, y2, rgba);
167 /* #### are colors getting freed here? */
175 fprintf (stderr, "%s: %s\n", progname, gerr->message);
178 fprintf (stderr, "%s: unable to load %s\n", progname, filename);
179 #endif /* HAVE_GTK2 */
184 fprintf (stderr, "%s: unable to initialize builtin texture\n", progname);
190 #elif defined(HAVE_XPM)
195 #include <X11/Intrinsic.h>
197 #include <X11/Xutil.h>
201 #define countof(x) (sizeof((x))/sizeof((*x)))
205 /* The libxpm version of this function...
208 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
209 const char *filename, char **xpm_data)
211 /* All we want to do is get RGB data out of the XPM file built in to this
212 program. This is a pain, because there is no way (as of XPM version
213 4.6, at least) to get libXpm to make an XImage without also allocating
214 colors with XAllocColor. So, instead, we create an XpmImage and parse
215 out the RGB values of the pixels ourselves; and construct an XImage
216 by hand. Regardless of the depth of the visual we're using, this
217 XImage will have 32 bits per pixel, 8 each per R, G, and B. We put
218 0xFF or 0x00 in the fourth (alpha) slot, depending on the file's mask.
224 int transparent_color_index = -1;
229 memset (&xpm_image, 0, sizeof(xpm_image));
230 memset (&xpm_info, 0, sizeof(xpm_info));
235 if (XpmSuccess != XpmReadFileToData ((char *) filename, &xpm_data))
237 fprintf (stderr, "%s: unable to read XPM file %s\n",
243 result = XpmCreateXpmImageFromData (xpm_data, &xpm_image, &xpm_info);
244 if (result != XpmSuccess)
246 fprintf(stderr, "%s: unable to parse xpm data (%d).\n", progname,
251 if (xpm_image.ncolors > countof(colors))
253 fprintf (stderr, "%s: too many colors (%d) in XPM.\n",
254 progname, xpm_image.ncolors);
258 ximage = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
259 xpm_image.width, xpm_image.height, 32, 0);
261 bpl = ximage->bytes_per_line;
264 ximage->data = (char *) malloc(xpm_image.height * bpl);
266 /* Parse the colors in the XPM into RGB values. */
267 for (i = 0; i < xpm_image.ncolors; i++)
269 const char *c = xpm_image.colorTable[i].c_color;
272 fprintf(stderr, "%s: bogus color table? (%d)\n", progname, i);
275 else if (!strncasecmp (c, "None", 4))
277 transparent_color_index = i;
278 colors[transparent_color_index].red = 0xFF;
279 colors[transparent_color_index].green = 0xFF;
280 colors[transparent_color_index].blue = 0xFF;
282 else if (!XParseColor (dpy, cmap, c, &colors[i]))
284 fprintf(stderr, "%s: unparsable color: %s\n", progname, c);
289 /* Translate the XpmImage to an RGB XImage. */
291 int rpos, gpos, bpos, apos; /* bitfield positions */
293 /* Note that unlike X, which is endianness-agnostic (since any XImage
294 can have its own specific bit ordering, with the server reversing
295 things as necessary) OpenGL pretends everything is client-side, so
296 we need to pack things in the right order for the client machine.
299 ximage->bitmap_bit_order =
301 (bigendian() ? MSBFirst : LSBFirst);
304 /* #### Cherub says that the little-endian case must be taken on MacOSX,
305 or else the colors/alpha are the wrong way around. How can
309 rpos = 24, gpos = 16, bpos = 8, apos = 0;
312 rpos = 0, gpos = 8, bpos = 16, apos = 24;
316 /* I sure hope these only free the contents, and not the args. */
317 #if 0 /* Apparently not? Gotta love those well-documented APIs! */
318 XpmFreeXpmImage (&xpm_image);
319 XpmFreeXpmInfo (&xpm_info);
326 #else /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
328 /* If we don't have libXPM or Pixbuf, then use "minixpm".
329 This can read XPM data from memory, but can't read files.
337 #define countof(x) (sizeof((x))/sizeof((*x)))
340 /* Given a bitmask, returns the position and width of the field.
343 decode_mask (unsigned long mask, unsigned long *pos_ret,
344 unsigned long *size_ret)
347 for (i = 0; i < 32; i++)
348 if (mask & (1L << i))
352 for (; i < 32; i++, j++)
353 if (! (mask & (1L << i)))
361 /* The minixpm version of this function...
364 xpm_to_ximage_1 (Display *dpy, Visual *visual, Colormap cmap,
365 const char *filename, char **xpm_data)
367 int iw, ih, w8, x, y;
370 unsigned char *mask = 0;
372 unsigned long background_color =
373 BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
374 unsigned long *pixels = 0;
378 unsigned long rpos=0, gpos=0, bpos=0, apos=0;
379 unsigned long rmsk=0, gmsk=0, bmsk=0, amsk=0;
380 unsigned long rsiz=0, gsiz=0, bsiz=0, asiz=0;
385 Screen *screen = DefaultScreenOfDisplay (dpy);
386 Window window = RootWindowOfScreen (screen);
387 XWindowAttributes xgwa;
388 XGetWindowAttributes (dpy, window, &xgwa);
390 XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
392 if (osx_load_image_file (screen, window, pixmap, filename, &geom)) {
393 ximage = XGetImage (dpy, pixmap, geom.x, geom.y, geom.width, geom.height,
396 /* Have to convert BGRA to ARGB */
398 for (y = 0; y < ximage->height; y++)
399 for (x = 0; x < ximage->width; x++) {
400 unsigned long p = XGetPixel (ximage, x, y);
401 unsigned long b = (p >> 24) & 0xFF;
402 unsigned long g = (p >> 16) & 0xFF;
403 unsigned long r = (p >> 8) & 0xFF;
404 unsigned long a = (p >> 0) & 0xFF;
405 p = (a << 24) | (r << 16) | (g << 8) | (b << 0);
406 XPutPixel (ximage, x, y, p);
412 XFreePixmap (dpy, pixmap);
415 fprintf (stderr, "%s: %s failed\n", progname, filename);
418 # endif /* HAVE_COCOA */
423 "%s: can't load %s: not compiled with XPM or Pixbuf support.\n",
428 if (! xpm_data) abort();
429 ximage = minixpm_to_ximage (dpy, visual, cmap, depth, background_color,
430 (const char * const *) xpm_data,
431 &iw, &ih, &pixels, &npixels, &mask);
432 if (!ximage) abort();
433 if (pixels) free (pixels);
435 bpl = ximage->bytes_per_line;
437 ximage->data = malloc (ximage->height * bpl);
439 /* Flip image upside down, for texture maps;
440 process the mask; and re-arrange the color components for GL.
442 w8 = (ximage->width + 7) / 8;
444 rmsk = ximage->red_mask;
445 gmsk = ximage->green_mask;
446 bmsk = ximage->blue_mask;
447 amsk = ~(rmsk|gmsk|bmsk);
449 decode_mask (rmsk, &rpos, &rsiz);
450 decode_mask (gmsk, &gpos, &gsiz);
451 decode_mask (bmsk, &bpos, &bsiz);
452 decode_mask (amsk, &apos, &asiz);
454 for (y = 0; y < ximage->height; y++)
456 int y2 = (ximage->height-1-y);
458 unsigned int *oline = (unsigned int *) (ximage->data + (y * bpl));
459 unsigned int *iline = (unsigned int *) (data + (y2 * bpl));
461 for (x = 0; x < ximage->width; x++)
463 unsigned int pixel = iline[x];
464 unsigned char r = (pixel & rmsk) >> rpos;
465 unsigned char g = (pixel & gmsk) >> gpos;
466 unsigned char b = (pixel & bmsk) >> bpos;
467 unsigned char a = (mask
468 ? ((mask [(y2 * w8) + (x >> 3)] & (1 << (x % 8)))
472 pixel = ((r << rpos) | (g << gpos) | (b << bpos) | (a << apos));
474 pixel = ((a << 24) | (b << 16) | (g << 8) | r);
484 #endif /* !HAVE_XPM */
487 /* Returns an XImage structure containing the bits of the given XPM image.
488 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
489 extra byte set to either 0xFF or 0x00 (based on the XPM file's mask.)
491 The Display and Visual arguments are used only for creating the XImage;
492 no bits are pushed to the server.
494 The Colormap argument is used just for parsing color names; no colors
498 xpm_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
501 return xpm_to_ximage_1 (dpy, visual, cmap, 0, xpm_data);
506 xpm_file_to_ximage (Display *dpy, Visual *visual, Colormap cmap,
507 const char *filename)
509 return xpm_to_ximage_1 (dpy, visual, cmap, filename, 0);