├── copylot.py ├── p.yaml ├── readme.md └── requirements.txt /copylot.py: -------------------------------------------------------------------------------- 1 | import os 2 | import io 3 | import time 4 | import base64 5 | import logging 6 | 7 | import win32gui 8 | import win32process 9 | 10 | import cv2 11 | import yaml 12 | import psutil 13 | import pynput 14 | import requests 15 | import psd_tools 16 | import numpy as np 17 | from pynput.keyboard import Key, Controller 18 | 19 | from rimo_utils.计时 import 计时 20 | 21 | 22 | 设置文件 = 'p.yaml' 23 | psd文件 = '1.psd' 24 | 25 | 默认设置 = { 26 | 'cfg_scale': 7, 27 | 'steps': 25, 28 | 'seed': 1, 29 | } 30 | 31 | 边长限制 = 640 32 | 33 | API = 'http://localhost:7860/sdapi/v1/img2img' 34 | 35 | 36 | def 当前窗口() -> str: 37 | hwnd = win32gui.GetForegroundWindow() 38 | threadid, pid = win32process.GetWindowThreadProcessId(hwnd) 39 | text = win32gui.GetWindowText(hwnd) or '' 40 | try: 41 | exe = psutil.Process(pid).exe() 42 | except Exception: 43 | exe = '' 44 | return exe, text 45 | 46 | _上次修改时间 = 0 47 | 48 | 当前按键 = {} 49 | pynput.keyboard.Listener( 50 | on_press=lambda x: 当前按键.setdefault(x, time.time()), 51 | on_release=lambda x: 当前按键.pop(x, None), 52 | ).start() 53 | keyboard_controller = Controller() 54 | 上次保存时间 = 0 55 | while True: 56 | try: 57 | 上次修改时间 = max(os.path.getmtime(设置文件), os.path.getmtime(psd文件)) 58 | if 上次修改时间 > _上次修改时间 + 0.00001: 59 | with 计时('预处理'): 60 | setting = yaml.safe_load(open(设置文件)) 61 | p = psd_tools.PSDImage.open(psd文件) 62 | bo = io.BytesIO() 63 | p.topil().save(bo, format='WEBP') 64 | b = bo.getvalue() 65 | img_base64 = base64.b64encode(b).decode('utf-8') 66 | with 计时('调用'): 67 | 设置 = 默认设置 | {'init_images': [img_base64]} | setting 68 | if not 设置.get('width'): 69 | 设置['width'] = p.width 70 | if not 设置.get('height'): 71 | 设置['height'] = p.height 72 | if max(设置['width'], 设置['height']) > 边长限制: 73 | if 设置['width'] > 设置['height']: 74 | 设置['height'] = int(设置['height'] * 边长限制 / 设置['width']) 75 | 设置['width'] = 边长限制 76 | else: 77 | 设置['width'] = int(设置['width'] * 边长限制 / 设置['height']) 78 | 设置['height'] = 边长限制 79 | r = requests.post(url=f'{API}', json=设置) 80 | with 计时('后处理'): 81 | 图 = [base64.b64decode(b64) for b64 in r.json()['images']][0] 82 | img = cv2.imdecode(np.frombuffer(图, dtype=np.uint8), cv2.IMREAD_COLOR) 83 | _上次修改时间 = 上次修改时间 84 | except Exception: 85 | logging.exception('奇怪!') 86 | time.sleep(0.5) 87 | t = time.time() 88 | for k, v in [*当前按键.items()]: 89 | if not isinstance(k, Key) and (not k.char or k.char <= '\x1f'): # 组合键有时候会多出奇怪的字符,我也不知道为什么 90 | 当前按键.pop(k, None) 91 | if t - v > 10: 92 | 当前按键.pop(k, None) 93 | exe, text = 当前窗口() 94 | if exe.lower().endswith('photoshop.exe') and ('*' in text) and not 当前按键: 95 | t = time.time() 96 | if t - 上次保存时间 > 0.5: 97 | 上次保存时间 = t 98 | keyboard_controller.press(Key.ctrl_l.value) 99 | keyboard_controller.press('s') 100 | keyboard_controller.release('s') 101 | keyboard_controller.release(Key.ctrl_l.value) 102 | cv2.imshow('', img) 103 | cv2.waitKey(1) 104 | -------------------------------------------------------------------------------- /p.yaml: -------------------------------------------------------------------------------- 1 | prompt: 1girl, loli, tears, smile, indoors, arms behind back, bdsm, white rope, twintails, white choker, white hair, nipples, nude 2 | negative_prompt: worst quality, low quality, blurry, greyscale, monochrome, from side 3 | denoising_strength: 0.6 4 | cfg_scale: 7 5 | sampler_index: DPM++ 2M SDE Karras 6 | steps: 30 7 | seed: 99 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 【copylot】Photoshop的实时stable diffusion插件! 2 | 3 | 大家有用过Github Copilot吗?Github Copilot可以在你写代码的时候,帮你把你不会写或者懒得写的部分直接写出来。 4 | 5 | 如果画画的时候也有copilot帮我画就好了! 6 | 7 | 于是聪明的莉沫酱发明了1个Photoshop的插件,叫copylot!它可以像Github Copilot那样实时帮你把你的画补充完整! 8 | 9 | 10 | ## 示例视频 11 | 12 | [好.webm](https://github.com/RimoChan/copylot/assets/20064807/92e052ef-5402-4c55-8f0d-4f80ebae1b05) 13 | 14 | 15 | ## 使用方法 16 | 17 | - 首先你需要1个Python和1个Photoshop。(我已经换Python 3.11了所以不知道最低版本号是多少) 18 | 19 | - 安装1个[stable-diffusion-webui](https://github.com/AUTOMATIC1111/stable-diffusion-webui)。运行webui-user.bat时,启动参数需要加上--api才能从API访问。 20 | 21 | - 给stable-diffusion-webui下载1个[LCM-LORA](https://huggingface.co/latent-consistency/lcm-lora-sdv1-5),可以大幅减少图像生成所需的steps以加快生成速度,不过模型的画风也会有1些改变……不用也行。 22 | 23 | - 把这个仓库clone回去,然后运行`pip install requirements.txt`。 24 | 25 | - 运行`python copylot.py`就可以了。运行参数都写在代码里,直接改掉就可以了,不过调用stable diffusion API的参数是写在`设置文件`里的,这部分参数在运行时可以动态刷新。 26 | 27 | 28 | ## 已知bug 29 | 30 | 由于这个插件的实现非常奇怪,所以可能出现各种异常。 31 | 32 | 比如Photoshop突然鬼畜,发出异响什么的,都是正常的…… 33 | 34 | 35 | ## 结束 36 | 37 | 就这样,大家88,我要回去报考维也呐艺术学院了! 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pynput~=1.7.6 2 | pywin32~=305 3 | opencv-python~=4.8.0 4 | PyYAML~=6.0 5 | psutil~=5.9.5 6 | requests~=2.31.0 7 | psd-tools~=1.9.28 8 | numpy~=1.24.3 9 | rimo-utils~=1.7.0 10 | --------------------------------------------------------------------------------