/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */ static gint32 create_new_image (const gchar *filename, const gchar *layername, guint width, guint height, GimpImageBaseType type, gdouble xres, gdouble yres, gint32 *layer_ID, GimpDrawable **drawable, GimpPixelRgn *pixel_rgn) { gint32 image_ID; image_ID = gimp_image_new (width, height, type); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); gimp_image_set_resolution (image_ID, xres, yres); *layer_ID = create_new_layer (image_ID, 0, layername, width, height, type, drawable, pixel_rgn); return image_ID; }
/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */ static gint32 create_new_image (const gchar *filename, const gchar *layername, guint width, guint height, GimpImageBaseType type, GimpPrecision precision, gdouble xres, gdouble yres, gint32 *layer_ID) { gint32 image_ID; image_ID = gimp_image_new_with_precision (width, height, type, precision); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); gimp_image_set_resolution (image_ID, xres, yres); *layer_ID = create_new_layer (image_ID, 0, layername, width, height, type); return image_ID; }
/* Decompose an image. It returns the number of new (gray) images. The image IDs for the new images are returned in image_ID_dst. On failure, -1 is returned. */ static gint32 decompose (gint32 image_ID, gint32 drawable_ID, const gchar *extract_type, gint32 *image_ID_dst, gint32 *nlayers, gint32 *layer_ID_dst) { const gchar *layername; gint i, j, extract_idx, scan_lines; gint height, width, tile_height, num_layers; gchar *filename; guchar *src; guchar *dst[MAX_EXTRACT_IMAGES]; GimpDrawable *drawable_src; GimpDrawable *drawable_dst[MAX_EXTRACT_IMAGES]; GimpPixelRgn pixel_rgn_src; GimpPixelRgn pixel_rgn_dst[MAX_EXTRACT_IMAGES]; extract_idx = -1; /* Search extract type */ for (j = 0; j < G_N_ELEMENTS (extract); j++) { if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0) { extract_idx = j; break; } } if (extract_idx < 0) return -1; /* Check structure of source image */ drawable_src = gimp_drawable_get (drawable_ID); if (drawable_src->bpp < 3) { g_message ("Not an RGB image."); return -1; } if ((extract[extract_idx].extract_fun == extract_alpha || extract[extract_idx].extract_fun == extract_rgba) && (!gimp_drawable_has_alpha (drawable_ID))) { g_message ("No alpha channel available."); return -1; } width = drawable_src->width; height = drawable_src->height; tile_height = gimp_tile_height (); gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height, FALSE, FALSE); /* allocate a buffer for retrieving information from the src pixel region */ src = g_new (guchar, tile_height * width * drawable_src->bpp); /* Create all new gray images */ num_layers = extract[extract_idx].num_images; if (num_layers > MAX_EXTRACT_IMAGES) num_layers = MAX_EXTRACT_IMAGES; for (j = 0; j < num_layers; j++) { /* Build a filename like <imagename>-<channel>.<extension> */ gchar *fname; gchar *extension; gdouble xres, yres; fname = gimp_image_get_filename (image_ID); if (fname) { extension = fname + strlen (fname) - 1; while (extension >= fname) { if (*extension == '.') break; extension--; } if (extension >= fname) { *(extension++) = '\0'; if (decovals.as_layers) filename = g_strdup_printf ("%s-%s.%s", fname, gettext (extract[extract_idx].type), extension); else filename = g_strdup_printf ("%s-%s.%s", fname, gettext (extract[extract_idx].channel_name[j]), extension); } else { if (decovals.as_layers) filename = g_strdup_printf ("%s-%s", fname, gettext (extract[extract_idx].type)); else filename = g_strdup_printf ("%s-%s", fname, gettext (extract[extract_idx].channel_name[j])); } } else { filename = g_strdup (gettext (extract[extract_idx].channel_name[j])); } gimp_image_get_resolution (image_ID, &xres, &yres); if (decovals.as_layers) { layername = gettext (extract[extract_idx].channel_name[j]); if (j == 0) image_ID_dst[j] = create_new_image (filename, layername, width, height, GIMP_GRAY, xres, yres, layer_ID_dst + j, drawable_dst + j, pixel_rgn_dst + j); else layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername, width, height, GIMP_GRAY, drawable_dst + j, pixel_rgn_dst + j); } else { image_ID_dst[j] = create_new_image (filename, NULL, width, height, GIMP_GRAY, xres, yres, layer_ID_dst + j, drawable_dst + j, pixel_rgn_dst + j); } g_free (filename); g_free (fname); dst[j] = g_new (guchar, tile_height * width); } i = 0; while (i < height) { /* Get source pixel region */ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines); /* Extract the channel information */ extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width, dst); /* Transfer the registration color */ if (decovals.use_registration) transfer_registration_color (src, drawable_src->bpp, scan_lines*width, dst, extract[extract_idx].num_images); /* Set destination pixel regions */ for (j = 0; j < num_layers; j++) gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width, scan_lines); i += scan_lines; gimp_progress_update ((gdouble) i / (gdouble) height); } g_free (src); for (j = 0; j < num_layers; j++) { gimp_drawable_detach (drawable_dst[j]); gimp_drawable_update (layer_ID_dst[j], 0, 0, gimp_drawable_width (layer_ID_dst[j]), gimp_drawable_height (layer_ID_dst[j])); gimp_layer_add_alpha (layer_ID_dst[j]); g_free (dst[j]); } gimp_drawable_detach (drawable_src); *nlayers = num_layers; return (decovals.as_layers ? 1 : num_layers); }
/* Decompose an image. It returns the number of new (gray) images. * The image IDs for the new images are returned in image_ID_dst. * On failure, -1 is returned. */ static gint32 decompose (gint32 image_ID, gint32 drawable_ID, const gchar *extract_type, gint32 *image_ID_dst, gint32 *nlayers, gint32 *layer_ID_dst) { const gchar *layername; gint j, extract_idx; gint height, width, num_layers; GeglBuffer *src_buffer; GeglBuffer *dst_buffer[MAX_EXTRACT_IMAGES]; GimpPrecision precision; gboolean requirments = FALSE, decomp_has_alpha = FALSE; extract_idx = -1; /* Search extract type */ for (j = 0; j < G_N_ELEMENTS (extract); j++) { if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0) { extract_idx = j; break; } } if (extract_idx < 0) return -1; num_layers = extract[extract_idx].num_images; /* Sanity checks */ src_buffer = gimp_drawable_get_buffer (drawable_ID); precision = gimp_image_get_precision (image_ID); for (j = 0; j < num_layers; j++) { /* FIXME: Not 100% reliable */ decomp_has_alpha |= !g_strcmp0 ("alpha", extract[extract_idx].component[j].babl_name); decomp_has_alpha |= !g_strcmp0 ("A", extract[extract_idx].component[j].babl_name); } requirments |= (gimp_drawable_is_rgb (drawable_ID)); requirments |= (gimp_drawable_is_indexed (drawable_ID)); requirments |= (gimp_drawable_is_gray (drawable_ID) && gimp_drawable_has_alpha (drawable_ID) && (num_layers <= 2) && decomp_has_alpha); requirments &= (!decomp_has_alpha || gimp_drawable_has_alpha (drawable_ID)); if (!requirments) { g_message (_("Image not suitable for this decomposition")); return -1; } width = gegl_buffer_get_width (src_buffer); height = gegl_buffer_get_height (src_buffer); /* Create all new gray images */ for (j = 0; j < num_layers; j++) { gchar *filename; gdouble xres, yres; filename = generate_filename (image_ID, extract_idx, j); gimp_image_get_resolution (image_ID, &xres, &yres); if (decovals.as_layers) { layername = gettext (extract[extract_idx].component[j].channel_name); if (j == 0) image_ID_dst[j] = create_new_image (filename, layername, width, height, GIMP_GRAY, precision, xres, yres, layer_ID_dst + j); else layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername, width, height, GIMP_GRAY); } else { image_ID_dst[j] = create_new_image (filename, NULL, width, height, GIMP_GRAY, precision, xres, yres, layer_ID_dst + j); } g_free (filename); dst_buffer[j] = gimp_drawable_get_buffer (layer_ID_dst[j]); } copy_n_components (src_buffer, dst_buffer, extract[extract_idx]); if (decovals.use_registration) transfer_registration_color (src_buffer, dst_buffer, num_layers); gimp_progress_update (1.0); g_object_unref (src_buffer); for (j = 0; j < num_layers; j++) { g_object_unref (dst_buffer[j]); } *nlayers = num_layers; return (decovals.as_layers ? 1 : num_layers); }