f122e3790773768c4cc16959cedd41b9c8ad44f2
[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\n", progname, filename);
109           return 0;
110         }
111 # endif /* HAVE_GTK2 */
112     }
113   else
114     {
115 # ifdef HAVE_GTK2
116       GInputStream *s =
117         g_memory_input_stream_new_from_data (image_data, data_size, 0);
118       pb = gdk_pixbuf_new_from_stream (s, 0, &gerr);
119       /* #### free s? */
120       if (! pb)
121         {
122           fprintf (stderr, "%s: GDK unable to parse built-in image data\n",
123                    progname);
124           return 0;
125         }
126 # else /* !HAVE_GTK2 */
127       fprintf (stderr, "%s: image loading not supported with GTK 1.x\n",
128                progname);
129       return 0;
130 # endif /* !HAVE_GTK2 */
131     }
132
133   if (!pb) abort();
134
135   {
136     XImage *image;
137     int w = gdk_pixbuf_get_width (pb);
138     int h = gdk_pixbuf_get_height (pb);
139     guchar *row = gdk_pixbuf_get_pixels (pb);
140     int stride = gdk_pixbuf_get_rowstride (pb);
141     int chan = gdk_pixbuf_get_n_channels (pb);
142     int x, y;
143
144     image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0, w, h, 32, 0);
145     image->data = (char *) malloc(h * image->bytes_per_line);
146
147     /* Set the bit order in the XImage structure to whatever the
148        local host's native bit order is.
149     */
150     image->bitmap_bit_order =
151       image->byte_order =
152       (bigendian() ? MSBFirst : LSBFirst);
153
154     if (!image->data)
155       {
156         fprintf (stderr, "%s: out of memory (%d x %d)\n", progname, w, h);
157         return 0;
158       }
159
160     for (y = 0; y < h; y++)
161       {
162         guchar *i = row;
163         for (x = 0; x < w; x++)
164           {
165             unsigned long rgba = 0;
166             switch (chan) {
167             case 1:
168               rgba = ((0xFF << 24) |
169                       (*i   << 16) |
170                       (*i   <<  8) |
171                        *i);
172               i++;
173               break;
174             case 3:
175               rgba = ((0xFF << 24) |
176                       (i[2] << 16) |
177                       (i[1] <<  8) |
178                       i[0]);
179               i += 3;
180               break;
181             case 4:
182               rgba = ((i[3] << 24) |
183                       (i[2] << 16) |
184                       (i[1] <<  8) |
185                       i[0]);
186               i += 4;
187               break;
188             default:
189               abort();
190               break;
191             }
192             XPutPixel (image, x, y, rgba);
193           }
194         row += stride;
195       }
196
197     g_object_unref (pb);
198     return image;
199   }
200 }
201
202 #elif defined(HAVE_JWXYZ) /* MacOS, iOS or Android */
203
204 /* Loads the image to an XImage, RGBA -- MacOS, iOS or Android version.
205  */
206 static XImage *
207 make_ximage (Display *dpy, Visual *visual, const char *filename,
208              const unsigned char *image_data, unsigned long data_size)
209 {
210   XImage *ximage = 0;
211
212   if (filename)
213     {
214 # ifdef HAVE_COCOA  /* MacOS */
215       XRectangle geom;
216       Screen *screen = DefaultScreenOfDisplay (dpy);
217       Window window = RootWindowOfScreen (screen);
218       XWindowAttributes xgwa;
219       XGetWindowAttributes (dpy, window, &xgwa);
220       Pixmap pixmap =
221         XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
222       int x, y;
223
224       if (! osx_load_image_file (screen, window, pixmap, filename, &geom))
225         {
226           fprintf (stderr, "%s: %s failed\n", progname, filename);
227           return 0;
228         }
229
230       ximage = XGetImage (dpy, pixmap, geom.x, geom.y,
231                           geom.width, geom.height,
232                           ~0L, ZPixmap);
233       if (!ximage) abort();
234
235       /* Have to convert ABGR to RGBA */
236       for (y = 0; y < ximage->height; y++)
237         for (x = 0; x < ximage->width; x++)
238           {
239             unsigned long p = XGetPixel (ximage, x, y);
240             unsigned long a = (p >> 24) & 0xFF;
241             unsigned long b = (p >> 16) & 0xFF;
242             unsigned long g = (p >>  8) & 0xFF;
243             unsigned long r = (p >>  0) & 0xFF;
244             p = (r << 24) | (g << 16) | (b << 8) | (a << 0);
245             XPutPixel (ximage, x, y, p);
246           }
247
248       XFreePixmap (dpy, pixmap);
249
250 # else   /* !HAVE_COCOA -- iOS or Android. */
251       fprintf (stderr, "%s: image file loading not supported\n", progname);
252       return 0;
253 # endif  /* !HAVE_COCOA */
254     }
255   else
256     {
257       ximage = jwxyz_png_to_ximage (dpy, visual, image_data, data_size);
258     }
259
260   return ximage;
261 }
262
263 #elif defined(HAVE_LIBPNG)
264
265 typedef struct {
266   const unsigned char *buf;
267   png_size_t siz, ptr;
268 } png_read_closure;
269
270 static void
271 png_reader_fn (png_structp png_ptr, png_bytep buf, png_size_t siz)
272 {
273   png_read_closure *r = png_get_io_ptr (png_ptr);
274   if (siz > r->siz - r->ptr)
275     png_error (png_ptr, "PNG internal read error");
276   memcpy (buf, r->buf + r->ptr, siz);
277   r->ptr += siz;
278 }
279
280
281 /* Loads the image to an XImage, RGBA -- libpng version.
282  */
283 static XImage *
284 make_ximage (Display *dpy, Visual *visual,
285              const char *filename, const unsigned char *image_data,
286              unsigned long data_size)
287 {
288   XImage *image = 0;
289   png_structp png_ptr;
290   png_infop info_ptr;
291   png_infop end_info;
292   png_uint_32 width, height, channels;
293   int bit_depth, color_type, interlace_type;
294   FILE *fp = 0;
295
296   png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
297   if (!png_ptr) return 0;
298
299   info_ptr = png_create_info_struct (png_ptr);
300   if (!info_ptr)
301     {
302       png_destroy_read_struct (&png_ptr, 0, 0);
303       return 0;
304     }
305
306   end_info = png_create_info_struct (png_ptr);
307   if (!end_info)
308     {
309       png_destroy_read_struct (&png_ptr, &info_ptr, 0);
310       return 0;
311     }
312
313   if (setjmp (png_jmpbuf(png_ptr)))
314     {
315       png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
316       return 0;
317     }
318
319   if (filename)
320     {
321       fp = fopen (filename, "r");
322       if (! fp)
323         {
324           fprintf (stderr, "%s: unable to read %s\n", progname, filename);
325           return 0;
326         }
327       png_init_io (png_ptr, fp);
328     }
329   else
330     {
331       png_read_closure closure;
332       closure.buf = image_data;
333       closure.siz = data_size;
334       closure.ptr = 0;
335       png_set_read_fn (png_ptr, (void *) &closure, png_reader_fn);
336     }
337
338   png_read_info (png_ptr, info_ptr);
339   png_get_IHDR (png_ptr, info_ptr,
340                 &width, &height, &bit_depth, &color_type,
341                 &interlace_type, 0, 0);
342
343   png_set_strip_16 (png_ptr);  /* Truncate 16 bits per component to 8 */
344   png_set_packing (png_ptr);   /* Unpack to 1 pixel per byte */
345
346 # if 0
347   if (color_type == PNG_COLOR_TYPE_PALETTE)  /* Colormap to RGB */
348     png_set_palette_rgb (png_ptr);
349
350   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)  /* Mono to 8bit */
351     png_set_gray_1_2_4_to_8 (png_ptr);
352 # endif
353
354   if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) /* Fix weird alpha */
355     png_set_tRNS_to_alpha (png_ptr);
356
357   /* At least 8 bits deep */
358   if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
359     png_set_expand (png_ptr);
360
361    if (bit_depth == 8 &&          /* Convert RGB to RGBA */
362            (color_type == PNG_COLOR_TYPE_RGB ||
363             color_type == PNG_COLOR_TYPE_PALETTE))
364      png_set_filler (png_ptr, 0xFF, PNG_FILLER_AFTER);
365
366   /* Grayscale to color */
367   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
368     png_set_expand (png_ptr);
369
370
371   /* Convert graysale to color */
372   if (color_type == PNG_COLOR_TYPE_GRAY ||
373       color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
374     png_set_gray_to_rgb (png_ptr);
375
376 # if 0
377   {
378     png_color_16 *bg;
379     if (png_get_bKGD (png_ptr, info_ptr, &bg))
380       png_set_background (png_ptr, bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
381   }
382 # endif
383
384   /* Commit */
385   png_read_update_info (png_ptr, info_ptr);
386
387   channels = png_get_channels (png_ptr, info_ptr);
388
389   {
390     png_bytep *rows = png_malloc (png_ptr, height * sizeof(*rows));
391     int x, y;
392     for (y = 0; y < height; y++)
393       rows[y] = png_malloc (png_ptr, png_get_rowbytes (png_ptr, info_ptr));
394     png_read_image (png_ptr, rows);
395     png_read_end (png_ptr, info_ptr);
396
397     image = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
398                           width, height, 32, 0);
399     image->data = (char *) malloc (height * image->bytes_per_line);
400
401     /* Set the bit order in the XImage structure to whatever the
402        local host's native bit order is.
403      */
404     image->bitmap_bit_order =
405       image->byte_order =
406         (bigendian() ? MSBFirst : LSBFirst);
407
408     if (!image->data)
409       {
410         fprintf (stderr, "%s: out of memory (%lu x %lu)\n",
411                  progname, (unsigned long)width, (unsigned long)height);
412         return 0;
413       }
414
415     for (y = 0; y < height; y++)
416       {
417         png_bytep i = rows[y];
418         for (x = 0; x < width; x++)
419           {
420             unsigned long rgba;
421             switch (channels) {
422             case 4:
423               rgba = ((i[3] << 24) |
424                       (i[2] << 16) |
425                       (i[1] << 8)  |
426                        i[0]);
427               break;
428             case 3:
429               rgba = ((0xFF << 24) |
430                       (i[2] << 16) |
431                       (i[1] << 8)  |
432                        i[0]);
433               break;
434             case 2:
435               rgba = ((i[1] << 24) |
436                       (i[0] << 16) |
437                       (i[0] << 8)  |
438                        i[0]);
439               break;
440             case 1:
441               rgba = ((0xFF << 24) |
442                       (i[0] << 16) |
443                       (i[0] << 8)  |
444                        i[0]);
445               break;
446             default:
447               abort();
448             }
449             XPutPixel (image, x, y, rgba);
450             i += channels;
451           }
452         png_free (png_ptr, rows[y]);
453       }
454
455     png_free (png_ptr, rows);
456   }
457
458   png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);  
459   if (fp) fclose (fp);
460
461   return image;
462 }
463
464
465 #else /* No image loaders! */
466
467 static XImage *
468 make_ximage (Display *dpy, Visual *visual,
469              const char *filename, const unsigned char *image_data,
470              unsigned long data_size)
471 {
472   fprintf (stderr, "%s: no image loading support!\n", progname);
473   return 0;
474 }
475
476 #endif /* no loaders */
477
478
479 /* Given a bitmask, returns the position and width of the field.
480  */
481 static void
482 decode_mask (unsigned long mask, unsigned long *pos_ret,
483              unsigned long *size_ret)
484 {
485   int i;
486   for (i = 0; i < 32; i++)
487     if (mask & (1L << i))
488       {
489         int j = 0;
490         *pos_ret = i;
491         for (; i < 32; i++, j++)
492           if (! (mask & (1L << i)))
493             break;
494         *size_ret = j;
495         return;
496       }
497 }
498
499
500 /* Loads the image to a Pixmap and optional 1-bit mask.
501  */
502 static Pixmap
503 make_pixmap (Display *dpy, Window window,
504              const char *filename,
505              const unsigned char *image_data, unsigned long data_size,
506              int *width_ret, int *height_ret, Pixmap *mask_ret)
507 {
508   XWindowAttributes xgwa;
509   XImage *in, *out, *mask = 0;
510   Pixmap pixmap;
511   XGCValues gcv;
512   GC gc;
513   int x, y;
514
515   unsigned long crpos=0, cgpos=0, cbpos=0, capos=0; /* bitfield positions */
516   unsigned long srpos=0, sgpos=0, sbpos=0;
517   unsigned long srmsk=0, sgmsk=0, sbmsk=0;
518   unsigned long srsiz=0, sgsiz=0, sbsiz=0;
519
520 # ifdef HAVE_JWXYZ
521   // BlackPixel has alpha: 0xFF000000.
522   unsigned long black = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
523 #else
524   unsigned long black = 0;
525 # endif
526
527   XGetWindowAttributes (dpy, window, &xgwa);
528
529   in = make_ximage (dpy, xgwa.visual, filename, image_data, data_size);
530   if (!in) return 0;
531
532   /* Create a new image in the depth and bit-order of the server. */
533   out = XCreateImage (dpy, xgwa.visual, xgwa.depth, ZPixmap, 0, 0,
534                       in->width, in->height, 8, 0);
535
536   out->bitmap_bit_order = in->bitmap_bit_order;
537   out->byte_order = in->byte_order;
538
539   out->bitmap_bit_order = BitmapBitOrder (dpy);
540   out->byte_order = ImageByteOrder (dpy);
541
542   out->data = (char *) malloc (out->height * out->bytes_per_line);
543   if (!out->data) abort();
544
545   if (mask_ret)
546     {
547       mask = XCreateImage (dpy, xgwa.visual, 1, XYPixmap, 0, 0,
548                            in->width, in->height, 8, 0);
549       mask->byte_order = in->byte_order;
550       mask->data = (char *) malloc (mask->height * mask->bytes_per_line);
551     }
552
553   /* Find the server's color masks.
554    */
555   srmsk = out->red_mask;
556   sgmsk = out->green_mask;
557   sbmsk = out->blue_mask;
558
559   if (!(srmsk && sgmsk && sbmsk)) abort();  /* No server color masks? */
560
561   decode_mask (srmsk, &srpos, &srsiz);
562   decode_mask (sgmsk, &sgpos, &sgsiz);
563   decode_mask (sbmsk, &sbpos, &sbsiz);
564
565   /* 'in' is RGBA in client endianness.  Convert to what the server wants. */
566   if (bigendian())
567     crpos = 24, cgpos = 16, cbpos =  8, capos =  0;
568   else
569     crpos =  0, cgpos =  8, cbpos = 16, capos = 24;
570
571   for (y = 0; y < in->height; y++)
572     for (x = 0; x < in->width; x++)
573       {
574         unsigned long p = XGetPixel (in, x, y);
575         unsigned char a = (p >> capos) & 0xFF;
576         unsigned char b = (p >> cbpos) & 0xFF;
577         unsigned char g = (p >> cgpos) & 0xFF;
578         unsigned char r = (p >> crpos) & 0xFF;
579         XPutPixel (out, x, y, ((r << srpos) |
580                                (g << sgpos) |
581                                (b << sbpos) |
582                                black));
583         if (mask)
584           XPutPixel (mask, x, y, (a ? 1 : 0));
585       }
586
587   XDestroyImage (in);
588   in = 0;
589
590   pixmap = XCreatePixmap (dpy, window, out->width, out->height, xgwa.depth);
591   gc = XCreateGC (dpy, pixmap, 0, &gcv);
592   XPutImage (dpy, pixmap, gc, out, 0, 0, 0, 0, out->width, out->height);
593   XFreeGC (dpy, gc);
594
595   if (mask)
596     {
597       Pixmap p2 = XCreatePixmap (dpy, window, mask->width, mask->height, 1);
598       gcv.foreground = 1;
599       gcv.background = 0;
600       gc = XCreateGC (dpy, p2, GCForeground|GCBackground, &gcv);
601       XPutImage (dpy, p2, gc, mask, 0, 0, 0, 0, mask->width, mask->height);
602       XFreeGC (dpy, gc);
603       XDestroyImage (mask);
604       mask = 0;
605       *mask_ret = p2;
606     }
607
608   if (width_ret)  *width_ret  = out->width;
609   if (height_ret) *height_ret = out->height;
610
611   XDestroyImage (out);
612
613   return pixmap;
614 }
615
616
617 /* Textures are upside down, so invert XImages before returning them.
618  */
619 static void
620 flip_ximage (XImage *ximage)
621 {
622   char *data2, *in, *out;
623   int y;
624
625   data2 = malloc (ximage->bytes_per_line * ximage->height);
626   if (!data2) abort();
627   in = ximage->data;
628   out = data2 + ximage->bytes_per_line * (ximage->height - 1);
629   for (y = 0; y < ximage->height; y++)
630     {
631       memcpy (out, in, ximage->bytes_per_line);
632       in  += ximage->bytes_per_line;
633       out -= ximage->bytes_per_line;
634     }
635   free (ximage->data);
636   ximage->data = data2;
637 }
638
639
640 Pixmap
641 image_data_to_pixmap (Display *dpy, Window window, 
642                       const unsigned char *image_data, unsigned long data_size,
643                       int *width_ret, int *height_ret,
644                       Pixmap *mask_ret)
645 {
646   return make_pixmap (dpy, window, 0, image_data, data_size,
647                       width_ret, height_ret, mask_ret);
648 }
649
650 Pixmap
651 file_to_pixmap (Display *dpy, Window window, const char *filename,
652                 int *width_ret, int *height_ret,
653                 Pixmap *mask_ret)
654 {
655   return make_pixmap (dpy, window, filename, 0, 0,
656                       width_ret, height_ret, mask_ret);
657 }
658
659
660 XImage *
661 image_data_to_ximage (Display *dpy, Visual *visual,
662                       const unsigned char *image_data,
663                       unsigned long data_size)
664 {
665   XImage *ximage = make_ximage (dpy, visual, 0, image_data, data_size);
666   flip_ximage (ximage);
667   return ximage;
668 }
669
670 /* This XImage has RGBA data, which is what OpenGL code typically expects.
671    X11 typically expects 0RGB as it has no notion of alpha, only 1-bit masks.
672    With X11 code, you should probably use the _pixmap routines instead.
673  */
674 XImage *
675 file_to_ximage (Display *dpy, Visual *visual, const char *filename)
676 {
677   XImage *ximage = make_ximage (dpy, visual, filename, 0, 0);
678   flip_ximage (ximage);
679   return ximage;
680 }