1 /* ximage-loader.c --- converts image files or data to XImages or Pixmap.
2 * xscreensaver, Copyright (c) 1998-2018 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
24 # include <X11/Xlib.h>
25 # include <X11/Xutil.h>
28 #include "ximage-loader.h"
30 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_COCOA) || defined(HAVE_ANDROID)
35 # include "grabscreen.h" /* for osx_load_image_file() */
38 #ifdef HAVE_GDK_PIXBUF
39 # include <gdk-pixbuf/gdk-pixbuf.h>
41 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
42 # else /* !HAVE_GTK2 */
43 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
44 # endif /* !HAVE_GTK2 */
45 #endif /* HAVE_GDK_PIXBUF */
52 /* So that debug output shows up in logcat... */
53 extern void Log(const char *format, ...);
55 # define fprintf(S, ...) Log(__VA_ARGS__)
58 extern char *progname;
63 union { int i; char c[sizeof(int)]; } u;
69 #ifdef HAVE_GDK_PIXBUF
71 /* Loads the image to an XImage, RGBA -- GDK Pixbuf version.
74 make_ximage (Display *dpy, Visual *visual, const char *filename,
75 const unsigned char *image_data, unsigned long data_size)
78 static int initted = 0;
86 # if !GLIB_CHECK_VERSION(2, 36 ,0)
90 gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
91 xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
98 pb = gdk_pixbuf_new_from_file (filename, &gerr);
101 fprintf (stderr, "%s: %s\n", progname, gerr->message);
105 pb = gdk_pixbuf_new_from_file (filename);
108 fprintf (stderr, "%s: GDK unable to load %s: %s\n",
109 progname, filename, (gerr ? gerr->message : "?"));
112 # endif /* HAVE_GTK2 */
118 g_memory_input_stream_new_from_data (image_data, data_size, 0);
119 pb = gdk_pixbuf_new_from_stream (s, 0, &gerr);
121 g_input_stream_close (s, NULL, NULL);
126 /* fprintf (stderr, "%s: GDK unable to parse image data: %s\n",
127 progname, (gerr ? gerr->message : "?")); */
130 # else /* !HAVE_GTK2 */
131 fprintf (stderr, "%s: image loading not supported with GTK 1.x\n",
134 # endif /* !HAVE_GTK2 */
141 int w = gdk_pixbuf_get_width (pb);
142 int h = gdk_pixbuf_get_height (pb);
143 guchar *row = gdk_pixbuf_get_pixels (pb);
144 int stride = gdk_pixbuf_get_rowstride (pb);
145 int chan = gdk_pixbuf_get_n_channels (pb);
148 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
149 image->data = (char *) malloc(h * image->bytes_per_line);
151 /* Set the bit order in the XImage structure to whatever the
152 local host's native bit order is.
154 image->bitmap_bit_order =
156 (bigendian() ? MSBFirst : LSBFirst);
160 fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
164 for (y = 0; y < h; y++)
167 for (x = 0; x < w; x++)
169 unsigned long rgba = 0;
172 rgba = ((0xFF << 24) |
179 rgba = ((0xFF << 24) |
186 rgba = ((i[3] << 24) |
196 XPutPixel (image, x, y, rgba);
206 #elif defined(HAVE_JWXYZ) /* MacOS, iOS or Android */
208 /* Loads the image to an XImage, RGBA -- MacOS, iOS or Android version.
211 make_ximage (Display *dpy, Visual *visual, const char *filename,
212 const unsigned char *image_data, unsigned long data_size)
218 # ifdef HAVE_COCOA /* MacOS */
220 Screen *screen = DefaultScreenOfDisplay (dpy);
221 Window window = RootWindowOfScreen (screen);
222 XWindowAttributes xgwa;
223 XGetWindowAttributes (dpy, window, &xgwa);
225 XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
228 if (! osx_load_image_file (screen, window, pixmap, filename, &geom))
230 fprintf (stderr, "%s: %s failed\n", progname, filename);
234 ximage = XGetImage (dpy, pixmap, geom.x, geom.y,
235 geom.width, geom.height,
237 if (!ximage) abort();
239 /* Have to convert ABGR to RGBA */
240 for (y = 0; y < ximage->height; y++)
241 for (x = 0; x < ximage->width; x++)
243 unsigned long p = XGetPixel (ximage, x, y);
244 unsigned long a = (p >> 24) & 0xFF;
245 unsigned long b = (p >> 16) & 0xFF;
246 unsigned long g = (p >> 8) & 0xFF;
247 unsigned long r = (p >> 0) & 0xFF;
248 p = (r << 24) | (g << 16) | (b << 8) | (a << 0);
249 XPutPixel (ximage, x, y, p);
252 XFreePixmap (dpy, pixmap);
254 # else /* !HAVE_COCOA -- iOS or Android. */
255 fprintf (stderr, "%s: image file loading not supported\n", progname);
257 # endif /* !HAVE_COCOA */
261 ximage = jwxyz_png_to_ximage (dpy, visual, image_data, data_size);
267 #elif defined(HAVE_LIBPNG)
270 const unsigned char *buf;
275 png_reader_fn (png_structp png_ptr, png_bytep buf, png_size_t siz)
277 png_read_closure *r = png_get_io_ptr (png_ptr);
278 if (siz > r->siz - r->ptr)
279 png_error (png_ptr, "PNG internal read error");
280 memcpy (buf, r->buf + r->ptr, siz);
285 /* Loads the image to an XImage, RGBA -- libpng version.
288 make_ximage (Display *dpy, Visual *visual,
289 const char *filename, const unsigned char *image_data,
290 unsigned long data_size)
296 png_uint_32 width, height, channels;
297 int bit_depth, color_type, interlace_type;
300 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
301 if (!png_ptr) return 0;
303 info_ptr = png_create_info_struct (png_ptr);
306 png_destroy_read_struct (&png_ptr, 0, 0);
310 end_info = png_create_info_struct (png_ptr);
313 png_destroy_read_struct (&png_ptr, &info_ptr, 0);
317 if (setjmp (png_jmpbuf(png_ptr)))
319 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
325 fp = fopen (filename, "r");
328 fprintf (stderr, "%s: unable to read %s\n", progname, filename);
331 png_init_io (png_ptr, fp);
335 png_read_closure closure;
336 closure.buf = image_data;
337 closure.siz = data_size;
339 png_set_read_fn (png_ptr, (void *) &closure, png_reader_fn);
342 png_read_info (png_ptr, info_ptr);
343 png_get_IHDR (png_ptr, info_ptr,
344 &width, &height, &bit_depth, &color_type,
345 &interlace_type, 0, 0);
347 png_set_strip_16 (png_ptr); /* Truncate 16 bits per component to 8 */
348 png_set_packing (png_ptr); /* Unpack to 1 pixel per byte */
351 if (color_type == PNG_COLOR_TYPE_PALETTE) /* Colormap to RGB */
352 png_set_palette_rgb (png_ptr);
354 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) /* Mono to 8bit */
355 png_set_gray_1_2_4_to_8 (png_ptr);
358 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) /* Fix weird alpha */
359 png_set_tRNS_to_alpha (png_ptr);
361 /* At least 8 bits deep */
362 if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
363 png_set_expand (png_ptr);
365 if (bit_depth == 8 && /* Convert RGB to RGBA */
366 (color_type == PNG_COLOR_TYPE_RGB ||
367 color_type == PNG_COLOR_TYPE_PALETTE))
368 png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER);
370 /* Grayscale to color */
371 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
372 png_set_expand (png_ptr);
375 /* Convert graysale to color */
376 if (color_type == PNG_COLOR_TYPE_GRAY ||
377 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
378 png_set_gray_to_rgb (png_ptr);
383 if (png_get_bKGD (png_ptr, info_ptr, &bg))
384 png_set_background (png_ptr, bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
389 png_read_update_info (png_ptr, info_ptr);
391 channels = png_get_channels (png_ptr, info_ptr);
394 png_bytep *rows = png_malloc (png_ptr, height * sizeof(*rows));
396 for (y = 0; y < height; y++)
397 rows[y] = png_malloc (png_ptr, png_get_rowbytes (png_ptr, info_ptr));
398 png_read_image (png_ptr, rows);
399 png_read_end (png_ptr, info_ptr);
401 image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
402 width, height, 32, 0);
403 image->data = (char *) malloc (height * image->bytes_per_line);
405 /* Set the bit order in the XImage structure to whatever the
406 local host's native bit order is.
408 image->bitmap_bit_order =
410 (bigendian() ? MSBFirst : LSBFirst);
414 fprintf (stderr, "%s: out of memory (%lu x %lu)\n",
415 progname, (unsigned long)width, (unsigned long)height);
419 for (y = 0; y < height; y++)
421 png_bytep i = rows[y];
422 for (x = 0; x < width; x++)
427 rgba = ((i[3] << 24) |
433 rgba = ((0xFF << 24) |
439 rgba = ((i[1] << 24) |
445 rgba = ((0xFF << 24) |
453 XPutPixel (image, x, y, rgba);
456 png_free (png_ptr, rows[y]);
459 png_free (png_ptr, rows);
462 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
469 #else /* No image loaders! */
472 make_ximage (Display *dpy, Visual *visual,
473 const char *filename, const unsigned char *image_data,
474 unsigned long data_size)
476 fprintf (stderr, "%s: no image loading support!\n", progname);
480 #endif /* no loaders */
483 /* Given a bitmask, returns the position and width of the field.
486 decode_mask (unsigned long mask, unsigned long *pos_ret,
487 unsigned long *size_ret)
490 for (i = 0; i < 32; i++)
491 if (mask & (1L << i))
495 for (; i < 32; i++, j++)
496 if (! (mask & (1L << i)))
504 /* Loads the image to a Pixmap and optional 1-bit mask.
507 make_pixmap (Display *dpy, Window window,
508 const char *filename,
509 const unsigned char *image_data, unsigned long data_size,
510 int *width_ret, int *height_ret, Pixmap *mask_ret)
512 XWindowAttributes xgwa;
513 XImage *in, *out, *mask = 0;
519 unsigned long crpos=0, cgpos=0, cbpos=0, capos=0; /* bitfield positions */
520 unsigned long srpos=0, sgpos=0, sbpos=0;
521 unsigned long srmsk=0, sgmsk=0, sbmsk=0;
522 unsigned long srsiz=0, sgsiz=0, sbsiz=0;
525 // BlackPixel has alpha: 0xFF000000.
526 unsigned long black = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
528 unsigned long black = 0;
531 XGetWindowAttributes (dpy, window, &xgwa);
533 in = make_ximage (dpy, xgwa.visual, filename, image_data, data_size);
536 /* Create a new image in the depth and bit-order of the server. */
537 out = XCreateImage (dpy, xgwa.visual, xgwa.depth, ZPixmap, 0, 0,
538 in->width, in->height, 8, 0);
540 out->bitmap_bit_order = in->bitmap_bit_order;
541 out->byte_order = in->byte_order;
543 out->bitmap_bit_order = BitmapBitOrder (dpy);
544 out->byte_order = ImageByteOrder (dpy);
546 out->data = (char *) malloc (out->height * out->bytes_per_line);
547 if (!out->data) abort();
551 mask = XCreateImage (dpy, xgwa.visual, 1, XYPixmap, 0, 0,
552 in->width, in->height, 8, 0);
553 mask->byte_order = in->byte_order;
554 mask->data = (char *) malloc (mask->height * mask->bytes_per_line);
557 /* Find the server's color masks.
559 srmsk = out->red_mask;
560 sgmsk = out->green_mask;
561 sbmsk = out->blue_mask;
563 if (!(srmsk && sgmsk && sbmsk)) abort(); /* No server color masks? */
565 decode_mask (srmsk, &srpos, &srsiz);
566 decode_mask (sgmsk, &sgpos, &sgsiz);
567 decode_mask (sbmsk, &sbpos, &sbsiz);
569 /* 'in' is RGBA in client endianness. Convert to what the server wants. */
571 crpos = 24, cgpos = 16, cbpos = 8, capos = 0;
573 crpos = 0, cgpos = 8, cbpos = 16, capos = 24;
575 for (y = 0; y < in->height; y++)
576 for (x = 0; x < in->width; x++)
578 unsigned long p = XGetPixel (in, x, y);
579 unsigned char a = (p >> capos) & 0xFF;
580 unsigned char b = (p >> cbpos) & 0xFF;
581 unsigned char g = (p >> cgpos) & 0xFF;
582 unsigned char r = (p >> crpos) & 0xFF;
583 XPutPixel (out, x, y, ((r << srpos) |
588 XPutPixel (mask, x, y, (a ? 1 : 0));
594 pixmap = XCreatePixmap (dpy, window, out->width, out->height, xgwa.depth);
595 gc = XCreateGC (dpy, pixmap, 0, &gcv);
596 XPutImage (dpy, pixmap, gc, out, 0, 0, 0, 0, out->width, out->height);
601 Pixmap p2 = XCreatePixmap (dpy, window, mask->width, mask->height, 1);
604 gc = XCreateGC (dpy, p2, GCForeground|GCBackground, &gcv);
605 XPutImage (dpy, p2, gc, mask, 0, 0, 0, 0, mask->width, mask->height);
607 XDestroyImage (mask);
612 if (width_ret) *width_ret = out->width;
613 if (height_ret) *height_ret = out->height;
621 /* Textures are upside down, so invert XImages before returning them.
624 flip_ximage (XImage *ximage)
626 char *data2, *in, *out;
630 data2 = malloc (ximage->bytes_per_line * ximage->height);
633 out = data2 + ximage->bytes_per_line * (ximage->height - 1);
634 for (y = 0; y < ximage->height; y++)
636 memcpy (out, in, ximage->bytes_per_line);
637 in += ximage->bytes_per_line;
638 out -= ximage->bytes_per_line;
641 ximage->data = data2;
646 image_data_to_pixmap (Display *dpy, Window window,
647 const unsigned char *image_data, unsigned long data_size,
648 int *width_ret, int *height_ret,
651 return make_pixmap (dpy, window, 0, image_data, data_size,
652 width_ret, height_ret, mask_ret);
656 file_to_pixmap (Display *dpy, Window window, const char *filename,
657 int *width_ret, int *height_ret,
660 return make_pixmap (dpy, window, filename, 0, 0,
661 width_ret, height_ret, mask_ret);
665 /* This XImage has RGBA data, which is what OpenGL code typically expects.
666 Also it is upside down: the origin is at the bottom left of the image.
667 X11 typically expects 0RGB as it has no notion of alpha, only 1-bit masks.
668 With X11 code, you should probably use the _pixmap routines instead.
671 image_data_to_ximage (Display *dpy, Visual *visual,
672 const unsigned char *image_data,
673 unsigned long data_size)
675 XImage *ximage = make_ximage (dpy, visual, 0, image_data, data_size);
676 flip_ximage (ximage);
681 file_to_ximage (Display *dpy, Visual *visual, const char *filename)
683 XImage *ximage = make_ximage (dpy, visual, filename, 0, 0);
684 flip_ximage (ximage);