2 /* Copyright (C) 1993, Robert Nation
3 * Copyright (C) 1999 Carsten Haitzler and various contributors (imlib2)
4 * Copyright (C) 2002 Olivier Chapuis */
5 /* This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * The png loader and PImageRGBtoPixel are from imlib2. The code is from raster
23 * (Carsten Haitzler) <raster@rasterman.com> <raster@valinux.com>
27 /* ---------------------------- included header files ---------------------- */
42 #include "PictureUtils.h"
44 #include "ColorUtils.h"
48 #include "FRenderInit.h"
52 /* ---------------------------- local definitions -------------------------- */
53 #define FIMAGE_CMD_ARGS \
54 Display *dpy, char *path, CARD32 **argb_data, int *width, int *height
56 #define FIMAGE_PASS_ARGS \
57 dpy, path, argb_data, width, height
59 typedef struct PImageLoader
63 int (*func
)(FIMAGE_CMD_ARGS
);
69 /* ---------------------------- local macros ------------------------------- */
71 /* ---------------------------- imports ------------------------------------ */
73 /* ---------------------------- included code files ------------------------ */
75 /* ---------------------------- local types -------------------------------- */
77 /* ---------------------------- forward declarations ----------------------- */
79 static Bool
PImageLoadSvg(FIMAGE_CMD_ARGS
);
80 static Bool
PImageLoadPng(FIMAGE_CMD_ARGS
);
81 static Bool
PImageLoadXpm(FIMAGE_CMD_ARGS
);
83 /* ---------------------------- local variables ---------------------------- */
85 PImageLoader Loaders
[] =
87 { "xpm", PImageLoadXpm
},
88 { "svg", PImageLoadSvg
},
89 { "png", PImageLoadPng
},
93 /* ---------------------------- exported variables (globals) --------------- */
95 /* ---------------------------- local functions ---------------------------- */
98 Bool
PImageLoadArgbDataFromFile(FIMAGE_CMD_ARGS
)
100 int done
= 0, i
= 0, tried
= -1;
106 if (strlen(path
) > 3)
108 ext
= path
+ strlen(path
) - 3;
110 /* first try to load by extension */
111 while (!done
&& ext
!= NULL
&& Loaders
[i
].extension
!= NULL
)
113 if (StrEquals(Loaders
[i
].extension
, ext
))
115 if (Loaders
[i
].func(FIMAGE_PASS_ARGS
))
126 while (Loaders
[i
].extension
!= NULL
)
128 if (i
!= tried
&& Loaders
[i
].func(FIMAGE_PASS_ARGS
))
144 Bool
PImageLoadSvg(FIMAGE_CMD_ARGS
)
146 char *allocated_path
;
149 FRsvgDimensionData dim
;
151 Fcairo_surface_t
*surface
;
167 Bool transpose
= False
;
168 unsigned char a_value
;
169 unsigned char r_value
;
170 unsigned char g_value
;
171 unsigned char b_value
;
178 /* Separate rendering options from path */
179 render_opts
= path
= allocated_path
= safestrdup(path
);
180 if (*path
== ':' && (path
= strchr(path
+ 1, ':')))
191 if (!(rsvg
= Frsvg_handle_new_from_file(path
, NULL
)))
193 free(allocated_path
);
198 /* Parsing of rendering options */
202 switch (*render_opts
)
205 transpose
= !transpose
;
208 if (sscanf(render_opts
, "*%lf%n", &buf
, &i
) >= 1)
210 switch (render_opts
[i
])
227 if (sscanf(render_opts
, "/%lf%n", &buf
, &i
) >= 1 &&
230 switch (render_opts
[i
])
247 if (sscanf(render_opts
, "@%lf%n", &buf
, &i
) >= 1)
256 render_opts
, "%dx%n%d%n", &b1
, &j
, &b2
,
263 if (w
< 0 || (!w
&& render_opts
[0] == '-'))
267 if (h
< 0 || (!h
&& render_opts
[j
] == '-'))
273 sscanf(render_opts
, "%d%d%n", &b1
, &b2
, &i
) >=
280 render_opts
+= i
? i
: 1;
282 free(allocated_path
);
284 /* Keep the original aspect ratio when either w or h is 0 */
285 Frsvg_handle_get_dimensions(rsvg
, &dim
);
293 w
= h
* dim
.em
/ dim
.ex
;
297 h
= w
* dim
.ex
/ dim
.em
;
320 data
= (CARD32
*)safemalloc(w
* h
* sizeof(CARD32
));
321 memset(data
, 0, w
* h
* sizeof(CARD32
));
322 surface
= Fcairo_image_surface_create_for_data((unsigned char *)data
,
323 FCAIRO_FORMAT_ARGB32
, w
, h
, w
* sizeof(CARD32
));
324 if (Fcairo_surface_status(surface
) != FCAIRO_STATUS_SUCCESS
)
326 Fg_object_unref(FG_OBJECT(rsvg
));
330 Fcairo_surface_destroy(surface
);
335 cr
= Fcairo_create(surface
);
336 Fcairo_surface_destroy(surface
);
337 if (Fcairo_status(cr
) != FCAIRO_STATUS_SUCCESS
)
339 Fg_object_unref(FG_OBJECT(rsvg
));
349 /* Affine transformations ...
350 * mirroring, rotation, scaling and translation */
351 Fcairo_translate(cr
, .5 * w
, .5 * h
);
352 Fcairo_scale(cr
, w_sgn
, h_sgn
);
353 Fcairo_translate(cr
, dw
, dh
);
354 Fcairo_rotate(cr
, angle
* M_PI
/ 180);
355 Fcairo_scale(cr
, w_scale
, h_scale
);
356 Fcairo_translate(cr
, -.5, -.5);
357 Fcairo_scale(cr
, 1 / dim
.em
, 1 / dim
.ex
);
359 Frsvg_handle_render_cairo(rsvg
, cr
);
360 Fg_object_unref(FG_OBJECT(rsvg
));
363 /* Cairo gave us alpha prescaled RGB values, hence we need
364 * to rescale them for PImageCreatePixmapFromArgbData() */
365 for (i
= 0; i
< w
* h
; i
++)
367 if ((a_value
= (data
[i
] >> 030) & 0xff))
369 r_value
= ((data
[i
] >> 020) & 0xff) * 0xff / a_value
;
370 g_value
= ((data
[i
] >> 010) & 0xff) * 0xff / a_value
;
371 b_value
= (data
[i
] & 0xff) * 0xff / a_value
;
374 (a_value
<< 030) | (r_value
<< 020) |
375 (g_value
<< 010) | b_value
;
392 Bool
PImageLoadPng(FIMAGE_CMD_ARGS
)
394 Fpng_uint_32 w32
, h32
;
395 Fpng_structp Fpng_ptr
= NULL
;
396 Fpng_infop Finfo_ptr
= NULL
;
399 char hasa
= 0, hasg
= 0;
404 unsigned char buf
[FPNG_BYTES_TO_CHECK
];
405 unsigned char **lines
;
410 /* suppress compiler warning */
415 if (!(f
= fopen(path
, "rb")))
419 fread(buf
, 1, FPNG_BYTES_TO_CHECK
, f
);
420 if (!Fpng_check_sig(buf
, FPNG_BYTES_TO_CHECK
))
426 Fpng_ptr
= Fpng_create_read_struct(FPNG_LIBPNG_VER_STRING
,
433 Finfo_ptr
= Fpng_create_info_struct(Fpng_ptr
);
436 Fpng_destroy_read_struct(&Fpng_ptr
, NULL
, NULL
);
441 if (setjmp(Fpng_ptr
->jmpbuf
))
443 Fpng_destroy_read_struct(&Fpng_ptr
, &Finfo_ptr
, NULL
);
448 Fpng_init_io(Fpng_ptr
, f
);
449 Fpng_read_info(Fpng_ptr
, Finfo_ptr
);
451 Fpng_ptr
, Finfo_ptr
, (Fpng_uint_32
*) (&w32
),
452 (Fpng_uint_32
*) (&h32
), &bit_depth
, &color_type
,
453 &interlace_type
, NULL
, NULL
);
454 interlace_type
= 0; /* not used */
455 *width
= w
= (int) w32
;
456 *height
= h
= (int) h32
;
457 if (color_type
== FPNG_COLOR_TYPE_PALETTE
)
459 Fpng_set_expand(Fpng_ptr
);
462 /* TA: XXX: (2011-02-14) -- Happy Valentines Day.
464 * png_get_color_type() defined in libpng 1.5 now hides a data member
467 * Finfo_ptr->color_type
469 * I'm not going to wrap this up in more #ifdef madness, but should
470 * this fail to build on much older libpng versions which we support
471 * (pre 1.3), then I might have to.
473 if (png_get_color_type(Fpng_ptr
, Finfo_ptr
) == FPNG_COLOR_TYPE_RGB_ALPHA
)
477 if (png_get_color_type(Fpng_ptr
, Finfo_ptr
) == FPNG_COLOR_TYPE_GRAY_ALPHA
)
482 if (png_get_color_type(Fpng_ptr
, Finfo_ptr
) == FPNG_COLOR_TYPE_GRAY
)
488 Fpng_set_expand(Fpng_ptr
);
491 * thanks to mustapha for helping debug this on PPC Linux remotely by
492 * sending across screenshots all the time and me figuring out form them
493 * what the hell was up with the colors
494 * now png loading should work on big endian machines nicely */
495 #ifdef WORDS_BIGENDIAN
496 Fpng_set_swap_alpha(Fpng_ptr
);
497 Fpng_set_filler(Fpng_ptr
, 0xff, FPNG_FILLER_BEFORE
);
499 Fpng_set_bgr(Fpng_ptr
);
500 Fpng_set_filler(Fpng_ptr
, 0xff, FPNG_FILLER_AFTER
);
502 /* 16bit color -> 8bit color */
503 Fpng_set_strip_16(Fpng_ptr
);
504 /* pack all pixels to byte boundaires */
505 Fpng_set_packing(Fpng_ptr
);
506 if (Fpng_get_valid(Fpng_ptr
, Finfo_ptr
, FPNG_INFO_tRNS
))
508 Fpng_set_expand(Fpng_ptr
);
511 data
= (CARD32
*)safemalloc(w
* h
* sizeof(CARD32
));
512 lines
= (unsigned char **) safemalloc(h
* sizeof(unsigned char *));
516 Fpng_set_gray_to_rgb(Fpng_ptr
);
517 if (Fpng_get_bit_depth(Fpng_ptr
, Finfo_ptr
) < 8)
519 Fpng_set_gray_1_2_4_to_8(Fpng_ptr
);
522 for (i
= 0; i
< h
; i
++)
524 lines
[i
] = (unsigned char *)data
+ (i
* w
* sizeof(CARD32
));
526 Fpng_read_image(Fpng_ptr
, lines
);
527 Fpng_read_end(Fpng_ptr
, Finfo_ptr
);
528 Fpng_destroy_read_struct(&Fpng_ptr
, &Finfo_ptr
, (png_infopp
) NULL
);
542 Bool
PImageLoadXpm(FIMAGE_CMD_ARGS
)
545 FxpmColor
*xpm_color
;
554 #ifdef HAVE_SIGACTION
555 struct sigaction defaultHandler
;
556 struct sigaction originalHandler
;
558 RETSIGTYPE (*originalHandler
)(int);
565 memset(&xpm_im
, 0, sizeof(FxpmImage
));
567 #ifdef HAVE_SIGACTION
568 sigemptyset(&defaultHandler
.sa_mask
);
569 defaultHandler
.sa_flags
= 0;
570 defaultHandler
.sa_handler
= SIG_DFL
;
571 sigaction(SIGCHLD
, &defaultHandler
, &originalHandler
);
573 originalHandler
= signal(SIGCHLD
, SIG_DFL
);
577 rc
= FxpmReadFileToXpmImage(path
, &xpm_im
, NULL
);
579 #ifdef HAVE_SIGACTION
580 sigaction(SIGCHLD
, &originalHandler
, NULL
);
582 signal(SIGCHLD
, originalHandler
);
585 if (rc
!= FxpmSuccess
)
590 if (xpm_im
.ncolors
<= 0)
592 FxpmFreeXpmImage(&xpm_im
);
595 colors
= (CARD32
*)safemalloc(xpm_im
.ncolors
* sizeof(CARD32
));
596 for (i
=0; i
< xpm_im
.ncolors
; i
++)
598 xpm_color
= &xpm_im
.colorTable
[i
];
599 if (xpm_color
->c_color
)
601 visual_color
= xpm_color
->c_color
;
603 else if (xpm_color
->g_color
)
605 visual_color
= xpm_color
->g_color
;
607 else if (xpm_color
->g4_color
)
609 visual_color
= xpm_color
->g4_color
;
613 visual_color
= xpm_color
->m_color
;
615 if (XParseColor(dpy
, Pcmap
, visual_color
, &color
))
617 colors
[i
] = 0xff000000 |
618 ((color
.red
<< 8) & 0xff0000) |
619 ((color
.green
) & 0xff00) |
620 ((color
.blue
>> 8) & 0xff);
627 *width
= w
= xpm_im
.width
;
628 *height
= h
= xpm_im
.height
;
629 data
= (CARD32
*)safemalloc(w
* h
* sizeof(CARD32
));
630 for (i
=0; i
< w
* h
; i
++)
632 data
[i
] = colors
[xpm_im
.data
[i
]];
642 * copy image to server
646 Pixmap
PImageCreatePixmapFromFImage(Display
*dpy
, Window win
, FImage
*fimage
)
655 w
= fimage
->im
->width
;
656 h
= fimage
->im
->height
;
657 depth
= fimage
->im
->depth
;
658 pixmap
= XCreatePixmap(dpy
, win
, w
, h
, depth
);
661 gc
= PictureDefaultGC(dpy
, win
);
666 gc
= fvwmlib_XCreateGC(dpy
, pixmap
, 0, NULL
);
669 FPutFImage(dpy
, pixmap
, gc
, fimage
, 0, 0, 0, 0, w
, h
);
678 /* ---------------------------- interface functions ------------------------ */
682 * argb data to pixmaps
685 Bool
PImageCreatePixmapFromArgbData(
686 Display
*dpy
, Window win
, CARD32
*data
, int start
, int width
,
687 int height
, Pixmap
*pixmap
, Pixmap
*mask
, Pixmap
*alpha
,
688 int *nalloc_pixels
, Pixel
**alloc_pixels
, int *no_limit
,
689 FvwmPictureAttributes fpa
)
692 FImage
*m_fim
= NULL
;
693 FImage
*a_fim
= NULL
;
698 PictureImageColorAllocator
*pica
= NULL
;
699 int alpha_limit
= PICTURE_ALPHA_LIMIT
;
700 int alpha_depth
= FRenderGetAlphaDepth();
701 Bool have_mask
= False
;
702 Bool have_alpha
= False
;
705 dpy
, Pvisual
, (fpa
.mask
& FPAM_MONOCHROME
) ? 1 : Pdepth
,
706 ZPixmap
, width
, height
);
713 m_fim
= FCreateFImage(
714 dpy
, Pvisual
, 1, ZPixmap
, width
, height
);
716 if (alpha
&& !(fpa
.mask
& FPAM_NO_ALPHA
) && alpha_depth
)
719 a_fim
= FCreateFImage(
720 dpy
, Pvisual
, alpha_depth
, ZPixmap
, width
, height
);
722 if (!(fpa
.mask
& FPAM_MONOCHROME
))
724 c
.flags
= DoRed
| DoGreen
| DoBlue
;
725 pica
= PictureOpenImageColorAllocator(
726 dpy
, Pcmap
, width
, height
,
727 !!(fpa
.mask
& FPAM_NO_COLOR_LIMIT
),
728 !!(fpa
.mask
& FPAM_NO_ALLOC_PIXELS
),
729 !!(fpa
.mask
& FPAM_DITHER
),
733 for (j
= 0; j
< height
; j
++)
735 for (i
= 0; i
< width
; i
++, data
++)
737 a
= (*data
>> 030) & 0xff;
740 c
.red
= (*data
>> 16) & 0xff;
741 c
.green
= (*data
>> 8) & 0xff;
742 c
.blue
= (*data
) & 0xff;
745 PictureAllocColorImage(
746 dpy
, pica
, &c
, i
, j
);
747 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
749 /* Brightness threshold */
750 else if ((0x99 * c
.red
+
752 0x3A * c
.blue
) >> 16)
754 XPutPixel(fim
->im
, i
, j
, 1);
758 XPutPixel(fim
->im
, i
, j
, 0);
762 XPutPixel(m_fim
->im
, i
, j
, 1);
765 else if (m_fim
!= NULL
)
767 XPutPixel(m_fim
->im
, i
, j
, 0);
772 XPutPixel(a_fim
->im
, i
, j
, a
);
773 if (a
> 0 && a
< 0xff)
782 PictureCloseImageColorAllocator(
783 dpy
, pica
, nalloc_pixels
, alloc_pixels
, no_limit
);
785 *pixmap
= PImageCreatePixmapFromFImage(dpy
, win
, fim
);
788 *alpha
= PImageCreatePixmapFromFImage(dpy
, win
, a_fim
);
792 *mask
= PImageCreatePixmapFromFImage(dpy
, win
, m_fim
);
794 FDestroyFImage(dpy
, fim
);
797 FDestroyFImage(dpy
, m_fim
);
801 FDestroyFImage(dpy
, a_fim
);
814 Bool
PImageLoadPixmapFromFile(
815 Display
*dpy
, Window win
, char *path
, Pixmap
*pixmap
, Pixmap
*mask
,
816 Pixmap
*alpha
, int *width
, int *height
, int *depth
,
817 int *nalloc_pixels
, Pixel
**alloc_pixels
,
818 int *no_limit
, FvwmPictureAttributes fpa
)
822 if (PImageLoadArgbDataFromFile(dpy
, path
, &data
, width
, height
))
824 *depth
= (fpa
.mask
& FPAM_MONOCHROME
) ? 1 : Pdepth
;
825 if (PImageCreatePixmapFromArgbData(
826 dpy
, win
, data
, 0, *width
, *height
, pixmap
, mask
,
827 alpha
, nalloc_pixels
, alloc_pixels
, no_limit
, fpa
))
835 /* Bitmap fallback */
838 dpy
, win
, path
, (unsigned int *)width
,
839 (unsigned int *)height
, pixmap
, NULL
, NULL
) ==
850 *width
= *height
= *depth
= 0;
851 if (nalloc_pixels
!= NULL
)
855 if (alloc_pixels
!= NULL
)
857 *alloc_pixels
= NULL
;
862 FvwmPicture
*PImageLoadFvwmPictureFromFile(
863 Display
*dpy
, Window win
, char *path
, FvwmPictureAttributes fpa
)
866 Pixmap pixmap
= None
;
869 int width
= 0, height
= 0;
870 int depth
= 0, no_limit
;
871 int nalloc_pixels
= 0;
872 Pixel
*alloc_pixels
= NULL
;
875 /* Remove any svg rendering options from real_path */
876 if (USE_SVG
&& *path
== ':' &&
877 (real_path
= strchr(path
+ 1, ':')))
885 if (!PImageLoadPixmapFromFile(
886 dpy
, win
, path
, &pixmap
, &mask
, &alpha
, &width
, &height
,
887 &depth
, &nalloc_pixels
, &alloc_pixels
, &no_limit
, fpa
))
892 p
= (FvwmPicture
*)safemalloc(sizeof(FvwmPicture
));
893 memset(p
, 0, sizeof(FvwmPicture
));
896 p
->fpa_mask
= fpa
.mask
;
898 setFileStamp(&p
->stamp
, real_path
);
905 p
->nalloc_pixels
= nalloc_pixels
;
906 p
->alloc_pixels
= alloc_pixels
;
907 p
->no_limit
= no_limit
;
911 Cursor
PImageLoadCursorFromFile(
912 Display
*dpy
, Window win
, char *path
, int x_hot
, int y_hot
)
922 /* First try the Xcursor loader (animated cursors) */
923 if ((fcis
= FcursorFilenameLoadImages(
924 path
, FcursorGetDefaultSize(dpy
))))
926 for (i
= 0; i
< fcis
->nimage
; i
++)
928 if (x_hot
< fcis
->images
[i
]->width
&& x_hot
>= 0 &&
929 y_hot
< fcis
->images
[i
]->height
&& y_hot
>= 0)
931 fcis
->images
[i
]->xhot
= x_hot
;
932 fcis
->images
[i
]->yhot
= y_hot
;
935 cursor
= FcursorImagesLoadCursor(dpy
, fcis
);
936 FcursorImagesDestroy(fcis
);
938 /* Get cursor data from the regular image loader */
939 else if (PImageLoadArgbDataFromFile(dpy
, path
, &data
, &width
, &height
))
943 FvwmPictureAttributes fpa
;
945 fpa
.mask
= FPAM_NO_ALPHA
| FPAM_MONOCHROME
;
947 /* Adjust the hot-spot if necessary */
949 x_hot
< 0 || x_hot
>= width
||
950 y_hot
< 0 || y_hot
>= height
)
955 memset(&xpm_im
, 0, sizeof(FxpmImage
));
956 memset(&xpm_info
, 0, sizeof(FxpmInfo
));
957 if (FxpmReadFileToXpmImage(path
, &xpm_im
, &xpm_info
)
960 if (xpm_info
.valuemask
& FxpmHotspot
)
962 x_hot
= xpm_info
.x_hotspot
;
963 y_hot
= xpm_info
.y_hotspot
;
965 FxpmFreeXpmImage(&xpm_im
);
966 FxpmFreeXpmInfo(&xpm_info
);
968 if (x_hot
< 0 || x_hot
>= width
)
972 if (y_hot
< 0 || y_hot
>= height
)
977 /* Use the Xcursor library to create the argb cursor */
978 if ((fci
= FcursorImageCreate(width
, height
)))
985 /* Xcursor expects alpha prescaled RGB values */
986 for (i
= 0; i
< width
* height
; i
++)
988 alpha
= ((data
[i
] >> 24) & 0xff);
989 red
= ((data
[i
] >> 16) & 0xff) * alpha
/0xff;
990 green
= ((data
[i
] >> 8) & 0xff) * alpha
/0xff;
991 blue
= ((data
[i
] ) & 0xff) * alpha
/0xff;
994 (alpha
<< 24) | (red
<< 16) |
1001 fci
->pixels
= (FcursorPixel
*)data
;
1002 cursor
= FcursorImageLoadCursor(dpy
, fci
);
1003 FcursorImageDestroy(fci
);
1005 /* Create monochrome cursor from argb data */
1006 else if (PImageCreatePixmapFromArgbData(
1007 dpy
, win
, data
, 0, width
, height
,
1008 &src
, &msk
, 0, 0, 0, 0, fpa
))
1012 c
[0].pixel
= GetColor(DEFAULT_CURSOR_FORE_COLOR
);
1013 c
[1].pixel
= GetColor(DEFAULT_CURSOR_BACK_COLOR
);
1014 XQueryColors(dpy
, Pcmap
, c
, 2);
1015 cursor
= XCreatePixmapCursor(
1016 dpy
, src
, msk
, &(c
[0]), &(c
[1]), x_hot
, y_hot
);
1017 XFreePixmap(dpy
, src
);
1018 XFreePixmap(dpy
, msk
);
1026 /* FIXME: Use color limit */
1027 Bool
PImageLoadPixmapFromXpmData(
1028 Display
*dpy
, Window win
, int color_limit
,
1030 Pixmap
*pixmap
, Pixmap
*mask
,
1031 int *width
, int *height
, int *depth
)
1033 FxpmAttributes xpm_attributes
;
1039 xpm_attributes
.valuemask
= FxpmCloseness
|
1040 FxpmExtensions
| FxpmVisual
| FxpmColormap
| FxpmDepth
;
1041 xpm_attributes
.closeness
= 40000;
1042 xpm_attributes
.visual
= Pvisual
;
1043 xpm_attributes
.colormap
= Pcmap
;
1044 xpm_attributes
.depth
= Pdepth
;
1045 /* suppress compiler warning if xpm library is not compiled in */
1046 xpm_attributes
.width
= 0;
1047 xpm_attributes
.height
= 0;
1049 FxpmCreatePixmapFromData(
1050 dpy
, win
, data
, pixmap
, mask
, &xpm_attributes
) !=
1055 *width
= xpm_attributes
.width
;
1056 *height
= xpm_attributes
.height
;