Image: Flip image operator

This implements an operator to flip the contents of an image buffer. It
supports flipping the image horizontally and vertically.

Reviewed By: JacquesLucke

Differential Revision: https://developer.blender.org/D10310
This commit is contained in:
Pablo Dobarro 2021-02-04 18:03:42 +01:00
parent faf45091b4
commit 7d874b0343
4 changed files with 131 additions and 0 deletions

View File

@ -235,6 +235,7 @@ class IMAGE_MT_image(Menu):
layout.menu("IMAGE_MT_image_invert")
layout.operator("image.resize", text="Resize")
layout.menu("IMAGE_MT_image_flip")
if ima and not show_render:
if ima.packed_file:
@ -250,6 +251,13 @@ class IMAGE_MT_image(Menu):
layout.operator("palette.extract_from_image", text="Extract Palette")
layout.operator("gpencil.image_to_grease_pencil", text="Generate Grease Pencil")
class IMAGE_MT_image_flip(Menu):
bl_label = "Flip"
def draw(self, _context):
layout = self.layout
layout.operator("image.flip", text="Horizontally").use_flip_horizontal = True
layout.operator("image.flip", text="Vertically").use_flip_vertical = True
class IMAGE_MT_image_invert(Menu):
bl_label = "Invert"
@ -1584,6 +1592,7 @@ classes = (
IMAGE_MT_select,
IMAGE_MT_select_linked,
IMAGE_MT_image,
IMAGE_MT_image_flip,
IMAGE_MT_image_invert,
IMAGE_MT_uvs,
IMAGE_MT_uvs_showhide,

View File

@ -71,6 +71,7 @@ void IMAGE_OT_save_all_modified(struct wmOperatorType *ot);
void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_flip(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
void IMAGE_OT_resize(struct wmOperatorType *ot);

View File

@ -2660,6 +2660,126 @@ void IMAGE_OT_new(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Flip Operator
* \{ */
static int image_flip_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
if (ibuf == NULL) {
/* TODO: this should actually never happen, but does for render-results -> cleanup. */
return OPERATOR_CANCELLED;
}
const bool flip_horizontal = RNA_boolean_get(op->ptr, "use_flip_horizontal");
const bool flip_vertical = RNA_boolean_get(op->ptr, "use_flip_vertical");
if (!flip_horizontal && !flip_vertical) {
BKE_image_release_ibuf(ima, ibuf, NULL);
return OPERATOR_FINISHED;
}
ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
}
const int size_x = ibuf->x;
const int size_y = ibuf->y;
if (ibuf->rect_float) {
float *float_pixels = (float *)ibuf->rect_float;
float *orig_float_pixels = MEM_dupallocN(float_pixels);
for (int x = 0; x < size_x; x++) {
for (int y = 0; y < size_y; y++) {
const int source_pixel_x = flip_horizontal ? size_x - x - 1 : x;
const int source_pixel_y = flip_vertical ? size_y - y - 1 : y;
float *source_pixel = &orig_float_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
float *target_pixel = &float_pixels[4 * (x + y * size_x)];
copy_v4_v4(target_pixel, source_pixel);
}
}
MEM_freeN(orig_float_pixels);
if (ibuf->rect) {
IMB_rect_from_float(ibuf);
}
}
else if (ibuf->rect) {
char *char_pixels = (char *)ibuf->rect;
char *orig_char_pixels = MEM_dupallocN(char_pixels);
for (int x = 0; x < size_x; x++) {
for (int y = 0; y < size_y; y++) {
const int source_pixel_x = flip_horizontal ? size_x - x - 1 : x;
const int source_pixel_y = flip_vertical ? size_y - y - 1 : y;
char *source_pixel = &orig_char_pixels[4 * (source_pixel_x + source_pixel_y * size_x)];
char *target_pixel = &char_pixels[4 * (x + y * size_x)];
copy_v4_v4_char(target_pixel, source_pixel);
}
}
MEM_freeN(orig_char_pixels);
}
else {
BKE_image_release_ibuf(ima, ibuf, NULL);
return OPERATOR_CANCELLED;
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
BKE_image_mark_dirty(ima, ibuf);
if (ibuf->mipmap[0]) {
ibuf->userflags |= IB_MIPMAP_INVALID;
}
ED_image_undo_push_end();
/* force GPU reupload, all image is invalid. */
BKE_image_free_gputextures(ima);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
BKE_image_release_ibuf(ima, ibuf, NULL);
return OPERATOR_FINISHED;
}
void IMAGE_OT_flip(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Flip Image";
ot->idname = "IMAGE_OT_flip";
ot->description = "Flip the image";
/* api callbacks */
ot->exec = image_flip_exec;
ot->poll = image_from_context_has_data_poll_no_image_user;
/* properties */
PropertyRNA *prop;
prop = RNA_def_boolean(
ot->srna, "use_flip_horizontal", false, "Horizontal", "Flip the image horizontally");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna, "use_flip_vertical", false, "Vertical", "Flip the image vertically");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* flags */
ot->flag = OPTYPE_REGISTER;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Invert Operators
* \{ */

View File

@ -234,6 +234,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_pack);
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_flip);
WM_operatortype_append(IMAGE_OT_invert);
WM_operatortype_append(IMAGE_OT_resize);