/* * rimage.c: Interface to wraster lib (conversion of RImage) * * Written by: Ullrich Hafner * * Copyright (C) 1999 Ullrich Hafner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. */ /* * $Date: 2000/10/16 18:24:42 $ * $Author: hafner $ * $Revision: 1.12 $ * $State: Exp $ */ #include "config.h" #if defined(PREVIEWS) && !defined(CONVERT) #if HAVE_STDLIB_H # include #endif /* not HAVE_STDLIB_H */ #if HAVE_STRING_H # include #else /* not HAVE_STRING_H */ # include #endif /* not HAVE_STRING_H */ #include #include #include #include #include "proplist_t.h" #include #include "window.h" #include "rimage.h" #include "error.h" /***************************************************************************** global and local variables *****************************************************************************/ static RContext *rc = NULL; extern GtkWidget *main_window; /***************************************************************************** prototypes *****************************************************************************/ #ifdef HAVE_LIBWMFUN RImage * bilinear (int argc, char **argv, int width, int height, int relief); RImage * fade (int argc, char **argv, int width, int height, int relief); RImage * waves (int argc, char **argv, int width, int height, int relief); void initWindowMaker (Display *d, Colormap c); #endif /* HAVE_LIBWMFUN */ static RColor * get_background_color (void); static RImage * rimage_load (const char *filename, int width, int height); static GtkWidget * rimage_2_preview (RImage *image, GtkWidget *preview, bool_t bevel); /***************************************************************************** public code *****************************************************************************/ void init_wraster_lib (void) { if (!rc) { RContextAttributes rattr; rattr.flags = 0; rc = RCreateContext (GDK_DISPLAY (), DefaultScreen (GDK_DISPLAY ()), &rattr); #ifdef HAVE_LIBWMFUN initWindowMaker (GDK_DISPLAY (), rc->cmap); #endif /* HAVE_LIBWMFUN */ } } /* We need this wrapper function since gdk_parse_color() no longer * understands "rgb:RR/GG/BB". */ gboolean make_color(const gchar *spec, GdkColor *color) { gboolean result; gchar * newspec = g_strdup (spec); if (strncmp(spec, "rgb:", 4) == 0) { const char * red_posn = spec + 4, * green_posn, * blue_posn; int red_len, green_len, blue_len; green_posn = strchr(red_posn, '/'); if (!green_posn) return FALSE; red_len = green_posn - red_posn; green_posn++; blue_posn = strchr(green_posn, '/'); if (!blue_posn) return FALSE; green_len = blue_posn - green_posn; blue_posn++; blue_len = strlen(spec) - (blue_posn - spec); if (red_len != green_len || green_len != blue_len || red_len < 1 || red_len > 4) return FALSE; newspec = malloc(3 * red_len + 2); strcpy(newspec, "#"); strncat(newspec, red_posn, red_len); strncat(newspec, green_posn, red_len); strncat(newspec, blue_posn, red_len); } result = gdk_color_parse (newspec, color); if (newspec != spec) free (newspec); return result; } GtkWidget * make_image (const char *filename, int width, int height, GtkWidget *preview) { RImage *rimage = rimage_load (filename, width, height); preview = rimage_2_preview (rimage, preview, FALSE); RReleaseImage (rimage); return preview; } GtkWidget * make_gradient (proplist_t array, unsigned width, unsigned height, gtype_e type, GtkWidget *preview) { if (!array || !WMIsPLArray (array) || WMGetPropListItemCount (array) < 3) return make_image (PKGDATADIR "/black.xpm", width, height, preview); else { unsigned n = WMGetPropListItemCount (array); unsigned start = n == 3 ? 1 : 2; RColor **colors = Calloc (n + 1, sizeof (RColor *)); unsigned k; for (k = start; k < n; k++) { GdkColor c; if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, k)), &c)) c.red = c.green = c.blue = 65535; /* white */ colors [k - start] = Calloc (1, sizeof (RColor)) ; colors [k - start]->red = c.red >> 8; colors [k - start]->green = c.green >> 8; colors [k - start]->blue = c.blue >> 8; } colors [k - start] = NULL; { RImage *rimage; if (n == 3) rimage = RRenderGradient (width, height, colors [0], colors [1], type == HGRADIENT ? RHorizontalGradient : (type == VGRADIENT ? RVerticalGradient : RDiagonalGradient)); else rimage = RRenderMultiGradient (width, height, colors, type == HGRADIENT ? RHorizontalGradient : (type == VGRADIENT ? RVerticalGradient : RDiagonalGradient)); preview = rimage_2_preview (rimage, preview, TRUE && rimage->height < 100); RReleaseImage (rimage); } for (k = start; k < n; k++) Free (colors [k - start]); Free (colors); return preview; } } GtkWidget * make_solid (const char *color, unsigned width, unsigned height, GtkWidget *preview) { if (!preview) { preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), width, height); } else { width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; } { guchar *row = Calloc (width * 3, sizeof (guchar)); unsigned x, y; GdkColor c; if (!make_color (color, &c)) c.red = c.green = c.blue = 65535; /* white */ for (y = 0; y < height; y++) { guchar *ptr = row; for (x = 0; x < width; x++) { *ptr++ = c.red >> 8; *ptr++ = c.green >> 8; *ptr++ = c.blue >> 8; } gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width); } Free (row); } gtk_widget_draw (preview, NULL); return preview; } GtkWidget * make_textured_gradient (const char *filename, proplist_t array, unsigned width, unsigned height, gtype_e type, GtkWidget *preview) { if (!filename || WMGetPropListItemCount (array) != 5) return make_image (PKGDATADIR "/black.xpm", width, height, preview); else { GdkColor c1, c2; RColor r1, r2; int opacity = strtol (WMGetFromPLString (WMGetFromPLArray (array, 2)), NULL, 10); RImage *gradient, *image, *tiled; if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 3)), &c1)) c1.red = c1.green = c1.blue = 65535; /* white */ if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 4)), &c2)) c2.red = c2.green = c2.blue = 65535; /* white */ r1.red = c1.red >> 8; r1.green = c1.green >> 8; r1.blue = c1.blue >> 8; r2.red = c2.red >> 8; r2.green = c2.green >> 8; r2.blue = c2.blue >> 8; if (!preview) { preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), width, height); } else { width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; } gradient = RRenderGradient (width, height, &r1, &r2, type == HGRADIENT ? RHorizontalGradient : (type == VGRADIENT ? RVerticalGradient : RDiagonalGradient)); image = rimage_load (filename, -1, -1); tiled = RMakeTiledImage (image, width, height); RReleaseImage (image); if (tiled) { RCombineImagesWithOpaqueness (tiled, gradient, opacity); RReleaseImage (gradient); preview = rimage_2_preview (tiled, preview, FALSE); RReleaseImage (tiled); } else { preview = rimage_2_preview (gradient, preview, FALSE); RReleaseImage (gradient); } return preview; } } #ifdef HAVE_INTERWOVEN_GRADIENT GtkWidget * make_igradient (proplist_t array, unsigned width, unsigned height, GtkWidget *preview) { if (WMGetPropListItemCount (array) != 7) return make_image (PKGDATADIR "/black.xpm", width, height, preview); else { GdkColor from1, to1, from2, to2; RColor r1 [2], r2 [2]; int thickness1 = strtol (WMGetFromPLString (WMGetFromPLArray (array, 3)), NULL, 10); int thickness2 = strtol (WMGetFromPLString (WMGetFromPLArray (array, 6)), NULL, 10); RImage *gradient; if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 1)), &from1)) from1.red = from1.green = from1.blue = 65535; /* white */ if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 2)), &to1)) to1.red = to1.green = to1.blue = 65535; /* white */ if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 4)), &from2)) from2.red = from2.green = from2.blue = 65535; /* white */ if (!make_color (WMGetFromPLString (WMGetFromPLArray (array, 5)), &to2)) to2.red = to2.green = to2.blue = 65535; /* white */ r1 [0].red = from1.red >> 8; r1 [0].green = from1.green >> 8; r1 [0].blue = from1.blue >> 8; r1 [1].red = to1.red >> 8; r1 [1].green = to1.green >> 8; r1 [1].blue = to1.blue >> 8; r2 [0].red = from2.red >> 8; r2 [0].green = from2.green >> 8; r2 [0].blue = from2.blue >> 8; r2 [1].red = to2.red >> 8; r2 [1].green = to2.green >> 8; r2 [1].blue = to2.blue >> 8; if (!preview) { preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), width, height); } else { width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; } gradient = RRenderInterwovenGradient (width, height, r1, thickness1, r2, thickness2); if (gradient) { preview = rimage_2_preview (gradient, preview, gradient->height < 100); RReleaseImage (gradient); } else preview = make_image (PKGDATADIR "/black.xpm", width, height, preview); return preview; } } #endif /* HAVE_INTERWOVEN_GRADIENT */ #ifdef HAVE_LIBWMFUN GtkWidget * make_wmfun (proplist_t array, unsigned width, unsigned height, GtkWidget *preview) { unsigned n = WMGetPropListItemCount (array); const char *library = n > 2 ? WMGetFromPLString (WMGetFromPLArray (array, 1)) : NULL; const char *type = n > 2 ? WMGetFromPLString (WMGetFromPLArray (array, 0)) : NULL; if (!array || !WMIsPLArray (array) || !library || !type || !strcaseeq (type, "function") || !strncaseeq (library, "libwmfun", strlen ("libwmfun"))) return make_image (PKGDATADIR "/black.xpm", width, height, preview); else { unsigned n = WMGetPropListItemCount (array); char **argv = Calloc (n + 2, sizeof (char *)); char *function = WMGetFromPLString (WMGetFromPLArray (array, 2)); unsigned k; unsigned argc; RImage *image; for (k = 2, argc = 0; k < n; k++) argv [argc++] = WMGetFromPLString (WMGetFromPLArray (array, k)); argv [argc] = NULL; if ((strcaseeq (function, "bilinear"))) image = bilinear (argc, argv, width, height, 0); else if ((strcaseeq (function, "fade"))) image = fade (argc, argv, width, height, 0); else if ((strcaseeq (function, "waves"))) image = waves (argc, argv, width, height, 0); else image = NULL; if (image) { preview = rimage_2_preview (image, preview, image->height < 100); RReleaseImage (image); } else preview = make_image (PKGDATADIR "/black.xpm", width, height, preview); Free (argv); return preview; } } #endif /* HAVE_LIBWMFUN */ /***************************************************************************** private code *****************************************************************************/ static RImage * rimage_load (const char *filename, int width, int height) { char *path = get_pixmap_path (filename); if (!path) return rimage_load (PKGDATADIR "/black.xpm", width, height); else { RImage *image; image = RLoadImage (rc, path, 0); if (!image || !image->width || !image->height) return rimage_load (PKGDATADIR "/black.xpm", width, height); if (height > 0 || width > 0) /* enforce scaling */ { if (height <= 0) height = image->height; if (width <= 0) width = image->width; if (streq (filename, PKGDATADIR "/black.xpm")) { RImage *scaled = RScaleImage (image, width, height); RReleaseImage (image); image = scaled; } else if (image->width > (unsigned) width || image->height > (unsigned) height) { RImage *scaled; if (height * image->width > width * image->height) height = width * image->height / image->width; else width = height * image->width / image->height; scaled = RScaleImage (image, max (width, 22), max (height, 22)); RReleaseImage (image); image = scaled; } } Free (path); return image; } } static GtkWidget * rimage_2_preview (RImage *image, GtkWidget *preview, bool_t bevel) { assert (image && image->width && image->height); #ifdef HAVE_WRASTER_0_20 { guchar *row; unsigned x, y; unsigned x0, y0, width, height; RColor *bg = get_background_color (); unsigned char *ptr = image->data; if (bevel) RBevelImage (image, RBEV_RAISED2); if (!preview) { preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), image->width, image->height); width = image->width; height = image->height; x0 = y0 = 0; } else { width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; assert (image->width <= width && image->height <= height); x0 = (width - image->width) / 2; y0 = (height - image->height) / 2; } row = Calloc (width * 3, sizeof (guchar)); { guchar *pixel = row; for (x = 0; x < width; x++) { *pixel++ = bg->red; *pixel++ = bg->green; *pixel++ = bg->blue; } } for (y = 0; y < height; y++) gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width); for (y = 0; y < image->height; y++) { guchar *pixel = row; for (x = 0; x < image->width; x++) if (image->format == RRGBAFormat) { unsigned int r = *ptr++; unsigned int g = *ptr++; unsigned int b = *ptr++; unsigned int a = *ptr++; unsigned int na = 255 - a; *pixel++ = (bg->red * na + r * a) / 256; *pixel++ = (bg->green * na + g * a) / 256; *pixel++ = (bg->blue * na + b * a) / 256; } else { *pixel++ = *ptr++; *pixel++ = *ptr++; *pixel++ = *ptr++; } gtk_preview_draw_row (GTK_PREVIEW (preview), row, x0, y0 + y, image->width); } Free (row); gtk_widget_draw (preview, NULL); return preview; } #else /* old wraster of wmaker < 0.62.0 */ { guchar *row; unsigned x, y; unsigned char *r, *g, *b, *a; unsigned x0, y0, width, height; RColor *bg = get_background_color (); r = image->data [0]; g = image->data [1]; b = image->data [2]; a = image->data [3]; if (bevel) RBevelImage (image, RBEV_RAISED2); if (!preview) { preview = gtk_preview_new (GTK_PREVIEW_COLOR); gtk_preview_size (GTK_PREVIEW (preview), image->width, image->height); width = image->width; height = image->height; x0 = y0 = 0; } else { width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; assert (image->width <= width && image->height <= height); x0 = (width - image->width) / 2; y0 = (height - image->height) / 2; } row = Calloc (width * 3, sizeof (guchar)); { guchar *pixel = row; for (x = 0; x < width; x++) { *pixel++ = bg->red; *pixel++ = bg->green; *pixel++ = bg->blue; } } for (y = 0; y < height; y++) gtk_preview_draw_row (GTK_PREVIEW (preview), row, 0, y, width); for (y = 0; y < image->height; y++) { guchar *pixel = row; for (x = 0; x < image->width; x++) if (!a || *a++) { *pixel++ = *r++; *pixel++ = *g++; *pixel++ = *b++; } else { *pixel++ = bg->red; *pixel++ = bg->green; *pixel++ = bg->blue; r++; g++; b++; } gtk_preview_draw_row (GTK_PREVIEW (preview), row, x0, y0 + y, image->width); } Free (row); gtk_widget_draw (preview, NULL); return preview; } #endif } static RColor * get_background_color (void) { static RColor *background = NULL; if (!background) { background = Calloc (1, sizeof (RColor)); if (main_window && main_window->style) { background->red = main_window->style->bg [GTK_STATE_NORMAL].red >> 8; background->green = main_window->style->bg [GTK_STATE_NORMAL].green >> 8; background->blue = main_window->style->bg [GTK_STATE_NORMAL].blue >> 8; } else { background->red = 0xa8; background->green = 0xa8; background->blue = 0xa8; } } return background; } #endif /* defined(PREVIEWS) && !defined(CONVERT) */