Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eeaaaf5b29 | |||
| 1f91a2db6f | |||
| 4fdc46460d | |||
| a7d9ccf0da | |||
| 80eb0edaec | |||
| 0a29707c3c | |||
| bbace1896a | |||
| 6fa5629403 | |||
| d5797c313c | |||
| a580a4e137 |
@@ -1,3 +1,57 @@
|
|||||||
# Image Editor Plus
|
# Image Editor Plus
|
||||||
|
|
||||||
Image Editor Plus is an add-on that lets you modify your image in seconds. Clear, fill, flip, rotation, adjusting colors, and applying some filters in just a few clicks without external editors such as PhotoShop or Gimp.
|

|
||||||
|
|
||||||
|
Image Editor Plus is a Blender add-on that lets you modify your image in seconds. Clear, fill, flip, rotation, adjusting colors, and applying some filters in just a few clicks without external editors such as PhotoShop or Gimp.
|
||||||
|
|
||||||
|
This add-on extends the UV/Image Editor in Blender and provides the following operations.
|
||||||
|
|
||||||
|
- Cut/Copy/Paste
|
||||||
|
- Clear, Fill
|
||||||
|
- Crop
|
||||||
|
- Adjust hue/saturation
|
||||||
|
- Adjust brightness/contrast
|
||||||
|
- Adjust gamma
|
||||||
|
- Adjust color curve
|
||||||
|
- Replace color
|
||||||
|
- Flip, Rotate
|
||||||
|
- Canvas size
|
||||||
|
- Offset
|
||||||
|
- Apply filters
|
||||||
|
|
||||||
|
NOTE: Currently, text editing is provided as a separate add-on: [Image Editor+ Text Tool](https://superhivemarket.com/products/imedp-text-tool)
|
||||||
|
|
||||||
|
These image operations can be applied to packed/unpacked images, and reflected to the 3D model view immediately.
|
||||||
|
|
||||||
|
You can make a selection to edit the desired area on your image (currently only rectangle selection supported).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
It's easy to copy/paste a selection or an entire image. The pasted images are displayed as layers, and they can be moved, rotated or scaled.
|
||||||
|
|
||||||
|
NOTE: To display pasted layers in the 3D View, you need to use a [Image Layers Node](https://superhivemarket.com/products/image-layers-node) instead of built-in Texture Node.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Filters
|
||||||
|
|
||||||
|
By applying the some filters, you can add special effects to your images.
|
||||||
|
|
||||||
|
- Blur
|
||||||
|
- Sharpen
|
||||||
|
- Add noise
|
||||||
|
- Pixelize (Mosaic)
|
||||||
|
- Make seamless
|
||||||
|
- Normal map
|
||||||
|
|
||||||
|
"Make seamless" filter is useful for making your image tileable.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Normal Map Generator
|
||||||
|
|
||||||
|
Normal Map is a texture where every pixel represents a normal vector and is used to add bumps to a surface.
|
||||||
|
|
||||||
|
This add-on uses a height map (black: low, white: high) as input and can convert it to a normal map.
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
+7
-3
@@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Copyright (C) 2021 - 2024 Akaneyu
|
Copyright (C) 2021 - 2025 Akaneyu
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Image Editor Plus",
|
"name": "Image Editor Plus",
|
||||||
"author": "akaneyu",
|
"author": "akaneyu",
|
||||||
"version": (1, 8, 0),
|
"version": (1, 11, 0),
|
||||||
"blender": (3, 3, 0),
|
"blender": (4, 2, 0),
|
||||||
"location": "Image",
|
"location": "Image",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
"description": "",
|
"description": "",
|
||||||
@@ -64,6 +64,7 @@ classes = [
|
|||||||
operators.IMAGE_EDITOR_PLUS_OT_flip,
|
operators.IMAGE_EDITOR_PLUS_OT_flip,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_rotate,
|
operators.IMAGE_EDITOR_PLUS_OT_rotate,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_scale,
|
operators.IMAGE_EDITOR_PLUS_OT_scale,
|
||||||
|
operators.IMAGE_EDITOR_PLUS_OT_change_canvas_size,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_flip_layer,
|
operators.IMAGE_EDITOR_PLUS_OT_flip_layer,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_rotate_layer,
|
operators.IMAGE_EDITOR_PLUS_OT_rotate_layer,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_rotate_layer_arbitrary,
|
operators.IMAGE_EDITOR_PLUS_OT_rotate_layer_arbitrary,
|
||||||
@@ -79,7 +80,9 @@ classes = [
|
|||||||
operators.IMAGE_EDITOR_PLUS_OT_add_noise,
|
operators.IMAGE_EDITOR_PLUS_OT_add_noise,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_pixelize,
|
operators.IMAGE_EDITOR_PLUS_OT_pixelize,
|
||||||
operators.IMAGE_EDITOR_PLUS_OT_make_seamless,
|
operators.IMAGE_EDITOR_PLUS_OT_make_seamless,
|
||||||
|
operators.IMAGE_EDITOR_PLUS_OT_normal_map,
|
||||||
ui.IMAGE_EDITOR_PLUS_OT_scale_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_scale_dialog,
|
||||||
|
ui.IMAGE_EDITOR_PLUS_OT_change_canvas_size_dialog,
|
||||||
ui.IMAGE_EDITOR_PLUS_OffsetPropertyGroup,
|
ui.IMAGE_EDITOR_PLUS_OffsetPropertyGroup,
|
||||||
ui.IMAGE_EDITOR_PLUS_OT_offset_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_offset_dialog,
|
||||||
ui.IMAGE_EDITOR_PLUS_OT_adjust_color_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_adjust_color_dialog,
|
||||||
@@ -92,6 +95,7 @@ classes = [
|
|||||||
ui.IMAGE_EDITOR_PLUS_OT_add_noise_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_add_noise_dialog,
|
||||||
ui.IMAGE_EDITOR_PLUS_OT_pixelize_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_pixelize_dialog,
|
||||||
ui.IMAGE_EDITOR_PLUS_OT_make_seamless_dialog,
|
ui.IMAGE_EDITOR_PLUS_OT_make_seamless_dialog,
|
||||||
|
ui.IMAGE_EDITOR_PLUS_OT_normal_map_dialog,
|
||||||
ui.IMAGE_EDITOR_PLUS_UL_layer_list,
|
ui.IMAGE_EDITOR_PLUS_UL_layer_list,
|
||||||
ui.IMAGE_EDITOR_PLUS_MT_edit_menu,
|
ui.IMAGE_EDITOR_PLUS_MT_edit_menu,
|
||||||
ui.IMAGE_EDITOR_PLUS_MT_layers_menu,
|
ui.IMAGE_EDITOR_PLUS_MT_layers_menu,
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Copyright (C) 2021 - 2024 Akaneyu
|
Copyright (C) 2021 - 2025 Akaneyu
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -136,6 +136,7 @@ def draw_handler():
|
|||||||
|
|
||||||
# release the selection if the image is changed
|
# release the selection if the image is changed
|
||||||
if area_session.selection or area_session.selection_region:
|
if area_session.selection or area_session.selection_region:
|
||||||
|
if area_session.prev_image:
|
||||||
if img != area_session.prev_image:
|
if img != area_session.prev_image:
|
||||||
cancel_selection(context)
|
cancel_selection(context)
|
||||||
|
|
||||||
|
|||||||
+151
-7
@@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Copyright (C) 2021 - 2023 Akaneyu
|
Copyright (C) 2021 - 2025 Akaneyu
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +26,9 @@ class IMAGE_EDITOR_PLUS_OT_make_selection(bpy.types.Operator):
|
|||||||
bl_idname = "image_editor_plus.make_selection"
|
bl_idname = "image_editor_plus.make_selection"
|
||||||
bl_label = "Make Selection"
|
bl_label = "Make Selection"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.lmb = False
|
self.lmb = False
|
||||||
|
|
||||||
def modal(self, context, event):
|
def modal(self, context, event):
|
||||||
@@ -43,12 +45,14 @@ class IMAGE_EDITOR_PLUS_OT_make_selection(bpy.types.Operator):
|
|||||||
|
|
||||||
if area_session.selection_region:
|
if area_session.selection_region:
|
||||||
area_session.selection_region[1] = region_pos
|
area_session.selection_region[1] = region_pos
|
||||||
else:
|
|
||||||
area_session.selection_region = [region_pos, region_pos]
|
|
||||||
|
|
||||||
elif event.type == 'LEFTMOUSE':
|
elif event.type == 'LEFTMOUSE':
|
||||||
if event.value == 'PRESS':
|
if event.value == 'PRESS':
|
||||||
self.lmb = True
|
self.lmb = True
|
||||||
|
|
||||||
|
region_pos = [event.mouse_region_x, event.mouse_region_y]
|
||||||
|
area_session.selection_region = [region_pos, region_pos]
|
||||||
|
|
||||||
elif event.value == 'RELEASE':
|
elif event.value == 'RELEASE':
|
||||||
self.lmb = False
|
self.lmb = False
|
||||||
|
|
||||||
@@ -397,7 +401,9 @@ class IMAGE_EDITOR_PLUS_OT_move_layer(bpy.types.Operator):
|
|||||||
bl_idname = "image_editor_plus.move_layer"
|
bl_idname = "image_editor_plus.move_layer"
|
||||||
bl_label = "Move Layer"
|
bl_label = "Move Layer"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.start_input_position = [0, 0]
|
self.start_input_position = [0, 0]
|
||||||
self.start_layer_location = [0, 0]
|
self.start_layer_location = [0, 0]
|
||||||
|
|
||||||
@@ -764,6 +770,77 @@ class IMAGE_EDITOR_PLUS_OT_scale(bpy.types.Operator):
|
|||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class IMAGE_EDITOR_PLUS_OT_change_canvas_size(bpy.types.Operator):
|
||||||
|
"""Apply settings"""
|
||||||
|
bl_idname = "image_editor_plus.change_canvas_size"
|
||||||
|
bl_label = "Change Canvas Size"
|
||||||
|
width: bpy.props.IntProperty()
|
||||||
|
height: bpy.props.IntProperty()
|
||||||
|
expand_from_center: bpy.props.BoolProperty()
|
||||||
|
use_background_color: bpy.props.BoolProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
wm = context.window_manager
|
||||||
|
|
||||||
|
props = wm.imageeditorplus_properties
|
||||||
|
if self.use_background_color:
|
||||||
|
color = props.background_color[:] + (1.0,)
|
||||||
|
else:
|
||||||
|
color = (0, 0, 0, 0)
|
||||||
|
|
||||||
|
img = context.area.spaces.active.image
|
||||||
|
if not img:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
width, height = img.size
|
||||||
|
pixels = utils.read_pixels_from_image(img)
|
||||||
|
|
||||||
|
if self.width > width or self.height > height:
|
||||||
|
expand_width = self.width - width if self.width > width else 0
|
||||||
|
expand_height = self.height - height if self.height > height else 0
|
||||||
|
|
||||||
|
if self.expand_from_center:
|
||||||
|
expand_left = int(expand_width / 2)
|
||||||
|
expand_top = int(expand_height / 2)
|
||||||
|
expand_right = expand_width - expand_left
|
||||||
|
expand_bottom = expand_height - expand_top
|
||||||
|
else:
|
||||||
|
expand_left, expand_top = 0, 0
|
||||||
|
expand_right = expand_width
|
||||||
|
expand_bottom = expand_height
|
||||||
|
|
||||||
|
new_pixels = np.pad(pixels, ((expand_bottom, expand_top),
|
||||||
|
(expand_left, expand_right), (0, 0)),
|
||||||
|
constant_values=np.array(((color, color), (color, color), (0, 0)),
|
||||||
|
dtype=object))
|
||||||
|
else:
|
||||||
|
new_pixels = pixels
|
||||||
|
|
||||||
|
if self.width < width or self.height < height:
|
||||||
|
shrink_width = width - self.width if self.width < width else 0
|
||||||
|
shrink_height = height - self.height if self.height < height else 0
|
||||||
|
|
||||||
|
if self.expand_from_center:
|
||||||
|
shrink_left = int(shrink_width / 2)
|
||||||
|
shrink_top = int(shrink_height / 2)
|
||||||
|
else:
|
||||||
|
shrink_left, shrink_top = 0, 0
|
||||||
|
|
||||||
|
if self.height < height:
|
||||||
|
new_pixels = new_pixels[height - self.height - shrink_top:height - shrink_top,
|
||||||
|
shrink_left:self.width + shrink_left]
|
||||||
|
else:
|
||||||
|
new_pixels = new_pixels[0:self.height,
|
||||||
|
shrink_left:self.width + shrink_left]
|
||||||
|
|
||||||
|
img.scale(self.width, self.height)
|
||||||
|
|
||||||
|
utils.write_pixels_to_image(img, new_pixels)
|
||||||
|
|
||||||
|
app.refresh_image(context)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_OT_flip_layer(bpy.types.Operator):
|
class IMAGE_EDITOR_PLUS_OT_flip_layer(bpy.types.Operator):
|
||||||
"""Flip the layer"""
|
"""Flip the layer"""
|
||||||
bl_idname = "image_editor_plus.flip_layer"
|
bl_idname = "image_editor_plus.flip_layer"
|
||||||
@@ -814,7 +891,9 @@ class IMAGE_EDITOR_PLUS_OT_rotate_layer_arbitrary(bpy.types.Operator):
|
|||||||
bl_idname = "image_editor_plus.rotate_layer_arbitrary"
|
bl_idname = "image_editor_plus.rotate_layer_arbitrary"
|
||||||
bl_label = "Rotate Layer Arbitrary"
|
bl_label = "Rotate Layer Arbitrary"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.start_input_position = [0, 0]
|
self.start_input_position = [0, 0]
|
||||||
self.start_layer_angle = 0
|
self.start_layer_angle = 0
|
||||||
|
|
||||||
@@ -896,7 +975,9 @@ class IMAGE_EDITOR_PLUS_OT_scale_layer(bpy.types.Operator):
|
|||||||
bl_idname = "image_editor_plus.scale_layer"
|
bl_idname = "image_editor_plus.scale_layer"
|
||||||
bl_label = "Scale Layer"
|
bl_label = "Scale Layer"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.start_input_position = [0, 0]
|
self.start_input_position = [0, 0]
|
||||||
self.start_layer_scale_x = 1.0
|
self.start_layer_scale_x = 1.0
|
||||||
self.start_layer_scale_y = 1.0
|
self.start_layer_scale_y = 1.0
|
||||||
@@ -1562,3 +1643,66 @@ class IMAGE_EDITOR_PLUS_OT_make_seamless(bpy.types.Operator):
|
|||||||
app.refresh_image(context)
|
app.refresh_image(context)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
class IMAGE_EDITOR_PLUS_OT_normal_map(bpy.types.Operator):
|
||||||
|
"""Apply settings"""
|
||||||
|
bl_idname = 'image_editor_plus.normal_map'
|
||||||
|
bl_label = "Normal Map"
|
||||||
|
scale: bpy.props.FloatProperty()
|
||||||
|
flip_x: bpy.props.BoolProperty()
|
||||||
|
flip_y: bpy.props.BoolProperty()
|
||||||
|
full_z: bpy.props.BoolProperty()
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
scale = self.scale
|
||||||
|
flip_x = self.flip_x
|
||||||
|
flip_y = self.flip_y
|
||||||
|
full_z = self.full_z
|
||||||
|
|
||||||
|
pixels, hsl = app.get_image_cache()
|
||||||
|
if pixels is None:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
selection = app.get_target_selection(context)
|
||||||
|
if selection:
|
||||||
|
target_hsl = hsl[selection[0][1]:selection[1][1],
|
||||||
|
selection[0][0]:selection[1][0]]
|
||||||
|
elif selection == []:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
else:
|
||||||
|
target_hsl = hsl
|
||||||
|
|
||||||
|
target_width, target_height = target_hsl.shape[1], target_hsl.shape[0]
|
||||||
|
|
||||||
|
target_hsl = np.pad(target_hsl, ((1, 1), (1, 1), (0, 0)), 'edge')
|
||||||
|
|
||||||
|
new_pixels = np.zeros((target_height, target_width, 4))
|
||||||
|
nx = (target_hsl[1:target_height + 1, 0:target_width, 2]
|
||||||
|
- target_hsl[1:target_height + 1, 2:target_width + 2, 2]) * scale
|
||||||
|
ny = (target_hsl[0:target_height, 1:target_width + 1, 2]
|
||||||
|
- target_hsl[2:target_height + 2, 1:target_width + 1, 2]) * scale
|
||||||
|
nz = 1.0 / np.sqrt(nx * nx + ny * ny + 1.0)
|
||||||
|
|
||||||
|
nx *= nz
|
||||||
|
ny *= nz
|
||||||
|
|
||||||
|
new_pixels = np.dstack([
|
||||||
|
0.5 + (-0.5 if flip_x else 0.5) * nx,
|
||||||
|
0.5 + (-0.5 if flip_y else 0.5) * ny,
|
||||||
|
(0 if full_z else 0.5) + (1.0 if full_z else 0.5) * nz,
|
||||||
|
])
|
||||||
|
|
||||||
|
new_pixels = np.clip(new_pixels, 0, None)
|
||||||
|
|
||||||
|
if selection:
|
||||||
|
pixels[selection[0][1]:selection[1][1],
|
||||||
|
selection[0][0]:selection[1][0], 0:3] = new_pixels
|
||||||
|
else:
|
||||||
|
pixels[:,:,0:3] = new_pixels
|
||||||
|
|
||||||
|
img = app.get_target_image(context)
|
||||||
|
utils.write_pixels_to_image(img, pixels)
|
||||||
|
|
||||||
|
app.refresh_image(context)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|||||||
+306
-206
@@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Copyright (C) 2021 - 2023 Akaneyu
|
Copyright (C) 2021 - 2025 Akaneyu
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -199,26 +199,103 @@ class IMAGE_EDITOR_PLUS_OT_scale_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_offset_properties(self, context):
|
def reset_canvas_size_properties(self, context):
|
||||||
if self.preview:
|
if self.reset:
|
||||||
update_offset_properties(self, context)
|
self.width = self.original_width
|
||||||
else:
|
self.height = self.original_height
|
||||||
img = app.get_target_image(context)
|
self.expand_from_center = False
|
||||||
if img:
|
self.use_background_color = False
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
self.reset = False
|
||||||
|
|
||||||
|
class IMAGE_EDITOR_PLUS_OT_change_canvas_size_dialog(bpy.types.Operator):
|
||||||
|
"""Change the canvas size"""
|
||||||
|
bl_idname = 'image_editor_plus.change_canvas_size_dialog'
|
||||||
|
bl_label = "Canvas Size"
|
||||||
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_canvas_size_properties)
|
||||||
|
width: bpy.props.IntProperty(name='Width',
|
||||||
|
min=1, options={'SKIP_SAVE'})
|
||||||
|
height: bpy.props.IntProperty(name='Height',
|
||||||
|
min=1, options={'SKIP_SAVE'})
|
||||||
|
expand_from_center: bpy.props.BoolProperty(name='Expand from Center', default=False)
|
||||||
|
use_background_color: bpy.props.BoolProperty(name='Use Background Color', default=False)
|
||||||
|
original_width: bpy.props.IntProperty()
|
||||||
|
original_height: bpy.props.IntProperty()
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
wm = context.window_manager
|
||||||
|
|
||||||
|
img = context.area.spaces.active.image
|
||||||
|
if not img:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
width, height = img.size
|
||||||
|
|
||||||
|
self.original_width = width
|
||||||
|
self.original_height = height
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
return wm.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
width = self.width
|
||||||
|
height = self.height
|
||||||
|
|
||||||
|
if width < 1:
|
||||||
|
width = 1
|
||||||
|
if height < 1:
|
||||||
|
height = 1
|
||||||
|
|
||||||
|
bpy.ops.image_editor_plus.change_canvas_size('EXEC_DEFAULT', False,
|
||||||
|
width=width, height=height, expand_from_center=self.expand_from_center,
|
||||||
|
use_background_color=self.use_background_color)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.alignment = 'RIGHT'
|
||||||
|
row.label(text='Width')
|
||||||
|
row.prop(self, 'width', text='')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.alignment = 'RIGHT'
|
||||||
|
row.label(text='Height')
|
||||||
|
row.prop(self, 'height', text='')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'expand_from_center')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'use_background_color')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
|
||||||
|
row = layout.split(factor=0.7)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def reset_offset_properties(self, context):
|
def reset_offset_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.offset_properties.property_unset('offset_x')
|
self.offset_properties.property_unset('offset_x')
|
||||||
self.offset_properties.property_unset('offset_y')
|
self.offset_properties.property_unset('offset_y')
|
||||||
self.property_unset('offset_edge_behavior')
|
self.property_unset('offset_edge_behavior')
|
||||||
update_offset_properties(self, context)
|
update_offset_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_offset_properties(self, context):
|
def update_offset_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.offset('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.offset('EXEC_DEFAULT', False,
|
||||||
offset_x=self.offset_properties.offset_x,
|
offset_x=self.offset_properties.offset_x,
|
||||||
offset_y=self.offset_properties.offset_y,
|
offset_y=self.offset_properties.offset_y,
|
||||||
@@ -233,15 +310,15 @@ class IMAGE_EDITOR_PLUS_OT_offset_dialog(bpy.types.Operator):
|
|||||||
"""Offset the image"""
|
"""Offset the image"""
|
||||||
bl_idname = 'image_editor_plus.offset_dialog'
|
bl_idname = 'image_editor_plus.offset_dialog'
|
||||||
bl_label = "Offset"
|
bl_label = "Offset"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_offset_properties)
|
update=update_offset_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_offset_properties)
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_offset_properties)
|
||||||
offset_properties: bpy.props.PointerProperty(options={'SKIP_SAVE'},
|
offset_properties: bpy.props.PointerProperty(options={'SKIP_SAVE'},
|
||||||
type=IMAGE_EDITOR_PLUS_OffsetPropertyGroup)
|
type=IMAGE_EDITOR_PLUS_OffsetPropertyGroup)
|
||||||
offset_edge_behavior: bpy.props.EnumProperty(options={'SKIP_SAVE'}, items=(
|
offset_edge_behavior: bpy.props.EnumProperty(options={'SKIP_SAVE'}, items=(
|
||||||
('wrap', 'Wrap', 'Wrap image around'),
|
('wrap', 'Wrap', 'Wrap image around'),
|
||||||
('edge', 'Edge', 'Repeat edge pixels')),
|
('edge', 'Edge', 'Repeat edge pixels')))
|
||||||
update=update_offset_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -261,13 +338,11 @@ class IMAGE_EDITOR_PLUS_OT_offset_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
IMAGE_EDITOR_PLUS_OffsetPropertyGroup.offset_x = \
|
IMAGE_EDITOR_PLUS_OffsetPropertyGroup.offset_x = \
|
||||||
bpy.props.IntProperty(name='Offset X', subtype='FACTOR',
|
bpy.props.IntProperty(name='Offset X', subtype='FACTOR',
|
||||||
min=-width + 1, max=width - 1,
|
min=-width + 1, max=width - 1)
|
||||||
update=(lambda _self, context: update_offset_properties(self, context)))
|
|
||||||
|
|
||||||
IMAGE_EDITOR_PLUS_OffsetPropertyGroup.offset_y = \
|
IMAGE_EDITOR_PLUS_OffsetPropertyGroup.offset_y = \
|
||||||
bpy.props.IntProperty(name='Offset Y', subtype='FACTOR',
|
bpy.props.IntProperty(name='Offset Y', subtype='FACTOR',
|
||||||
min=-width + 1, max=width - 1,
|
min=-height + 1, max=height - 1)
|
||||||
update=(lambda _self, context: update_offset_properties(self, context)))
|
|
||||||
|
|
||||||
update_offset_properties(self, context)
|
update_offset_properties(self, context)
|
||||||
|
|
||||||
@@ -295,7 +370,7 @@ class IMAGE_EDITOR_PLUS_OT_offset_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -316,26 +391,19 @@ class IMAGE_EDITOR_PLUS_OT_offset_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_adjust_color_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_adjust_color_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_adjust_color_properties(self, context):
|
def reset_adjust_color_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('adjust_hue')
|
self.property_unset('adjust_hue')
|
||||||
self.property_unset('adjust_lightness')
|
self.property_unset('adjust_lightness')
|
||||||
self.property_unset('adjust_saturation')
|
self.property_unset('adjust_saturation')
|
||||||
update_adjust_color_properties(self, context)
|
update_adjust_color_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_adjust_color_properties(self, context):
|
def update_adjust_color_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.adjust_color('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.adjust_color('EXEC_DEFAULT', False,
|
||||||
adjust_hue=self.adjust_hue,
|
adjust_hue=self.adjust_hue,
|
||||||
adjust_lightness=self.adjust_lightness,
|
adjust_lightness=self.adjust_lightness,
|
||||||
@@ -345,19 +413,17 @@ class IMAGE_EDITOR_PLUS_OT_adjust_color_dialog(bpy.types.Operator):
|
|||||||
"""Adjust hue/saturation/lightness of the image"""
|
"""Adjust hue/saturation/lightness of the image"""
|
||||||
bl_idname = 'image_editor_plus.adjust_color_dialog'
|
bl_idname = 'image_editor_plus.adjust_color_dialog'
|
||||||
bl_label = "Hue/Saturation"
|
bl_label = "Hue/Saturation"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_adjust_color_properties)
|
update=update_adjust_color_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=reset_adjust_color_properties)
|
update=reset_adjust_color_properties)
|
||||||
adjust_hue: bpy.props.FloatProperty(name='Hue', subtype='FACTOR',
|
adjust_hue: bpy.props.FloatProperty(name='Hue', subtype='FACTOR',
|
||||||
min=-180, max=180, default=0, options={'SKIP_SAVE'},
|
min=-180, max=180, default=0, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_color_properties)
|
|
||||||
adjust_lightness: bpy.props.FloatProperty(name='Lightness', subtype='PERCENTAGE',
|
adjust_lightness: bpy.props.FloatProperty(name='Lightness', subtype='PERCENTAGE',
|
||||||
min=0, max=200, default=100, options={'SKIP_SAVE'},
|
min=0, max=200, default=100, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_color_properties)
|
|
||||||
adjust_saturation: bpy.props.FloatProperty(name='Saturation', subtype='PERCENTAGE',
|
adjust_saturation: bpy.props.FloatProperty(name='Saturation', subtype='PERCENTAGE',
|
||||||
min=0, max=200, default=100, options={'SKIP_SAVE'},
|
min=0, max=200, default=100, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_color_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -394,7 +460,7 @@ class IMAGE_EDITOR_PLUS_OT_adjust_color_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -417,25 +483,18 @@ class IMAGE_EDITOR_PLUS_OT_adjust_color_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_adjust_brightness_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_adjust_brightness_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_adjust_brightness_properties(self, context):
|
def reset_adjust_brightness_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('adjust_brightness')
|
self.property_unset('adjust_brightness')
|
||||||
self.property_unset('adjust_contrast')
|
self.property_unset('adjust_contrast')
|
||||||
update_adjust_brightness_properties(self, context)
|
update_adjust_brightness_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_adjust_brightness_properties(self, context):
|
def update_adjust_brightness_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.adjust_brightness('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.adjust_brightness('EXEC_DEFAULT', False,
|
||||||
adjust_brightness=self.adjust_brightness,
|
adjust_brightness=self.adjust_brightness,
|
||||||
adjust_contrast=self.adjust_contrast)
|
adjust_contrast=self.adjust_contrast)
|
||||||
@@ -444,16 +503,15 @@ class IMAGE_EDITOR_PLUS_OT_adjust_brightness_dialog(bpy.types.Operator):
|
|||||||
"""Adjust brightness/contrast of the image"""
|
"""Adjust brightness/contrast of the image"""
|
||||||
bl_idname = 'image_editor_plus.adjust_brightness_dialog'
|
bl_idname = 'image_editor_plus.adjust_brightness_dialog'
|
||||||
bl_label = "Brightness/Contrast"
|
bl_label = "Brightness/Contrast"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_adjust_brightness_properties)
|
update=update_adjust_brightness_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=reset_adjust_brightness_properties)
|
update=reset_adjust_brightness_properties)
|
||||||
adjust_brightness: bpy.props.FloatProperty(name='Brightness', subtype='PERCENTAGE',
|
adjust_brightness: bpy.props.FloatProperty(name='Brightness', subtype='PERCENTAGE',
|
||||||
min=0, max=200, default=100, options={'SKIP_SAVE'},
|
min=0, max=200, default=100, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_brightness_properties)
|
|
||||||
adjust_contrast: bpy.props.FloatProperty(name='Contrast', subtype='PERCENTAGE',
|
adjust_contrast: bpy.props.FloatProperty(name='Contrast', subtype='PERCENTAGE',
|
||||||
min=0, max=200, default=100, options={'SKIP_SAVE'},
|
min=0, max=200, default=100, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_brightness_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -489,7 +547,7 @@ class IMAGE_EDITOR_PLUS_OT_adjust_brightness_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -507,24 +565,17 @@ class IMAGE_EDITOR_PLUS_OT_adjust_brightness_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_adjust_gamma_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_adjust_gamma_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_adjust_gamma_properties(self, context):
|
def reset_adjust_gamma_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('adjust_gamma')
|
self.property_unset('adjust_gamma')
|
||||||
update_adjust_gamma_properties(self, context)
|
update_adjust_gamma_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_adjust_gamma_properties(self, context):
|
def update_adjust_gamma_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.adjust_gamma('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.adjust_gamma('EXEC_DEFAULT', False,
|
||||||
adjust_gamma=self.adjust_gamma)
|
adjust_gamma=self.adjust_gamma)
|
||||||
|
|
||||||
@@ -532,13 +583,13 @@ class IMAGE_EDITOR_PLUS_OT_adjust_gamma_dialog(bpy.types.Operator):
|
|||||||
"""Adjust gamma of the image"""
|
"""Adjust gamma of the image"""
|
||||||
bl_idname = 'image_editor_plus.adjust_gamma_dialog'
|
bl_idname = 'image_editor_plus.adjust_gamma_dialog'
|
||||||
bl_label = "Gamma"
|
bl_label = "Gamma"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_adjust_gamma_properties)
|
update=update_adjust_gamma_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=reset_adjust_gamma_properties)
|
update=reset_adjust_gamma_properties)
|
||||||
adjust_gamma: bpy.props.FloatProperty(name='Gamma', subtype='FACTOR',
|
adjust_gamma: bpy.props.FloatProperty(name='Gamma', subtype='FACTOR',
|
||||||
min=0.01, soft_max=3.0, default=1.0, options={'SKIP_SAVE'},
|
min=0.01, soft_max=3.0, default=1.0, options={'SKIP_SAVE'})
|
||||||
update=update_adjust_gamma_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -573,7 +624,7 @@ class IMAGE_EDITOR_PLUS_OT_adjust_gamma_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -586,33 +637,23 @@ class IMAGE_EDITOR_PLUS_OT_adjust_gamma_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_adjust_color_curve_properties(self, context):
|
|
||||||
if not self.preview:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_adjust_color_curve_properties(self, context):
|
def reset_adjust_color_curve_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
app.reset_curve_mapping()
|
|
||||||
|
|
||||||
self.reset = False
|
self.reset = False
|
||||||
|
|
||||||
|
app.reset_curve_mapping()
|
||||||
|
update_adjust_color_curve_properties(self, context)
|
||||||
|
|
||||||
def update_adjust_color_curve_properties(self, context):
|
def update_adjust_color_curve_properties(self, context):
|
||||||
if self.update_preview:
|
if self.update_preview:
|
||||||
self.update_preview = False
|
self.update_preview = False
|
||||||
|
|
||||||
if self.preview:
|
|
||||||
bpy.ops.image_editor_plus.adjust_color_curve('EXEC_DEFAULT', False)
|
bpy.ops.image_editor_plus.adjust_color_curve('EXEC_DEFAULT', False)
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog(bpy.types.Operator):
|
class IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog(bpy.types.Operator):
|
||||||
"""Adjust color curve of the image"""
|
"""Adjust color curve of the image"""
|
||||||
bl_idname = 'image_editor_plus.adjust_curve_dialog'
|
bl_idname = 'image_editor_plus.adjust_curve_dialog'
|
||||||
bl_label = "Adjust Color Curve"
|
bl_label = "Adjust Color Curve"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
|
||||||
update=preview_adjust_color_curve_properties,
|
|
||||||
description='Preview manually (Need an update operation)')
|
|
||||||
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=update_adjust_color_curve_properties,
|
update=update_adjust_color_curve_properties,
|
||||||
description='Update preview')
|
description='Update preview')
|
||||||
@@ -651,8 +692,7 @@ class IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
row.prop(self, 'update_preview', text='Update', toggle=True, icon='FILE_REFRESH')
|
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -665,26 +705,19 @@ class IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_replace_color_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_replace_color_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_replace_color_properties(self, context):
|
def reset_replace_color_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('source_color')
|
self.property_unset('source_color')
|
||||||
self.property_unset('replace_color')
|
self.property_unset('replace_color')
|
||||||
self.property_unset('color_threshold')
|
self.property_unset('color_threshold')
|
||||||
update_replace_color_properties(self, context)
|
update_replace_color_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_replace_color_properties(self, context):
|
def update_replace_color_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.replace_color('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.replace_color('EXEC_DEFAULT', False,
|
||||||
source_color=self.source_color,
|
source_color=self.source_color,
|
||||||
replace_color=self.replace_color,
|
replace_color=self.replace_color,
|
||||||
@@ -694,19 +727,17 @@ class IMAGE_EDITOR_PLUS_OT_replace_color_dialog(bpy.types.Operator):
|
|||||||
"""Replace one color in the image with another"""
|
"""Replace one color in the image with another"""
|
||||||
bl_idname = 'image_editor_plus.replace_color_dialog'
|
bl_idname = 'image_editor_plus.replace_color_dialog'
|
||||||
bl_label = "Replace Color"
|
bl_label = "Replace Color"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_replace_color_properties)
|
update=update_replace_color_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=reset_replace_color_properties)
|
update=reset_replace_color_properties)
|
||||||
source_color: bpy.props.FloatVectorProperty(name='Source Color', subtype='COLOR_GAMMA',
|
source_color: bpy.props.FloatVectorProperty(name='Source Color', subtype='COLOR_GAMMA',
|
||||||
min=0, max=1.0, size=3, default=(1.0, 1.0, 1.0), options={'SKIP_SAVE'},
|
min=0, max=1.0, size=3, default=(1.0, 1.0, 1.0), options={'SKIP_SAVE'}) # no alpha
|
||||||
update=update_replace_color_properties) # no alpha
|
|
||||||
replace_color: bpy.props.FloatVectorProperty(name='Replace Color', subtype='COLOR_GAMMA',
|
replace_color: bpy.props.FloatVectorProperty(name='Replace Color', subtype='COLOR_GAMMA',
|
||||||
min=0, max=1.0, size=4, default=(0, 0, 0, 1.0), options={'SKIP_SAVE'},
|
min=0, max=1.0, size=4, default=(0, 0, 0, 1.0), options={'SKIP_SAVE'})
|
||||||
update=update_replace_color_properties)
|
|
||||||
color_threshold: bpy.props.FloatProperty(name='Threshold', subtype='FACTOR',
|
color_threshold: bpy.props.FloatProperty(name='Threshold', subtype='FACTOR',
|
||||||
min=0, max=1.0, default=0.1, options={'SKIP_SAVE'},
|
min=0, max=1.0, default=0.1, options={'SKIP_SAVE'})
|
||||||
update=update_replace_color_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -743,7 +774,7 @@ class IMAGE_EDITOR_PLUS_OT_replace_color_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -766,25 +797,18 @@ class IMAGE_EDITOR_PLUS_OT_replace_color_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_blur_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_blur_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_blur_properties(self, context):
|
def reset_blur_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('blur_size')
|
self.property_unset('blur_size')
|
||||||
self.property_unset('expand_layer')
|
self.property_unset('expand_layer')
|
||||||
update_blur_properties(self, context)
|
update_blur_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_blur_properties(self, context):
|
def update_blur_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.blur('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.blur('EXEC_DEFAULT', False,
|
||||||
blur_size=self.blur_size,
|
blur_size=self.blur_size,
|
||||||
expand_layer=False)
|
expand_layer=False)
|
||||||
@@ -793,14 +817,13 @@ class IMAGE_EDITOR_PLUS_OT_blur_dialog(bpy.types.Operator):
|
|||||||
"""Blur the image"""
|
"""Blur the image"""
|
||||||
bl_idname = 'image_editor_plus.blur_dialog'
|
bl_idname = 'image_editor_plus.blur_dialog'
|
||||||
bl_label = "Blur (Gaussian Blur)"
|
bl_label = "Blur (Gaussian Blur)"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_blur_properties)
|
update=update_blur_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_blur_properties)
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_blur_properties)
|
||||||
blur_size: bpy.props.FloatProperty(name='Size', subtype='FACTOR',
|
blur_size: bpy.props.FloatProperty(name='Size', subtype='FACTOR',
|
||||||
min=0, soft_max=10.0, default=3.0, options={'SKIP_SAVE'},
|
min=0, soft_max=10.0, default=3.0, options={'SKIP_SAVE'})
|
||||||
update=update_blur_properties)
|
expand_layer: bpy.props.BoolProperty(name='Expand Layer', default=True, options={'SKIP_SAVE'})
|
||||||
expand_layer: bpy.props.BoolProperty(name='Expand Layer', default=True, options={'SKIP_SAVE'},
|
|
||||||
update=update_blur_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
session = app.get_session()
|
session = app.get_session()
|
||||||
@@ -842,7 +865,7 @@ class IMAGE_EDITOR_PLUS_OT_blur_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -859,26 +882,19 @@ class IMAGE_EDITOR_PLUS_OT_blur_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_sharpen_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_sharpen_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_sharpen_properties(self, context):
|
def reset_sharpen_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('sharpen_radius')
|
self.property_unset('sharpen_radius')
|
||||||
self.property_unset('sharpen_amount')
|
self.property_unset('sharpen_amount')
|
||||||
self.property_unset('sharpen_threshold')
|
self.property_unset('sharpen_threshold')
|
||||||
update_sharpen_properties(self, context)
|
update_sharpen_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_sharpen_properties(self, context):
|
def update_sharpen_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.sharpen('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.sharpen('EXEC_DEFAULT', False,
|
||||||
sharpen_radius=self.sharpen_radius,
|
sharpen_radius=self.sharpen_radius,
|
||||||
sharpen_amount=self.sharpen_amount,
|
sharpen_amount=self.sharpen_amount,
|
||||||
@@ -888,18 +904,16 @@ class IMAGE_EDITOR_PLUS_OT_sharpen_dialog(bpy.types.Operator):
|
|||||||
"""Sharpen the image"""
|
"""Sharpen the image"""
|
||||||
bl_idname = 'image_editor_plus.sharpen_dialog'
|
bl_idname = 'image_editor_plus.sharpen_dialog'
|
||||||
bl_label = "Sharpen (Unsharp Mask)"
|
bl_label = "Sharpen (Unsharp Mask)"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_sharpen_properties)
|
update=update_sharpen_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(update=reset_sharpen_properties, options={'SKIP_SAVE'})
|
reset: bpy.props.BoolProperty(update=reset_sharpen_properties, options={'SKIP_SAVE'})
|
||||||
sharpen_radius: bpy.props.FloatProperty(name='Radius', subtype='FACTOR',
|
sharpen_radius: bpy.props.FloatProperty(name='Radius', subtype='FACTOR',
|
||||||
min=0, soft_max=10.0, default=3.0, options={'SKIP_SAVE'},
|
min=0, soft_max=10.0, default=3.0, options={'SKIP_SAVE'})
|
||||||
update=update_sharpen_properties)
|
|
||||||
sharpen_amount: bpy.props.FloatProperty(name='Amount', subtype='FACTOR',
|
sharpen_amount: bpy.props.FloatProperty(name='Amount', subtype='FACTOR',
|
||||||
min=0, soft_max=10.0, default=0.5, options={'SKIP_SAVE'},
|
min=0, soft_max=10.0, default=0.5, options={'SKIP_SAVE'})
|
||||||
update=update_sharpen_properties)
|
|
||||||
sharpen_threshold: bpy.props.FloatProperty(name='Threshold', subtype='FACTOR',
|
sharpen_threshold: bpy.props.FloatProperty(name='Threshold', subtype='FACTOR',
|
||||||
min=0, soft_max=1.0, default=0, options={'SKIP_SAVE'},
|
min=0, soft_max=1.0, default=0, options={'SKIP_SAVE'})
|
||||||
update=update_sharpen_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -936,7 +950,7 @@ class IMAGE_EDITOR_PLUS_OT_sharpen_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -959,24 +973,17 @@ class IMAGE_EDITOR_PLUS_OT_sharpen_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_add_noise_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_add_noise_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_add_noise_properties(self, context):
|
def reset_add_noise_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('add_noise_intensity')
|
self.property_unset('add_noise_intensity')
|
||||||
update_add_noise_properties(self, context)
|
update_add_noise_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_add_noise_properties(self, context):
|
def update_add_noise_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.add_noise('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.add_noise('EXEC_DEFAULT', False,
|
||||||
add_noise_intensity=self.add_noise_intensity)
|
add_noise_intensity=self.add_noise_intensity)
|
||||||
|
|
||||||
@@ -984,12 +991,12 @@ class IMAGE_EDITOR_PLUS_OT_add_noise_dialog(bpy.types.Operator):
|
|||||||
"""Add some noise to the image"""
|
"""Add some noise to the image"""
|
||||||
bl_idname = 'image_editor_plus.add_noise_dialog'
|
bl_idname = 'image_editor_plus.add_noise_dialog'
|
||||||
bl_label = "Add Noise (Gaussian Noise)"
|
bl_label = "Add Noise (Gaussian Noise)"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_add_noise_properties)
|
update=update_add_noise_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_add_noise_properties)
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_add_noise_properties)
|
||||||
add_noise_intensity: bpy.props.FloatProperty(name='Intensity', subtype='FACTOR',
|
add_noise_intensity: bpy.props.FloatProperty(name='Intensity', subtype='FACTOR',
|
||||||
min=0, soft_max=10.0, default=0.1, options={'SKIP_SAVE'},
|
min=0, soft_max=10.0, default=0.1, options={'SKIP_SAVE'})
|
||||||
update=update_add_noise_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -1024,7 +1031,7 @@ class IMAGE_EDITOR_PLUS_OT_add_noise_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -1037,24 +1044,17 @@ class IMAGE_EDITOR_PLUS_OT_add_noise_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_pixelize_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_pixelize_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def reset_pixelize_properties(self, context):
|
def reset_pixelize_properties(self, context):
|
||||||
if self.reset:
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
self.property_unset('pixelize_pixel_size')
|
self.property_unset('pixelize_pixel_size')
|
||||||
update_pixelize_properties(self, context)
|
update_pixelize_properties(self, context)
|
||||||
|
|
||||||
self.reset = False
|
|
||||||
|
|
||||||
def update_pixelize_properties(self, context):
|
def update_pixelize_properties(self, context):
|
||||||
if self.preview:
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
bpy.ops.image_editor_plus.pixelize('EXEC_DEFAULT', False,
|
bpy.ops.image_editor_plus.pixelize('EXEC_DEFAULT', False,
|
||||||
pixelize_pixel_size=self.pixelize_pixel_size)
|
pixelize_pixel_size=self.pixelize_pixel_size)
|
||||||
|
|
||||||
@@ -1062,12 +1062,12 @@ class IMAGE_EDITOR_PLUS_OT_pixelize_dialog(bpy.types.Operator):
|
|||||||
"""Pixelize the image"""
|
"""Pixelize the image"""
|
||||||
bl_idname = 'image_editor_plus.pixelize_dialog'
|
bl_idname = 'image_editor_plus.pixelize_dialog'
|
||||||
bl_label = "Pixelize"
|
bl_label = "Pixelize"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
update=preview_pixelize_properties)
|
update=update_pixelize_properties,
|
||||||
|
description='Update preview')
|
||||||
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_pixelize_properties)
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_pixelize_properties)
|
||||||
pixelize_pixel_size: bpy.props.IntProperty(name='Pixel Size', subtype='FACTOR',
|
pixelize_pixel_size: bpy.props.IntProperty(name='Pixel Size', subtype='FACTOR',
|
||||||
min=1, soft_max=64, default=16, options={'SKIP_SAVE'},
|
min=1, soft_max=64, default=16, options={'SKIP_SAVE'})
|
||||||
update=update_pixelize_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -1102,7 +1102,7 @@ class IMAGE_EDITOR_PLUS_OT_pixelize_dialog(bpy.types.Operator):
|
|||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
@@ -1115,25 +1115,13 @@ class IMAGE_EDITOR_PLUS_OT_pixelize_dialog(bpy.types.Operator):
|
|||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'reset', text='Reset', toggle=True)
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
def preview_make_seamless_properties(self, context):
|
|
||||||
if self.preview:
|
|
||||||
update_make_seamless_properties(self, context)
|
|
||||||
else:
|
|
||||||
img = app.get_target_image(context)
|
|
||||||
if img:
|
|
||||||
app.revert_image_cache(img)
|
|
||||||
app.refresh_image(context)
|
|
||||||
|
|
||||||
def update_make_seamless_properties(self, context):
|
def update_make_seamless_properties(self, context):
|
||||||
if self.preview:
|
|
||||||
bpy.ops.image_editor_plus.make_seamless('EXEC_DEFAULT', False)
|
bpy.ops.image_editor_plus.make_seamless('EXEC_DEFAULT', False)
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_OT_make_seamless_dialog(bpy.types.Operator):
|
class IMAGE_EDITOR_PLUS_OT_make_seamless_dialog(bpy.types.Operator):
|
||||||
"""Turn the image into seamless tile"""
|
"""Turn the image into seamless tile"""
|
||||||
bl_idname = 'image_editor_plus.make_seamless_dialog'
|
bl_idname = 'image_editor_plus.make_seamless_dialog'
|
||||||
bl_label = "Make Seamless"
|
bl_label = "Make Seamless"
|
||||||
preview: bpy.props.BoolProperty(default=True, options={'SKIP_SAVE'},
|
|
||||||
update=preview_make_seamless_properties)
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
wm = context.window_manager
|
wm = context.window_manager
|
||||||
@@ -1162,12 +1150,109 @@ class IMAGE_EDITOR_PLUS_OT_make_seamless_dialog(bpy.types.Operator):
|
|||||||
app.clear_image_cache()
|
app.clear_image_cache()
|
||||||
app.refresh_image(context)
|
app.refresh_image(context)
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def reset_normal_map_properties(self, context):
|
||||||
|
if self.reset:
|
||||||
|
self.reset = False
|
||||||
|
|
||||||
|
self.property_unset('scale')
|
||||||
|
self.property_unset('flip_x')
|
||||||
|
self.property_unset('flip_y')
|
||||||
|
self.property_unset('full_z')
|
||||||
|
update_normal_map_properties(self, context)
|
||||||
|
|
||||||
|
def update_normal_map_properties(self, context):
|
||||||
|
if self.update_preview:
|
||||||
|
self.update_preview = False
|
||||||
|
|
||||||
|
bpy.ops.image_editor_plus.normal_map('EXEC_DEFAULT', False,
|
||||||
|
scale=self.scale,
|
||||||
|
flip_x=self.flip_x,
|
||||||
|
flip_y=self.flip_y,
|
||||||
|
full_z=self.full_z)
|
||||||
|
|
||||||
|
class IMAGE_EDITOR_PLUS_OT_normal_map_dialog(bpy.types.Operator):
|
||||||
|
"""Generate a normal map"""
|
||||||
|
bl_idname = 'image_editor_plus.normal_map_dialog'
|
||||||
|
bl_label = "Normal Map"
|
||||||
|
update_preview: bpy.props.BoolProperty(options={'SKIP_SAVE'},
|
||||||
|
update=update_normal_map_properties,
|
||||||
|
description='Update preview')
|
||||||
|
reset: bpy.props.BoolProperty(options={'SKIP_SAVE'}, update=reset_normal_map_properties)
|
||||||
|
scale: bpy.props.FloatProperty(name='Scale', subtype='FACTOR',
|
||||||
|
min=0, soft_max=250.0, default=10.0, options={'SKIP_SAVE'})
|
||||||
|
flip_x: bpy.props.BoolProperty(name='Flip X', default=False, options={'SKIP_SAVE'})
|
||||||
|
flip_y: bpy.props.BoolProperty(name='Flip Y', default=False, options={'SKIP_SAVE'})
|
||||||
|
full_z: bpy.props.BoolProperty(name='Full Range for Z', default=False, options={'SKIP_SAVE'})
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
session = app.get_session()
|
||||||
|
|
||||||
|
wm = context.window_manager
|
||||||
|
|
||||||
|
img = app.get_target_image(context)
|
||||||
|
if not img:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
app.cache_image(img, need_hsl=True)
|
||||||
|
|
||||||
|
layer = app.get_active_layer(context)
|
||||||
|
if layer:
|
||||||
|
session.cached_layer_location = layer.location[:]
|
||||||
|
|
||||||
|
update_normal_map_properties(self, context)
|
||||||
|
|
||||||
|
return wm.invoke_props_dialog(self)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
bpy.ops.image_editor_plus.normal_map('EXEC_DEFAULT', False,
|
||||||
|
scale=self.scale,
|
||||||
|
flip_x=self.flip_x,
|
||||||
|
flip_y=self.flip_y,
|
||||||
|
full_z=self.full_z)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def cancel(self, context):
|
||||||
|
img = app.get_target_image(context)
|
||||||
|
if not img:
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
app.revert_image_cache(img)
|
||||||
|
app.clear_image_cache()
|
||||||
|
app.refresh_image(context)
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
|
||||||
row = layout.split(align=True)
|
row = layout.split(align=True)
|
||||||
row.column()
|
row.column()
|
||||||
row.prop(self, 'preview', text='Preview', toggle=True, icon='VIEWZOOM')
|
row.prop(self, 'update_preview', text='Update Preview', toggle=True, icon='FILE_REFRESH')
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.alignment = 'RIGHT'
|
||||||
|
row.label(text='Scale')
|
||||||
|
row.prop(self, 'scale', text='')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'flip_x')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'flip_y')
|
||||||
|
|
||||||
|
row = layout.split(align=True)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'full_z')
|
||||||
|
|
||||||
|
row = layout.split(factor=0.7)
|
||||||
|
row.column()
|
||||||
|
row.prop(self, 'reset', text='Reset', toggle=True)
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_UL_layer_list(bpy.types.UIList):
|
class IMAGE_EDITOR_PLUS_UL_layer_list(bpy.types.UIList):
|
||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
@@ -1261,6 +1346,9 @@ class IMAGE_EDITOR_PLUS_MT_transform_menu(bpy.types.Menu):
|
|||||||
op = layout.operator(IMAGE_EDITOR_PLUS_OT_scale_dialog.bl_idname, text='Scale...',
|
op = layout.operator(IMAGE_EDITOR_PLUS_OT_scale_dialog.bl_idname, text='Scale...',
|
||||||
icon_value=get_icon_id('scale'))
|
icon_value=get_icon_id('scale'))
|
||||||
|
|
||||||
|
op = layout.operator(IMAGE_EDITOR_PLUS_OT_change_canvas_size_dialog.bl_idname, text='Canvas Size...',
|
||||||
|
icon_value=get_icon_id('scale'))
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_MT_transform_layer_menu(bpy.types.Menu):
|
class IMAGE_EDITOR_PLUS_MT_transform_layer_menu(bpy.types.Menu):
|
||||||
bl_idname = "IMAGE_EDITOR_PLUS_MT_transform_layer_menu"
|
bl_idname = "IMAGE_EDITOR_PLUS_MT_transform_layer_menu"
|
||||||
bl_label = "Transform Layer"
|
bl_label = "Transform Layer"
|
||||||
@@ -1320,8 +1408,8 @@ class IMAGE_EDITOR_PLUS_MT_adjust_menu(bpy.types.Menu):
|
|||||||
layout.operator(IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog.bl_idname, text='Color Curve...',
|
layout.operator(IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog.bl_idname, text='Color Curve...',
|
||||||
icon_value=get_icon_id('color_curve'))
|
icon_value=get_icon_id('color_curve'))
|
||||||
|
|
||||||
#layout.operator(IMAGE_EDITOR_PLUS_OT_replace_color_dialog.bl_idname, text="Replace Color...",
|
layout.operator(IMAGE_EDITOR_PLUS_OT_replace_color_dialog.bl_idname, text="Replace Color...",
|
||||||
# icon='COLOR')
|
icon='COLOR')
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_MT_filter_menu(bpy.types.Menu):
|
class IMAGE_EDITOR_PLUS_MT_filter_menu(bpy.types.Menu):
|
||||||
bl_idname = "IMAGE_EDITOR_PLUS_MT_filter_menu"
|
bl_idname = "IMAGE_EDITOR_PLUS_MT_filter_menu"
|
||||||
@@ -1345,6 +1433,9 @@ class IMAGE_EDITOR_PLUS_MT_filter_menu(bpy.types.Menu):
|
|||||||
layout.operator(IMAGE_EDITOR_PLUS_OT_make_seamless_dialog.bl_idname, text='Make Seamless...',
|
layout.operator(IMAGE_EDITOR_PLUS_OT_make_seamless_dialog.bl_idname, text='Make Seamless...',
|
||||||
icon_value=get_icon_id('filter'))
|
icon_value=get_icon_id('filter'))
|
||||||
|
|
||||||
|
layout.operator(IMAGE_EDITOR_PLUS_OT_normal_map_dialog.bl_idname, text='Normal Map...',
|
||||||
|
icon_value=get_icon_id('filter'))
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_PT_select_panel(bpy.types.Panel):
|
class IMAGE_EDITOR_PLUS_PT_select_panel(bpy.types.Panel):
|
||||||
bl_label = "Select"
|
bl_label = "Select"
|
||||||
bl_space_type = "IMAGE_EDITOR"
|
bl_space_type = "IMAGE_EDITOR"
|
||||||
@@ -1536,6 +1627,11 @@ class IMAGE_EDITOR_PLUS_PT_transform_panel(bpy.types.Panel):
|
|||||||
op = row.operator(IMAGE_EDITOR_PLUS_OT_scale_dialog.bl_idname, text='Scale...',
|
op = row.operator(IMAGE_EDITOR_PLUS_OT_scale_dialog.bl_idname, text='Scale...',
|
||||||
icon_value=get_icon_id('scale'))
|
icon_value=get_icon_id('scale'))
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
op = row.operator(IMAGE_EDITOR_PLUS_OT_change_canvas_size_dialog.bl_idname,
|
||||||
|
text='Canvas Size...',
|
||||||
|
icon_value=get_icon_id('scale'))
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_PT_transform_layer_panel(bpy.types.Panel):
|
class IMAGE_EDITOR_PLUS_PT_transform_layer_panel(bpy.types.Panel):
|
||||||
bl_label = "Transform Layer"
|
bl_label = "Transform Layer"
|
||||||
bl_space_type = "IMAGE_EDITOR"
|
bl_space_type = "IMAGE_EDITOR"
|
||||||
@@ -1660,9 +1756,9 @@ class IMAGE_EDITOR_PLUS_PT_adjust_panel(bpy.types.Panel):
|
|||||||
row.operator(IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog.bl_idname, text='Color Curve...',
|
row.operator(IMAGE_EDITOR_PLUS_OT_adjust_color_curve_dialog.bl_idname, text='Color Curve...',
|
||||||
icon_value=get_icon_id('color_curve'))
|
icon_value=get_icon_id('color_curve'))
|
||||||
|
|
||||||
#row = layout.row()
|
row = layout.row()
|
||||||
#row.operator(IMAGE_EDITOR_PLUS_OT_replace_color_dialog.bl_idname, text='Replace Color...',
|
row.operator(IMAGE_EDITOR_PLUS_OT_replace_color_dialog.bl_idname, text='Replace Color...',
|
||||||
# icon='COLOR')
|
icon='COLOR')
|
||||||
|
|
||||||
class IMAGE_EDITOR_PLUS_PT_filter_panel(bpy.types.Panel):
|
class IMAGE_EDITOR_PLUS_PT_filter_panel(bpy.types.Panel):
|
||||||
bl_label = "Filter"
|
bl_label = "Filter"
|
||||||
@@ -1701,3 +1797,7 @@ class IMAGE_EDITOR_PLUS_PT_filter_panel(bpy.types.Panel):
|
|||||||
row = layout.row()
|
row = layout.row()
|
||||||
row.operator(IMAGE_EDITOR_PLUS_OT_make_seamless_dialog.bl_idname, text='Make Seamless...',
|
row.operator(IMAGE_EDITOR_PLUS_OT_make_seamless_dialog.bl_idname, text='Make Seamless...',
|
||||||
icon_value=get_icon_id('filter'))
|
icon_value=get_icon_id('filter'))
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
row.operator(IMAGE_EDITOR_PLUS_OT_normal_map_dialog.bl_idname, text='Normal Map...',
|
||||||
|
icon_value=get_icon_id('filter'))
|
||||||
|
|||||||
+42
-48
@@ -1,5 +1,5 @@
|
|||||||
'''
|
'''
|
||||||
Copyright (C) 2020 - 2024 Akaneyu
|
Copyright (C) 2020 - 2025 Akaneyu
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,15 +18,12 @@
|
|||||||
import sys
|
import sys
|
||||||
import math
|
import math
|
||||||
import gpu
|
import gpu
|
||||||
|
from gpu.shader import create_from_info
|
||||||
from gpu_extras.batch import batch_for_shader
|
from gpu_extras.batch import batch_for_shader
|
||||||
from mathutils import Matrix, Vector
|
from mathutils import Matrix, Vector
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
default_vertex_shader = '''
|
default_vertex_shader = '''
|
||||||
uniform mat4 ModelViewProjectionMatrix;
|
|
||||||
|
|
||||||
in vec2 pos;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||||
@@ -34,10 +31,6 @@ void main()
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
default_fragment_shader = '''
|
default_fragment_shader = '''
|
||||||
uniform vec4 color;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = color;
|
fragColor = color;
|
||||||
@@ -45,34 +38,18 @@ void main()
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
dotted_line_vertex_shader = '''
|
dotted_line_vertex_shader = '''
|
||||||
uniform mat4 ModelViewProjectionMatrix;
|
|
||||||
|
|
||||||
in vec2 pos;
|
|
||||||
in float arcLength;
|
|
||||||
|
|
||||||
out float arcLengthOut;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
arcLengthOut = arcLength;
|
arcLengthInter = arcLength;
|
||||||
|
|
||||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||||
}
|
}
|
||||||
'''
|
'''
|
||||||
|
|
||||||
dotted_line_fragment_shader = '''
|
dotted_line_fragment_shader = '''
|
||||||
uniform float scale;
|
|
||||||
uniform float offset;
|
|
||||||
uniform vec4 color1;
|
|
||||||
uniform vec4 color2;
|
|
||||||
|
|
||||||
in float arcLengthOut;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
if (step(sin((arcLengthOut + offset) * scale), 0.5) == 1) {
|
if (step(sin((arcLengthInter + offset) * scale), 0.5) == 1) {
|
||||||
fragColor = color1;
|
fragColor = color1;
|
||||||
} else {
|
} else {
|
||||||
fragColor = color2;
|
fragColor = color2;
|
||||||
@@ -81,13 +58,6 @@ void main()
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
image_vertex_shader = '''
|
image_vertex_shader = '''
|
||||||
uniform mat4 ModelViewProjectionMatrix;
|
|
||||||
|
|
||||||
in vec2 pos;
|
|
||||||
in vec2 texCoord;
|
|
||||||
|
|
||||||
out vec2 texCoordOut;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
gl_Position = ModelViewProjectionMatrix * vec4(pos, 0, 1.0);
|
||||||
@@ -96,12 +66,6 @@ void main()
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
image_fragment_shader = '''
|
image_fragment_shader = '''
|
||||||
uniform sampler2D image;
|
|
||||||
|
|
||||||
in vec2 texCoordOut;
|
|
||||||
|
|
||||||
out vec4 fragColor;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = texture(image, texCoordOut);
|
fragColor = texture(image, texCoordOut);
|
||||||
@@ -118,18 +82,48 @@ def make_scale_matrix(scale):
|
|||||||
|
|
||||||
class UIRenderer:
|
class UIRenderer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.default_shader = gpu.types.GPUShader(default_vertex_shader,
|
default_shader_info = gpu.types.GPUShaderCreateInfo()
|
||||||
default_fragment_shader)
|
default_shader_info.push_constant('MAT4', 'ModelViewProjectionMatrix')
|
||||||
self.default_shader_u_color = self.default_shader.uniform_from_name("color")
|
default_shader_info.push_constant('VEC4', 'color')
|
||||||
|
default_shader_info.vertex_in(0, 'VEC2', 'pos')
|
||||||
|
default_shader_info.fragment_out(0, 'VEC4', 'fragColor')
|
||||||
|
default_shader_info.vertex_source(default_vertex_shader)
|
||||||
|
default_shader_info.fragment_source(default_fragment_shader)
|
||||||
|
self.default_shader = create_from_info(default_shader_info)
|
||||||
|
self.default_shader_u_color = self.default_shader.uniform_from_name('color')
|
||||||
|
|
||||||
self.dotted_line_shader = gpu.types.GPUShader(dotted_line_vertex_shader,
|
dotted_line_shader_inter = gpu.types.GPUStageInterfaceInfo("dotted_line")
|
||||||
dotted_line_fragment_shader)
|
dotted_line_shader_inter.smooth('FLOAT', "arcLengthInter")
|
||||||
|
|
||||||
|
dotted_line_shader_info = gpu.types.GPUShaderCreateInfo()
|
||||||
|
dotted_line_shader_info.push_constant('MAT4', 'ModelViewProjectionMatrix')
|
||||||
|
dotted_line_shader_info.push_constant('FLOAT', 'scale')
|
||||||
|
dotted_line_shader_info.push_constant('FLOAT', 'offset')
|
||||||
|
dotted_line_shader_info.push_constant('VEC4', 'color1')
|
||||||
|
dotted_line_shader_info.push_constant('VEC4', 'color2')
|
||||||
|
dotted_line_shader_info.vertex_in(0, 'VEC2', 'pos')
|
||||||
|
dotted_line_shader_info.vertex_in(1, 'FLOAT', 'arcLength')
|
||||||
|
dotted_line_shader_info.vertex_out(dotted_line_shader_inter)
|
||||||
|
dotted_line_shader_info.fragment_out(0, 'VEC4', 'fragColor')
|
||||||
|
dotted_line_shader_info.vertex_source(dotted_line_vertex_shader)
|
||||||
|
dotted_line_shader_info.fragment_source(dotted_line_fragment_shader)
|
||||||
|
self.dotted_line_shader = create_from_info(dotted_line_shader_info)
|
||||||
self.dotted_line_shader_u_color1 = self.dotted_line_shader.uniform_from_name("color1")
|
self.dotted_line_shader_u_color1 = self.dotted_line_shader.uniform_from_name("color1")
|
||||||
self.dotted_line_shader_u_color2 = self.dotted_line_shader.uniform_from_name("color2")
|
self.dotted_line_shader_u_color2 = self.dotted_line_shader.uniform_from_name("color2")
|
||||||
|
|
||||||
#self.image_shader = gpu.shader.from_builtin('2D_IMAGE')
|
image_shader_inter = gpu.types.GPUStageInterfaceInfo("image_shader")
|
||||||
self.image_shader = gpu.types.GPUShader(image_vertex_shader,
|
image_shader_inter.smooth('VEC2', "texCoordOut")
|
||||||
image_fragment_shader)
|
|
||||||
|
image_shader_info = gpu.types.GPUShaderCreateInfo()
|
||||||
|
image_shader_info.push_constant('MAT4', 'ModelViewProjectionMatrix')
|
||||||
|
image_shader_info.sampler(0, 'FLOAT_2D', 'image')
|
||||||
|
image_shader_info.vertex_in(0, 'VEC2', 'pos')
|
||||||
|
image_shader_info.vertex_in(1, 'VEC2', 'texCoord')
|
||||||
|
image_shader_info.vertex_out(image_shader_inter)
|
||||||
|
image_shader_info.fragment_out(0, 'VEC4', 'fragColor')
|
||||||
|
image_shader_info.vertex_source(image_vertex_shader)
|
||||||
|
image_shader_info.fragment_source(image_fragment_shader)
|
||||||
|
self.image_shader = create_from_info(image_shader_info)
|
||||||
|
|
||||||
def render_selection_frame(self, pos, size, rot=0, scale=(1.0, 1.0)):
|
def render_selection_frame(self, pos, size, rot=0, scale=(1.0, 1.0)):
|
||||||
width, height = size[0], size[1]
|
width, height = size[0], size[1]
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 584 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 509 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 482 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 308 KiB |
Reference in New Issue
Block a user