Files

142 lines
5.0 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# Copyright 2025-2026 Raykosan (RaykoStudio)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
import server
from aiohttp import web
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
PRESETS_DIR = os.path.join(CURRENT_DIR, "preset_colors")
if not os.path.exists(PRESETS_DIR):
os.makedirs(PRESETS_DIR)
class RSColorPicker:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"node_data": ("STRING", {
"default": "{}",
"hidden": True
}),
},
}
RETURN_TYPES = ("INT", "STRING", "STRING")
RETURN_NAMES = ("HEX_INT", "HEX_STR", "RGB")
FUNCTION = "get_color"
CATEGORY = "🦊 RaykoStudio"
DESCRIPTION = "Professional color picker node with advanced features including eyedropper and color history"
def get_color(self, node_data="{}"):
try:
data = json.loads(node_data) if node_data else {}
color = data.get("color", "#ff0000")
except Exception:
color = "#ff0000"
hex_value = color.lstrip('#')
if len(hex_value) > 6:
hex_value = hex_value[:6]
elif len(hex_value) < 6:
hex_value = hex_value.ljust(6, '0')
int_value = int(hex_value, 16)
hex_str = '#' + hex_value.upper()
r = int(hex_value[0:2], 16) / 255.0
g = int(hex_value[2:4], 16) / 255.0
b = int(hex_value[4:6], 16) / 255.0
rgb_str = f"{r:.3f}, {g:.3f}, {b:.3f}"
return (int_value, hex_str, rgb_str)
@server.PromptServer.instance.routes.post("/rs_colorpicker_save_preset")
async def rs_colorpicker_save_preset(request):
try:
data = await request.json()
name = data.get("name", "").strip()
if not name:
return web.json_response({"error": "Name required"}, status=400)
name = "".join(c for c in name if c.isalnum() or c in " _-").strip()
if not name:
return web.json_response({"error": "Invalid name"}, status=400)
filepath = os.path.join(PRESETS_DIR, f"{name}.json")
preset_data = {
"color": data.get("color", "#ff0000"),
"history": data.get("history", [])
}
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(preset_data, f, indent=2)
return web.json_response({"success": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@server.PromptServer.instance.routes.get("/rs_colorpicker_list_presets")
async def rs_colorpicker_list_presets(request):
try:
presets = []
if os.path.exists(PRESETS_DIR):
presets = [f[:-5] for f in os.listdir(PRESETS_DIR) if f.endswith('.json')]
return web.json_response(sorted(presets, key=lambda x: x.lower()))
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@server.PromptServer.instance.routes.post("/rs_colorpicker_load_preset")
async def rs_colorpicker_load_preset(request):
try:
data = await request.json()
name = data.get("name")
if not name:
return web.json_response({"error": "Name required"}, status=400)
filepath = os.path.join(PRESETS_DIR, f"{name}.json")
if os.path.exists(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
return web.json_response(json.load(f))
return web.json_response({"error": "Preset not found"}, status=404)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@server.PromptServer.instance.routes.post("/rs_colorpicker_delete_preset")
async def rs_colorpicker_delete_preset(request):
try:
data = await request.json()
name = data.get("name")
if not name:
return web.json_response({"error": "Name required"}, status=400)
filepath = os.path.join(PRESETS_DIR, f"{name}.json")
if os.path.exists(filepath):
os.remove(filepath)
return web.json_response({"success": True})
return web.json_response({"error": "Preset not found"}, status=404)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
NODE_CLASS_MAPPINGS = {
"RSColorPicker": RSColorPicker
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RSColorPicker": "🦊 RS Color Picker"
}