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 ----------------------- */
40 #include "safemalloc.h"
42 #include "PictureUtils.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
58 int (*func
)(FIMAGE_CMD_ARGS
);
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
},
88 /* ---------------------------- exported variables (globals) ---------------- */
90 /* ---------------------------- local functions ----------------------------- */
93 /* ***************************************************************************
97 * ***************************************************************************/
99 Bool
PImageLoadPng(FIMAGE_CMD_ARGS
)
101 Fpng_uint_32 w32
, h32
;
102 Fpng_structp Fpng_ptr
= NULL
;
103 Fpng_infop Finfo_ptr
= NULL
;
106 char hasa
= 0, hasg
= 0;
108 int bit_depth
, color_type
, interlace_type
;
109 unsigned char buf
[FPNG_BYTES_TO_CHECK
];
110 unsigned char **lines
;
117 if (!(f
= fopen(path
, "rb")))
122 fread(buf
, 1, FPNG_BYTES_TO_CHECK
, f
);
123 if (!Fpng_check_sig(buf
, FPNG_BYTES_TO_CHECK
))
129 Fpng_ptr
= Fpng_create_read_struct(FPNG_LIBPNG_VER_STRING
,
136 Finfo_ptr
= Fpng_create_info_struct(Fpng_ptr
);
139 Fpng_destroy_read_struct(&Fpng_ptr
, NULL
, NULL
);
144 if (setjmp(Fpng_ptr
->jmpbuf
))
146 Fpng_destroy_read_struct(&Fpng_ptr
, &Finfo_ptr
, NULL
);
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
;
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
)
168 if (Finfo_ptr
->color_type
== FPNG_COLOR_TYPE_GRAY_ALPHA
)
173 if (Finfo_ptr
->color_type
== FPNG_COLOR_TYPE_GRAY
)
178 Fpng_set_expand(Fpng_ptr
);
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
);
189 Fpng_set_bgr(Fpng_ptr
);
190 Fpng_set_filler(Fpng_ptr
, 0xff, FPNG_FILLER_AFTER
);
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 *));
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
);
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
)
232 XFreePixmap(dpy
, *pixmap
);
235 XFreePixmap(dpy
, *alpha
);
238 XFreePixmap(dpy
, *mask
);
243 if (!have_alpha
&& *alpha
!= None
)
245 XFreePixmap(dpy
, *alpha
);
253 /* ***************************************************************************
257 * ***************************************************************************/
259 Bool
PImageLoadXpm(FIMAGE_CMD_ARGS
)
261 FxpmImage xpm_im
= {0};
262 FxpmColor
*xpm_color
;
265 XImage
*im
, *im_mask
= NULL
;
272 Bool have_mask
= False
;
273 PictureImageColorAllocator
*pica
;
274 #ifdef HAVE_SIGACTION
275 struct sigaction defaultHandler
;
276 struct sigaction originalHandler
;
278 void (*originalHandler
)(int);
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
);
290 originalHandler
= signal(SIGCHLD
, SIG_DFL
);
294 rc
= FxpmReadFileToXpmImage(path
, &xpm_im
, NULL
);
296 #ifdef HAVE_SIGACTION
297 sigaction(SIGCHLD
, &originalHandler
, NULL
);
299 signal(SIGCHLD
, originalHandler
);
302 if (rc
!= FxpmSuccess
)
307 if (xpm_im
.ncolors
<= 0)
309 FxpmFreeXpmImage(&xpm_im
);
316 dpy
, Pvisual
, Pdepth
, ZPixmap
, 0, 0, w
, h
,
317 Pdepth
> 16 ? 32 : (Pdepth
> 8 ? 16 : 8), 0);
320 FxpmFreeXpmImage(&xpm_im
);
324 colors
= (XColor
*)safemalloc(xpm_im
.ncolors
* sizeof(XColor
));
325 color_mask
= (char *)safemalloc(xpm_im
.ncolors
);
326 pica
= PictureOpenImageColorAllocator(
328 fpa
.mask
& FPAM_NO_COLOR_LIMIT
,
329 fpa
.mask
& FPAM_NO_ALLOC_PIXELS
,
330 fpa
.mask
& FPAM_DITHER
,
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
;
343 visual_color
= xpm_color
->m_color
;
345 if (strcasecmp(visual_color
,"none") == 0)
348 colors
[i
].pixel
= colors
[i
].red
=
349 colors
[i
].green
= colors
[i
].blue
= 0;
352 else if (!XParseColor(
353 dpy
, Pcmap
, visual_color
, &colors
[i
]))
355 colors
[i
].pixel
= colors
[i
].red
= colors
[i
].green
=
365 PictureAllocColorImage(
366 dpy
, pica
, &colors
[i
], 0, 0);
372 im
->data
= safemalloc(im
->bytes_per_line
* h
);
375 im_mask
= XCreateImage(
376 dpy
, Pvisual
, 1, ZPixmap
, 0, 0, w
, h
,
377 Pdepth
> 16 ? 32 : (Pdepth
> 8 ? 16 : 8), 0);
380 im_mask
->data
= safemalloc(im_mask
->bytes_per_line
* h
);
387 for (i
= 0; i
< w
; i
++)
389 tc
= colors
[xpm_im
.data
[m
]];
390 point_mask
= color_mask
[xpm_im
.data
[m
]];
392 if (point_mask
&& im_mask
)
394 XPutPixel(im_mask
, i
,j
, 0);
400 PictureAllocColorImage(
401 dpy
, pica
, &tc
, i
, j
);
405 XPutPixel(im_mask
, i
,j
, 1);
408 XPutPixel(im
, i
,j
, tc
.pixel
);
412 *pixmap
= XCreatePixmap(dpy
, win
, w
, h
, Pdepth
);
414 dpy
, *pixmap
, PictureDefaultGC(dpy
, win
), im
,
421 *mask
= XCreatePixmap(dpy
, win
, w
, h
, 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
);
436 PictureCloseImageColorAllocator(
437 dpy
, pica
, nalloc_pixels
, alloc_pixels
, no_limit
);
440 FxpmFreeXpmImage(&xpm_im
);
444 /* ***************************************************************************
448 * ***************************************************************************/
450 Bool
PImageLoadBitmap(FIMAGE_CMD_ARGS
)
454 if (XReadBitmapFile(dpy
, win
, path
, width
, height
, pixmap
, &l
, &l
)
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
)
481 XImage
*image
, *m_image
= NULL
;
482 XImage
*a_image
= NULL
;
485 Bool use_alpha_pix
= (alpha
!= None
&& !(fpa
.mask
& FPAM_NO_ALPHA
)
486 && FRenderGetAlphaDepth());
487 PictureImageColorAllocator
*pica
;
493 a_gc
= fvwmlib_XCreateGC(dpy
, alpha
, 0, NULL
);
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);
510 XFreeGC(dpy
, mono_gc
);
513 fprintf(stderr
, "[FVWM][PImageCreatePixmapFromArgbData] "
514 "-- WARN cannot create an XImage\n");
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
);
527 m_image
->data
= safemalloc(m_image
->bytes_per_line
* height
);
531 a_image
= XCreateImage(
532 dpy
, Pvisual
, FRenderGetAlphaDepth(), ZPixmap
,
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
),
545 c
.flags
= DoRed
| DoGreen
| DoBlue
;
548 alpha_limit
= PICTURE_ALPHA_LIMIT
;
550 for (j
= 0; j
< height
; j
++)
552 for (i
= 0; i
< width
; i
++)
561 PictureAllocColorImage(
562 dpy
, pica
, &c
, i
, j
);
568 XPutPixel(image
, i
, j
, c
.pixel
);
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 */
584 dpy
, pixmap
, PictureDefaultGC(dpy
, win
), image
,
585 0, 0, 0, 0, width
, height
);
589 dpy
, mask
, mono_gc
, m_image
, 0, 0, 0, 0, width
, height
);
593 XPutImage(dpy
, alpha
, a_gc
, a_image
, 0, 0, 0, 0, width
, height
);
595 XDestroyImage(image
);
597 XDestroyImage(m_image
);
598 if (use_alpha_pix
&& a_image
)
599 XDestroyImage(a_image
);
601 XFreeGC(dpy
, mono_gc
);
604 PictureCloseImageColorAllocator(
605 dpy
, pica
, nalloc_pixels
, alloc_pixels
, no_limit
);
610 /* ***************************************************************************
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;
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
))
637 dpy
, win
, path
, pixmap
, mask
, alpha
, width
,
638 height
, depth
, nalloc_pixels
, alloc_pixels
,
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
))
663 *width
= *height
= *depth
= 0;
664 if (nalloc_pixels
!= NULL
)
668 if (alloc_pixels
!= NULL
)
670 *alloc_pixels
= NULL
;
675 FvwmPicture
*PImageLoadFvwmPictureFromFile(
676 Display
*dpy
, Window win
, char *path
, FvwmPictureAttributes fpa
)
679 Pixmap pixmap
= 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
))
693 p
= (FvwmPicture
*)safemalloc(sizeof(FvwmPicture
));
694 memset(p
, 0, sizeof(FvwmPicture
));
697 p
->fpa_mask
= fpa
.mask
;
699 setFileStamp(&p
->stamp
, p
->name
);
706 p
->nalloc_pixels
= nalloc_pixels
;
707 p
->alloc_pixels
= alloc_pixels
;
708 p
->no_limit
= no_limit
;
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
;
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",
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;
748 /* FIXME: Use color limit */
749 Bool
PImageLoadPixmapFromXpmData(
750 Display
*dpy
, Window win
, int color_limit
,
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
)
768 *width
= xpm_attributes
.width
;
769 *height
= xpm_attributes
.height
;