* FvwmTheme/FvwmTheme.1: Language check, general edits,
[fvwm.git] / libs / PictureImageLoader.c
blobc4b75606277e92cd9ac64e1350418a4818fc9e57
1 /* -*-c-*- */
2 /* Copyright (C) 1993, Robert Nation
3 * Copyright (C) 1999 Carsten Haitzler and various contributors (imlib2)
4 * Copyright (C) 2002 Olivier Chapuis
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * The png loader and PImageRGBtoPixel are from imlib2. The code is from raster
24 * (Carsten Haitzler) <raster@rasterman.com> <raster@valinux.com>
28 /* ---------------------------- included header files ----------------------- */
30 #include "config.h"
32 #include <stdio.h>
33 #include <signal.h>
34 #include <ctype.h>
36 #include <X11/Xlib.h>
37 #include <X11/Xmd.h>
39 #include <fvwmlib.h>
40 #include "safemalloc.h"
41 #include "Picture.h"
42 #include "PictureUtils.h"
43 #include "Fxpm.h"
44 #include "Fpng.h"
45 #include "FRenderInit.h"
47 /* ---------------------------- local definitions --------------------------- */
48 #define FIMAGE_CMD_ARGS Display *dpy, Window win, char *path, \
49 Pixmap *pixmap, Pixmap *mask, Pixmap *alpha, \
50 int *width, int *height, int *depth, \
51 int *nalloc_pixels, Pixel **alloc_pixels, int *no_limit, \
52 FvwmPictureAttributes fpa
54 typedef struct PImageLoader
56 char *extension;
57 #ifdef __STDC__
58 int (*func)(FIMAGE_CMD_ARGS);
59 #else
60 int (*func)();
61 #endif
62 } PImageLoader;
64 /* ---------------------------- local macros -------------------------------- */
66 /* ---------------------------- imports ------------------------------------- */
68 /* ---------------------------- included code files ------------------------- */
70 /* ---------------------------- local types --------------------------------- */
72 /* ---------------------------- forward declarations ------------------------ */
74 static Bool PImageLoadPng(FIMAGE_CMD_ARGS);
75 static Bool PImageLoadXpm(FIMAGE_CMD_ARGS);
76 static Bool PImageLoadBitmap(FIMAGE_CMD_ARGS);
78 /* ---------------------------- local variables ----------------------------- */
80 PImageLoader Loaders[] =
82 { "xpm", PImageLoadXpm },
83 { "png", PImageLoadPng },
84 { "bmp", PImageLoadBitmap },
85 {NULL,0}
88 /* ---------------------------- exported variables (globals) ---------------- */
90 /* ---------------------------- local functions ----------------------------- */
93 /* ***************************************************************************
95 * png loader
97 * ***************************************************************************/
98 static
99 Bool PImageLoadPng(FIMAGE_CMD_ARGS)
101 Fpng_uint_32 w32, h32;
102 Fpng_structp Fpng_ptr = NULL;
103 Fpng_infop Finfo_ptr = NULL;
104 CARD32 *data;
105 int w, h;
106 char hasa = 0, hasg = 0;
107 FILE *f;
108 int bit_depth, color_type, interlace_type;
109 unsigned char buf[FPNG_BYTES_TO_CHECK];
110 unsigned char **lines;
111 int i;
112 int have_alpha;
114 if (!PngSupport)
115 return False;
117 if (!(f = fopen(path, "rb")))
119 return False;
122 fread(buf, 1, FPNG_BYTES_TO_CHECK, f);
123 if (!Fpng_check_sig(buf, FPNG_BYTES_TO_CHECK))
125 fclose(f);
126 return False;
128 rewind(f);
129 Fpng_ptr = Fpng_create_read_struct(FPNG_LIBPNG_VER_STRING,
130 NULL, NULL, NULL);
131 if (!Fpng_ptr)
133 fclose(f);
134 return False;
136 Finfo_ptr = Fpng_create_info_struct(Fpng_ptr);
137 if (!Finfo_ptr)
139 Fpng_destroy_read_struct(&Fpng_ptr, NULL, NULL);
140 fclose(f);
141 return False;
143 #if 0
144 if (setjmp(Fpng_ptr->jmpbuf))
146 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, NULL);
147 fclose(f);
148 return False;
150 #endif
151 Fpng_init_io(Fpng_ptr, f);
152 Fpng_read_info(Fpng_ptr, Finfo_ptr);
153 Fpng_get_IHDR(Fpng_ptr, Finfo_ptr, (Fpng_uint_32 *) (&w32),
154 (Fpng_uint_32 *) (&h32), &bit_depth, &color_type,
155 &interlace_type, NULL, NULL);
156 interlace_type = 0; /* not used */
157 *width = w = (int) w32;
158 *height = h = (int) h32;
159 *depth = bit_depth;
160 if (color_type == FPNG_COLOR_TYPE_PALETTE)
162 Fpng_set_expand(Fpng_ptr);
164 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_RGB_ALPHA)
166 hasa = 1;
168 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_GRAY_ALPHA)
170 hasa = 1;
171 hasg = 1;
173 if (Finfo_ptr->color_type == FPNG_COLOR_TYPE_GRAY)
175 hasg = 1;
177 if (hasa)
178 Fpng_set_expand(Fpng_ptr);
179 /* we want ARGB */
180 /* note form raster:
181 * thanks to mustapha for helping debug this on PPC Linux remotely by
182 * sending across screenshots all the tiem and me figuring out form them
183 * what the hell was up with the colors
184 * now png loading shoudl work on big endian machines nicely */
185 #ifdef WORDS_BIGENDIAN
186 Fpng_set_swap_alpha(Fpng_ptr);
187 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_BEFORE);
188 #else
189 Fpng_set_bgr(Fpng_ptr);
190 Fpng_set_filler(Fpng_ptr, 0xff, FPNG_FILLER_AFTER);
191 #endif
192 /* 16bit color -> 8bit color */
193 Fpng_set_strip_16(Fpng_ptr);
194 /* pack all pixels to byte boundaires */
195 Fpng_set_packing(Fpng_ptr);
196 if (Fpng_get_valid(Fpng_ptr, Finfo_ptr, FPNG_INFO_tRNS))
197 Fpng_set_expand(Fpng_ptr);
199 data = (CARD32 *)safemalloc(w * h * sizeof(CARD32));
200 lines = (unsigned char **) safemalloc(h * sizeof(unsigned char *));
202 if (hasg)
204 Fpng_set_gray_to_rgb(Fpng_ptr);
205 if (Fpng_get_bit_depth(Fpng_ptr, Finfo_ptr) < 8)
207 Fpng_set_gray_1_2_4_to_8(Fpng_ptr);
210 for (i = 0; i < h; i++)
212 lines[i] =((unsigned char *) (data)) + (i * w * sizeof(CARD32));
214 Fpng_read_image(Fpng_ptr, lines);
215 Fpng_read_end(Fpng_ptr, Finfo_ptr);
216 Fpng_destroy_read_struct(&Fpng_ptr, &Finfo_ptr, (png_infopp) NULL);
217 fclose(f);
219 *depth = Pdepth;
220 *pixmap = XCreatePixmap(dpy, win, w, h, Pdepth);
221 *mask = XCreatePixmap(dpy, win, w, h, 1);
222 if (!(fpa.mask & FPAM_NO_ALPHA) && FRenderGetAlphaDepth())
224 *alpha = XCreatePixmap(dpy, win, w, h, FRenderGetAlphaDepth());
226 if (!PImageCreatePixmapFromArgbData(
227 dpy, win, (unsigned char *)data, 0, w, h, *pixmap, *mask,
228 *alpha, &have_alpha, nalloc_pixels, alloc_pixels, no_limit, fpa)
229 || *pixmap == None)
231 if (*pixmap != None)
232 XFreePixmap(dpy, *pixmap);
233 if (*alpha != None)
235 XFreePixmap(dpy, *alpha);
237 if (*mask != None)
238 XFreePixmap(dpy, *mask);
239 free(data);
240 free(lines);
241 return False;
243 if (!have_alpha && *alpha != None)
245 XFreePixmap(dpy, *alpha);
246 *alpha = None;
248 free(lines);
249 free(data);
250 return True;
253 /* ***************************************************************************
255 * xpm loader
257 * ***************************************************************************/
258 static
259 Bool PImageLoadXpm(FIMAGE_CMD_ARGS)
261 FxpmImage xpm_im = {0};
262 FxpmColor *xpm_color;
263 char *visual_color;
264 int rc;
265 XImage *im, *im_mask = NULL;
266 XColor *colors;
267 XColor tc;
268 int i,j,w,h;
269 int k = 0, m = 0;
270 char *color_mask;
271 char point_mask;
272 Bool have_mask = False;
273 PictureImageColorAllocator *pica;
274 #ifdef HAVE_SIGACTION
275 struct sigaction defaultHandler;
276 struct sigaction originalHandler;
277 #else
278 void (*originalHandler)(int);
279 #endif
281 if (!XpmSupport)
282 return False;
284 #ifdef HAVE_SIGACTION
285 sigemptyset(&defaultHandler.sa_mask);
286 defaultHandler.sa_flags = 0;
287 defaultHandler.sa_handler = SIG_DFL;
288 sigaction(SIGCHLD, &defaultHandler, &originalHandler);
289 #else
290 originalHandler = signal(SIGCHLD, SIG_DFL);
291 #endif
294 rc = FxpmReadFileToXpmImage(path, &xpm_im, NULL);
296 #ifdef HAVE_SIGACTION
297 sigaction(SIGCHLD, &originalHandler, NULL);
298 #else
299 signal(SIGCHLD, originalHandler);
300 #endif
302 if (rc != FxpmSuccess)
304 return False;
307 if (xpm_im.ncolors <= 0)
309 FxpmFreeXpmImage(&xpm_im);
310 return False;
313 w = xpm_im.width;
314 h = xpm_im.height;
315 im = XCreateImage(
316 dpy, Pvisual, Pdepth, ZPixmap, 0, 0, w, h,
317 Pdepth > 16 ? 32 : (Pdepth > 8 ? 16 : 8), 0);
318 if (!im)
320 FxpmFreeXpmImage(&xpm_im);
321 return False;
324 colors = (XColor *)safemalloc(xpm_im.ncolors * sizeof(XColor));
325 color_mask = (char *)safemalloc(xpm_im.ncolors);
326 pica = PictureOpenImageColorAllocator(
327 dpy, Pcmap, w, h,
328 fpa.mask & FPAM_NO_COLOR_LIMIT,
329 fpa.mask & FPAM_NO_ALLOC_PIXELS,
330 fpa.mask & FPAM_DITHER,
331 False);
332 for(i=0; i < xpm_im.ncolors; i++)
334 xpm_color = &xpm_im.colorTable[i];
335 if (xpm_color->c_color)
337 visual_color = xpm_color->c_color;
338 } else if (xpm_color->g_color) {
339 visual_color = xpm_color->g_color;
340 } else if (xpm_color->g4_color) {
341 visual_color = xpm_color->g4_color;
342 } else {
343 visual_color = xpm_color->m_color;
345 if (strcasecmp(visual_color,"none") == 0)
347 have_mask = True;
348 colors[i].pixel = colors[i].red =
349 colors[i].green = colors[i].blue = 0;
350 color_mask[i] = 1;
352 else if (!XParseColor(
353 dpy, Pcmap, visual_color, &colors[i]))
355 colors[i].pixel = colors[i].red = colors[i].green =
356 colors[i].blue = 0;
357 color_mask[i] = 0;
358 k++;
360 else
362 color_mask[i] = 0;
363 if (!pica->dither)
365 PictureAllocColorImage(
366 dpy, pica, &colors[i], 0, 0);
368 k++;
372 im->data = safemalloc(im->bytes_per_line * h);
373 if (have_mask)
375 im_mask = XCreateImage(
376 dpy, Pvisual, 1, ZPixmap, 0, 0, w, h,
377 Pdepth > 16 ? 32 : (Pdepth > 8 ? 16 : 8), 0);
378 if (im_mask)
380 im_mask->data = safemalloc(im_mask->bytes_per_line * h);
384 m=0;
385 for(j=0; j < h; j++)
387 for (i = 0; i < w; i++)
389 tc = colors[xpm_im.data[m]];
390 point_mask = color_mask[xpm_im.data[m]];
391 m++;
392 if (point_mask && im_mask)
394 XPutPixel(im_mask, i,j, 0);
396 else
398 if (pica->dither)
400 PictureAllocColorImage(
401 dpy, pica, &tc, i, j);
403 if (im_mask)
405 XPutPixel(im_mask, i,j, 1);
408 XPutPixel(im, i,j, tc.pixel);
412 *pixmap = XCreatePixmap(dpy, win, w, h, Pdepth);
413 XPutImage(
414 dpy, *pixmap, PictureDefaultGC(dpy, win), im,
415 0, 0, 0, 0, w, h);
416 if (im_mask)
418 GC mono_gc = None;
419 XGCValues xgcv;
421 *mask = XCreatePixmap(dpy, win, w, h, 1);
422 xgcv.foreground = 0;
423 xgcv.background = 1;
424 mono_gc = fvwmlib_XCreateGC(
425 dpy, *mask, GCForeground | GCBackground, &xgcv);
426 XPutImage(dpy, *mask, mono_gc, im_mask, 0, 0, 0, 0, w, h);
427 XFreeGC(dpy, mono_gc);
428 XDestroyImage(im_mask);
431 XDestroyImage(im);
432 *width = w;
433 *height = h;
434 *depth = Pdepth;
436 PictureCloseImageColorAllocator(
437 dpy, pica, nalloc_pixels, alloc_pixels, no_limit);
438 free(colors);
439 free(color_mask);
440 FxpmFreeXpmImage(&xpm_im);
441 return True;
444 /* ***************************************************************************
446 * bitmap loader
448 * ***************************************************************************/
449 static
450 Bool PImageLoadBitmap(FIMAGE_CMD_ARGS)
452 int l;
454 if (XReadBitmapFile(dpy, win, path, width, height, pixmap, &l, &l)
455 == BitmapSuccess)
457 *mask = None;
458 *depth = 1;
459 return True;
461 return False;
464 /* ---------------------------- interface functions ------------------------- */
466 /* ***************************************************************************
468 * argb data to pixmaps
470 * ***************************************************************************/
471 Bool PImageCreatePixmapFromArgbData(
472 Display *dpy, Window win, unsigned char *data, int start, int width,
473 int height, Pixmap pixmap, Pixmap mask, Pixmap alpha, int *have_alpha,
474 int *nalloc_pixels, Pixel **alloc_pixels, int *no_limit,
475 FvwmPictureAttributes fpa)
477 GC mono_gc = None;
478 GC a_gc = None;
479 XGCValues xgcv;
480 register int i,j,k;
481 XImage *image, *m_image = NULL;
482 XImage *a_image = NULL;
483 XColor c;
484 int a;
485 Bool use_alpha_pix = (alpha != None && !(fpa.mask & FPAM_NO_ALPHA)
486 && FRenderGetAlphaDepth());
487 PictureImageColorAllocator *pica;
488 int alpha_limit = 0;
490 *have_alpha = False;
491 if (use_alpha_pix)
493 a_gc = fvwmlib_XCreateGC(dpy, alpha, 0, NULL);
495 if (mask)
497 xgcv.foreground = 0;
498 xgcv.background = 1;
499 mono_gc = fvwmlib_XCreateGC(dpy, mask,
500 GCForeground | GCBackground, &xgcv);
503 /* create an XImage structure */
504 image = XCreateImage(
505 dpy, Pvisual, Pdepth, ZPixmap, 0, 0, width, height,
506 Pdepth > 16 ? 32 : (Pdepth > 8 ? 16 : 8), 0);
507 if (!image)
509 if (mono_gc != None)
510 XFreeGC(dpy, mono_gc);
511 if (a_gc != None)
512 XFreeGC(dpy, a_gc);
513 fprintf(stderr, "[FVWM][PImageCreatePixmapFromArgbData] "
514 "-- WARN cannot create an XImage\n");
515 return False;
517 if (mask)
519 m_image = XCreateImage(
520 dpy, Pvisual, 1, ZPixmap, 0, 0, width, height,
521 Pdepth > 16 ? 32 : (Pdepth > 8 ? 16 : 8), 0);
523 /* create space for drawing the image locally */
524 image->data = safemalloc(image->bytes_per_line * height);
525 if (m_image)
527 m_image->data = safemalloc(m_image->bytes_per_line * height);
529 if (use_alpha_pix)
531 a_image = XCreateImage(
532 dpy, Pvisual, FRenderGetAlphaDepth(), ZPixmap,
533 0, 0, width, height,
534 Pdepth > 16 ? 32 : (Pdepth > 8 ? 16 : 8), 0);
535 a_image->data = safemalloc(a_image->bytes_per_line * height);
538 pica = PictureOpenImageColorAllocator(
539 dpy, Pcmap, width, height,
540 !!(fpa.mask & FPAM_NO_COLOR_LIMIT),
541 !!(fpa.mask & FPAM_NO_ALLOC_PIXELS),
542 !!(fpa.mask & FPAM_DITHER),
543 True);
544 k = 4*start;
545 c.flags = DoRed | DoGreen | DoBlue;
546 if (!use_alpha_pix)
548 alpha_limit = PICTURE_ALPHA_LIMIT;
550 for (j = 0; j < height; j++)
552 for (i = 0; i < width; i++)
554 c.blue = data[k++];
555 c.green = data[k++];
556 c.red = data[k++];
557 a = data[k++];
559 if (a > alpha_limit)
561 PictureAllocColorImage(
562 dpy, pica, &c, i, j);
564 else
566 c.pixel = 0;
568 XPutPixel(image, i, j, c.pixel);
569 if (m_image)
571 XPutPixel(
572 m_image, i, j,
573 (a > alpha_limit)? 1:0);
575 if (use_alpha_pix && a_image)
577 XPutPixel(a_image, i, j, a);
578 *have_alpha |= (a < 255 && a > 0);
582 /* copy the image to the server */
583 XPutImage(
584 dpy, pixmap, PictureDefaultGC(dpy, win), image,
585 0, 0, 0, 0, width, height);
586 if (m_image)
588 XPutImage(
589 dpy, mask, mono_gc, m_image, 0, 0, 0, 0, width, height);
591 if (*have_alpha)
593 XPutImage(dpy, alpha, a_gc, a_image, 0, 0, 0, 0, width, height);
595 XDestroyImage(image);
596 if (m_image)
597 XDestroyImage(m_image);
598 if (use_alpha_pix && a_image)
599 XDestroyImage(a_image);
600 if (mono_gc != None)
601 XFreeGC(dpy, mono_gc);
602 if (a_gc != None)
603 XFreeGC(dpy, a_gc);
604 PictureCloseImageColorAllocator(
605 dpy, pica, nalloc_pixels, alloc_pixels, no_limit);
606 return True;
610 /* ***************************************************************************
612 * the images loaders
614 * ***************************************************************************/
616 Bool PImageLoadPixmapFromFile(
617 Display *dpy, Window win, char *path, Pixmap *pixmap, Pixmap *mask,
618 Pixmap *alpha, int *width, int *height, int *depth, int *nalloc_pixels,
619 Pixel **alloc_pixels, int *no_limit, FvwmPictureAttributes fpa)
621 int done = 0, i = 0, tried = -1;
622 char *ext = NULL;
624 if (path == NULL)
625 return False;
627 if (strlen(path) > 3)
629 ext = path + strlen(path) - 3;
631 /* first try to load by extension */
632 while(!done && ext != NULL && Loaders[i].extension != NULL)
634 if (StrEquals(Loaders[i].extension, ext))
636 if (Loaders[i].func(
637 dpy, win, path, pixmap, mask, alpha, width,
638 height, depth, nalloc_pixels, alloc_pixels,
639 no_limit, fpa))
641 return True;
643 tried = i;
644 done = 1;
646 i++;
649 i = 0;
650 while(Loaders[i].extension != NULL)
652 if (i != tried && Loaders[i].func(
653 dpy, win, path, pixmap, mask, alpha, width, height,
654 depth, nalloc_pixels, alloc_pixels, no_limit, fpa))
656 return True;
658 i++;
660 pixmap = None;
661 mask = None;
662 alpha = None;
663 *width = *height = *depth = 0;
664 if (nalloc_pixels != NULL)
666 *nalloc_pixels = 0;
668 if (alloc_pixels != NULL)
670 *alloc_pixels = NULL;
672 return False;
675 FvwmPicture *PImageLoadFvwmPictureFromFile(
676 Display *dpy, Window win, char *path, FvwmPictureAttributes fpa)
678 FvwmPicture *p;
679 Pixmap pixmap = None;
680 Pixmap mask = None;
681 Pixmap alpha = None;
682 int width = 0, height = 0, depth = 0, no_limit;
683 int nalloc_pixels = 0;
684 Pixel *alloc_pixels = NULL;
686 if (!PImageLoadPixmapFromFile(
687 dpy, win, path, &pixmap, &mask, &alpha, &width, &height,
688 &depth, &nalloc_pixels, &alloc_pixels, &no_limit, fpa))
690 return NULL;
693 p = (FvwmPicture*)safemalloc(sizeof(FvwmPicture));
694 memset(p, 0, sizeof(FvwmPicture));
695 p->count = 1;
696 p->name = path;
697 p->fpa_mask = fpa.mask;
698 p->next = NULL;
699 setFileStamp(&p->stamp, p->name);
700 p->picture = pixmap;
701 p->mask = mask;
702 p->alpha = alpha;
703 p->width = width;
704 p->height = height;
705 p->depth = depth;
706 p->nalloc_pixels = nalloc_pixels;
707 p->alloc_pixels = alloc_pixels;
708 p->no_limit = no_limit;
709 return p;
713 Bool PImageLoadCursorPixmapFromFile(
714 Display *dpy, Window win, char *path, Pixmap *source, Pixmap *mask,
715 unsigned int *x, unsigned int *y)
718 FxpmAttributes xpm_attributes;
720 if (!XpmSupport)
721 return False;
723 /* we need source to be a bitmap */
724 xpm_attributes.depth = 1;
725 xpm_attributes.valuemask = FxpmSize | FxpmDepth | FxpmHotspot;
726 if (FxpmReadFileToPixmap(dpy, win, path, source, mask,
727 &xpm_attributes) != FxpmSuccess)
729 fprintf(stderr, "[FVWM][PImageLoadCursorPixmapFromFile]"
730 " Error reading cursor xpm %s",
731 path);
732 return False;
735 *x = xpm_attributes.x_hotspot;
736 if (*x >= xpm_attributes.width)
738 *x = xpm_attributes.width / 2;
740 *y = xpm_attributes.y_hotspot;
741 if (*y >= xpm_attributes.height)
743 *y = xpm_attributes.height / 2;
745 return True;
748 /* FIXME: Use color limit */
749 Bool PImageLoadPixmapFromXpmData(
750 Display *dpy, Window win, int color_limit,
751 char **data,
752 Pixmap *pixmap, Pixmap *mask,
753 int *width, int *height, int *depth)
755 FxpmAttributes xpm_attributes;
757 xpm_attributes.valuemask = FxpmCloseness |
758 FxpmExtensions | FxpmVisual | FxpmColormap | FxpmDepth;
759 xpm_attributes.closeness = 40000;
760 xpm_attributes.visual = Pvisual;
761 xpm_attributes.colormap = Pcmap;
762 xpm_attributes.depth = Pdepth;
763 if(FxpmCreatePixmapFromData(dpy, win, data, pixmap, mask,
764 &xpm_attributes)!=FxpmSuccess)
766 return False;
768 *width = xpm_attributes.width;
769 *height = xpm_attributes.height;
770 *depth = Pdepth;
771 return True;