static void gimp_layer_new_convert_buffer (GimpLayer *layer, GeglBuffer *src_buffer, GimpColorProfile *src_profile, GError **error) { GimpDrawable *drawable = GIMP_DRAWABLE (layer); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); GimpColorConfig *config = image->gimp->config->color_management; GeglBuffer *dest_buffer = gimp_drawable_get_buffer (drawable); GimpColorProfile *dest_profile; dest_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer)); if (! src_profile || ! dest_profile || /* FIXME: this is the wrong check, need something like file import * conversion config */ config->mode == GIMP_COLOR_MANAGEMENT_OFF) { gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE, dest_buffer, NULL); return; } gimp_gegl_convert_color_profile (src_buffer, NULL, src_profile, dest_buffer, NULL, dest_profile, GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL, TRUE, NULL); }
static void gimp_view_renderer_transform_create (GimpViewRenderer *renderer, GtkWidget *widget, GeglBuffer *src_buffer, GeglBuffer *dest_buffer) { if (GIMP_IS_COLOR_MANAGED (renderer->viewable)) { GimpColorManaged *managed = GIMP_COLOR_MANAGED (renderer->viewable); GimpPickable *pickable = GIMP_PICKABLE (renderer->viewable); GimpColorProfile *profile; profile = gimp_color_managed_get_color_profile (managed); if (profile) { GimpImage *image = gimp_pickable_get_image (pickable); GimpColorConfig *config = image->gimp->config->color_management; renderer->profile_src_format = gegl_buffer_get_format (src_buffer); renderer->profile_dest_format = gegl_buffer_get_format (dest_buffer); renderer->profile_transform = gimp_widget_get_color_transform (widget, config, profile, &renderer->profile_src_format, &renderer->profile_dest_format); } } }
static GimpBuffer * gimp_edit_extract (GimpImage *image, GimpPickable *pickable, GimpContext *context, gboolean cut_pixels, GError **error) { GeglBuffer *buffer; gint offset_x; gint offset_y; if (cut_pixels) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_CUT, C_("undo-type", "Cut")); /* Cut/copy the mask portion from the image */ buffer = gimp_selection_extract (GIMP_SELECTION (gimp_image_get_mask (image)), pickable, context, cut_pixels, FALSE, &offset_x, &offset_y, error); if (cut_pixels) gimp_image_undo_group_end (image); if (buffer) { GimpBuffer *gimp_buffer; gdouble res_x; gdouble res_y; gimp_buffer = gimp_buffer_new (buffer, _("Global Buffer"), offset_x, offset_y, FALSE); g_object_unref (buffer); gimp_image_get_resolution (image, &res_x, &res_y); gimp_buffer_set_resolution (gimp_buffer, res_x, res_y); gimp_buffer_set_unit (gimp_buffer, gimp_image_get_unit (image)); if (GIMP_IS_COLOR_MANAGED (pickable)) { GimpColorProfile *profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (pickable)); if (profile) gimp_buffer_set_color_profile (gimp_buffer, profile); } return gimp_buffer; } return NULL; }
static GimpValueArray * image_get_effective_color_profile_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; GimpImage *image; gint32 num_bytes = 0; guint8 *profile_data = NULL; image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp); if (success) { GimpColorProfile *profile; profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image)); if (profile) { const guint8 *data; gsize length; data = gimp_color_profile_get_icc_profile (profile, &length); profile_data = g_memdup (data, length); num_bytes = length; } } return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) { g_value_set_int (gimp_value_array_index (return_vals, 1), num_bytes); gimp_value_take_int8array (gimp_value_array_index (return_vals, 2), profile_data, num_bytes); } return return_vals; }
gboolean gimp_image_convert_color_profile (GimpImage *image, GimpColorProfile *dest_profile, GimpColorRenderingIntent intent, gboolean bpc, GimpProgress *progress, GError **error) { GimpColorProfile *src_profile; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (dest_profile != NULL, FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (! gimp_image_validate_color_profile (image, dest_profile, NULL, error)) return FALSE; src_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image)); if (! src_profile || gimp_color_profile_is_equal (src_profile, dest_profile)) return TRUE; if (progress) gimp_progress_start (progress, FALSE, _("Converting from '%s' to '%s'"), gimp_color_profile_get_label (src_profile), gimp_color_profile_get_label (dest_profile)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT, _("Color profile conversion")); gimp_image_set_color_profile (image, dest_profile, NULL); /* omg... */ gimp_image_parasite_detach (image, "icc-profile-name"); switch (gimp_image_get_base_type (image)) { case GIMP_RGB: gimp_image_convert_profile_rgb (image, src_profile, dest_profile, intent, bpc, progress); break; case GIMP_GRAY: break; case GIMP_INDEXED: gimp_image_convert_profile_indexed (image, src_profile, dest_profile, intent, bpc, progress); break; } gimp_image_undo_group_end (image); if (progress) gimp_progress_end (progress); return TRUE; }
static void gimp_display_shell_profile_changed_handler (GimpColorManaged *image, GimpDisplayShell *shell) { gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell)); }
void gimp_display_shell_connect (GimpDisplayShell *shell) { GimpImage *image; GimpContainer *vectors; GList *list; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (GIMP_IS_DISPLAY (shell->display)); image = gimp_display_get_image (shell->display); vectors = gimp_image_get_vectors (image); g_return_if_fail (GIMP_IS_IMAGE (image)); g_signal_connect (image, "clean", G_CALLBACK (gimp_display_shell_clean_dirty_handler), shell); g_signal_connect (image, "dirty", G_CALLBACK (gimp_display_shell_clean_dirty_handler), shell); g_signal_connect (image, "undo-event", G_CALLBACK (gimp_display_shell_undo_event_handler), shell); g_signal_connect (gimp_image_get_grid (image), "notify", G_CALLBACK (gimp_display_shell_grid_notify_handler), shell); g_object_set (shell->grid, "grid", gimp_image_get_grid (image), NULL); g_signal_connect (image, "name-changed", G_CALLBACK (gimp_display_shell_name_changed_handler), shell); g_signal_connect (image, "selection-invalidate", G_CALLBACK (gimp_display_shell_selection_invalidate_handler), shell); g_signal_connect (image, "size-changed-detailed", G_CALLBACK (gimp_display_shell_size_changed_detailed_handler), shell); g_signal_connect (image, "resolution-changed", G_CALLBACK (gimp_display_shell_resolution_changed_handler), shell); g_signal_connect (image, "quick-mask-changed", G_CALLBACK (gimp_display_shell_quick_mask_changed_handler), shell); g_signal_connect (image, "guide-added", G_CALLBACK (gimp_display_shell_guide_add_handler), shell); g_signal_connect (image, "guide-removed", G_CALLBACK (gimp_display_shell_guide_remove_handler), shell); g_signal_connect (image, "guide-moved", G_CALLBACK (gimp_display_shell_guide_move_handler), shell); for (list = gimp_image_get_guides (image); list; list = g_list_next (list)) { gimp_display_shell_guide_add_handler (image, list->data, shell); } g_signal_connect (image, "sample-point-added", G_CALLBACK (gimp_display_shell_sample_point_add_handler), shell); g_signal_connect (image, "sample-point-removed", G_CALLBACK (gimp_display_shell_sample_point_remove_handler), shell); g_signal_connect (image, "sample-point-moved", G_CALLBACK (gimp_display_shell_sample_point_move_handler), shell); for (list = gimp_image_get_sample_points (image); list; list = g_list_next (list)) { gimp_display_shell_sample_point_add_handler (image, list->data, shell); } g_signal_connect (image, "invalidate-preview", G_CALLBACK (gimp_display_shell_invalidate_preview_handler), shell); g_signal_connect (image, "precision-changed", G_CALLBACK (gimp_display_shell_precision_changed_handler), shell); g_signal_connect (image, "profile-changed", G_CALLBACK (gimp_display_shell_profile_changed_handler), shell); g_signal_connect (image, "precision-changed", G_CALLBACK (gimp_display_shell_precision_changed_handler), shell); g_signal_connect (image, "saved", G_CALLBACK (gimp_display_shell_saved_handler), shell); g_signal_connect (image, "exported", G_CALLBACK (gimp_display_shell_exported_handler), shell); g_signal_connect (image, "active-vectors-changed", G_CALLBACK (gimp_display_shell_active_vectors_handler), shell); shell->vectors_freeze_handler = gimp_tree_handler_connect (vectors, "freeze", G_CALLBACK (gimp_display_shell_vectors_freeze_handler), shell); shell->vectors_thaw_handler = gimp_tree_handler_connect (vectors, "thaw", G_CALLBACK (gimp_display_shell_vectors_thaw_handler), shell); shell->vectors_visible_handler = gimp_tree_handler_connect (vectors, "visibility-changed", G_CALLBACK (gimp_display_shell_vectors_visible_handler), shell); g_signal_connect (vectors, "add", G_CALLBACK (gimp_display_shell_vectors_add_handler), shell); g_signal_connect (vectors, "remove", G_CALLBACK (gimp_display_shell_vectors_remove_handler), shell); for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (vectors)); list; list = g_list_next (list)) { gimp_display_shell_vectors_add_handler (vectors, list->data, shell); } g_signal_connect (shell->display->config, "notify::transparency-size", G_CALLBACK (gimp_display_shell_check_notify_handler), shell); g_signal_connect (shell->display->config, "notify::transparency-type", G_CALLBACK (gimp_display_shell_check_notify_handler), shell); g_signal_connect (shell->display->config, "notify::image-title-format", G_CALLBACK (gimp_display_shell_title_notify_handler), shell); g_signal_connect (shell->display->config, "notify::image-status-format", G_CALLBACK (gimp_display_shell_title_notify_handler), shell); g_signal_connect (shell->display->config, "notify::navigation-preview-size", G_CALLBACK (gimp_display_shell_nav_size_notify_handler), shell); g_signal_connect (shell->display->config, "notify::monitor-resolution-from-windowing-system", G_CALLBACK (gimp_display_shell_monitor_res_notify_handler), shell); g_signal_connect (shell->display->config, "notify::monitor-xresolution", G_CALLBACK (gimp_display_shell_monitor_res_notify_handler), shell); g_signal_connect (shell->display->config, "notify::monitor-yresolution", G_CALLBACK (gimp_display_shell_monitor_res_notify_handler), shell); g_signal_connect (shell->display->config->default_view, "notify::padding-mode", G_CALLBACK (gimp_display_shell_padding_notify_handler), shell); g_signal_connect (shell->display->config->default_view, "notify::padding-color", G_CALLBACK (gimp_display_shell_padding_notify_handler), shell); g_signal_connect (shell->display->config->default_fullscreen_view, "notify::padding-mode", G_CALLBACK (gimp_display_shell_padding_notify_handler), shell); g_signal_connect (shell->display->config->default_fullscreen_view, "notify::padding-color", G_CALLBACK (gimp_display_shell_padding_notify_handler), shell); g_signal_connect (shell->display->config, "notify::marching-ants-speed", G_CALLBACK (gimp_display_shell_ants_speed_notify_handler), shell); g_signal_connect (shell->display->config, "notify::zoom-quality", G_CALLBACK (gimp_display_shell_quality_notify_handler), shell); gimp_display_shell_invalidate_preview_handler (image, shell); gimp_display_shell_quick_mask_changed_handler (image, shell); gimp_display_shell_profile_changed_handler (GIMP_COLOR_MANAGED (image), shell); gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary), gimp_image_get_active_layer (image)); }
static void gimp_image_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpImageUndo *image_undo = GIMP_IMAGE_UNDO (undo); GimpImage *image = undo->image; GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image); GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); switch (undo->undo_type) { case GIMP_UNDO_IMAGE_TYPE: { GimpImageBaseType base_type; base_type = image_undo->base_type; image_undo->base_type = gimp_image_get_base_type (image); g_object_set (image, "base-type", base_type, NULL); gimp_image_colormap_changed (image, -1); if (image_undo->base_type != gimp_image_get_base_type (image)) { if ((image_undo->base_type == GIMP_GRAY) || (gimp_image_get_base_type (image) == GIMP_GRAY)) { /* in case ther was no profile undo, we need to emit * profile-changed anyway */ gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image)); } accum->mode_changed = TRUE; } } break; case GIMP_UNDO_IMAGE_PRECISION: { GimpPrecision precision; precision = image_undo->precision; image_undo->precision = gimp_image_get_precision (image); g_object_set (image, "precision", precision, NULL); if (image_undo->precision != gimp_image_get_precision (image)) accum->precision_changed = TRUE; } break; case GIMP_UNDO_IMAGE_SIZE: { gint width; gint height; gint previous_origin_x; gint previous_origin_y; gint previous_width; gint previous_height; width = image_undo->width; height = image_undo->height; previous_origin_x = image_undo->previous_origin_x; previous_origin_y = image_undo->previous_origin_y; previous_width = image_undo->previous_width; previous_height = image_undo->previous_height; /* Transform to a redo */ image_undo->width = gimp_image_get_width (image); image_undo->height = gimp_image_get_height (image); image_undo->previous_origin_x = -previous_origin_x; image_undo->previous_origin_y = -previous_origin_y; image_undo->previous_width = width; image_undo->previous_height = height; g_object_set (image, "width", width, "height", height, NULL); gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (gimp_image_get_mask (image))); if (gimp_image_get_width (image) != image_undo->width || gimp_image_get_height (image) != image_undo->height) { accum->size_changed = TRUE; accum->previous_origin_x = previous_origin_x; accum->previous_origin_y = previous_origin_y; accum->previous_width = previous_width; accum->previous_height = previous_height; } } break; case GIMP_UNDO_IMAGE_RESOLUTION: { gdouble xres; gdouble yres; gimp_image_get_resolution (image, &xres, &yres); if (ABS (image_undo->xresolution - xres) >= 1e-5 || ABS (image_undo->yresolution - yres) >= 1e-5) { private->xresolution = image_undo->xresolution; private->yresolution = image_undo->yresolution; image_undo->xresolution = xres; image_undo->yresolution = yres; accum->resolution_changed = TRUE; } }
GtkWidget * color_profile_dialog_new (ColorProfileDialogType dialog_type, GimpImage *image, GimpContext *context, GtkWidget *parent, GimpProgress *progress) { ProfileDialog *dialog; GtkWidget *frame; GtkWidget *vbox; GtkWidget *expander; GtkWidget *label; GimpColorProfile *src_profile; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GTK_IS_WIDGET (parent), NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); dialog = g_slice_new0 (ProfileDialog); dialog->dialog_type = dialog_type; dialog->image = image; dialog->progress = progress; dialog->config = image->gimp->config->color_management; if (saved_intent == -1) { dialog->intent = GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC; dialog->bpc = TRUE; } else { dialog->intent = saved_intent; dialog->bpc = saved_bpc; } switch (dialog_type) { const Babl *format; case COLOR_PROFILE_DIALOG_ASSIGN_PROFILE: dialog->dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), context, _("Assign ICC Color Profile"), "gimp-image-color-profile-assign", NULL, _("Assign a color profile to the image"), parent, gimp_standard_help_func, GIMP_HELP_IMAGE_COLOR_PROFILE_ASSIGN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Assign"), GTK_RESPONSE_OK, NULL); dialog->builtin_profile = gimp_image_get_builtin_color_profile (dialog->image); break; case COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE: dialog->dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), context, _("Convert to ICC Color Profile"), "gimp-image-color-profile-convert", NULL, _("Convert the image to a color profile"), parent, gimp_standard_help_func, GIMP_HELP_IMAGE_COLOR_PROFILE_CONVERT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_OK, NULL); dialog->builtin_profile = gimp_image_get_builtin_color_profile (dialog->image); break; case COLOR_PROFILE_DIALOG_CONVERT_TO_RGB: dialog->dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), context, _("RGB Conversion"), "gimp-image-convert-rgb", GIMP_STOCK_CONVERT_RGB, _("Convert Image to RGB"), parent, gimp_standard_help_func, GIMP_HELP_IMAGE_CONVERT_RGB, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_OK, NULL); format = gimp_babl_format (GIMP_RGB, gimp_image_get_precision (dialog->image), TRUE); dialog->builtin_profile = gimp_babl_format_get_color_profile (format); break; case COLOR_PROFILE_DIALOG_CONVERT_TO_GRAY: dialog->dialog = gimp_viewable_dialog_new (GIMP_VIEWABLE (image), context, _("Grayscale Conversion"), "gimp-image-convert-gray", GIMP_STOCK_CONVERT_GRAYSCALE, _("Convert Image to Grayscale"), parent, gimp_standard_help_func, GIMP_HELP_IMAGE_CONVERT_GRAYSCALE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_OK, NULL); format = gimp_babl_format (GIMP_GRAY, gimp_image_get_precision (dialog->image), TRUE); dialog->builtin_profile = gimp_babl_format_get_color_profile (format); break; } gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog->dialog), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); gtk_window_set_resizable (GTK_WINDOW (dialog->dialog), FALSE); g_object_weak_ref (G_OBJECT (dialog->dialog), (GWeakNotify) color_profile_dialog_free, dialog); g_signal_connect (dialog->dialog, "response", G_CALLBACK (color_profile_dialog_response), dialog); dialog->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); gtk_container_set_border_width (GTK_CONTAINER (dialog->main_vbox), 12); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog->dialog))), dialog->main_vbox, TRUE, TRUE, 0); gtk_widget_show (dialog->main_vbox); frame = gimp_frame_new (_("Current Color Profile")); gtk_box_pack_start (GTK_BOX (dialog->main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); src_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image)); label = gimp_color_profile_label_new (src_profile); gtk_container_add (GTK_CONTAINER (frame), label); gtk_widget_show (label); frame = gimp_frame_new (dialog_type == COLOR_PROFILE_DIALOG_ASSIGN_PROFILE ? _("Assign") : _("Convert to")); gtk_box_pack_start (GTK_BOX (dialog->main_vbox), frame, FALSE, FALSE, 0); gtk_widget_show (frame); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_widget_show (vbox); dialog->combo = color_profile_combo_box_new (dialog); gtk_box_pack_start (GTK_BOX (vbox), dialog->combo, FALSE, FALSE, 0); gtk_widget_show (dialog->combo); expander = gtk_expander_new_with_mnemonic (_("Profile _details")); gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0); gtk_widget_show (expander); dialog->dest_view = gimp_color_profile_view_new (); gtk_container_add (GTK_CONTAINER (expander), dialog->dest_view); gtk_widget_show (dialog->dest_view); g_signal_connect (dialog->combo, "changed", G_CALLBACK (color_profile_dest_changed), dialog); color_profile_dest_changed (dialog->combo, dialog); if (dialog_type == COLOR_PROFILE_DIALOG_CONVERT_TO_PROFILE) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *combo; GtkWidget *toggle; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); gtk_box_pack_start (GTK_BOX (dialog->main_vbox), vbox, FALSE, FALSE, 0); gtk_widget_show (vbox); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); label = gtk_label_new_with_mnemonic (_("_Rendering Intent:")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); combo = gimp_enum_combo_box_new (GIMP_TYPE_COLOR_RENDERING_INTENT); gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0); gtk_widget_show (combo); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), dialog->intent, G_CALLBACK (gimp_int_combo_box_get_active), &dialog->intent); gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo); toggle = gtk_check_button_new_with_mnemonic (_("_Black Point Compensation")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), dialog->bpc); gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); gtk_widget_show (toggle); g_signal_connect (toggle, "toggled", G_CALLBACK (gimp_toggle_button_update), &dialog->bpc); } return dialog->dialog; }
GeglBuffer * gimp_drawable_transform_buffer_affine (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, const GimpMatrix3 *matrix, GimpTransformDirection direction, GimpInterpolationType interpolation_type, GimpTransformResize clip_result, GimpColorProfile **buffer_profile, gint *new_offset_x, gint *new_offset_y, GimpProgress *progress) { GeglBuffer *new_buffer; GimpMatrix3 m; gint u1, v1, u2, v2; /* source bounding box */ gint x1, y1, x2, y2; /* target bounding box */ GimpMatrix3 gegl_matrix; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (matrix != NULL, NULL); g_return_val_if_fail (buffer_profile != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), NULL); *buffer_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable)); m = *matrix; if (direction == GIMP_TRANSFORM_BACKWARD) { /* Find the inverse of the transformation matrix */ gimp_matrix3_invert (&m); } u1 = orig_offset_x; v1 = orig_offset_y; u2 = u1 + gegl_buffer_get_width (orig_buffer); v2 = v1 + gegl_buffer_get_height (orig_buffer); /* Don't modify the clipping mode of layer masks here, so that, * when transformed together with their layer, they match the * layer's clipping mode. */ if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL) { clip_result = gimp_drawable_transform_get_effective_clip (drawable, orig_buffer, clip_result); } /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&m, clip_result, u1, v1, u2, v2, &x1, &y1, &x2, &y2); /* Get the new temporary buffer for the transformed result */ new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gegl_buffer_get_format (orig_buffer)); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_translate (&gegl_matrix, u1, v1); gimp_matrix3_mult (&m, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1, -y1); gimp_gegl_apply_transform (orig_buffer, progress, NULL, new_buffer, interpolation_type, &gegl_matrix); *new_offset_x = x1; *new_offset_y = y1; return new_buffer; }
GeglBuffer * gimp_drawable_transform_buffer_rotate (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, GimpRotationType rotate_type, gdouble center_x, gdouble center_y, gboolean clip_result, GimpColorProfile **buffer_profile, gint *new_offset_x, gint *new_offset_y) { const Babl *format; GeglBuffer *new_buffer; GeglRectangle src_rect; GeglRectangle dest_rect; gint orig_x, orig_y; gint orig_width, orig_height; gint orig_bpp; gint new_x, new_y; gint new_width, new_height; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (buffer_profile != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); *buffer_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable)); orig_x = orig_offset_x; orig_y = orig_offset_y; orig_width = gegl_buffer_get_width (orig_buffer); orig_height = gegl_buffer_get_height (orig_buffer); orig_bpp = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer)); switch (rotate_type) { case GIMP_ROTATE_90: gimp_drawable_transform_rotate_point (orig_x, orig_y + orig_height, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_height; new_height = orig_width; break; case GIMP_ROTATE_180: gimp_drawable_transform_rotate_point (orig_x + orig_width, orig_y + orig_height, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_width; new_height = orig_height; break; case GIMP_ROTATE_270: gimp_drawable_transform_rotate_point (orig_x + orig_width, orig_y, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_height; new_height = orig_width; break; default: g_return_val_if_reached (NULL); break; } format = gegl_buffer_get_format (orig_buffer); if (clip_result && (new_x != orig_x || new_y != orig_y || new_width != orig_width || new_height != orig_height)) { GimpRGB bg; GeglColor *color; gint clip_x, clip_y; gint clip_width, clip_height; new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, orig_width, orig_height), format); *new_offset_x = orig_x; *new_offset_y = orig_y; /* Use transparency, rather than the bg color, as the "outside" color of * channels, and drawables with an alpha channel. */ if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format)) { gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0); } else { gimp_context_get_background (context, &bg); gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable), &bg, &bg); } color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable)); gegl_buffer_set_color (new_buffer, NULL, color); g_object_unref (color); if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height, new_x, new_y, new_width, new_height, &clip_x, &clip_y, &clip_width, &clip_height)) { gint saved_orig_x = orig_x; gint saved_orig_y = orig_y; new_x = clip_x - orig_x; new_y = clip_y - orig_y; switch (rotate_type) { case GIMP_ROTATE_90: gimp_drawable_transform_rotate_point (clip_x + clip_width, clip_y, GIMP_ROTATE_270, center_x, center_y, &orig_x, &orig_y); orig_x -= saved_orig_x; orig_y -= saved_orig_y; orig_width = clip_height; orig_height = clip_width; break; case GIMP_ROTATE_180: orig_x = clip_x - orig_x; orig_y = clip_y - orig_y; orig_width = clip_width; orig_height = clip_height; break; case GIMP_ROTATE_270: gimp_drawable_transform_rotate_point (clip_x, clip_y + clip_height, GIMP_ROTATE_90, center_x, center_y, &orig_x, &orig_y); orig_x -= saved_orig_x; orig_y -= saved_orig_y; orig_width = clip_height; orig_height = clip_width; break; } new_width = clip_width; new_height = clip_height; } else { new_width = 0; new_height = 0; } } else { new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height), format); *new_offset_x = new_x; *new_offset_y = new_y; orig_x = 0; orig_y = 0; new_x = 0; new_y = 0; } if (new_width < 1 || new_height < 1) return new_buffer; src_rect.x = orig_x; src_rect.y = orig_y; src_rect.width = orig_width; src_rect.height = orig_height; dest_rect.x = new_x; dest_rect.y = new_y; dest_rect.width = new_width; dest_rect.height = new_height; switch (rotate_type) { case GIMP_ROTATE_90: { guchar *buf = g_new (guchar, new_height * orig_bpp); gint i; /* Not cool, we leak memory if we return, but anyway that is * never supposed to happen. If we see this warning, a bug has * to be fixed! */ g_return_val_if_fail (new_height == orig_width, NULL); src_rect.y = orig_y + orig_height - 1; src_rect.height = 1; dest_rect.x = new_x; dest_rect.width = 1; for (i = 0; i < orig_height; i++) { src_rect.y = orig_y + orig_height - 1 - i; dest_rect.x = new_x + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; case GIMP_ROTATE_180: { guchar *buf = g_new (guchar, new_width * orig_bpp); gint i, j, k; /* Not cool, we leak memory if we return, but anyway that is * never supposed to happen. If we see this warning, a bug has * to be fixed! */ g_return_val_if_fail (new_width == orig_width, NULL); src_rect.y = orig_y + orig_height - 1; src_rect.height = 1; dest_rect.y = new_y; dest_rect.height = 1; for (i = 0; i < orig_height; i++) { src_rect.y = orig_y + orig_height - 1 - i; dest_rect.y = new_y + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (j = 0; j < orig_width / 2; j++) { guchar *left = buf + j * orig_bpp; guchar *right = buf + (orig_width - 1 - j) * orig_bpp; for (k = 0; k < orig_bpp; k++) { guchar tmp = left[k]; left[k] = right[k]; right[k] = tmp; } } gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; case GIMP_ROTATE_270: { guchar *buf = g_new (guchar, new_width * orig_bpp); gint i; /* Not cool, we leak memory if we return, but anyway that is * never supposed to happen. If we see this warning, a bug has * to be fixed! */ g_return_val_if_fail (new_width == orig_height, NULL); src_rect.x = orig_x + orig_width - 1; src_rect.width = 1; dest_rect.y = new_y; dest_rect.height = 1; for (i = 0; i < orig_width; i++) { src_rect.x = orig_x + orig_width - 1 - i; dest_rect.y = new_y + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; } return new_buffer; }
GeglBuffer * gimp_drawable_transform_buffer_flip (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, GimpOrientationType flip_type, gdouble axis, gboolean clip_result, GimpColorProfile **buffer_profile, gint *new_offset_x, gint *new_offset_y) { const Babl *format; GeglBuffer *new_buffer; GeglBufferIterator *iter; GeglRectangle src_rect; GeglRectangle dest_rect; gint bpp; gint orig_x, orig_y; gint orig_width, orig_height; gint new_x, new_y; gint new_width, new_height; gint x, y; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); g_return_val_if_fail (buffer_profile != NULL, NULL); g_return_val_if_fail (new_offset_x != NULL, NULL); g_return_val_if_fail (new_offset_y != NULL, NULL); *buffer_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (drawable)); orig_x = orig_offset_x; orig_y = orig_offset_y; orig_width = gegl_buffer_get_width (orig_buffer); orig_height = gegl_buffer_get_height (orig_buffer); new_x = orig_x; new_y = orig_y; new_width = orig_width; new_height = orig_height; switch (flip_type) { case GIMP_ORIENTATION_HORIZONTAL: new_x = RINT (-((gdouble) orig_x + (gdouble) orig_width - axis) + axis); break; case GIMP_ORIENTATION_VERTICAL: new_y = RINT (-((gdouble) orig_y + (gdouble) orig_height - axis) + axis); break; case GIMP_ORIENTATION_UNKNOWN: g_return_val_if_reached (NULL); break; } format = gegl_buffer_get_format (orig_buffer); bpp = babl_format_get_bytes_per_pixel (format); new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height), format); if (clip_result && (new_x != orig_x || new_y != orig_y)) { GimpRGB bg; GeglColor *color; gint clip_x, clip_y; gint clip_width, clip_height; *new_offset_x = orig_x; *new_offset_y = orig_y; /* Use transparency, rather than the bg color, as the "outside" color of * channels, and drawables with an alpha channel. */ if (GIMP_IS_CHANNEL (drawable) || babl_format_has_alpha (format)) { gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0); } else { gimp_context_get_background (context, &bg); gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable), &bg, &bg); } color = gimp_gegl_color_new (&bg, gimp_drawable_get_space (drawable)); gegl_buffer_set_color (new_buffer, NULL, color); g_object_unref (color); if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height, new_x, new_y, new_width, new_height, &clip_x, &clip_y, &clip_width, &clip_height)) { orig_x = new_x = clip_x - orig_x; orig_y = new_y = clip_y - orig_y; } orig_width = new_width = clip_width; orig_height = new_height = clip_height; } else { *new_offset_x = new_x; *new_offset_y = new_y; orig_x = 0; orig_y = 0; new_x = 0; new_y = 0; } if (new_width == 0 && new_height == 0) return new_buffer; dest_rect.x = new_x; dest_rect.y = new_y; dest_rect.width = new_width; dest_rect.height = new_height; iter = gegl_buffer_iterator_new (new_buffer, &dest_rect, 0, NULL, GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE, 1); switch (flip_type) { case GIMP_ORIENTATION_HORIZONTAL: while (gegl_buffer_iterator_next (iter)) { gint stride = iter->items[0].roi.width * bpp; src_rect = iter->items[0].roi; src_rect.x = (orig_x + orig_width) - (iter->items[0].roi.x - dest_rect.x) - iter->items[0].roi.width; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data, stride, GEGL_ABYSS_NONE); for (y = 0; y < iter->items[0].roi.height; y++) { guint8 *left = iter->items[0].data; guint8 *right = iter->items[0].data; left += y * stride; right += y * stride + (iter->items[0].roi.width - 1) * bpp; for (x = 0; x < iter->items[0].roi.width / 2; x++) { guint8 temp[bpp]; memcpy (temp, left, bpp); memcpy (left, right, bpp); memcpy (right, temp, bpp); left += bpp; right -= bpp; } } } break; case GIMP_ORIENTATION_VERTICAL: while (gegl_buffer_iterator_next (iter)) { gint stride = iter->items[0].roi.width * bpp; src_rect = iter->items[0].roi; src_rect.y = (orig_y + orig_height) - (iter->items[0].roi.y - dest_rect.y) - iter->items[0].roi.height; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, iter->items[0].data, stride, GEGL_ABYSS_NONE); for (x = 0; x < iter->items[0].roi.width; x++) { guint8 *top = iter->items[0].data; guint8 *bottom = iter->items[0].data; top += x * bpp; bottom += x * bpp + (iter->items[0].roi.height - 1) * stride; for (y = 0; y < iter->items[0].roi.height / 2; y++) { guint8 temp[bpp]; memcpy (temp, top, bpp); memcpy (top, bottom, bpp); memcpy (bottom, temp, bpp); top += stride; bottom -= stride; } } } break; case GIMP_ORIENTATION_UNKNOWN: gegl_buffer_iterator_stop (iter); break; } return new_buffer; }
gboolean gimp_image_convert_color_profile (GimpImage *image, GimpColorProfile *dest_profile, GimpColorRenderingIntent intent, gboolean bpc, GimpProgress *progress, GError **error) { GimpColorProfile *src_profile; GimpColorProfile *builtin_profile; const Babl *layer_format; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (dest_profile != NULL, FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (! gimp_image_validate_color_profile (image, dest_profile, error)) return FALSE; src_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image)); if (gimp_color_profile_is_equal (src_profile, dest_profile)) { g_object_unref (src_profile); return TRUE; } if (progress) gimp_progress_start (progress, FALSE, _("Converting from '%s' to '%s'"), gimp_color_profile_get_label (src_profile), gimp_color_profile_get_label (dest_profile)); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT, _("Color profile conversion")); layer_format = gimp_image_get_layer_format (image, FALSE); if (gimp_babl_format_get_linear (layer_format)) builtin_profile = gimp_color_profile_new_linear_rgb (); else builtin_profile = gimp_color_profile_new_srgb (); if (gimp_color_profile_is_equal (dest_profile, builtin_profile)) { /* don't tag the image with the built-in profile */ gimp_image_set_color_profile (image, NULL, NULL); } else { gimp_image_set_color_profile (image, dest_profile, NULL); } g_object_unref (builtin_profile); /* omg... */ gimp_image_parasite_detach (image, "icc-profile-name"); switch (gimp_image_get_base_type (image)) { case GIMP_RGB: gimp_image_convert_profile_rgb (image, src_profile, dest_profile, intent, bpc, progress); break; case GIMP_GRAY: break; case GIMP_INDEXED: gimp_image_convert_profile_indexed (image, src_profile, dest_profile, intent, bpc, progress); break; } gimp_image_undo_group_end (image); if (progress) gimp_progress_end (progress); g_object_unref (src_profile); return TRUE; }