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