/* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include "gtk/gtk.h" #include "libgimp/gimp.h" /* Originally S&P, I guess, hacked for 0.99 by Josh MacDonald. */ /* Hacked about to preserve transparency by Jens Tingleff */ /* Declare some local functions. */ static void query (void); static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals); static gint32 load_image (char *filename); GPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; MAIN (); static void query () { static GParamDef load_args[] = { { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, { PARAM_STRING, "filename", "The name of the file to load" }, { PARAM_STRING, "raw_filename", "The name entered" }, }; static GParamDef load_return_vals[] = { { PARAM_IMAGE, "image", "Output image" }, }; static int nload_args = sizeof (load_args) / sizeof (load_args[0]); static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]); gimp_install_procedure ("file_xpm_load", "loads files of the xpm file format", "FIXME: write help for xpm_load", "Spencer Kimball & Peter Mattis", "Spencer Kimball & Peter Mattis", "1995-1997", "/Xpm", NULL, PROC_PLUG_IN, nload_args, nload_return_vals, load_args, load_return_vals); gimp_register_load_handler ("file_xpm_load", "xpm", ""); } static void run (char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals) { static GParam values[2]; GRunModeType run_mode; gint32 image_ID; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = PARAM_STATUS; values[0].data.d_status = STATUS_CALLING_ERROR; if (strcmp (name, "file_xpm_load") == 0) { image_ID = load_image (param[1].data.d_string); if (image_ID != -1) { *nreturn_vals = 2; values[0].data.d_status = STATUS_SUCCESS; values[1].type = PARAM_IMAGE; values[1].data.d_image = image_ID; } else { values[0].data.d_status = STATUS_EXECUTION_ERROR; } } else g_assert (FALSE); } static gint32 load_image (char *filename) { Display *display; XpmImage xpm_image; XpmColor *xpm_color; GPixelRgn pixel_rgn; GDrawable *drawable; gint32 image_ID; gint32 layer_ID; gchar *temp; guint *src; gint screen; guchar *dest, *dest_base; guchar *gimp_cmap; Colormap colormap; gint i, j, tile_height, val, row; XColor xcolor; /* Transparency handling */ gint trnsp_col_inx = -1; /* Index in Pixmap CTab for mask */ gint src_col; /* For copying from pixmap */ #define TRNS_YES 0 /* alpha chann value for transparent */ #define TRNS_NO 255 /* alpha chann value for foreground */ temp = malloc(strlen (filename) + 12); if (!temp) gimp_quit (); sprintf (temp, "Loading %s:", filename); gimp_progress_init (temp); free (temp); display = XOpenDisplay (NULL); screen = DefaultScreen (display); colormap = DefaultColormap (display, screen); XpmReadFileToXpmImage (filename, &xpm_image, NULL); gimp_cmap = malloc (sizeof (guchar) * 3 * xpm_image.ncolors); for (i = 0, j = 0; i < xpm_image.ncolors; i++) { xpm_color = &xpm_image.colorTable[i]; if (xpm_color->c_color) { if(strcasecmp (xpm_color->c_color, "none") == 0) { trnsp_col_inx = i; xcolor.red = xcolor.green = xcolor.blue = USHRT_MAX; } else { XParseColor (display, colormap, xpm_color->c_color, &xcolor); } } else if (xpm_color->g_color) { XParseColor (display, colormap, xpm_color->g_color, &xcolor); } else if (xpm_color->g4_color) { XParseColor (display, colormap, xpm_color->g4_color, &xcolor); } else if (xpm_color->m_color) { XParseColor (display, colormap, xpm_color->m_color, &xcolor); } gimp_cmap[j++] = xcolor.red >> 8; gimp_cmap[j++] = xcolor.green >> 8; gimp_cmap[j++] = xcolor.blue >> 8; } XCloseDisplay (display); if (xpm_image.ncolors > 256) { image_ID = gimp_image_new (xpm_image.width, xpm_image.height, RGB); gimp_image_set_filename (image_ID, filename); layer_ID = gimp_layer_new (image_ID, "Background", xpm_image.width, xpm_image.height, (trnsp_col_inx < 0 ? RGB_IMAGE : RGBA_IMAGE), 100, NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, 0); drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); tile_height = gimp_tile_height (); dest_base = dest = g_new (guchar, pixel_rgn.bpp * xpm_image.width * tile_height); src = xpm_image.data; /* Put the "doing transparent yes/no" question outside * the busy loop. Save approx one CPU cycle per 1000 * so sue me ... */ if (trnsp_col_inx < 0) /* No alpha channel */ { for (i = 0; i < xpm_image.height;) { for (dest = dest_base, row = 0; row < tile_height && i < xpm_image.height; i += 1, row += 1) { for (j = 0; j < xpm_image.width; j++) { val = *src++ * 3; *dest++ = gimp_cmap[val+0]; *dest++ = gimp_cmap[val+1]; *dest++ = gimp_cmap[val+2]; } } gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row); gimp_progress_update ((double) i / (double) xpm_image.height); } } else /* Alpha channel */ { for (i = 0; i < xpm_image.height;) { for (dest = dest_base, row = 0; row < tile_height && i < xpm_image.height; i += 1, row += 1) { for (j = 0; j < xpm_image.width; j++) { src_col = *src++; if (src_col == trnsp_col_inx) { *dest++ = 0; /* Color */ *dest++ = 0; *dest++ = 0; *dest++ = TRNS_YES; /* Alpha */ } else { val = src_col * 3; /* Color */ *dest++ = gimp_cmap[val+0]; *dest++ = gimp_cmap[val+1]; *dest++ = gimp_cmap[val+2]; *dest++ = TRNS_NO; /* Alpha */ } } } gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row); gimp_progress_update ((double) i / (double) xpm_image.height); } } /* Alpha chan handling done */ } else { image_ID = gimp_image_new (xpm_image.width, xpm_image.height, INDEXED); gimp_image_set_filename (image_ID, filename); layer_ID = gimp_layer_new (image_ID, "Background", xpm_image.width, xpm_image.height, (trnsp_col_inx < 0 ? INDEXED_IMAGE : INDEXEDA_IMAGE), 100, NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, 0); drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); gimp_image_set_cmap (image_ID, gimp_cmap, xpm_image.ncolors); tile_height = gimp_tile_height (); dest_base = dest = g_new (guchar, pixel_rgn.bpp * xpm_image.width * tile_height); src = xpm_image.data; if (trnsp_col_inx < 0) /* No Alpha chan. */ { for (i = 0; i < xpm_image.height;) { for (dest = dest_base, row = 0; row < tile_height && i < xpm_image.height; i += 1, row += 1) { for (j = 0; j < xpm_image.width; j++) *dest++ = *src++; } gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row); gimp_progress_update ((double) i / (double) xpm_image.height); } } else /* Alpha chan. */ { for (i = 0; i < xpm_image.height;) { for (dest = dest_base, row = 0; row < tile_height && i < xpm_image.height; i += 1, row += 1) { for (j = 0; j < xpm_image.width; j++) { src_col = *src++; if (src_col == trnsp_col_inx) { *dest++ = 0; /* Color value (dummy) */ *dest++ = TRNS_YES; /* transparancy (yes) */ } else { *dest++ = src_col; /* Color */ *dest++ = TRNS_NO; /* Alpha */ } } } gimp_pixel_rgn_set_rect (&pixel_rgn, dest_base, 0, i-row, xpm_image.width, row); gimp_progress_update ((double) i / (double) xpm_image.height); } } } /* else */ gimp_drawable_flush (drawable); gimp_drawable_detach (drawable); return image_ID; }