diff --git a/modules/config.py b/modules/config.py index 2da611c..68fd995 100644 --- a/modules/config.py +++ b/modules/config.py @@ -25,14 +25,15 @@ 'imgedit_dir': os.path.join(CURRENT_DIR, "outputs/imgedit/"), 'any2video_dir': os.path.join(CURRENT_DIR, "outputs/any2video/"), 'upscale_dir': os.path.join(CURRENT_DIR, "outputs/upscale/"), + 'enable_encryption': True, + 'encryption_password': '123', 'def_type': "Default", - 'def_lora_strength': 1.0, - 'def_sampling': "euler_a", - 'def_steps': 20, + 'def_sampling': "euler", + 'def_steps': 8, 'def_scheduler': "discrete", - 'def_width': 512, - 'def_height': 512, - 'def_cfg': 7.0, + 'def_width': 1024, + 'def_height': 1024, + 'def_cfg': 1.0, 'def_flow_shift_bool': False, 'def_flow_shift': 3.0, 'def_guidance_bool': False, diff --git a/modules/core/cli/sdcpp_cli.py b/modules/core/cli/sdcpp_cli.py index 041f706..3db351f 100644 --- a/modules/core/cli/sdcpp_cli.py +++ b/modules/core/cli/sdcpp_cli.py @@ -27,6 +27,8 @@ def __init__(self, mode: str, params: Dict[str, Any]): self.outputs = [] self.output_path = "" self.preview_path = None + self.enable_encryption = config.get('enable_encryption', False) + self.encryption_password = config.get('encryption_password', '123') def _set_output_path(self, dir_key: str, subctrl_id: int, extension: str): """Determines and sets the output path for the command.""" @@ -75,6 +77,9 @@ def _add_base_args(self): '--lora-apply-mode', str(self._get_param('in_lora_apply')), '-o', self.output_path ]) + + if self.enable_encryption: + self.command.extend(['--encrypt', self.encryption_password]) def _prepare_for_run(self): """ @@ -97,8 +102,8 @@ def _prepare_for_run(self): self.outputs = [self.output_path] else: base, ext = os.path.splitext(self.output_path) - self.outputs = [self.output_path] + [ - f"{base}_{i}{ext}" for i in range(2, batch_count + 1) + self.outputs = [ + f"{base}_{i}{ext}" for i in range(batch_count) ] def build_command(self): diff --git a/modules/gallery.py b/modules/gallery.py index 89f4d6d..df07d21 100644 --- a/modules/gallery.py +++ b/modules/gallery.py @@ -99,7 +99,18 @@ def reload_gallery( page_files = files[start_index:end_index] - imgs = [Image.open(path) for path in page_files] + # 解密图片 + from modules.utils.image_display import decrypt_and_display + imgs = [] + for path in page_files: + try: + img = decrypt_and_display(path) + if img is None: + img = Image.open(path) + imgs.append(img) + except Exception as e: + print(f"Failed to load image {path}: {e}") + imgs.append(Image.open(path)) dir_map = { 0: 'txt2img', diff --git a/modules/interfaces/common/options_tab.py b/modules/interfaces/common/options_tab.py index b7f267a..d89c878 100644 --- a/modules/interfaces/common/options_tab.py +++ b/modules/interfaces/common/options_tab.py @@ -247,6 +247,23 @@ def save_settings_wrapper(*args): with gr.Tab(label="sd.cpp-webui settings"): + with gr.Accordion(label="Encryption Settings", open=False): + with gr.Row(): + enable_encryption = gr.Checkbox( + label="Enable Image Encryption", + value=config.get('enable_encryption', False), + interactive=True + ) + settings_map['enable_encryption'] = enable_encryption + with gr.Row(): + encryption_password = gr.Textbox( + label="Encryption Password", + value=config.get('encryption_password', '123'), + interactive=True, + type="password" + ) + settings_map['encryption_password'] = encryption_password + with gr.Row(): # Output options output_scheme = gr.Dropdown( diff --git a/modules/ui/prompts.py b/modules/ui/prompts.py index c61bcc5..1d0613b 100644 --- a/modules/ui/prompts.py +++ b/modules/ui/prompts.py @@ -55,6 +55,7 @@ def refresh_prompt_list(): save_prompt_btn = gr.Button( value="Save prompt", size="lg", ) + with gr.Row(): pprompt = gr.Textbox( placeholder="Positive prompt\nUse loras from the loras folder with: , for example: ", diff --git a/modules/utils/encryption.py b/modules/utils/encryption.py new file mode 100644 index 0000000..b70e541 --- /dev/null +++ b/modules/utils/encryption.py @@ -0,0 +1,34 @@ +"""sd.cpp-webui - Image encryption module""" + +import os +import io +from PIL import Image + + +class ImageEncryption: + """处理图片的加密和解密(兼容 sd-cli 的 XOR 加密)""" + + def __init__(self, password="123"): + self.password = password + + def _generate_key(self): + """生成 256 字节密钥(与 decrypt.js 相同算法)""" + key = bytearray(256) + password_bytes = self.password.encode('utf-8') + for i in range(256): + key[i] = password_bytes[i % len(password_bytes)] ^ (i & 0xFF) + return bytes(key) + + def decrypt_image_file(self, encrypted_path): + """解密图片文件并返回 PIL Image 对象""" + with open(encrypted_path, 'rb') as f: + encrypted_data = f.read() + + # XOR 解密 + key = self._generate_key() + decrypted_data = bytearray(len(encrypted_data)) + for i in range(len(encrypted_data)): + decrypted_data[i] = encrypted_data[i] ^ key[i % len(key)] + + # 转换为 PIL Image + return Image.open(io.BytesIO(bytes(decrypted_data))) diff --git a/modules/utils/image_display.py b/modules/utils/image_display.py new file mode 100644 index 0000000..b0b69ff --- /dev/null +++ b/modules/utils/image_display.py @@ -0,0 +1,49 @@ +"""sd.cpp-webui - Encrypted image display utilities""" + +import os +from modules.utils.encryption import ImageEncryption +from modules.shared_instance import config + + +def decrypt_and_display(image_paths): + """ + 解密图片列表并返回可显示的图片对象 + + Args: + image_paths: 图片路径列表或单个路径 + + Returns: + 解密后的 PIL Image 对象或列表 + """ + enable_encryption = config.get('enable_encryption', False) + + if not enable_encryption: + return image_paths + + password = config.get('encryption_password', '123') + encryptor = ImageEncryption(password) + + is_single = isinstance(image_paths, str) + if is_single: + image_paths = [image_paths] + + from PIL import Image + decrypted_images = [] + for path in image_paths: + if path and os.path.exists(path): + try: + img = encryptor.decrypt_image_file(path) + decrypted_images.append(img) + except Exception as e: + print(f"Failed to decrypt {path}: {e}, trying direct open") + try: + decrypted_images.append(Image.open(path)) + except Exception as e2: + print(f"Failed to open {path}: {e2}") + else: + print(f"Path does not exist: {path}") + + if not decrypted_images: + return None if is_single else [] + + return decrypted_images[0] if is_single else decrypted_images diff --git a/modules/utils/ui_events.py b/modules/utils/ui_events.py index 680dc1d..a9d0e52 100644 --- a/modules/utils/ui_events.py +++ b/modules/utils/ui_events.py @@ -71,12 +71,30 @@ def poll_status(): visible=(q_len > 0) ) + # 解密图片 + images = state["images"] + if images: + from modules.utils.image_display import decrypt_and_display + if isinstance(images, list): + decrypted = [] + for img in images: + if isinstance(img, str): + result = decrypt_and_display(img) + if result: + decrypted.append(result) + else: + decrypted.append(img) + images = decrypted if decrypted else None + else: + result = decrypt_and_display(images) + images = result + return ( state["command"], prog, stat, state["stats"], - state["images"], + images, gr.skip(), queue_display )