From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[xscreensaver] / hacks / ximage-loader.c
1 /* ximage-loader.c --- converts image files or data to XImages or Pixmap.
2  * xscreensaver, Copyright (c) 1998-2018 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #ifdef HAVE_JWXYZ
22 # include "jwxyz.h"
23 #else
24 # include <X11/Xlib.h>
25 # include <X11/Xutil.h>
26 #endif
27
28 #include "ximage-loader.h"
29
30 #if defined(HAVE_GDK_PIXBUF) || defined(HAVE_COCOA) || defined(HAVE_ANDROID)
31 # undef HAVE_LIBPNG
32 #endif
33
34 #ifdef HAVE_COCOA
35 # include "grabscreen.h"  /* for osx_load_image_file() */
36 #endif
37
38 #ifdef HAVE_GDK_PIXBUF
39 # include <gdk-pixbuf/gdk-pixbuf.h>
40 # ifdef HAVE_GTK2
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 */
46
47 #ifdef HAVE_LIBPNG
48 # include <png.h>
49 #endif
50
51 #ifdef HAVE_ANDROID
52  /* So that debug output shows up in logcat... */
53 extern void Log(const char *format, ...);
54 # undef  fprintf
55 # define fprintf(S, ...) Log(__VA_ARGS__)
56 #endif
57
58 extern char *progname;
59
60 static Bool
61 bigendian (void)
62 {
63   union { int i; char c[sizeof(int)]; } u;
64   u.i = 1;
65   return !u.c[0];
66 }
67
68
69 #ifdef HAVE_GDK_PIXBUF
70
71 /* Loads the image to an XImage, RGBA -- GDK Pixbuf version.
72  */
73 static XImage *
74 make_ximage (Display *dpy, Visual *visual, const char *filename,
75              const unsigned char *image_data, unsigned long data_size)
76 {
77   GdkPixbuf *pb;
78   static int initted = 0;
79 # ifdef HAVE_GTK2
80   GError *gerr = NULL;
81 # endif
82
83   if (!initted)
84     {
85 # ifdef HAVE_GTK2
86 #  if !GLIB_CHECK_VERSION(2, 36 ,0)
87       g_type_init ();
88 #  endif
89 # endif
90       gdk_pixbuf_xlib_init (dpy, DefaultScreen (dpy));
91       xlib_rgb_init (dpy, DefaultScreenOfDisplay (dpy));
92       initted = 1;
93     }
94
95   if (filename)
96     {
97 # ifdef HAVE_GTK2
98       pb = gdk_pixbuf_new_from_file (filename, &gerr);
99       if (!pb)
100         {
101           fprintf (stderr, "%s: %s\n", progname, gerr->message);
102           return 0;
103         }
104 # else
105       pb = gdk_pixbuf_new_from_file (filename);
106       if (!pb)
107         {
108           fprintf (stderr, "%s: GDK unable to load %s: %s\n",
109                    progname, filename, (gerr ? gerr->message : "?"));
110           return 0;
111         }
112 # endif /* HAVE_GTK2 */
113     }
114   else
115     {
116 # ifdef HAVE_GTK2
117       GInputStream *s =
118         g_memory_input_stream_new_from_data (image_data, data_size, 0);
119       pb = gdk_pixbuf_new_from_stream (s, 0, &gerr);
120
121       g_input_stream_close (s, NULL, NULL);
122       g_object_unref (s);
123
124       if (! pb)
125         {
126           /* fprintf (stderr, "%s: GDK unable to parse image data: %s\n",
127                    progname, (gerr ? gerr->message : "?")); */
128           return 0;
129         }
130 # else /* !HAVE_GTK2 */
131       fprintf (stderr, "%s: image loading not supported with GTK 1.x\n",
132                progname);
133       return 0;
134 # endif /* !HAVE_GTK2 */
135     }
136
137   if (!pb) abort();
138
139   {
140     XImage *image;
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);
146     int x, y;
147
148     image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
149     image->data = (char *) malloc(h * image->bytes_per_line);
150
151     /* Set the bit order in the XImage structure to whatever the
152        local host's native bit order is.
153     */
154     image->bitmap_bit_order =
155       image->byte_order =
156       (bigendian() ? MSBFirst : LSBFirst);
157
158     if (!image->data)
159       {
160         fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
161         return 0;
162       }
163
164     for (y = 0; y < h; y++)
165       {
166         guchar *i = row;
167         for (x = 0; x < w; x++)
168           {
169             unsigned long rgba = 0;
170             switch (chan) {
171             case 1:
172               rgba = ((0xFF << 24) |
173                       (*i   << 16) |
174                       (*i   <<  8) |
175                        *i);
176               i++;
177               break;
178             case 3:
179               rgba = ((0xFF << 24) |
180                       (i[2] << 16) |
181                       (i[1] <<  8) |
182                       i[0]);
183               i += 3;
184               break;
185             case 4:
186               rgba = ((i[3] << 24) |
187                       (i[2] << 16) |
188                       (i[1] <<  8) |
189                       i[0]);
190               i += 4;
191               break;
192             default:
193               abort();
194               break;
195             }
196             XPutPixel (image, x, y, rgba);
197           }
198         row += stride;
199       }
200
201     g_object_unref (pb);
202     return image;
203   }
204 }
205
206 #elif defined(HAVE_JWXYZ) /* MacOS, iOS or Android */
207
208 /* Loads the image to an XImage, RGBA -- MacOS, iOS or Android version.
209  */
210 static XImage *
211 make_ximage (Display *dpy, Visual *visual, const char *filename,
212              const unsigned char *image_data, unsigned long data_size)
213 {
214   XImage *ximage = 0;
215
216   if (filename)
217     {
218 # ifdef HAVE_COCOA  /* MacOS */
219       XRectangle geom;
220       Screen *screen = DefaultScreenOfDisplay (dpy);
221       Window window = RootWindowOfScreen (screen);
222       XWindowAttributes xgwa;
223       XGetWindowAttributes (dpy, window, &xgwa);
224       Pixmap pixmap =
225         XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
226       int x, y;
227
228       if (! osx_load_image_file (screen, window, pixmap, filename, &geom))
229         {
230           fprintf (stderr, "%s: %s failed\n", progname, filename);
231           return 0;
232         }
233
234       ximage = XGetImage (dpy, pixmap, geom.x, geom.y,
235                           geom.width, geom.height,
236                           ~0L, ZPixmap);
237       if (!ximage) abort();
238
239       /* Have to convert ABGR to RGBA */
240       for (y = 0; y < ximage->height; y++)
241         for (x = 0; x < ximage->width; x++)
242           {
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);
250           }
251
252       XFreePixmap (dpy, pixmap);
253
254 # else   /* !HAVE_COCOA -- iOS or Android. */
255       fprintf (stderr, "%s: image file loading not supported\n", progname);
256       return 0;
257 # endif  /* !HAVE_COCOA */
258     }
259   else
260     {
261       ximage = jwxyz_png_to_ximage (dpy, visual, image_data, data_size);
262     }
263
264   return ximage;
265 }
266
267 #elif defined(HAVE_LIBPNG)
268
269 typedef struct {
270   const unsigned char *buf;
271   png_size_t siz, ptr;
272 } png_read_closure;
273
274 static void
275 png_reader_fn (png_structp png_ptr, png_bytep buf, png_size_t siz)
276 {
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);
281   r->ptr += siz;
282 }
283
284
285 /* Loads the image to an XImage, RGBA -- libpng version.
286  */
287 static XImage *
288 make_ximage (Display *dpy, Visual *visual,
289              const char *filename, const unsigned char *image_data,
290              unsigned long data_size)
291 {
292   XImage *image = 0;
293   png_structp png_ptr;
294   png_infop info_ptr;
295   png_infop end_info;
296   png_uint_32 width, height, channels;
297   int bit_depth, color_type, interlace_type;
298   FILE *fp = 0;
299
300   png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
301   if (!png_ptr) return 0;
302
303   info_ptr = png_create_info_struct (png_ptr);
304   if (!info_ptr)
305     {
306       png_destroy_read_struct (&png_ptr, 0, 0);
307       return 0;
308     }
309
310   end_info = png_create_info_struct (png_ptr);
311   if (!end_info)
312     {
313       png_destroy_read_struct (&png_ptr, &info_ptr, 0);
314       return 0;
315     }
316
317   if (setjmp (png_jmpbuf(png_ptr)))
318     {
319       png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
320       return 0;
321     }
322
323   if (filename)
324     {
325       fp = fopen (filename, "r");
326       if (! fp)
327         {
328           fprintf (stderr, "%s: unable to read %s\n", progname, filename);
329           return 0;
330         }
331       png_init_io (png_ptr, fp);
332     }
333   else
334     {
335       png_read_closure closure;
336       closure.buf = image_data;
337       closure.siz = data_size;
338       closure.ptr = 0;
339       png_set_read_fn (png_ptr, (void *) &closure, png_reader_fn);
340     }
341
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);
346
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 */
349
350 # if 0
351   if (color_type == PNG_COLOR_TYPE_PALETTE)  /* Colormap to RGB */
352     png_set_palette_rgb (png_ptr);
353
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);
356 # endif
357
358   if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) /* Fix weird alpha */
359     png_set_tRNS_to_alpha (png_ptr);
360
361   /* At least 8 bits deep */
362   if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
363     png_set_expand (png_ptr);
364
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);
369
370   /* Grayscale to color */
371   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
372     png_set_expand (png_ptr);
373
374
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);
379
380 # if 0
381   {
382     png_color_16 *bg;
383     if (png_get_bKGD (png_ptr, info_ptr, &bg))
384       png_set_background (png_ptr, bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
385   }
386 # endif
387
388   /* Commit */
389   png_read_update_info (png_ptr, info_ptr);
390
391   channels = png_get_channels (png_ptr, info_ptr);
392
393   {
394     png_bytep *rows = png_malloc (png_ptr, height * sizeof(*rows));
395     int x, y;
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);
400
401     image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
402                           width, height, 32, 0);
403     image->data = (char *) malloc (height * image->bytes_per_line);
404
405     /* Set the bit order in the XImage structure to whatever the
406        local host's native bit order is.
407      */
408     image->bitmap_bit_order =
409       image->byte_order =
410         (bigendian() ? MSBFirst : LSBFirst);
411
412     if (!image->data)
413       {
414         fprintf (stderr, "%s: out of memory (%lu x %lu)\n",
415                  progname, (unsigned long)width, (unsigned long)height);
416         return 0;
417       }
418
419     for (y = 0; y < height; y++)
420       {
421         png_bytep i = rows[y];
422         for (x = 0; x < width; x++)
423           {
424             unsigned long rgba;
425             switch (channels) {
426             case 4:
427               rgba = ((i[3] << 24) |
428                       (i[2] << 16) |
429                       (i[1] << 8)  |
430                        i[0]);
431               break;
432             case 3:
433               rgba = ((0xFF << 24) |
434                       (i[2] << 16) |
435                       (i[1] << 8)  |
436                        i[0]);
437               break;
438             case 2:
439               rgba = ((i[1] << 24) |
440                       (i[0] << 16) |
441                       (i[0] << 8)  |
442                        i[0]);
443               break;
444             case 1:
445               rgba = ((0xFF << 24) |
446                       (i[0] << 16) |
447                       (i[0] << 8)  |
448                        i[0]);
449               break;
450             default:
451               abort();
452             }
453             XPutPixel (image, x, y, rgba);
454             i += channels;
455           }
456         png_free (png_ptr, rows[y]);
457       }
458
459     png_free (png_ptr, rows);
460   }
461
462   png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);  
463   if (fp) fclose (fp);
464
465   return image;
466 }
467
468
469 #else /* No image loaders! */
470
471 static XImage *
472 make_ximage (Display *dpy, Visual *visual,
473              const char *filename, const unsigned char *image_data,
474              unsigned long data_size)
475 {
476   fprintf (stderr, "%s: no image loading support!\n", progname);
477   return 0;
478 }
479
480 #endif /* no loaders */
481
482
483 /* Given a bitmask, returns the position and width of the field.
484  */
485 static void
486 decode_mask (unsigned long mask, unsigned long *pos_ret,
487              unsigned long *size_ret)
488 {
489   int i;
490   for (i = 0; i < 32; i++)
491     if (mask & (1L << i))
492       {
493         int j = 0;
494         *pos_ret = i;
495         for (; i < 32; i++, j++)
496           if (! (mask & (1L << i)))
497             break;
498         *size_ret = j;
499         return;
500       }
501 }
502
503
504 /* Loads the image to a Pixmap and optional 1-bit mask.
505  */
506 static Pixmap
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)
511 {
512   XWindowAttributes xgwa;
513   XImage *in, *out, *mask = 0;
514   Pixmap pixmap;
515   XGCValues gcv;
516   GC gc;
517   int x, y;
518
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;
523
524 # ifdef HAVE_JWXYZ
525   // BlackPixel has alpha: 0xFF000000.
526   unsigned long black = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
527 #else
528   unsigned long black = 0;
529 # endif
530
531   XGetWindowAttributes (dpy, window, &xgwa);
532
533   in = make_ximage (dpy, xgwa.visual, filename, image_data, data_size);
534   if (!in) return 0;
535
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);
539
540   out->bitmap_bit_order = in->bitmap_bit_order;
541   out->byte_order = in->byte_order;
542
543   out->bitmap_bit_order = BitmapBitOrder (dpy);
544   out->byte_order = ImageByteOrder (dpy);
545
546   out->data = (char *) malloc (out->height * out->bytes_per_line);
547   if (!out->data) abort();
548
549   if (mask_ret)
550     {
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);
555     }
556
557   /* Find the server's color masks.
558    */
559   srmsk = out->red_mask;
560   sgmsk = out->green_mask;
561   sbmsk = out->blue_mask;
562
563   if (!(srmsk && sgmsk && sbmsk)) abort();  /* No server color masks? */
564
565   decode_mask (srmsk, &srpos, &srsiz);
566   decode_mask (sgmsk, &sgpos, &sgsiz);
567   decode_mask (sbmsk, &sbpos, &sbsiz);
568
569   /* 'in' is RGBA in client endianness.  Convert to what the server wants. */
570   if (bigendian())
571     crpos = 24, cgpos = 16, cbpos =  8, capos =  0;
572   else
573     crpos =  0, cgpos =  8, cbpos = 16, capos = 24;
574
575   for (y = 0; y < in->height; y++)
576     for (x = 0; x < in->width; x++)
577       {
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) |
584                                (g << sgpos) |
585                                (b << sbpos) |
586                                black));
587         if (mask)
588           XPutPixel (mask, x, y, (a ? 1 : 0));
589       }
590
591   XDestroyImage (in);
592   in = 0;
593
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);
597   XFreeGC (dpy, gc);
598
599   if (mask)
600     {
601       Pixmap p2 = XCreatePixmap (dpy, window, mask->width, mask->height, 1);
602       gcv.foreground = 1;
603       gcv.background = 0;
604       gc = XCreateGC (dpy, p2, GCForeground|GCBackground, &gcv);
605       XPutImage (dpy, p2, gc, mask, 0, 0, 0, 0, mask->width, mask->height);
606       XFreeGC (dpy, gc);
607       XDestroyImage (mask);
608       mask = 0;
609       *mask_ret = p2;
610     }
611
612   if (width_ret)  *width_ret  = out->width;
613   if (height_ret) *height_ret = out->height;
614
615   XDestroyImage (out);
616
617   return pixmap;
618 }
619
620
621 /* Textures are upside down, so invert XImages before returning them.
622  */
623 static void
624 flip_ximage (XImage *ximage)
625 {
626   char *data2, *in, *out;
627   int y;
628
629   if (!ximage) return;
630   data2 = malloc (ximage->bytes_per_line * ximage->height);
631   if (!data2) abort();
632   in = ximage->data;
633   out = data2 + ximage->bytes_per_line * (ximage->height - 1);
634   for (y = 0; y < ximage->height; y++)
635     {
636       memcpy (out, in, ximage->bytes_per_line);
637       in  += ximage->bytes_per_line;
638       out -= ximage->bytes_per_line;
639     }
640   free (ximage->data);
641   ximage->data = data2;
642 }
643
644
645 Pixmap
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,
649                       Pixmap *mask_ret)
650 {
651   return make_pixmap (dpy, window, 0, image_data, data_size,
652                       width_ret, height_ret, mask_ret);
653 }
654
655 Pixmap
656 file_to_pixmap (Display *dpy, Window window, const char *filename,
657                 int *width_ret, int *height_ret,
658                 Pixmap *mask_ret)
659 {
660   return make_pixmap (dpy, window, filename, 0, 0,
661                       width_ret, height_ret, mask_ret);
662 }
663
664
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.
669  */
670 XImage *
671 image_data_to_ximage (Display *dpy, Visual *visual,
672                       const unsigned char *image_data,
673                       unsigned long data_size)
674 {
675   XImage *ximage = make_ximage (dpy, visual, 0, image_data, data_size);
676   flip_ximage (ximage);
677   return ximage;
678 }
679
680 XImage *
681 file_to_ximage (Display *dpy, Visual *visual, const char *filename)
682 {
683   XImage *ximage = make_ximage (dpy, visual, filename, 0, 0);
684   flip_ximage (ximage);
685   return ximage;
686 }