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; }
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; }