Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions modules/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 7 additions & 2 deletions modules/core/cli/sdcpp_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down Expand Up @@ -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):
"""
Expand All @@ -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):
Expand Down
13 changes: 12 additions & 1 deletion modules/gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
17 changes: 17 additions & 0 deletions modules/interfaces/common/options_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions modules/ui/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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: <lora:lora_name:lora_strength>, for example: <lora:anime:0.8>",
Expand Down
34 changes: 34 additions & 0 deletions modules/utils/encryption.py
Original file line number Diff line number Diff line change
@@ -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)))
49 changes: 49 additions & 0 deletions modules/utils/image_display.py
Original file line number Diff line number Diff line change
@@ -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
20 changes: 19 additions & 1 deletion modules/utils/ui_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down