-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e0f6fed
Showing
13 changed files
with
1,202 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
bl_info = { | ||
"name": "Color Helper", | ||
"author": "Atticus", | ||
"blender": (3, 0, 0), | ||
"version": (0, 1), | ||
"category": "Interface", | ||
"support": "COMMUNITY", | ||
"doc_url": "", | ||
"tracker_url": "", | ||
"description": "", | ||
'warning': "Only support Windows", | ||
"location": "Node Editor N panel", | ||
} | ||
|
||
import importlib | ||
import sys | ||
import os | ||
from itertools import groupby | ||
|
||
# get folder name | ||
__folder_name__ = __name__ | ||
__dict__ = {} | ||
|
||
addon_dir = os.path.dirname(__file__) | ||
|
||
# get all .py file dir | ||
py_paths = [os.path.join(root, f) for root, dirs, files in os.walk(addon_dir) for f in files if | ||
f.endswith('.py') and f != '__init__.py'] | ||
|
||
for path in py_paths: | ||
name = os.path.basename(path)[:-3] | ||
correct_path = path.replace('\\', '/') | ||
# split dir with folder name | ||
dir_list = [list(g) for k, g in groupby(correct_path.split('/'), lambda x: x == __folder_name__) if | ||
not k] | ||
# combine dir and make dict like this: 'name:folder.name' | ||
if 'colorthief' not in dir_list[-1]: | ||
r_name_raw = __folder_name__ + '.' + '.'.join(dir_list[-1]) | ||
__dict__[name] = r_name_raw[:-3] | ||
|
||
# auto reload | ||
for name in __dict__.values(): | ||
if name in sys.modules: | ||
importlib.reload(sys.modules[name]) | ||
else: | ||
globals()[name] = importlib.import_module(name) | ||
setattr(globals()[name], 'modules', __dict__) | ||
|
||
def prepare(): | ||
from addon_utils import enable | ||
addons = [ | ||
'io_import_images_as_planes', | ||
'io_import_dxf', | ||
] | ||
for addon in addons: | ||
enable(addon) | ||
|
||
def register(): | ||
for name in __dict__.values(): | ||
if name in sys.modules and hasattr(sys.modules[name], 'register'): | ||
try: | ||
sys.modules[name].register() | ||
except ValueError: # open template file may cause this problem | ||
pass | ||
|
||
prepare() | ||
|
||
def unregister(): | ||
for name in __dict__.values(): | ||
if name in sys.modules and hasattr(sys.modules[name], 'unregister'): | ||
sys.modules[name].unregister() | ||
|
||
|
||
if __name__ == '__main__': | ||
register() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import bpy | ||
import os | ||
from bpy.props import EnumProperty, IntProperty, BoolProperty | ||
|
||
|
||
class CH_OT_create_nodes_from_palette(bpy.types.Operator): | ||
"""Create/Update shader node group from this palette\nShift to create/update and add group node to current material""" | ||
bl_idname = 'ch.create_nodes_from_palette' | ||
bl_label = 'Create Color From Palette' | ||
|
||
palette_index: IntProperty() | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
return context.space_data.type == "NODE_EDITOR" and context.space_data.tree_type == 'ShaderNodeTree' | ||
|
||
def _return(self, error_msg=None, info_msg=None): | ||
if error_msg: | ||
self.report({'ERROR'}, error_msg) | ||
elif info_msg: | ||
self.report({'INFO'}, info_msg) | ||
|
||
return {'FINISHED'} | ||
|
||
def invoke(self, context, event): | ||
collection = context.scene.ch_palette_collection[context.scene.ch_palette_collection_index] | ||
palette = collection.palettes[self.palette_index] | ||
self.create_node_group(palette, create=event.shift) | ||
return {'FINISHED'} | ||
|
||
def create_node_group(self, palette, create): | ||
if palette.node_group is not None: | ||
nt = palette.node_group | ||
for node in nt.nodes: | ||
nt.nodes.remove(node) | ||
else: | ||
nt = bpy.data.node_groups.new(palette.name, 'ShaderNodeTree') | ||
palette.node_group = nt | ||
|
||
loc_x, loc_y = 0, 0 | ||
|
||
node_output = nt.nodes.new('NodeGroupOutput') | ||
|
||
for i, color_item in enumerate(palette.colors): | ||
color = color_item.color | ||
node = nt.nodes.new('ShaderNodeRGB') | ||
node.outputs[0].default_value = color | ||
node.location = loc_x + i * 150, loc_y - i * 50 | ||
nt.links.new(node.outputs[0], node_output.inputs[i]) | ||
|
||
node_output.location = len(palette.colors) * 150 + 200, 0 | ||
|
||
loc_x, loc_y = bpy.context.space_data.cursor_location | ||
bpy.ops.node.select_all(action='DESELECT') | ||
|
||
# # Create Node Group | ||
if bpy.context.space_data.edit_tree is None or not create: return | ||
|
||
edit_tree = bpy.context.space_data.edit_tree | ||
|
||
if edit_tree != nt and not (edit_tree.nodes.active and | ||
hasattr(edit_tree.nodes.active, 'node_tree') and | ||
getattr(edit_tree.nodes.active, 'node_tree') == nt): | ||
group_node = edit_tree.nodes.new('ShaderNodeGroup') | ||
group_node.node_tree = nt | ||
group_node.location = loc_x, loc_y | ||
|
||
bpy.ops.transform.translate('INVOKE_DEFAULT') | ||
|
||
|
||
def draw_context(self, context): | ||
layout = self.layout | ||
layout.operator('ch.create_nodes_from_palette', text='Get Image Color') | ||
layout.separator() | ||
|
||
|
||
def register(): | ||
bpy.utils.register_class(CH_OT_create_nodes_from_palette) | ||
# bpy.types.NODE_MT_context_menu.prepend(draw_context) | ||
|
||
|
||
def unregister(): | ||
bpy.utils.unregister_class(CH_OT_create_nodes_from_palette) | ||
# bpy.types.NODE_MT_context_menu.remove(draw_context) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import bpy | ||
import os | ||
from bpy.props import EnumProperty, StringProperty, CollectionProperty | ||
from bpy_extras.io_utils import ExportHelper, ImportHelper | ||
|
||
|
||
class CreatPaletteBase: | ||
|
||
@classmethod | ||
def poll(cls, context): | ||
return context.space_data.type == "NODE_EDITOR" and context.space_data.tree_type == 'ShaderNodeTree' | ||
|
||
def _return(self, error_msg=None, info_msg=None): | ||
if error_msg: | ||
self.report({'ERROR'}, error_msg) | ||
elif info_msg: | ||
self.report({'INFO'}, info_msg) | ||
|
||
return {'FINISHED'} | ||
|
||
def create_palette(self, palette): | ||
if len(bpy.context.scene.ch_palette_collection) == 0: | ||
collection = bpy.context.scene.ch_palette_collection.add() | ||
collection.name = 'Collection' | ||
bpy.context.scene.ch_palette_collection_index = 0 | ||
|
||
collection = bpy.context.scene.ch_palette_collection[bpy.context.scene.ch_palette_collection_index] | ||
|
||
palette_item = collection.palettes.add() | ||
palette_item.name = 'Palettes' + str(len(collection.palettes)) | ||
for i, color in enumerate(palette): | ||
clr = palette_item.colors.add() | ||
clr.color = color | ||
return palette_item | ||
|
||
class CH_OT_create_palette_from_palette(CreatPaletteBase, bpy.types.Operator, ImportHelper): | ||
bl_idname = 'ch.create_palette_from_palette' | ||
bl_label = 'Platte From Palette Files' | ||
bl_options = {'UNDO_GROUPED'} | ||
|
||
filename_ext = ".png" | ||
|
||
files: CollectionProperty(type=bpy.types.PropertyGroup) | ||
|
||
filter_glob: StringProperty( | ||
default="*.png", | ||
options={'HIDDEN'} | ||
) | ||
|
||
def execute(self, context): | ||
from ..utils.process_image import extract_from_palette | ||
|
||
dirname = os.path.dirname(self.filepath) | ||
for f in self.files: | ||
image = bpy.data.images.load(os.path.join(dirname, f.name), check_existing=False) | ||
palette = extract_from_palette(image) | ||
|
||
palette_item = self.create_palette(palette) | ||
palette_item.name = f.name | ||
|
||
bpy.data.images.remove(image) | ||
return {'FINISHED'} | ||
|
||
|
||
class CH_OT_create_palette_from_clipboard(CreatPaletteBase, bpy.types.Operator): | ||
bl_idname = 'ch.create_palette_from_clipboard' | ||
bl_label = 'Platte From Clipboard' | ||
bl_options = {'UNDO_GROUPED'} | ||
|
||
def execute(self, context): | ||
from ..utils.process_image import extract_from_image | ||
from ..utils.clipboard import Clipboard | ||
|
||
clipboard = Clipboard() | ||
filepath = clipboard.pull_image_from_clipboard() | ||
|
||
if not os.path.exists(filepath) or not os.path.isfile(filepath): | ||
return self._return(error_msg='Clipboard has no file') | ||
|
||
image = bpy.data.images.load(filepath, check_existing=False) | ||
channel_count = image.channels | ||
|
||
if image.file_format not in ['JPEG', 'PNG']: | ||
return self._return(error_msg=f'Currently, this only works for JPEG and PNG image files') | ||
if channel_count not in [3, 4]: | ||
return self._return( | ||
error_msg=f"This image has {channel_count} channels, but this method can only handle 3 or 4 channels") | ||
palette = extract_from_image(image) | ||
|
||
self.create_palette(palette) | ||
|
||
bpy.data.images.remove(image) | ||
|
||
return {'FINISHED'} | ||
|
||
|
||
def register(): | ||
bpy.utils.register_class(CH_OT_create_palette_from_palette) | ||
bpy.utils.register_class(CH_OT_create_palette_from_clipboard) | ||
|
||
|
||
def unregister(): | ||
bpy.utils.unregister_class(CH_OT_create_palette_from_palette) | ||
bpy.utils.unregister_class(CH_OT_create_palette_from_clipboard) |
Oops, something went wrong.