void gimp_transform_matrix_flip (GimpMatrix3 *matrix, GimpOrientationType flip_type, gdouble axis) { g_return_if_fail (matrix != NULL); switch (flip_type) { case GIMP_ORIENTATION_HORIZONTAL: gimp_matrix3_translate (matrix, - axis, 0.0); gimp_matrix3_scale (matrix, -1.0, 1.0); gimp_matrix3_translate (matrix, axis, 0.0); break; case GIMP_ORIENTATION_VERTICAL: gimp_matrix3_translate (matrix, 0.0, - axis); gimp_matrix3_scale (matrix, 1.0, -1.0); gimp_matrix3_translate (matrix, 0.0, axis); break; case GIMP_ORIENTATION_UNKNOWN: break; } }
void gimp_transform_matrix_shear (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, GimpOrientationType orientation, gdouble amount) { gdouble center_x; gdouble center_y; g_return_if_fail (matrix != NULL); if (width == 0) width = 1; if (height == 0) height = 1; center_x = (gdouble) x + (gdouble) width / 2.0; center_y = (gdouble) y + (gdouble) height / 2.0; gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -center_x, -center_y); if (orientation == GIMP_ORIENTATION_HORIZONTAL) gimp_matrix3_xshear (matrix, amount / height); else gimp_matrix3_yshear (matrix, amount / width); gimp_matrix3_translate (matrix, +center_x, +center_y); }
void gimp_transform_matrix_scale (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, gdouble t_x, gdouble t_y, gdouble t_width, gdouble t_height) { gdouble scale_x = 1.0; gdouble scale_y = 1.0; g_return_if_fail (matrix != NULL); if (width > 0) scale_x = t_width / (gdouble) width; if (height > 0) scale_y = t_height / (gdouble) height; gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -x, -y); gimp_matrix3_scale (matrix, scale_x, scale_y); gimp_matrix3_translate (matrix, t_x, t_y); }
void gimp_transform_matrix_rotate_center (GimpMatrix3 *matrix, gdouble center_x, gdouble center_y, gdouble angle) { g_return_if_fail (matrix != NULL); gimp_matrix3_translate (matrix, -center_x, -center_y); gimp_matrix3_rotate (matrix, angle); gimp_matrix3_translate (matrix, +center_x, +center_y); }
static void gimp_mandala_update_strokes (GimpSymmetry *sym, GimpDrawable *drawable, GimpCoords *origin) { GimpMandala *mandala = GIMP_MANDALA (sym); GimpCoords *coords; GimpMatrix3 matrix; gint i; g_list_free_full (sym->strokes, g_free); sym->strokes = NULL; coords = g_memdup (sym->origin, sizeof (GimpCoords)); sym->strokes = g_list_prepend (sym->strokes, coords); for (i = 1; i < mandala->size; i++) { gdouble new_x, new_y; coords = g_memdup (sym->origin, sizeof (GimpCoords)); gimp_matrix3_identity (&matrix); gimp_matrix3_translate (&matrix, - mandala->center_x, - mandala->center_y); gimp_matrix3_rotate (&matrix, - i * 2.0 * G_PI / (gdouble) mandala->size); gimp_matrix3_translate (&matrix, mandala->center_x, mandala->center_y); gimp_matrix3_transform_point (&matrix, coords->x, coords->y, &new_x, &new_y); coords->x = new_x; coords->y = new_y; sym->strokes = g_list_prepend (sym->strokes, coords); } sym->strokes = g_list_reverse (sym->strokes); g_signal_emit_by_name (sym, "strokes-updated", sym->image); }
void gimp_transform_matrix_rotate_rect (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, gdouble angle) { gdouble center_x; gdouble center_y; g_return_if_fail (matrix != NULL); center_x = (gdouble) x + (gdouble) width / 2.0; center_y = (gdouble) y + (gdouble) height / 2.0; gimp_matrix3_translate (matrix, -center_x, -center_y); gimp_matrix3_rotate (matrix, angle); gimp_matrix3_translate (matrix, +center_x, +center_y); }
void gimp_transform_matrix_flip_free (GimpMatrix3 *matrix, gdouble x1, gdouble y1, gdouble x2, gdouble y2) { gdouble angle; g_return_if_fail (matrix != NULL); angle = atan2 (y2 - y1, x2 - x1); gimp_matrix3_identity (matrix); gimp_matrix3_translate (matrix, -x1, -y1); gimp_matrix3_rotate (matrix, -angle); gimp_matrix3_scale (matrix, 1.0, -1.0); gimp_matrix3_rotate (matrix, angle); gimp_matrix3_translate (matrix, x1, y1); }
static void gimp_perspective_clone_get_matrix (GimpPerspectiveClone *clone, GimpMatrix3 *matrix) { GimpMatrix3 temp; gimp_matrix3_identity (&temp); gimp_matrix3_translate (&temp, clone->dest_x_fv - clone->src_x_fv, clone->dest_y_fv - clone->src_y_fv); *matrix = clone->transform_inv; gimp_matrix3_mult (&temp, matrix); gimp_matrix3_mult (&clone->transform, matrix); }
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, gint recursion_level, GimpTransformResize clip_result, gint *new_offset_x, gint *new_offset_y, GimpProgress *progress) { GeglBuffer *new_buffer; GimpMatrix3 m; GimpMatrix3 inv; gint u1, v1, u2, v2; /* source bounding box */ gint x1, y1, x2, y2; /* target bounding box */ GeglNode *affine; 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 (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); m = *matrix; inv = *matrix; if (direction == GIMP_TRANSFORM_BACKWARD) { /* keep the original matrix here, so we dont need to recalculate * the inverse later */ gimp_matrix3_invert (&inv); } else { /* 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); /* Always clip unfloated buffers since they must keep their size */ if (G_TYPE_FROM_INSTANCE (drawable) == GIMP_TYPE_CHANNEL && ! babl_format_has_alpha (gegl_buffer_get_format (orig_buffer))) clip_result = GIMP_TRANSFORM_RESIZE_CLIP; /* Find the bounding coordinates of target */ gimp_transform_resize_boundary (&inv, clip_result, u1, v1, u2, v2, &x1, &y1, &x2, &y2); /* Get the new temporary buffer for the transformed result */ new_buffer = gimp_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 (&inv, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1, -y1); affine = gegl_node_new_child (NULL, "operation", "gegl:transform", "filter", gimp_interpolation_to_gegl_filter (interpolation_type), "hard-edges", TRUE, NULL); gimp_gegl_node_set_matrix (affine, &gegl_matrix); gimp_apply_operation (orig_buffer, progress, NULL, affine, new_buffer, NULL); g_object_unref (affine); *new_offset_x = x1; *new_offset_y = y1; return new_buffer; }
static GeglBuffer * gimp_perspective_clone_get_source (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpPickable *src_pickable, gint src_offset_x, gint src_offset_y, GeglBuffer *paint_buffer, gint paint_buffer_x, gint paint_buffer_y, gint *paint_area_offset_x, gint *paint_area_offset_y, gint *paint_area_width, gint *paint_area_height, GeglRectangle *src_rect) { GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (source_core); GimpCloneOptions *clone_options = GIMP_CLONE_OPTIONS (paint_options); GeglBuffer *src_buffer; GeglBuffer *dest_buffer; const Babl *src_format_alpha; gint x1d, y1d, x2d, y2d; gdouble x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s; gint xmin, ymin, xmax, ymax; GimpMatrix3 matrix; GimpMatrix3 gegl_matrix; src_buffer = gimp_pickable_get_buffer (src_pickable); src_format_alpha = gimp_pickable_get_format_with_alpha (src_pickable); /* Destination coordinates that will be painted */ x1d = paint_buffer_x; y1d = paint_buffer_y; x2d = paint_buffer_x + gegl_buffer_get_width (paint_buffer); y2d = paint_buffer_y + gegl_buffer_get_height (paint_buffer); /* Boundary box for source pixels to copy: Convert all the vertex of * the box to paint in destination area to its correspondent in * source area bearing in mind perspective */ gimp_perspective_clone_get_source_point (clone, x1d, y1d, &x1s, &y1s); gimp_perspective_clone_get_source_point (clone, x1d, y2d, &x2s, &y2s); gimp_perspective_clone_get_source_point (clone, x2d, y1d, &x3s, &y3s); gimp_perspective_clone_get_source_point (clone, x2d, y2d, &x4s, &y4s); xmin = floor (MIN4 (x1s, x2s, x3s, x4s)); ymin = floor (MIN4 (y1s, y2s, y3s, y4s)); xmax = ceil (MAX4 (x1s, x2s, x3s, x4s)); ymax = ceil (MAX4 (y1s, y2s, y3s, y4s)); switch (clone_options->clone_type) { case GIMP_IMAGE_CLONE: if (! gimp_rectangle_intersect (xmin, ymin, xmax - xmin, ymax - ymin, 0, 0, gegl_buffer_get_width (src_buffer), gegl_buffer_get_height (src_buffer), NULL, NULL, NULL, NULL)) { /* if the source area is completely out of the image */ return NULL; } break; case GIMP_PATTERN_CLONE: gegl_node_set (clone->crop, "x", (gdouble) xmin, "y", (gdouble) ymin, "width", (gdouble) xmax - xmin, "height", (gdouble) ymax - ymin, NULL); break; } dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d), src_format_alpha); gimp_perspective_clone_get_matrix (clone, &matrix); gimp_matrix3_identity (&gegl_matrix); gimp_matrix3_mult (&matrix, &gegl_matrix); gimp_matrix3_translate (&gegl_matrix, -x1d, -y1d); gimp_gegl_node_set_matrix (clone->transform_node, &gegl_matrix); gegl_node_set (clone->dest_node, "buffer", dest_buffer, NULL); gegl_node_blit (clone->dest_node, 1.0, GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d), NULL, NULL, 0, GEGL_BLIT_DEFAULT); *src_rect = *GEGL_RECTANGLE (0, 0, x2d - x1d, y2d - y1d); return dest_buffer; }
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; }
void gimp_transform_matrix_perspective (GimpMatrix3 *matrix, gint x, gint y, gint width, gint height, gdouble t_x1, gdouble t_y1, gdouble t_x2, gdouble t_y2, gdouble t_x3, gdouble t_y3, gdouble t_x4, gdouble t_y4) { GimpMatrix3 trafo; gdouble scalex; gdouble scaley; g_return_if_fail (matrix != NULL); scalex = scaley = 1.0; if (width > 0) scalex = 1.0 / (gdouble) width; if (height > 0) scaley = 1.0 / (gdouble) height; gimp_matrix3_translate (matrix, -x, -y); gimp_matrix3_scale (matrix, scalex, scaley); /* Determine the perspective transform that maps from * the unit cube to the transformed coordinates */ { gdouble dx1, dx2, dx3, dy1, dy2, dy3; dx1 = t_x2 - t_x4; dx2 = t_x3 - t_x4; dx3 = t_x1 - t_x2 + t_x4 - t_x3; dy1 = t_y2 - t_y4; dy2 = t_y3 - t_y4; dy3 = t_y1 - t_y2 + t_y4 - t_y3; /* Is the mapping affine? */ if ((dx3 == 0.0) && (dy3 == 0.0)) { trafo.coeff[0][0] = t_x2 - t_x1; trafo.coeff[0][1] = t_x4 - t_x2; trafo.coeff[0][2] = t_x1; trafo.coeff[1][0] = t_y2 - t_y1; trafo.coeff[1][1] = t_y4 - t_y2; trafo.coeff[1][2] = t_y1; trafo.coeff[2][0] = 0.0; trafo.coeff[2][1] = 0.0; } else { gdouble det1, det2; det1 = dx3 * dy2 - dy3 * dx2; det2 = dx1 * dy2 - dy1 * dx2; trafo.coeff[2][0] = (det2 == 0.0) ? 1.0 : det1 / det2; det1 = dx1 * dy3 - dy1 * dx3; trafo.coeff[2][1] = (det2 == 0.0) ? 1.0 : det1 / det2; trafo.coeff[0][0] = t_x2 - t_x1 + trafo.coeff[2][0] * t_x2; trafo.coeff[0][1] = t_x3 - t_x1 + trafo.coeff[2][1] * t_x3; trafo.coeff[0][2] = t_x1; trafo.coeff[1][0] = t_y2 - t_y1 + trafo.coeff[2][0] * t_y2; trafo.coeff[1][1] = t_y3 - t_y1 + trafo.coeff[2][1] * t_y3; trafo.coeff[1][2] = t_y1; } trafo.coeff[2][2] = 1.0; } gimp_matrix3_mult (&trafo, matrix); }
static GimpValueArray * transform_2d_invoker (GimpProcedure *procedure, Gimp *gimp, GimpContext *context, GimpProgress *progress, const GimpValueArray *args, GError **error) { gboolean success = TRUE; GimpValueArray *return_vals; GimpDrawable *drawable; gboolean interpolation; gdouble source_x; gdouble source_y; gdouble scale_x; gdouble scale_y; gdouble angle; gdouble dest_x; gdouble dest_y; drawable = gimp_value_get_drawable (gimp_value_array_index (args, 0), gimp); interpolation = g_value_get_boolean (gimp_value_array_index (args, 1)); source_x = g_value_get_double (gimp_value_array_index (args, 2)); source_y = g_value_get_double (gimp_value_array_index (args, 3)); scale_x = g_value_get_double (gimp_value_array_index (args, 4)); scale_y = g_value_get_double (gimp_value_array_index (args, 5)); angle = g_value_get_double (gimp_value_array_index (args, 6)); dest_x = g_value_get_double (gimp_value_array_index (args, 7)); dest_y = g_value_get_double (gimp_value_array_index (args, 8)); if (success) { gint x, y, width, height; success = gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, TRUE, error); if (success && gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) { GimpMatrix3 matrix; GimpInterpolationType interpolation_type = GIMP_INTERPOLATION_NONE; /* Assemble the transformation matrix */ gimp_matrix3_identity (&matrix); gimp_matrix3_translate (&matrix, -source_x, -source_y); gimp_matrix3_scale (&matrix, scale_x, scale_y); gimp_matrix3_rotate (&matrix, angle); gimp_matrix3_translate (&matrix, dest_x, dest_y); if (interpolation) interpolation_type = gimp->config->interpolation_type; if (progress) gimp_progress_start (progress, _("2D Transform"), FALSE); if (! gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) && ! gimp_channel_is_empty (gimp_image_get_mask (gimp_item_get_image (GIMP_ITEM (drawable))))) { if (! gimp_drawable_transform_affine (drawable, context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation_type, 3, FALSE, progress)) { success = FALSE; } } else { gimp_item_transform (GIMP_ITEM (drawable), context, &matrix, GIMP_TRANSFORM_FORWARD, interpolation, 3, FALSE, progress); } if (progress) gimp_progress_end (progress); } } return_vals = gimp_procedure_get_return_values (procedure, success, error ? *error : NULL); if (success) gimp_value_set_drawable (gimp_value_array_index (return_vals, 1), drawable); return return_vals; }