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
bigendian(void)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 *
make_ximage(Display * dpy,Visual * visual,const char * filename,const unsigned char * image_data,unsigned long data_size)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 *
make_ximage(Display * dpy,Visual * visual,const char * filename,const unsigned char * image_data,unsigned long data_size)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
png_reader_fn(png_structp png_ptr,png_bytep buf,png_size_t siz)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 *
make_ximage(Display * dpy,Visual * visual,const char * filename,const unsigned char * image_data,unsigned long data_size)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 *
make_ximage(Display * dpy,Visual * visual,const char * filename,const unsigned char * image_data,unsigned long data_size)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
decode_mask(unsigned long mask,unsigned long * pos_ret,unsigned long * size_ret)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
make_pixmap(Display * dpy,Window window,const char * filename,const unsigned char * image_data,unsigned long data_size,int * width_ret,int * height_ret,Pixmap * mask_ret)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
flip_ximage(XImage * ximage)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
image_data_to_pixmap(Display * dpy,Window window,const unsigned char * image_data,unsigned long data_size,int * width_ret,int * height_ret,Pixmap * mask_ret)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
file_to_pixmap(Display * dpy,Window window,const char * filename,int * width_ret,int * height_ret,Pixmap * mask_ret)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 *
image_data_to_ximage(Display * dpy,Visual * visual,const unsigned char * image_data,unsigned long data_size)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 *
file_to_ximage(Display * dpy,Visual * visual,const char * filename)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 }
687