c5e5aafbd355d40c9a6098a76e091f0ce9686827f74aacd3a679fc72967ac606
Browse files- Auto-Photoshop-StableDiffusion-Plugin/icon/discard_all.svg +1 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/discard_all_border.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected.svg +1 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected_border.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/ftcopy.svg +153 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/icon_D.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/icon_N.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/image-search.svg +15 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/layer_to_selection.svg +8 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/reset_settings.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/reset_settings2.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/search.svg +19 -0
- Auto-Photoshop-StableDiffusion-Plugin/icon/writing-icon.svg +1 -0
- Auto-Photoshop-StableDiffusion-Plugin/index.html +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/index.js +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/install.py +53 -0
- Auto-Photoshop-StableDiffusion-Plugin/jimp/browser/lib/jimp.min.js +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/manifest.json +141 -0
- Auto-Photoshop-StableDiffusion-Plugin/outpaint.js +518 -0
- Auto-Photoshop-StableDiffusion-Plugin/output_image.png +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/package-lock.json +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/package.json +55 -0
- Auto-Photoshop-StableDiffusion-Plugin/psapi.js +1598 -0
- Auto-Photoshop-StableDiffusion-Plugin/requirements.txt +26 -0
- Auto-Photoshop-StableDiffusion-Plugin/scripts/__pycache__/main.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/scripts/__pycache__/test.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/scripts/main.py +105 -0
- Auto-Photoshop-StableDiffusion-Plugin/scripts/test.py +5 -0
- Auto-Photoshop-StableDiffusion-Plugin/sdapi_py_re.js +814 -0
- Auto-Photoshop-StableDiffusion-Plugin/selection.js +167 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/img2imgapi.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/metadata_to_json.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/prompt_shortcut.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/search.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/serverHelper.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/serverMain.cpython-310.pyc +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/control_net.py +65 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/img2imgapi.py +163 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/init_images/.gitignore +4 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/metadata_to_json.py +78 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/.gitignore +4 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/prompt_shortcut - Copy.json +12 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/prompt_shortcut.py +61 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/search.py +24 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/serverHelper.py +64 -0
- Auto-Photoshop-StableDiffusion-Plugin/server/python_server/serverMain.py +495 -0
- Auto-Photoshop-StableDiffusion-Plugin/start_server.bat +51 -0
- Auto-Photoshop-StableDiffusion-Plugin/start_server.sh +36 -0
- Auto-Photoshop-StableDiffusion-Plugin/start_server_MacOS.sh +17 -0
Auto-Photoshop-StableDiffusion-Plugin/icon/discard_all.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/discard_all_border.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/discard_selected_border.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/ftcopy.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/icon_D.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/icon_N.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/image-search.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/layer_to_selection.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/reset_settings.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/reset_settings2.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/icon/search.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/icon/writing-icon.svg
ADDED
|
Auto-Photoshop-StableDiffusion-Plugin/index.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Auto-Photoshop-StableDiffusion-Plugin/index.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Auto-Photoshop-StableDiffusion-Plugin/install.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from pathlib import Path
|
3 |
+
from launch import git, run
|
4 |
+
import launch
|
5 |
+
import sys
|
6 |
+
|
7 |
+
# launch.run(f'git pull', f"updating auto-photoshop plugin",
|
8 |
+
# f"Couldn't update auto-photoshop plugin")
|
9 |
+
|
10 |
+
|
11 |
+
REPO_LOCATION = Path(__file__).parent
|
12 |
+
# auto_update = os.environ.get("AUTO_UPDATE", "True").lower() in {"true", "yes"}
|
13 |
+
auto_update = True
|
14 |
+
extension_branch = "master"
|
15 |
+
# extension_branch = "horde_native"
|
16 |
+
# extension_branch = "auto_extension_ccx_1_1_7"
|
17 |
+
|
18 |
+
if auto_update:
|
19 |
+
print("[Auto-Photoshop-SD] Attempting auto-update...")
|
20 |
+
|
21 |
+
try:
|
22 |
+
|
23 |
+
checkout_result = run(f'"{git}" -C "{REPO_LOCATION}" checkout {extension_branch}', "[Auto-Photoshop-SD] switch branch to extension branch.")
|
24 |
+
print("checkout_result:",checkout_result)
|
25 |
+
|
26 |
+
branch_result = run(f'"{git}" -C "{REPO_LOCATION}" branch', "[Auto-Photoshop-SD] Current Branch.")
|
27 |
+
print("branch_result:",branch_result)
|
28 |
+
|
29 |
+
fetch_result = run(f'"{git}" -C "{REPO_LOCATION}" fetch', "[Auto-Photoshop-SD] Fetch upstream.")
|
30 |
+
print("fetch_result:",fetch_result)
|
31 |
+
|
32 |
+
pull_result = run(f'"{git}" -C "{REPO_LOCATION}" pull', "[Auto-Photoshop-SD] Pull upstream.")
|
33 |
+
print("pull_result:",pull_result)
|
34 |
+
|
35 |
+
except Exception as e:
|
36 |
+
print("[Auto-Photoshop-SD] Auto-update failed:")
|
37 |
+
print(e)
|
38 |
+
print("[Auto-Photoshop-SD] Ensure git was used to install extension.")
|
39 |
+
|
40 |
+
|
41 |
+
# print("Auto-Photoshop-SD plugin is installing")
|
42 |
+
|
43 |
+
package_name = 'duckduckgo_search'
|
44 |
+
package_version= '3.7.1'
|
45 |
+
if not launch.is_installed(package_name):
|
46 |
+
launch.run_pip(f"install {package_name}=={package_version}", "requirements for Auto-Photoshop Image Search")
|
47 |
+
else:# it's installed but we need to check for update
|
48 |
+
import pkg_resources
|
49 |
+
|
50 |
+
version = pkg_resources.get_distribution(package_name).version
|
51 |
+
if(version != package_version):
|
52 |
+
print(f'{package_name} version: {version} will update to version: {package_version}')
|
53 |
+
launch.run_pip(f"install {package_name}=={package_version}", "update requirements for Auto-Photoshop Image Search")
|
Auto-Photoshop-StableDiffusion-Plugin/jimp/browser/lib/jimp.min.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Auto-Photoshop-StableDiffusion-Plugin/manifest.json
ADDED
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"id": "auto.photoshop.stable.diffusion.plugin",
|
3 |
+
"name": "Auto Photoshop Stable Diffusion Plugin",
|
4 |
+
"version": "1.1.0",
|
5 |
+
"host": [
|
6 |
+
{
|
7 |
+
"app": "PS",
|
8 |
+
"minVersion": "24.0.0"
|
9 |
+
}
|
10 |
+
],
|
11 |
+
"main": "index.html",
|
12 |
+
"manifestVersion": 5,
|
13 |
+
"requiredPermissions": {
|
14 |
+
"network": {
|
15 |
+
"domains": "all"
|
16 |
+
},
|
17 |
+
"launchProcess": {
|
18 |
+
"schemes": [
|
19 |
+
"http",
|
20 |
+
"https",
|
21 |
+
"mailto"
|
22 |
+
],
|
23 |
+
"extensions": [
|
24 |
+
".png",
|
25 |
+
".jpg",
|
26 |
+
".pdf",
|
27 |
+
""
|
28 |
+
]
|
29 |
+
},
|
30 |
+
"clipboard": "readAndWrite",
|
31 |
+
"localFileSystem": "request",
|
32 |
+
"ipc": {
|
33 |
+
"enablePluginCommunication": true
|
34 |
+
}
|
35 |
+
},
|
36 |
+
"entrypoints": [
|
37 |
+
{
|
38 |
+
"type": "panel",
|
39 |
+
"id": "vanilla",
|
40 |
+
"label": {
|
41 |
+
"default": "Auto-Photoshop-SD",
|
42 |
+
"en-US": "Auto-Photoshop-SD",
|
43 |
+
"es-ES": "Auto-Photoshop-SD"
|
44 |
+
},
|
45 |
+
"minimumSize": {
|
46 |
+
"width": 400,
|
47 |
+
"height": 800
|
48 |
+
},
|
49 |
+
"maximumSize": {
|
50 |
+
"width": 1200,
|
51 |
+
"height": 10000
|
52 |
+
},
|
53 |
+
"preferredDockedSize": {
|
54 |
+
"width": 150,
|
55 |
+
"height": 800
|
56 |
+
},
|
57 |
+
"preferredFloatingSize": {
|
58 |
+
"width": 300,
|
59 |
+
"height": 800
|
60 |
+
},
|
61 |
+
"commands": [
|
62 |
+
{
|
63 |
+
"id": "show_alert",
|
64 |
+
"label": {
|
65 |
+
"default": "Show Alert",
|
66 |
+
"en-US": "Show Alert (US)",
|
67 |
+
"es-ES": "Show Alert (ES)"
|
68 |
+
}
|
69 |
+
}
|
70 |
+
],
|
71 |
+
"icons": [
|
72 |
+
{
|
73 |
+
"width": 32,
|
74 |
+
"height": 32,
|
75 |
+
"path": "icon/icon_D.png",
|
76 |
+
"scale": [
|
77 |
+
1,
|
78 |
+
2
|
79 |
+
],
|
80 |
+
"theme": [
|
81 |
+
"dark",
|
82 |
+
"darkest"
|
83 |
+
],
|
84 |
+
"species": [
|
85 |
+
"generic"
|
86 |
+
]
|
87 |
+
},
|
88 |
+
{
|
89 |
+
"width": 32,
|
90 |
+
"height": 32,
|
91 |
+
"path": "icon/icon_N.png",
|
92 |
+
"scale": [
|
93 |
+
1,
|
94 |
+
2
|
95 |
+
],
|
96 |
+
"theme": [
|
97 |
+
"lightest",
|
98 |
+
"light"
|
99 |
+
],
|
100 |
+
"species": [
|
101 |
+
"generic"
|
102 |
+
]
|
103 |
+
}
|
104 |
+
]
|
105 |
+
}
|
106 |
+
],
|
107 |
+
"icons": [
|
108 |
+
{
|
109 |
+
"width": 32,
|
110 |
+
"height": 32,
|
111 |
+
"path": "icon/icon_D.png",
|
112 |
+
"scale": [
|
113 |
+
1,
|
114 |
+
2
|
115 |
+
],
|
116 |
+
"theme": [
|
117 |
+
"dark",
|
118 |
+
"darkest"
|
119 |
+
],
|
120 |
+
"species": [
|
121 |
+
"generic"
|
122 |
+
]
|
123 |
+
},
|
124 |
+
{
|
125 |
+
"width": 32,
|
126 |
+
"height": 32,
|
127 |
+
"path": "icon/icon_N.png",
|
128 |
+
"scale": [
|
129 |
+
1,
|
130 |
+
2
|
131 |
+
],
|
132 |
+
"theme": [
|
133 |
+
"lightest",
|
134 |
+
"light"
|
135 |
+
],
|
136 |
+
"species": [
|
137 |
+
"generic"
|
138 |
+
]
|
139 |
+
}
|
140 |
+
]
|
141 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/outpaint.js
ADDED
@@ -0,0 +1,518 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const app = window.require('photoshop').app
|
2 |
+
|
3 |
+
const batchPlay = require('photoshop').action.batchPlay
|
4 |
+
const psapi = require('./psapi')
|
5 |
+
|
6 |
+
async function moveLayersToGroup(group_id) {
|
7 |
+
const activeLayers = await app.activeDocument.activeLayers
|
8 |
+
const layerIDs = activeLayers.map((layer) => layer.id)
|
9 |
+
const { executeAsModal } = require('photoshop').core
|
10 |
+
await executeAsModal(async () => {
|
11 |
+
await psapi.moveToGroupCommand(group_id, layerIDs)
|
12 |
+
})
|
13 |
+
}
|
14 |
+
|
15 |
+
async function createSnapshot() {
|
16 |
+
const { executeAsModal } = require('photoshop').core
|
17 |
+
//get all layers,
|
18 |
+
//duplicate the layers
|
19 |
+
//create a group
|
20 |
+
//move the duplicate layers to the group
|
21 |
+
let snapshotLayer, snapshotGroup
|
22 |
+
try {
|
23 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
24 |
+
await psapi.unSelectMarqueeExe()
|
25 |
+
|
26 |
+
//get all layers
|
27 |
+
const allLayers = await app.activeDocument.layers
|
28 |
+
|
29 |
+
// const allLayerNames = allLayers.map(
|
30 |
+
// layer => `${layer.name} (${layer.opacity} %)`
|
31 |
+
// )
|
32 |
+
// for (layer of allLayerNames){
|
33 |
+
// console.log(layer)
|
34 |
+
// }
|
35 |
+
//duplicate the layers
|
36 |
+
let duplicatedLayers = []
|
37 |
+
|
38 |
+
// const group_id = await createGroup()
|
39 |
+
const groupLayer = await psapi.createEmptyGroup()
|
40 |
+
|
41 |
+
console.log('createSnapshot(), group_id:', groupLayer.id)
|
42 |
+
// let bHasBackground = false
|
43 |
+
let indexOffset = 0
|
44 |
+
|
45 |
+
const result1 = await executeAsModal(async () => {
|
46 |
+
for (layer of allLayers) {
|
47 |
+
if (layer.id == 1) {
|
48 |
+
//skip the background layer
|
49 |
+
// bHasBackground = true
|
50 |
+
indexOffset = 1
|
51 |
+
continue
|
52 |
+
}
|
53 |
+
if (layer.visible) {
|
54 |
+
const copyLayer = await layer.duplicate()
|
55 |
+
duplicatedLayers.push(copyLayer)
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
const layerIDs = duplicatedLayers.map((layer) => layer.id)
|
60 |
+
console.log('createSnapshot, layerIDs:', layerIDs)
|
61 |
+
|
62 |
+
//select the layer since layerIDs don't seem to have an affect on moveToGroupCommand(), don't know why!!!!
|
63 |
+
psapi.selectLayers(duplicatedLayers)
|
64 |
+
let group_index = await psapi.getLayerIndex(groupLayer.id)
|
65 |
+
|
66 |
+
await psapi.moveToGroupCommand(group_index - indexOffset, layerIDs)
|
67 |
+
|
68 |
+
await psapi.collapseGroup(duplicatedLayers[0])
|
69 |
+
snapshotLayer = app.activeDocument.activeLayers[0]
|
70 |
+
await psapi.createSolidLayer(255, 255, 255)
|
71 |
+
const whiteSolidLayer = app.activeDocument.activeLayers[0]
|
72 |
+
await snapshotLayer.moveAbove(whiteSolidLayer)
|
73 |
+
snapshotGroup = await psapi.createEmptyGroup()
|
74 |
+
let snapshot_group_index = await psapi.getLayerIndex(
|
75 |
+
snapshotGroup.id
|
76 |
+
)
|
77 |
+
|
78 |
+
await psapi.selectLayers([snapshotLayer, whiteSolidLayer])
|
79 |
+
await psapi.moveToGroupCommand(
|
80 |
+
snapshot_group_index - indexOffset,
|
81 |
+
[]
|
82 |
+
)
|
83 |
+
await psapi.selectLayers([snapshotGroup])
|
84 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
85 |
+
await psapi.createMaskExe()
|
86 |
+
// await psapi.selectLayerChannelCommand()
|
87 |
+
// await psapi.createSolidLayer(0, 0, 0)
|
88 |
+
})
|
89 |
+
|
90 |
+
return [snapshotLayer, snapshotGroup]
|
91 |
+
} catch (e) {
|
92 |
+
console.warn('createSnapshot Error:', e)
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
function executeCommand(batchPlayCommandFunc) {
|
97 |
+
const { executeAsModal } = require('photoshop').core
|
98 |
+
try {
|
99 |
+
executeAsModal(async () => {
|
100 |
+
await batchPlayCommandFunc()
|
101 |
+
})
|
102 |
+
} catch (e) {
|
103 |
+
console.warn('executeCommand error:', e)
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
async function snapAndFillExe(session_id) {
|
108 |
+
//create a snapshot of canvas
|
109 |
+
//select opaque pixel and create black fill layer
|
110 |
+
//create a snapshot of mask
|
111 |
+
//set initial image
|
112 |
+
//set mask image
|
113 |
+
|
114 |
+
try {
|
115 |
+
let snapAndFillLayers = []
|
116 |
+
await executeAsModal(async (context) => {
|
117 |
+
const history_id = await context.hostControl.suspendHistory({
|
118 |
+
documentID: app.activeDocument.id, //TODO: change this to the session document id
|
119 |
+
name: 'Img2Img layers',
|
120 |
+
})
|
121 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
122 |
+
// await psapi.unSelectMarqueeExe()
|
123 |
+
|
124 |
+
//create a snapshot of canvas
|
125 |
+
// let [snapshotLayer,snapshotGroup] = await createSnapshot()
|
126 |
+
await psapi.snapshot_layerExe()
|
127 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
128 |
+
const snapshotGroup = await psapi.createEmptyGroup()
|
129 |
+
snapshotLayer.name = 'Init Image Snapshot -- temporary'
|
130 |
+
snapshotGroup.name = 'Init Image Group -- temporary'
|
131 |
+
|
132 |
+
// snapshotGroup.name = `${snapshotGroup.name}_init_image`
|
133 |
+
await psapi.createSolidLayer(255, 255, 255)
|
134 |
+
const whiteSolidLayer = await app.activeDocument.activeLayers[0]
|
135 |
+
whiteSolidLayer.name = 'Background Color -- temporary'
|
136 |
+
snapshotLayer.moveAbove(whiteSolidLayer)
|
137 |
+
console.log('[snapshotLayer,snapshotGroup]:', [
|
138 |
+
snapshotLayer,
|
139 |
+
snapshotGroup,
|
140 |
+
])
|
141 |
+
|
142 |
+
//create a snapshot of mask
|
143 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
144 |
+
// let [snapshotMaskLayer,snapshotMaskGroup] = await createSnapshot()
|
145 |
+
|
146 |
+
await psapi.selectLayers([snapshotGroup])
|
147 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
148 |
+
await psapi.createClippingMaskExe()
|
149 |
+
|
150 |
+
await psapi.selectLayers([snapshotGroup])
|
151 |
+
|
152 |
+
snapAndFillLayers = [snapshotLayer, snapshotGroup, whiteSolidLayer]
|
153 |
+
|
154 |
+
// g_init_image_related_layers['init_image_group'] = snapshotGroup
|
155 |
+
// g_init_image_related_layers['init_image_layer'] = snapshotLayer
|
156 |
+
// g_init_image_related_layers['solid_white'] = whiteSolidLayer
|
157 |
+
|
158 |
+
const image_info = await psapi.silentSetInitImage(
|
159 |
+
snapshotGroup,
|
160 |
+
session_id
|
161 |
+
)
|
162 |
+
const image_name = image_info['name']
|
163 |
+
const path = `./server/python_server/init_images/${image_name}`
|
164 |
+
|
165 |
+
g_viewer_manager.initializeInitImage(
|
166 |
+
snapshotGroup,
|
167 |
+
snapshotLayer,
|
168 |
+
whiteSolidLayer,
|
169 |
+
path
|
170 |
+
) //this will be called once a session and will add the first init image to th viewer manager
|
171 |
+
|
172 |
+
for (layer of snapAndFillLayers) {
|
173 |
+
layer.visible = false
|
174 |
+
}
|
175 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
176 |
+
const layer_util = require('./utility/layer')
|
177 |
+
await layer_util.collapseFolderExe([snapshotGroup], false)
|
178 |
+
await context.hostControl.resumeHistory(history_id)
|
179 |
+
})
|
180 |
+
console.log('snapAndFillLayers: ', snapAndFillLayers)
|
181 |
+
return snapAndFillLayers
|
182 |
+
} catch (e) {
|
183 |
+
console.error(`snapAndFill error: ${e}`)
|
184 |
+
}
|
185 |
+
return []
|
186 |
+
}
|
187 |
+
|
188 |
+
async function addClippingMaskToLayer(layer, selectionInfo) {
|
189 |
+
await psapi.selectLayers([layer]) //select the layer
|
190 |
+
await psapi.reSelectMarqueeExe(selectionInfo) //reselect the selection
|
191 |
+
await psapi.createClippingMaskExe() //this will create an cliping mask and select the mask of the layer
|
192 |
+
await psapi.selectLayers([layer]) //reselect the layer instead of the mask
|
193 |
+
await psapi.reSelectMarqueeExe(selectionInfo) //reselect the selection
|
194 |
+
|
195 |
+
////test addClippingMaskToLayer
|
196 |
+
// await executeAsModal(
|
197 |
+
// async ()=>{
|
198 |
+
// await outpaint.addClippingMaskToLayer(await app.activeDocument.activeLayers[0],await psapi.getSelectionInfoExe()
|
199 |
+
// )})
|
200 |
+
}
|
201 |
+
|
202 |
+
async function outpaintExe(session_id) {
|
203 |
+
//create a snapshot of canvas
|
204 |
+
//select opaque pixel and create black fill layer
|
205 |
+
//create a snapshot of mask
|
206 |
+
//set initial image
|
207 |
+
//set mask image
|
208 |
+
|
209 |
+
try {
|
210 |
+
let outpaintLayers = []
|
211 |
+
await executeAsModal(async (context) => {
|
212 |
+
const history_id = await context.hostControl.suspendHistory({
|
213 |
+
documentID: app.activeDocument.id, //TODO: change this to the session document id
|
214 |
+
name: 'Outpaint Mask Related layers',
|
215 |
+
})
|
216 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
217 |
+
// await psapi.unSelectMarqueeExe()
|
218 |
+
|
219 |
+
//create a snapshot of canvas
|
220 |
+
// let [snapshotLayer,snapshotGroup] = await createSnapshot()
|
221 |
+
await psapi.snapshot_layerExe()
|
222 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
223 |
+
snapshotLayer.name = 'Init Image Snapshot -- temporary'
|
224 |
+
const snapshotGroup = await psapi.createEmptyGroup()
|
225 |
+
// snapshotGroup.name = `${snapshotGroup.name}_init_image`
|
226 |
+
snapshotGroup.name = 'Init Image Group -- temporary'
|
227 |
+
await psapi.createSolidLayer(255, 255, 255) //solid white inside the Init Image Group
|
228 |
+
const whiteSolidLayer = await app.activeDocument.activeLayers[0]
|
229 |
+
whiteSolidLayer.name = 'Background Color -- temporary'
|
230 |
+
snapshotLayer.moveAbove(whiteSolidLayer) //move the snapshot layer to be the first layer in "Init Image Group"
|
231 |
+
console.log('[snapshotLayer,snapshotGroup]:', [
|
232 |
+
snapshotLayer,
|
233 |
+
snapshotGroup,
|
234 |
+
])
|
235 |
+
|
236 |
+
//select opaque pixel and create black fill layer
|
237 |
+
await psapi.selectLayers([snapshotLayer])
|
238 |
+
await psapi.selectLayerChannelCommand()
|
239 |
+
const snapshotMaskGroup = await psapi.createEmptyGroup()
|
240 |
+
|
241 |
+
await psapi.createSolidLayer(0, 0, 0)
|
242 |
+
let solid_black_layer = app.activeDocument.activeLayers[0]
|
243 |
+
//create a snapshot of mask
|
244 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
245 |
+
// let [snapshotMaskLayer,snapshotMaskGroup] = await createSnapshot()
|
246 |
+
await psapi.snapshot_layerExe()
|
247 |
+
const snapshotMaskLayer = await app.activeDocument.activeLayers[0]
|
248 |
+
snapshotMaskLayer.name = 'Mask -- Paint White to Mask -- temporary'
|
249 |
+
// const snapshotMaskGroup = await psapi.createEmptyGroup()
|
250 |
+
|
251 |
+
// snapshotMaskGroup.name = `${snapshotMaskGroup.name}_mask`
|
252 |
+
snapshotMaskGroup.name = 'Mask Group -- temporary'
|
253 |
+
snapshotMaskLayer.moveBelow(solid_black_layer)
|
254 |
+
await snapshotMaskGroup.moveAbove(snapshotGroup)
|
255 |
+
await solid_black_layer.delete() //
|
256 |
+
|
257 |
+
await addClippingMaskToLayer(snapshotGroup, selectionInfo)
|
258 |
+
|
259 |
+
const mask_info = await psapi.silentSetInitImageMask(
|
260 |
+
snapshotMaskGroup,
|
261 |
+
session_id
|
262 |
+
)
|
263 |
+
snapshotMaskGroup.visible = false
|
264 |
+
|
265 |
+
const image_info = await psapi.silentSetInitImage(
|
266 |
+
snapshotGroup,
|
267 |
+
session_id
|
268 |
+
)
|
269 |
+
snapshotGroup.visible = false
|
270 |
+
|
271 |
+
const init_image_name = image_info['name']
|
272 |
+
const init_path = `./server/python_server/init_images/${init_image_name}`
|
273 |
+
|
274 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
275 |
+
|
276 |
+
await addClippingMaskToLayer(snapshotMaskGroup, selectionInfo)
|
277 |
+
|
278 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
279 |
+
|
280 |
+
// await psapi.silentSetInitImageMask(snapshotMaskGroup,session_id)
|
281 |
+
|
282 |
+
const mask_name = mask_info['name']
|
283 |
+
const mask_path = `./server/python_server/init_images/${mask_name}`
|
284 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
285 |
+
//set initial image
|
286 |
+
//set mask image
|
287 |
+
outpaintLayers = [
|
288 |
+
snapshotMaskGroup,
|
289 |
+
snapshotMaskLayer,
|
290 |
+
snapshotLayer,
|
291 |
+
snapshotGroup,
|
292 |
+
whiteSolidLayer,
|
293 |
+
]
|
294 |
+
// g_mask_related_layers['mask_group'] = snapshotMaskGroup
|
295 |
+
// g_mask_related_layers['white_mark'] = snapshotMaskLayer
|
296 |
+
// // g_mask_related_layers['solid_black'] = blackSolidLayer
|
297 |
+
g_viewer_manager.initializeMask(
|
298 |
+
snapshotMaskGroup,
|
299 |
+
snapshotMaskLayer,
|
300 |
+
null,
|
301 |
+
mask_path,
|
302 |
+
mask_info['base64']
|
303 |
+
)
|
304 |
+
// g_init_image_related_layers['init_image_group'] = snapshotGroup
|
305 |
+
// g_init_image_related_layers['init_image_layer'] = snapshotLayer
|
306 |
+
// g_init_image_related_layers['solid_white'] = whiteSolidLayer
|
307 |
+
g_viewer_manager.initializeInitImage(
|
308 |
+
snapshotGroup,
|
309 |
+
snapshotLayer,
|
310 |
+
whiteSolidLayer,
|
311 |
+
init_path
|
312 |
+
) //this will be called once a session and will add the first init image to th viewer manager
|
313 |
+
|
314 |
+
for (layer of outpaintLayers) {
|
315 |
+
layer.visible = false
|
316 |
+
}
|
317 |
+
|
318 |
+
//collapse the folders
|
319 |
+
const layer_util = require('./utility/layer')
|
320 |
+
await layer_util.collapseFolderExe(
|
321 |
+
[snapshotGroup, snapshotMaskGroup],
|
322 |
+
false
|
323 |
+
)
|
324 |
+
await context.hostControl.resumeHistory(history_id)
|
325 |
+
})
|
326 |
+
console.log('outpaintLayers 2: ', outpaintLayers)
|
327 |
+
return outpaintLayers
|
328 |
+
} catch (e) {
|
329 |
+
console.error(`outpaintExe error: ${e}`)
|
330 |
+
}
|
331 |
+
return []
|
332 |
+
}
|
333 |
+
|
334 |
+
async function inpaintFasterExe(session_id) {
|
335 |
+
//
|
336 |
+
//create a snapshot of canvas
|
337 |
+
//select opaque pixel and create black fill layer
|
338 |
+
//create a snapshot of mask
|
339 |
+
//set initial image
|
340 |
+
//set mask image
|
341 |
+
try {
|
342 |
+
let inpaintLayers = []
|
343 |
+
await executeAsModal(async (context) => {
|
344 |
+
const history_id = await context.hostControl.suspendHistory({
|
345 |
+
documentID: app.activeDocument.id,
|
346 |
+
name: 'Inpaint Mask Related layers',
|
347 |
+
})
|
348 |
+
const original_white_mark_layer = await app.activeDocument
|
349 |
+
.activeLayers[0]
|
350 |
+
original_white_mark_layer.visible = false
|
351 |
+
|
352 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
353 |
+
|
354 |
+
//duplicate the current active layer and use it as the white mark layer
|
355 |
+
const white_mark_layer =
|
356 |
+
await app.activeDocument.activeLayers[0].duplicate()
|
357 |
+
white_mark_layer.visible = true
|
358 |
+
const mask_layer_opacity = await white_mark_layer.opacity
|
359 |
+
white_mark_layer.opacity = 100 //make sure the opacity is full
|
360 |
+
await psapi.selectLayers([white_mark_layer])
|
361 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
362 |
+
await psapi.createClippingMaskExe()
|
363 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
364 |
+
|
365 |
+
white_mark_layer.visible = false
|
366 |
+
white_mark_layer.name = 'Mask -- Paint White to Mask -- temporary'
|
367 |
+
// white_mark_layer.visible = true
|
368 |
+
|
369 |
+
//create a snapshot of canvas
|
370 |
+
|
371 |
+
// let [snapshotLayer,snapshotGroup] = await createSnapshot()
|
372 |
+
// await psapi.snapshot_layer()
|
373 |
+
await psapi.unselectActiveLayersExe() //invisible layer will cause problem with merging "command is not available" type of error
|
374 |
+
// await psapi.mergeVisibleExe()
|
375 |
+
await psapi.snapshot_layerExe()
|
376 |
+
|
377 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
378 |
+
snapshotLayer.name = 'Init Image Snapshot -- temporary'
|
379 |
+
const snapshotGroup = await psapi.createEmptyGroup()
|
380 |
+
snapshotGroup.name = 'Init Image Group -- temporary'
|
381 |
+
await psapi.createSolidLayer(255, 255, 255)
|
382 |
+
const whiteSolidLayer = await app.activeDocument.activeLayers[0]
|
383 |
+
whiteSolidLayer.name = 'Background Color -- temporary'
|
384 |
+
await snapshotLayer.moveAbove(whiteSolidLayer)
|
385 |
+
|
386 |
+
await psapi.selectLayers([snapshotGroup])
|
387 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
388 |
+
await psapi.createClippingMaskExe()
|
389 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
390 |
+
|
391 |
+
const maskGroup = await psapi.createEmptyGroup()
|
392 |
+
// maskGroup.name = `${maskGroup.name}_mask`
|
393 |
+
|
394 |
+
maskGroup.name = 'Mask Group -- temporary'
|
395 |
+
|
396 |
+
await psapi.createSolidLayer(0, 0, 0)
|
397 |
+
const blackSolidLayer = await app.activeDocument.activeLayers[0]
|
398 |
+
blackSolidLayer.name = "Don't Edit -- temporary"
|
399 |
+
// snapshotLayer.moveAbove(blackSolidLayer)
|
400 |
+
white_mark_layer.moveAbove(blackSolidLayer)
|
401 |
+
white_mark_layer.visible = true
|
402 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
403 |
+
|
404 |
+
console.log('[snapshotLayer,maskGroup]:', [
|
405 |
+
snapshotLayer,
|
406 |
+
maskGroup,
|
407 |
+
])
|
408 |
+
// //select opaque pixel and create black fill layer
|
409 |
+
// await psapi.selectLayers([snapshotLayer])
|
410 |
+
// await psapi.selectLayerChannelCommand()
|
411 |
+
// const snapshotMaskGroup = await psapi.createEmptyGroup()
|
412 |
+
|
413 |
+
// await psapi.createSolidLayer(0, 0, 0)
|
414 |
+
// let solid_black_layer = app.activeDocument.activeLayers[0]
|
415 |
+
// //create a snapshot of mask
|
416 |
+
// await psapi.reSelectMarqueeExe(selectionInfo)
|
417 |
+
// // let [snapshotMaskLayer,snapshotMaskGroup] = await createSnapshot()
|
418 |
+
// await psapi.snapshot_layer()
|
419 |
+
// const snapshotMaskLayer = await app.activeDocument.activeLayers[0]
|
420 |
+
// // const snapshotMaskGroup = await psapi.createEmptyGroup()
|
421 |
+
|
422 |
+
// snapshotMaskGroup.name = `${snapshotMaskGroup.name}_mask`
|
423 |
+
// snapshotMaskLayer.moveBelow(solid_black_layer)
|
424 |
+
// await snapshotMaskGroup.moveAbove(snapshotGroup)
|
425 |
+
// solid_black_layer.delete()
|
426 |
+
|
427 |
+
await psapi.selectLayers([maskGroup])
|
428 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
429 |
+
await psapi.createClippingMaskExe()
|
430 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
431 |
+
|
432 |
+
// await psapi.selectLayers([snapshotGroup])
|
433 |
+
|
434 |
+
await psapi.selectLayers([maskGroup])
|
435 |
+
// await psapi.silentSetInitImageMask(maskGroup,session_id)
|
436 |
+
const mask_info = await psapi.silentSetInitImageMask(
|
437 |
+
maskGroup,
|
438 |
+
session_id
|
439 |
+
)
|
440 |
+
maskGroup.visible = false
|
441 |
+
//hide the mask so you can take screenshot of the init image
|
442 |
+
const mask_name = mask_info['name']
|
443 |
+
const mask_path = `./server/python_server/init_images/${mask_name}`
|
444 |
+
|
445 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
446 |
+
await psapi.selectLayers([snapshotGroup])
|
447 |
+
|
448 |
+
const image_info = await psapi.silentSetInitImage(
|
449 |
+
snapshotGroup,
|
450 |
+
session_id
|
451 |
+
)
|
452 |
+
const image_name = image_info['name']
|
453 |
+
const path = `./server/python_server/init_images/${image_name}`
|
454 |
+
|
455 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
456 |
+
// await psapi.selectLayers([snapshotMaskGroup])
|
457 |
+
// await psapi.setInitImageMask(snapshotMaskGroup)
|
458 |
+
// //set initial image
|
459 |
+
// //set mask image
|
460 |
+
|
461 |
+
await psapi.selectLayers([maskGroup])
|
462 |
+
inpaintLayers = [
|
463 |
+
maskGroup,
|
464 |
+
white_mark_layer,
|
465 |
+
blackSolidLayer,
|
466 |
+
snapshotGroup,
|
467 |
+
snapshotLayer,
|
468 |
+
whiteSolidLayer,
|
469 |
+
]
|
470 |
+
// g_mask_related_layers['mask_group'] = maskGroup
|
471 |
+
// g_mask_related_layers['white_mark'] = white_mark_layer
|
472 |
+
// g_mask_related_layers['solid_black'] = blackSolidLayer
|
473 |
+
g_viewer_manager.initializeMask(
|
474 |
+
maskGroup,
|
475 |
+
white_mark_layer,
|
476 |
+
blackSolidLayer,
|
477 |
+
mask_path,
|
478 |
+
mask_info['bases64']
|
479 |
+
)
|
480 |
+
// g_init_image_related_layers['init_image_group'] = snapshotGroup
|
481 |
+
// g_init_image_related_layers['init_image_layer'] = snapshotLayer
|
482 |
+
// g_init_image_related_layers['solid_white'] = whiteSolidLayer
|
483 |
+
g_viewer_manager.initializeInitImage(
|
484 |
+
snapshotGroup,
|
485 |
+
snapshotLayer,
|
486 |
+
whiteSolidLayer,
|
487 |
+
path
|
488 |
+
) //this will be called once a session and will add the first init image to th viewer manager
|
489 |
+
for (layer of inpaintLayers) {
|
490 |
+
layer.visible = false
|
491 |
+
}
|
492 |
+
const layer_util = require('./utility/layer')
|
493 |
+
|
494 |
+
await layer_util.collapseFolderExe(
|
495 |
+
[snapshotGroup, maskGroup],
|
496 |
+
false
|
497 |
+
)
|
498 |
+
white_mark_layer.opacity = mask_layer_opacity // restore the opacity
|
499 |
+
// original_white_mark_layer.visible = true// leave it off so we can toggle using the viewer manager
|
500 |
+
await context.hostControl.resumeHistory(history_id)
|
501 |
+
})
|
502 |
+
return inpaintLayers
|
503 |
+
} catch (e) {
|
504 |
+
console.warn('inpaintFasterExe error:', e)
|
505 |
+
}
|
506 |
+
return []
|
507 |
+
}
|
508 |
+
module.exports = {
|
509 |
+
createSnapshot,
|
510 |
+
|
511 |
+
moveLayersToGroup,
|
512 |
+
executeCommand,
|
513 |
+
outpaintExe,
|
514 |
+
// outpaintFasterExe,
|
515 |
+
inpaintFasterExe,
|
516 |
+
snapAndFillExe,
|
517 |
+
addClippingMaskToLayer,
|
518 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/output_image.png
ADDED
![]() |
Auto-Photoshop-StableDiffusion-Plugin/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Auto-Photoshop-StableDiffusion-Plugin/package.json
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "uxp-template-default-starter",
|
3 |
+
"version": "1.0.0",
|
4 |
+
"description": "Default template for creating Adobe UXP based photoshop plugin.",
|
5 |
+
"author": "Adobe Inc",
|
6 |
+
"license": "Apache-2.0",
|
7 |
+
"dependencies": {
|
8 |
+
"@types/react": "^18.2.6",
|
9 |
+
"@types/react-dom": "^18.2.4",
|
10 |
+
"fastify": "^4.10.2",
|
11 |
+
"jimp": "^0.16.2",
|
12 |
+
"md5": "^2.3.0",
|
13 |
+
"mobx": "^6.9.0",
|
14 |
+
"mobx-react": "^7.6.0",
|
15 |
+
"react": "^18.2.0",
|
16 |
+
"react-dom": "^18.2.0"
|
17 |
+
},
|
18 |
+
"main": "index.js",
|
19 |
+
"directories": {
|
20 |
+
"test": "test"
|
21 |
+
},
|
22 |
+
"devDependencies": {
|
23 |
+
"@babel/core": "^7.21.8",
|
24 |
+
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
|
25 |
+
"@babel/plugin-syntax-class-properties": "^7.12.13",
|
26 |
+
"@babel/plugin-transform-react-jsx": "^7.21.5",
|
27 |
+
"babel-loader": "^9.1.2",
|
28 |
+
"clean-webpack-plugin": "^4.0.0",
|
29 |
+
"copy-webpack-plugin": "^11.0.0",
|
30 |
+
"css-loader": "^6.7.3",
|
31 |
+
"file-loader": "^6.2.0",
|
32 |
+
"nodemon": "^2.0.22",
|
33 |
+
"prettier": "2.8.3",
|
34 |
+
"style-loader": "^3.3.2",
|
35 |
+
"terser-webpack-plugin": "^3.0.8",
|
36 |
+
"ts-loader": "^9.4.2",
|
37 |
+
"typescript": "^5.0.4",
|
38 |
+
"webpack": "^5.82.1",
|
39 |
+
"webpack-cli": "^5.1.1"
|
40 |
+
},
|
41 |
+
"scripts": {
|
42 |
+
"test": "echo \"Error: no test specified\" && exit 1",
|
43 |
+
"build": "cd ultimate_sd_upscaler && npx webpack --config webpack.config.js",
|
44 |
+
"watch": "cd ultimate_sd_upscaler && npx webpack --config webpack.config.js --watch"
|
45 |
+
},
|
46 |
+
"repository": {
|
47 |
+
"type": "git",
|
48 |
+
"url": "git+https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin.git"
|
49 |
+
},
|
50 |
+
"keywords": [],
|
51 |
+
"bugs": {
|
52 |
+
"url": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin/issues"
|
53 |
+
},
|
54 |
+
"homepage": "https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin#readme"
|
55 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/psapi.js
ADDED
@@ -0,0 +1,1598 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const app = window.require('photoshop').app
|
2 |
+
const batchPlay = require('photoshop').action.batchPlay
|
3 |
+
const { executeAsModal } = require('photoshop').core
|
4 |
+
// const export_png = require('./export_png')
|
5 |
+
|
6 |
+
// const { layerToSelection } = require('./helper')
|
7 |
+
|
8 |
+
const storage = require('uxp').storage
|
9 |
+
const fs = storage.localFileSystem
|
10 |
+
|
11 |
+
async function createSolidLayer(r, g, b) {
|
12 |
+
console.warn('this function is deprecated')
|
13 |
+
await executeAsModal(async () => {
|
14 |
+
const result = await batchPlay(
|
15 |
+
[
|
16 |
+
{
|
17 |
+
_obj: 'make',
|
18 |
+
_target: [
|
19 |
+
{
|
20 |
+
_ref: 'contentLayer',
|
21 |
+
},
|
22 |
+
],
|
23 |
+
using: {
|
24 |
+
_obj: 'contentLayer',
|
25 |
+
type: {
|
26 |
+
_obj: 'solidColorLayer',
|
27 |
+
color: {
|
28 |
+
_obj: 'RGBColor',
|
29 |
+
red: r,
|
30 |
+
grain: g,
|
31 |
+
blue: b,
|
32 |
+
},
|
33 |
+
},
|
34 |
+
},
|
35 |
+
_options: {
|
36 |
+
dialogOptions: 'dontDisplay',
|
37 |
+
},
|
38 |
+
},
|
39 |
+
],
|
40 |
+
{
|
41 |
+
synchronousExecution: true,
|
42 |
+
modalBehavior: 'execute',
|
43 |
+
}
|
44 |
+
)
|
45 |
+
})
|
46 |
+
}
|
47 |
+
|
48 |
+
async function makeGroupCommand() {
|
49 |
+
const result = await batchPlay(
|
50 |
+
[
|
51 |
+
{
|
52 |
+
_obj: 'make',
|
53 |
+
_target: [
|
54 |
+
{
|
55 |
+
_ref: 'layerSection',
|
56 |
+
},
|
57 |
+
],
|
58 |
+
layerSectionStart: 405,
|
59 |
+
layerSectionEnd: 406,
|
60 |
+
name: 'Group 16',
|
61 |
+
_options: {
|
62 |
+
dialogOptions: 'dontDisplay',
|
63 |
+
},
|
64 |
+
},
|
65 |
+
],
|
66 |
+
{
|
67 |
+
synchronousExecution: true,
|
68 |
+
modalBehavior: 'execute',
|
69 |
+
}
|
70 |
+
)
|
71 |
+
|
72 |
+
console.log('makeGroupCommand: ', result)
|
73 |
+
|
74 |
+
return result
|
75 |
+
}
|
76 |
+
async function createEmptyGroup(name = 'New Group') {
|
77 |
+
let groupLayer
|
78 |
+
await executeAsModal(async () => {
|
79 |
+
await makeGroupCommand()
|
80 |
+
groupLayer = app.activeDocument.activeLayers[0]
|
81 |
+
groupLayer.name = name
|
82 |
+
})
|
83 |
+
console.log('groupLayer:', groupLayer)
|
84 |
+
return groupLayer
|
85 |
+
}
|
86 |
+
|
87 |
+
async function moveToGroupCommand(to_index, layerIDs) {
|
88 |
+
const batchPlay = require('photoshop').action.batchPlay
|
89 |
+
console.log('to_index:', to_index)
|
90 |
+
console.log('layerIDs:', layerIDs)
|
91 |
+
|
92 |
+
const result = await batchPlay(
|
93 |
+
[
|
94 |
+
{
|
95 |
+
_obj: 'move',
|
96 |
+
_target: [
|
97 |
+
{
|
98 |
+
_ref: 'layer',
|
99 |
+
_enum: 'ordinal',
|
100 |
+
_value: 'targetEnum',
|
101 |
+
},
|
102 |
+
],
|
103 |
+
to: {
|
104 |
+
_ref: 'layer',
|
105 |
+
_index: to_index,
|
106 |
+
},
|
107 |
+
adjustment: false,
|
108 |
+
version: 5,
|
109 |
+
layerID: layerIDs,
|
110 |
+
_options: {
|
111 |
+
dialogOptions: 'dontDisplay',
|
112 |
+
},
|
113 |
+
},
|
114 |
+
],
|
115 |
+
{
|
116 |
+
synchronousExecution: true,
|
117 |
+
modalBehavior: 'execute',
|
118 |
+
}
|
119 |
+
)
|
120 |
+
}
|
121 |
+
function MoveToGroupExe(toIndex, layerIDs) {
|
122 |
+
try {
|
123 |
+
executeAsModal(async () => {
|
124 |
+
await moveToGroupCommand(toIndex, layerIDs)
|
125 |
+
})
|
126 |
+
} catch (e) {
|
127 |
+
console.warn('executeCommand error:', e)
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
async function getIndexCommand(layer_id) {
|
132 |
+
const idx = batchPlay(
|
133 |
+
[
|
134 |
+
{
|
135 |
+
_obj: 'get',
|
136 |
+
_target: [
|
137 |
+
{
|
138 |
+
_property: 'itemIndex',
|
139 |
+
},
|
140 |
+
{
|
141 |
+
_ref: 'layer',
|
142 |
+
// _name: 'myGroup'
|
143 |
+
_id: layer_id,
|
144 |
+
},
|
145 |
+
],
|
146 |
+
_options: {
|
147 |
+
dialogOptions: 'dontDisplay',
|
148 |
+
},
|
149 |
+
},
|
150 |
+
],
|
151 |
+
{ synchronousExecution: true }
|
152 |
+
)[0]['itemIndex']
|
153 |
+
console.log('index:', idx)
|
154 |
+
return idx
|
155 |
+
}
|
156 |
+
|
157 |
+
async function getLayerIndex(layer_id) {
|
158 |
+
const { executeAsModal } = require('photoshop').core
|
159 |
+
try {
|
160 |
+
let index
|
161 |
+
await executeAsModal(async () => {
|
162 |
+
index = await getIndexCommand(layer_id)
|
163 |
+
console.log('getIndex: ', index)
|
164 |
+
})
|
165 |
+
return index
|
166 |
+
} catch (e) {
|
167 |
+
console.warn('getIndex error:', e)
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
async function unselectActiveLayers() {
|
172 |
+
const layers = await app.activeDocument.activeLayers
|
173 |
+
for (layer of layers) {
|
174 |
+
layer.selected = false
|
175 |
+
}
|
176 |
+
}
|
177 |
+
async function unselectActiveLayersExe() {
|
178 |
+
await executeAsModal(async () => {
|
179 |
+
await unselectActiveLayers()
|
180 |
+
})
|
181 |
+
}
|
182 |
+
async function selectLayers(layers) {
|
183 |
+
await unselectActiveLayers()
|
184 |
+
for (layer of layers) {
|
185 |
+
try {
|
186 |
+
if (layer) {
|
187 |
+
const is_visible = layer.visible // don't change the visibility when selecting the layer
|
188 |
+
layer.selected = true
|
189 |
+
layer.visible = is_visible
|
190 |
+
}
|
191 |
+
} catch (e) {
|
192 |
+
console.warn(e)
|
193 |
+
}
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
async function setVisibleExe(layer, is_visible) {
|
198 |
+
try {
|
199 |
+
await executeAsModal(async () => {
|
200 |
+
layer.visible = is_visible
|
201 |
+
})
|
202 |
+
} catch (e) {
|
203 |
+
console.warn(e)
|
204 |
+
}
|
205 |
+
}
|
206 |
+
async function selectLayersExe(layers) {
|
207 |
+
await executeAsModal(async () => {
|
208 |
+
await selectLayers(layers)
|
209 |
+
})
|
210 |
+
}
|
211 |
+
async function selectGroup(layer) {
|
212 |
+
await unselectActiveLayers()
|
213 |
+
layer.parent.selected = true
|
214 |
+
}
|
215 |
+
async function collapseGroup(layer) {
|
216 |
+
await selectGroup(layer)
|
217 |
+
await app.activeDocument.activeLayers[0].merge()
|
218 |
+
}
|
219 |
+
|
220 |
+
async function createMaskCommand() {
|
221 |
+
const batchPlay = require('photoshop').action.batchPlay
|
222 |
+
|
223 |
+
const result = await batchPlay(
|
224 |
+
[
|
225 |
+
{
|
226 |
+
_obj: 'make',
|
227 |
+
new: {
|
228 |
+
_class: 'channel',
|
229 |
+
},
|
230 |
+
at: {
|
231 |
+
_ref: 'channel',
|
232 |
+
_enum: 'channel',
|
233 |
+
_value: 'mask',
|
234 |
+
},
|
235 |
+
using: {
|
236 |
+
_enum: 'userMaskEnabled',
|
237 |
+
_value: 'revealSelection',
|
238 |
+
},
|
239 |
+
_options: {
|
240 |
+
dialogOptions: 'dontDisplay',
|
241 |
+
},
|
242 |
+
},
|
243 |
+
],
|
244 |
+
{
|
245 |
+
synchronousExecution: true,
|
246 |
+
modalBehavior: 'execute',
|
247 |
+
}
|
248 |
+
)
|
249 |
+
}
|
250 |
+
|
251 |
+
async function createMaskExe() {
|
252 |
+
const { executeAsModal } = require('photoshop').core
|
253 |
+
await executeAsModal(createMaskCommand)
|
254 |
+
}
|
255 |
+
|
256 |
+
//unselect the rectangular marquee selection area
|
257 |
+
async function unSelectMarqueeCommand() {
|
258 |
+
const batchPlay = require('photoshop').action.batchPlay
|
259 |
+
|
260 |
+
const result = await batchPlay(
|
261 |
+
[
|
262 |
+
{
|
263 |
+
_obj: 'set',
|
264 |
+
_target: [
|
265 |
+
{
|
266 |
+
_ref: 'channel',
|
267 |
+
_property: 'selection',
|
268 |
+
},
|
269 |
+
],
|
270 |
+
to: {
|
271 |
+
_enum: 'ordinal',
|
272 |
+
_value: 'none',
|
273 |
+
},
|
274 |
+
_options: {
|
275 |
+
dialogOptions: 'dontDisplay',
|
276 |
+
},
|
277 |
+
},
|
278 |
+
],
|
279 |
+
{
|
280 |
+
synchronousExecution: true,
|
281 |
+
modalBehavior: 'execute',
|
282 |
+
}
|
283 |
+
)
|
284 |
+
|
285 |
+
return result
|
286 |
+
}
|
287 |
+
async function unSelectMarqueeExe() {
|
288 |
+
try {
|
289 |
+
await executeAsModal(unSelectMarqueeCommand)
|
290 |
+
} catch (e) {
|
291 |
+
console.warn(e)
|
292 |
+
}
|
293 |
+
}
|
294 |
+
|
295 |
+
//REFACTOR: move to selection.js
|
296 |
+
async function selectMarqueeRectangularToolExe() {
|
297 |
+
async function selectMarqueeRectangularToolCommand() {
|
298 |
+
const result = await batchPlay(
|
299 |
+
[
|
300 |
+
{
|
301 |
+
_obj: 'select',
|
302 |
+
_target: [
|
303 |
+
{
|
304 |
+
_ref: 'marqueeRectTool',
|
305 |
+
},
|
306 |
+
],
|
307 |
+
_options: {
|
308 |
+
dialogOptions: 'dontDisplay',
|
309 |
+
},
|
310 |
+
},
|
311 |
+
],
|
312 |
+
{
|
313 |
+
synchronousExecution: true,
|
314 |
+
modalBehavior: 'execute',
|
315 |
+
}
|
316 |
+
)
|
317 |
+
return result
|
318 |
+
}
|
319 |
+
await executeAsModal(async () => {
|
320 |
+
await selectMarqueeRectangularToolCommand()
|
321 |
+
})
|
322 |
+
}
|
323 |
+
|
324 |
+
async function promptForMarqueeTool() {
|
325 |
+
console.warn('promptForMarqueeTool is deprecated use Notification class')(
|
326 |
+
async () => {
|
327 |
+
const r1 = await dialog_box.prompt(
|
328 |
+
'Please Select a Rectangular Area',
|
329 |
+
'You Forgot to select a Rectangular Area',
|
330 |
+
['Cancel', 'Rectangular Marquee']
|
331 |
+
)
|
332 |
+
if ((r1 || 'Rectangular Marquee') !== 'Rectangular Marquee') {
|
333 |
+
/* cancelled or No */
|
334 |
+
console.log('cancel')
|
335 |
+
} else {
|
336 |
+
/* Yes */
|
337 |
+
console.log('Rectangular Marquee')
|
338 |
+
selectMarqueeRectangularToolExe()
|
339 |
+
}
|
340 |
+
}
|
341 |
+
)()
|
342 |
+
}
|
343 |
+
|
344 |
+
async function selectLayerChannelCommand() {
|
345 |
+
// const result = await batchPlay(
|
346 |
+
// [
|
347 |
+
// {
|
348 |
+
// _obj: 'set',
|
349 |
+
// _target: [
|
350 |
+
// {
|
351 |
+
// _ref: 'channel',
|
352 |
+
// _property: 'selection'
|
353 |
+
// }
|
354 |
+
// ],
|
355 |
+
// to: {
|
356 |
+
// _ref: [
|
357 |
+
// {
|
358 |
+
// _ref: 'channel',
|
359 |
+
// _enum: 'channel',
|
360 |
+
// _value: 'transparencyEnum'
|
361 |
+
// },
|
362 |
+
// {
|
363 |
+
// _ref: 'layer',
|
364 |
+
// _name: 'Group 5'
|
365 |
+
// }
|
366 |
+
// ]
|
367 |
+
// },
|
368 |
+
// _options: {
|
369 |
+
// dialogOptions: 'dontDisplay'
|
370 |
+
// }
|
371 |
+
// }
|
372 |
+
// ],
|
373 |
+
// {
|
374 |
+
// synchronousExecution: false,
|
375 |
+
// modalBehavior: 'execute'
|
376 |
+
// }
|
377 |
+
// )
|
378 |
+
const batchPlay = require('photoshop').action.batchPlay
|
379 |
+
|
380 |
+
const result = await batchPlay(
|
381 |
+
[
|
382 |
+
{
|
383 |
+
_obj: 'set',
|
384 |
+
_target: [
|
385 |
+
{
|
386 |
+
_ref: 'channel',
|
387 |
+
_property: 'selection',
|
388 |
+
},
|
389 |
+
],
|
390 |
+
to: {
|
391 |
+
_ref: 'channel',
|
392 |
+
_enum: 'channel',
|
393 |
+
_value: 'transparencyEnum',
|
394 |
+
},
|
395 |
+
_options: {
|
396 |
+
dialogOptions: 'dontDisplay',
|
397 |
+
},
|
398 |
+
},
|
399 |
+
],
|
400 |
+
{
|
401 |
+
synchronousExecution: true,
|
402 |
+
modalBehavior: 'execute',
|
403 |
+
}
|
404 |
+
)
|
405 |
+
}
|
406 |
+
|
407 |
+
async function getSelectionInfoCommand() {
|
408 |
+
// console.warn('getSelectionInfoCommand is deprecated use SelectionInfoDesc')
|
409 |
+
const result = await batchPlay(
|
410 |
+
[
|
411 |
+
{
|
412 |
+
_obj: 'get',
|
413 |
+
_target: [
|
414 |
+
{
|
415 |
+
_property: 'selection',
|
416 |
+
},
|
417 |
+
{
|
418 |
+
_ref: 'document',
|
419 |
+
_id: app.activeDocument._id,
|
420 |
+
},
|
421 |
+
],
|
422 |
+
_options: {
|
423 |
+
dialogOptions: 'dontDisplay',
|
424 |
+
},
|
425 |
+
},
|
426 |
+
],
|
427 |
+
{
|
428 |
+
synchronousExecution: true,
|
429 |
+
modalBehavior: 'execute',
|
430 |
+
}
|
431 |
+
)
|
432 |
+
|
433 |
+
return result
|
434 |
+
}
|
435 |
+
|
436 |
+
function isSelectionValid(selection) {
|
437 |
+
// console.warn(
|
438 |
+
// 'isSelectionValid is deprecated use selection.isSelectionValid instead'
|
439 |
+
// )
|
440 |
+
if (
|
441 |
+
selection && // check if the selection is defined
|
442 |
+
selection.hasOwnProperty('left') &&
|
443 |
+
selection.hasOwnProperty('right') &&
|
444 |
+
selection.hasOwnProperty('top') &&
|
445 |
+
selection.hasOwnProperty('bottom')
|
446 |
+
) {
|
447 |
+
return true
|
448 |
+
}
|
449 |
+
|
450 |
+
return false
|
451 |
+
}
|
452 |
+
|
453 |
+
async function getSelectionInfoExe() {
|
454 |
+
// console.log('getSelectionInfo was called')
|
455 |
+
// console.warn(
|
456 |
+
// 'getSelectionInfoExe is deprecated use selection.getSelectionInfoExe instead'
|
457 |
+
// )
|
458 |
+
try {
|
459 |
+
const selection = (await executeAsModal(getSelectionInfoCommand))[0]
|
460 |
+
.selection
|
461 |
+
|
462 |
+
if (isSelectionValid(selection)) {
|
463 |
+
let selection_info = {
|
464 |
+
left: selection.left._value,
|
465 |
+
right: selection.right._value,
|
466 |
+
bottom: selection.bottom._value,
|
467 |
+
top: selection.top._value,
|
468 |
+
height: selection.bottom._value - selection.top._value,
|
469 |
+
width: selection.right._value - selection.left._value,
|
470 |
+
}
|
471 |
+
// console.dir({selection_info})
|
472 |
+
return selection_info
|
473 |
+
}
|
474 |
+
} catch (e) {
|
475 |
+
console.warn('selection info error', e)
|
476 |
+
}
|
477 |
+
}
|
478 |
+
|
479 |
+
async function reSelectMarqueeCommand(selectionInfo) {
|
480 |
+
const result = await batchPlay(
|
481 |
+
[
|
482 |
+
{
|
483 |
+
_obj: 'set',
|
484 |
+
_target: [
|
485 |
+
{
|
486 |
+
_ref: 'channel',
|
487 |
+
_property: 'selection',
|
488 |
+
},
|
489 |
+
],
|
490 |
+
to: {
|
491 |
+
_obj: 'rectangle',
|
492 |
+
top: {
|
493 |
+
_unit: 'pixelsUnit',
|
494 |
+
_value: selectionInfo.top,
|
495 |
+
},
|
496 |
+
left: {
|
497 |
+
_unit: 'pixelsUnit',
|
498 |
+
_value: selectionInfo.left,
|
499 |
+
},
|
500 |
+
bottom: {
|
501 |
+
_unit: 'pixelsUnit',
|
502 |
+
_value: selectionInfo.bottom,
|
503 |
+
},
|
504 |
+
right: {
|
505 |
+
_unit: 'pixelsUnit',
|
506 |
+
_value: selectionInfo.right,
|
507 |
+
},
|
508 |
+
},
|
509 |
+
_options: {
|
510 |
+
dialogOptions: 'dontDisplay',
|
511 |
+
},
|
512 |
+
},
|
513 |
+
],
|
514 |
+
{
|
515 |
+
synchronousExecution: true,
|
516 |
+
modalBehavior: 'execute',
|
517 |
+
}
|
518 |
+
)
|
519 |
+
}
|
520 |
+
async function reSelectMarqueeExe(selectionInfo) {
|
521 |
+
try {
|
522 |
+
if (isSelectionValid(selectionInfo)) {
|
523 |
+
//only try to reactivate the selection area if it is valid
|
524 |
+
await executeAsModal(async () => {
|
525 |
+
await reSelectMarqueeCommand(selectionInfo)
|
526 |
+
})
|
527 |
+
}
|
528 |
+
} catch (e) {
|
529 |
+
console.warn(e)
|
530 |
+
}
|
531 |
+
}
|
532 |
+
|
533 |
+
async function snapshot_layer() {
|
534 |
+
let psAction = require('photoshop').action
|
535 |
+
// const ids = (await app.activeDocument.activeLayers).map(layer => layer.id)
|
536 |
+
const ids = await app.activeDocument.layers.map((layer) => layer.id)
|
537 |
+
let command = [
|
538 |
+
// Select All Layers current layer
|
539 |
+
{
|
540 |
+
_obj: 'selectAllLayers',
|
541 |
+
_target: [
|
542 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
543 |
+
],
|
544 |
+
},
|
545 |
+
// Duplicate current layer
|
546 |
+
// {"ID":[459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513],"_obj":"duplicate","_target":[{"_enum":"ordinal","_ref":"layer","_value":"targetEnum"}],"version":5},
|
547 |
+
{
|
548 |
+
ID: ids,
|
549 |
+
_obj: 'duplicate',
|
550 |
+
_target: [
|
551 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
552 |
+
],
|
553 |
+
// version: 5
|
554 |
+
},
|
555 |
+
|
556 |
+
// Merge Layers
|
557 |
+
{ _obj: 'mergeLayersNew' },
|
558 |
+
// Make
|
559 |
+
{
|
560 |
+
_obj: 'make',
|
561 |
+
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
562 |
+
new: { _class: 'channel' },
|
563 |
+
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
564 |
+
},
|
565 |
+
// Set Selection
|
566 |
+
{
|
567 |
+
_obj: 'set',
|
568 |
+
_target: [{ _property: 'selection', _ref: 'channel' }],
|
569 |
+
to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
570 |
+
},
|
571 |
+
]
|
572 |
+
const result = await psAction.batchPlay(command, {
|
573 |
+
synchronousExecution: true,
|
574 |
+
modalBehavior: 'execute',
|
575 |
+
})
|
576 |
+
console.log('snapshot_layer: result: ', result)
|
577 |
+
return result
|
578 |
+
}
|
579 |
+
async function snapshot_layer_new() {
|
580 |
+
//similar to snapshot_layer() but fixes the problem with smart effects
|
581 |
+
|
582 |
+
let psAction = require('photoshop').action
|
583 |
+
|
584 |
+
const ids = await app.activeDocument.layers.map((layer) => layer.id)
|
585 |
+
const selection_info = await getSelectionInfoExe()
|
586 |
+
|
587 |
+
let create_snapshot_layer_command = [
|
588 |
+
// Select All Layers current layer
|
589 |
+
{
|
590 |
+
_obj: 'selectAllLayers',
|
591 |
+
_target: [
|
592 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
593 |
+
],
|
594 |
+
},
|
595 |
+
// Duplicate current layer
|
596 |
+
|
597 |
+
{
|
598 |
+
ID: ids,
|
599 |
+
_obj: 'duplicate',
|
600 |
+
_target: [
|
601 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
602 |
+
],
|
603 |
+
// version: 5
|
604 |
+
},
|
605 |
+
|
606 |
+
// Merge Layers
|
607 |
+
{ _obj: 'mergeLayersNew' },
|
608 |
+
]
|
609 |
+
const result = await psAction.batchPlay(create_snapshot_layer_command, {
|
610 |
+
synchronousExecution: true,
|
611 |
+
modalBehavior: 'execute',
|
612 |
+
})
|
613 |
+
await reSelectMarqueeExe(selection_info) //reselect the selection area for the mask
|
614 |
+
//make a mask of the selection area
|
615 |
+
const make_mask_command = [
|
616 |
+
// Make
|
617 |
+
{
|
618 |
+
_obj: 'make',
|
619 |
+
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
620 |
+
new: { _class: 'channel' },
|
621 |
+
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
622 |
+
},
|
623 |
+
// // Set Selection
|
624 |
+
// {
|
625 |
+
// _obj: 'set',
|
626 |
+
// _target: [{ _property: 'selection', _ref: 'channel' }],
|
627 |
+
// to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
628 |
+
// },
|
629 |
+
]
|
630 |
+
const result_2 = await psAction.batchPlay(make_mask_command, {
|
631 |
+
synchronousExecution: true,
|
632 |
+
modalBehavior: 'execute',
|
633 |
+
})
|
634 |
+
await reSelectMarqueeExe(selection_info) //reselect the selection area again so we don't break other functionality
|
635 |
+
|
636 |
+
console.log('snapshot_layer: result: ', result)
|
637 |
+
return result
|
638 |
+
}
|
639 |
+
|
640 |
+
async function snapshot_layerExe() {
|
641 |
+
try {
|
642 |
+
await executeAsModal(
|
643 |
+
async () => {
|
644 |
+
await snapshot_layer_new()
|
645 |
+
},
|
646 |
+
{
|
647 |
+
commandName: 'Action Commands',
|
648 |
+
}
|
649 |
+
)
|
650 |
+
} catch (e) {
|
651 |
+
console.error(e)
|
652 |
+
}
|
653 |
+
}
|
654 |
+
|
655 |
+
async function snapshot_layer_no_slide() {
|
656 |
+
let psAction = require('photoshop').action
|
657 |
+
// const ids = (await app.activeDocument.activeLayers).map(layer => layer.id)
|
658 |
+
const ids = await app.activeDocument.layers.map((layer) => layer.id)
|
659 |
+
let command = [
|
660 |
+
// Select All Layers current layer
|
661 |
+
{
|
662 |
+
_obj: 'selectAllLayers',
|
663 |
+
_target: [
|
664 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
665 |
+
],
|
666 |
+
},
|
667 |
+
// Duplicate current layer
|
668 |
+
// {"ID":[459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513],"_obj":"duplicate","_target":[{"_enum":"ordinal","_ref":"layer","_value":"targetEnum"}],"version":5},
|
669 |
+
{
|
670 |
+
ID: ids,
|
671 |
+
_obj: 'duplicate',
|
672 |
+
_target: [
|
673 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
674 |
+
],
|
675 |
+
// version: 5
|
676 |
+
},
|
677 |
+
|
678 |
+
// // Merge Layers
|
679 |
+
// { _obj: 'mergeLayersNew' },
|
680 |
+
// // Make
|
681 |
+
// {
|
682 |
+
// _obj: 'make',
|
683 |
+
// at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
684 |
+
// new: { _class: 'channel' },
|
685 |
+
// using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
686 |
+
// },
|
687 |
+
// // Set Selection
|
688 |
+
// {
|
689 |
+
// _obj: 'set',
|
690 |
+
// _target: [{ _property: 'selection', _ref: 'channel' }],
|
691 |
+
// to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
692 |
+
// },
|
693 |
+
]
|
694 |
+
const result = await psAction.batchPlay(command, {
|
695 |
+
synchronousExecution: true,
|
696 |
+
modalBehavior: 'execute',
|
697 |
+
})
|
698 |
+
console.log('snapshot_layer: result: ', result)
|
699 |
+
return result
|
700 |
+
}
|
701 |
+
|
702 |
+
async function snapshot_layer_no_slide_Exe() {
|
703 |
+
try {
|
704 |
+
await executeAsModal(
|
705 |
+
async () => {
|
706 |
+
await snapshot_layer_no_slide()
|
707 |
+
},
|
708 |
+
{
|
709 |
+
commandName: 'Action Commands',
|
710 |
+
}
|
711 |
+
)
|
712 |
+
} catch (e) {
|
713 |
+
console.error(e)
|
714 |
+
}
|
715 |
+
}
|
716 |
+
|
717 |
+
// await runModalFunction();
|
718 |
+
|
719 |
+
async function fillAndGroup() {
|
720 |
+
let result
|
721 |
+
let psAction = require('photoshop').action
|
722 |
+
|
723 |
+
// let newCommand =[
|
724 |
+
// // snapshotLayer
|
725 |
+
|
726 |
+
// // makeGroupCommand
|
727 |
+
|
728 |
+
// // Make fill layer
|
729 |
+
// {"_obj":"make","_target":[{"_ref":"contentLayer"}],"using":{"_obj":"contentLayer","type":{"_obj":"solidColorLayer","color":{"_obj":"RGBColor","blue":255.0,"grain":255.0,"red":255.0}}}},
|
730 |
+
|
731 |
+
// ]
|
732 |
+
|
733 |
+
let command = [
|
734 |
+
// Make fill layer
|
735 |
+
{
|
736 |
+
_obj: 'make',
|
737 |
+
_target: [{ _ref: 'contentLayer' }],
|
738 |
+
using: {
|
739 |
+
_obj: 'contentLayer',
|
740 |
+
type: {
|
741 |
+
_obj: 'solidColorLayer',
|
742 |
+
color: {
|
743 |
+
_obj: 'RGBColor',
|
744 |
+
blue: 255.0,
|
745 |
+
grain: 255.0,
|
746 |
+
red: 255.0,
|
747 |
+
},
|
748 |
+
},
|
749 |
+
},
|
750 |
+
},
|
751 |
+
// Move current layer
|
752 |
+
// {"_obj":"move","_target":[{"_enum":"ordinal","_ref":"layer","_value":"targetEnum"}],"adjustment":false,"layerID":[17],"to":{"_index":7,"_ref":"layer"},"version":5},
|
753 |
+
// Select layer “Layer 4 copy”
|
754 |
+
// {"_obj":"select","_target":[{"_name":"Layer 4 copy","_ref":"layer"}],"layerID":[17,15],"makeVisible":false,"selectionModifier":{"_enum":"selectionModifierType","_value":"addToSelectionContinuous"}},
|
755 |
+
// Make Group
|
756 |
+
// {"_obj":"make","_target":[{"_ref":"layerSection"}],"from":{"_enum":"ordinal","_ref":"layer","_value":"targetEnum"},"layerSectionEnd":19,"layerSectionStart":18,"name":"Group 1"}
|
757 |
+
]
|
758 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
759 |
+
await makeGroupCommand()
|
760 |
+
const groupLayer = app.activeDocument.activeLayers[0]
|
761 |
+
result = await psAction.batchPlay(command, {})
|
762 |
+
const fillLayer = app.activeDocument.activeLayers[0]
|
763 |
+
snapshotLayer.moveAbove(fillLayer)
|
764 |
+
// await app.activeDocument.activeLayers[0].moveAbove()
|
765 |
+
// const layerIDs = []
|
766 |
+
// const to_index = await getIndexCommand(groupLayer.id)
|
767 |
+
// await moveToGroupCommand(to_index, layerIDs)
|
768 |
+
}
|
769 |
+
|
770 |
+
async function fillAndGroupExe() {
|
771 |
+
await require('photoshop').core.executeAsModal(fillAndGroup, {
|
772 |
+
commandName: 'Action Commands',
|
773 |
+
})
|
774 |
+
}
|
775 |
+
async function fastSnapshot() {
|
776 |
+
await snapshot_layerExe()
|
777 |
+
await fillAndGroupExe()
|
778 |
+
}
|
779 |
+
|
780 |
+
function layerToFileName(layer, session_id) {
|
781 |
+
file_name = `${layer.name}_${layer.id}_${session_id}`
|
782 |
+
return file_name
|
783 |
+
}
|
784 |
+
function layerNameToFileName(layer_name, layer_id, session_id) {
|
785 |
+
file_name = `${layer_name}_${layer_id}_${session_id}`
|
786 |
+
return file_name
|
787 |
+
}
|
788 |
+
|
789 |
+
async function silentSetInitImage(layer, session_id) {
|
790 |
+
try {
|
791 |
+
const html_manip = require('./utility/html_manip')
|
792 |
+
const io = require('./utility/io')
|
793 |
+
// const layer = await app.activeDocument.activeLayers[0]
|
794 |
+
const old_name = layer.name
|
795 |
+
|
796 |
+
// image_name = await app.activeDocument.activeLayers[0].name
|
797 |
+
|
798 |
+
//convert layer name to a file name
|
799 |
+
let image_name = layerNameToFileName(old_name, layer.id, session_id)
|
800 |
+
image_name = `${image_name}.png`
|
801 |
+
|
802 |
+
//the width and height of the exported image
|
803 |
+
const width = html_manip.getWidth()
|
804 |
+
const height = html_manip.getHeight()
|
805 |
+
|
806 |
+
//get the selection from the canvas as base64 png, make sure to resize to the width and height slider
|
807 |
+
const selectionInfo = g_generation_session.selectionInfo
|
808 |
+
// const base64_image = await io.IO.getSelectionFromCanvasAsBase64Silent(
|
809 |
+
// selectionInfo,
|
810 |
+
// true,
|
811 |
+
// width,
|
812 |
+
// height
|
813 |
+
// )
|
814 |
+
|
815 |
+
const use_silent_mode = html_manip.getUseSilentMode()
|
816 |
+
// if (use_silent_mode) {
|
817 |
+
// base64_image = await io.IO.getSelectionFromCanvasAsBase64Silent(
|
818 |
+
// selectionInfo,
|
819 |
+
// true,
|
820 |
+
// width,
|
821 |
+
// height
|
822 |
+
// )
|
823 |
+
// } else {
|
824 |
+
// base64_image = await io.IO.getSelectionFromCanvasAsBase64NonSilent(
|
825 |
+
// layer,
|
826 |
+
|
827 |
+
// image_name,
|
828 |
+
// width,
|
829 |
+
// height
|
830 |
+
// )
|
831 |
+
// }
|
832 |
+
const base64_image =
|
833 |
+
await io.IO.getSelectionFromCanvasAsBase64Interface(
|
834 |
+
width,
|
835 |
+
height,
|
836 |
+
layer,
|
837 |
+
selectionInfo,
|
838 |
+
true,
|
839 |
+
use_silent_mode,
|
840 |
+
image_name
|
841 |
+
)
|
842 |
+
//save base64 as file in the init_images directory
|
843 |
+
const init_entry = await getInitImagesDir()
|
844 |
+
await io.IO.base64PngToPngFile(base64_image, init_entry, image_name)
|
845 |
+
|
846 |
+
g_init_image_name = image_name
|
847 |
+
console.log(image_name)
|
848 |
+
|
849 |
+
const path = `${g_init_images_dir}/${image_name}`
|
850 |
+
|
851 |
+
//store the base64 init image and also set it as the active/latest init image
|
852 |
+
g_generation_session.base64initImages[path] = base64_image
|
853 |
+
g_generation_session.activeBase64InitImage = base64_image
|
854 |
+
|
855 |
+
const init_src = base64ToSrc(g_generation_session.activeBase64InitImage)
|
856 |
+
html_manip.setInitImageSrc(init_src)
|
857 |
+
|
858 |
+
return (image_info = { name: image_name, base64: base64_image })
|
859 |
+
} catch (e) {
|
860 |
+
console.error(`psapi.js silentSetInitImage error:, ${e}`)
|
861 |
+
}
|
862 |
+
}
|
863 |
+
async function silentSetInitImageMask(layer, session_id) {
|
864 |
+
try {
|
865 |
+
const html_manip = require('./utility/html_manip')
|
866 |
+
|
867 |
+
// const layer = await app.activeDocument.activeLayers[0]
|
868 |
+
const old_name = layer.name
|
869 |
+
|
870 |
+
image_name = layerNameToFileName(old_name, layer.id, session_id)
|
871 |
+
image_name = `${image_name}.png`
|
872 |
+
const width = html_manip.getWidth()
|
873 |
+
const height = html_manip.getHeight()
|
874 |
+
|
875 |
+
//get the selection from the canvas as base64 png, make sure to resize to the width and height slider
|
876 |
+
const selectionInfo = g_generation_session.selectionInfo
|
877 |
+
|
878 |
+
const use_silent_mode = html_manip.getUseSilentMode()
|
879 |
+
|
880 |
+
const base64_image =
|
881 |
+
await io.IO.getSelectionFromCanvasAsBase64Interface(
|
882 |
+
width,
|
883 |
+
height,
|
884 |
+
layer,
|
885 |
+
selectionInfo,
|
886 |
+
true,
|
887 |
+
use_silent_mode,
|
888 |
+
image_name
|
889 |
+
)
|
890 |
+
|
891 |
+
//save base64 as file in the init_images directory
|
892 |
+
const init_entry = await getInitImagesDir()
|
893 |
+
await io.IO.base64PngToPngFile(base64_image, init_entry, image_name)
|
894 |
+
|
895 |
+
g_init_image_mask_name = image_name // this is the name we will send to the server
|
896 |
+
|
897 |
+
console.log(image_name)
|
898 |
+
|
899 |
+
const path = `${g_init_images_dir}/${image_name}`
|
900 |
+
g_generation_session.base64maskImage[path] = base64_image
|
901 |
+
g_generation_session.activeBase64MaskImage = base64_image
|
902 |
+
|
903 |
+
const mask_src = base64ToSrc(g_generation_session.activeBase64MaskImage)
|
904 |
+
html_manip.setInitImageMaskSrc(mask_src)
|
905 |
+
return (image_info = { name: image_name, base64: base64_image })
|
906 |
+
} catch (e) {
|
907 |
+
console.error(`psapi.js setInitImageMask error: `, e)
|
908 |
+
}
|
909 |
+
}
|
910 |
+
async function setInitImage(layer, session_id) {
|
911 |
+
try {
|
912 |
+
const html_manip = require('./utility/html_manip')
|
913 |
+
// const layer = await app.activeDocument.activeLayers[0]
|
914 |
+
const old_name = layer.name
|
915 |
+
|
916 |
+
// image_name = await app.activeDocument.activeLayers[0].name
|
917 |
+
|
918 |
+
//convert layer name to a file name
|
919 |
+
let image_name = layerNameToFileName(old_name, layer.id, session_id)
|
920 |
+
image_name = `${image_name}.png`
|
921 |
+
|
922 |
+
//the width and height of the exported image
|
923 |
+
const width = html_manip.getWidth()
|
924 |
+
const height = html_manip.getHeight()
|
925 |
+
const image_buffer = await newExportPng(
|
926 |
+
layer,
|
927 |
+
image_name,
|
928 |
+
width,
|
929 |
+
height
|
930 |
+
)
|
931 |
+
const base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
|
932 |
+
//send the base64 to the server to save the file in the desired directory
|
933 |
+
await sdapi.requestSavePng(base64_image, image_name)
|
934 |
+
|
935 |
+
g_init_image_name = image_name
|
936 |
+
console.log(image_name)
|
937 |
+
|
938 |
+
const image_src = await sdapi.getInitImage(g_init_image_name)
|
939 |
+
let ini_image_element = document.getElementById('init_image')
|
940 |
+
ini_image_element.src = image_src
|
941 |
+
const path = `${g_init_images_dir}/${image_name}`
|
942 |
+
|
943 |
+
g_generation_session.base64initImages[path] = base64_image
|
944 |
+
g_generation_session.activeBase64InitImage =
|
945 |
+
g_generation_session.base64initImages[path]
|
946 |
+
|
947 |
+
const init_src = base64ToSrc(g_generation_session.activeBase64InitImage)
|
948 |
+
html_manip.setInitImageSrc(init_src)
|
949 |
+
|
950 |
+
return (image_info = { name: image_name, base64: base64_image })
|
951 |
+
} catch (e) {
|
952 |
+
console.error(`psapi.js setInitImage error:, ${e}`)
|
953 |
+
}
|
954 |
+
}
|
955 |
+
async function setInitImageMask(layer, session_id) {
|
956 |
+
try {
|
957 |
+
const html_manip = require('./utility/html_manip')
|
958 |
+
|
959 |
+
// const layer = await app.activeDocument.activeLayers[0]
|
960 |
+
const old_name = layer.name
|
961 |
+
|
962 |
+
//get the active layer name
|
963 |
+
// image_name = await app.activeDocument.activeLayers[0].name
|
964 |
+
// image_name = layerNameToFileName(old_name,layer.id,random_session_id)
|
965 |
+
image_name = layerNameToFileName(old_name, layer.id, session_id)
|
966 |
+
image_name = `${image_name}.png`
|
967 |
+
const width = html_manip.getWidth()
|
968 |
+
const height = html_manip.getHeight()
|
969 |
+
image_buffer = await newExportPng(layer, image_name, width, height)
|
970 |
+
g_init_image_mask_name = image_name // this is the name we will send to the server
|
971 |
+
// g_init_mask_layer = layer
|
972 |
+
// g_mask_related_layers = {}
|
973 |
+
|
974 |
+
console.log(image_name)
|
975 |
+
base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
|
976 |
+
//send the base64 to the server to save the file in the desired directory
|
977 |
+
await sdapi.requestSavePng(base64_image, image_name)
|
978 |
+
|
979 |
+
const image_src = await sdapi.getInitImage(g_init_image_mask_name) // we should replace this with getInitImagePath which return path to local disk
|
980 |
+
const ini_image_mask_element =
|
981 |
+
document.getElementById('init_image_mask')
|
982 |
+
ini_image_mask_element.src = image_src
|
983 |
+
ini_image_mask_element.dataset.layer_id = layer.id
|
984 |
+
|
985 |
+
const path = `${g_init_images_dir}/${image_name}`
|
986 |
+
g_generation_session.base64maskImage[path] = base64_image
|
987 |
+
g_generation_session.activeBase64MaskImage =
|
988 |
+
g_generation_session.base64maskImage[path]
|
989 |
+
//create viewer init image obj
|
990 |
+
{
|
991 |
+
}
|
992 |
+
// return image_name
|
993 |
+
const mask_src = base64ToSrc(g_generation_session.activeBase64MaskImage)
|
994 |
+
html_manip.setInitImageMaskSrc(mask_src)
|
995 |
+
return (image_info = { name: image_name, base64: base64_image })
|
996 |
+
} catch (e) {
|
997 |
+
console.error(`psapi.js setInitImageMask error: `, e)
|
998 |
+
}
|
999 |
+
}
|
1000 |
+
|
1001 |
+
// remove the generated mask related layers from the canvas and "layers" panel
|
1002 |
+
|
1003 |
+
// async function cleanSnapAndFill(layers){
|
1004 |
+
// // we can delete this function and use cleanLayers() instead
|
1005 |
+
// //delete init image group
|
1006 |
+
// //delete init image (snapshot layer)
|
1007 |
+
// //delete fill layer
|
1008 |
+
|
1009 |
+
// for (layer of layers){
|
1010 |
+
// try{
|
1011 |
+
|
1012 |
+
// await executeAsModal(async ()=>{await layer.delete()})
|
1013 |
+
// }catch(e){
|
1014 |
+
// console.warn("cleanSnapAndFill, issue deleting a layer",e)
|
1015 |
+
// }
|
1016 |
+
// }
|
1017 |
+
// return []
|
1018 |
+
// }
|
1019 |
+
|
1020 |
+
async function cleanLayers(layers) {
|
1021 |
+
// g_init_image_related_layers = {}
|
1022 |
+
// g_mask_related_layers = {}
|
1023 |
+
// await loadViewerImages()// we should move loadViewerImages to a new file viewer.js
|
1024 |
+
console.log('cleanLayers() -> layers:', layers)
|
1025 |
+
for (layer of layers) {
|
1026 |
+
try {
|
1027 |
+
if (layer_util.Layer.doesLayerExist(layer)) {
|
1028 |
+
await executeAsModal(async () => {
|
1029 |
+
await layer.delete()
|
1030 |
+
})
|
1031 |
+
}
|
1032 |
+
} catch (e) {
|
1033 |
+
console.warn(
|
1034 |
+
'warning attempting to a delete layer,layer.name: ',
|
1035 |
+
layer.name,
|
1036 |
+
layer,
|
1037 |
+
e
|
1038 |
+
)
|
1039 |
+
continue
|
1040 |
+
}
|
1041 |
+
}
|
1042 |
+
return []
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
// async function cleanLayersOutpaint(layers){
|
1046 |
+
// //delete group mask layer
|
1047 |
+
// //delete mask layer
|
1048 |
+
// //delete group init image layer
|
1049 |
+
// //delete init image layer (snapshot layer)
|
1050 |
+
// //delete fill layer
|
1051 |
+
|
1052 |
+
// for (layer of layers){
|
1053 |
+
// try {
|
1054 |
+
// await executeAsModal(async ()=>{await layer.delete()})}
|
1055 |
+
// catch(e){
|
1056 |
+
// console.warn("warning attempting to a delete layer: ",e)
|
1057 |
+
// }
|
1058 |
+
// }
|
1059 |
+
|
1060 |
+
// return []
|
1061 |
+
// }
|
1062 |
+
// async function cleanLayersInpaint(layers){
|
1063 |
+
// //delete group mask layer
|
1064 |
+
// //delete white mask layer
|
1065 |
+
// //delete the black fill layer
|
1066 |
+
// //delete init image layer (snapshot layer)
|
1067 |
+
|
1068 |
+
// for (layer of layers){
|
1069 |
+
// await executeAsModal(async ()=>{await layer.delete()})
|
1070 |
+
// }
|
1071 |
+
|
1072 |
+
// return []
|
1073 |
+
// }
|
1074 |
+
async function createClippingMaskExe() {
|
1075 |
+
const batchPlay = require('photoshop').action.batchPlay
|
1076 |
+
|
1077 |
+
async function createClippingMaskCommand() {
|
1078 |
+
const result = await batchPlay(
|
1079 |
+
[
|
1080 |
+
{
|
1081 |
+
_obj: 'make',
|
1082 |
+
new: {
|
1083 |
+
_class: 'channel',
|
1084 |
+
},
|
1085 |
+
at: {
|
1086 |
+
_ref: 'channel',
|
1087 |
+
_enum: 'channel',
|
1088 |
+
_value: 'mask',
|
1089 |
+
},
|
1090 |
+
using: {
|
1091 |
+
_enum: 'userMaskEnabled',
|
1092 |
+
_value: 'revealSelection',
|
1093 |
+
},
|
1094 |
+
_options: {
|
1095 |
+
dialogOptions: 'dontDisplay',
|
1096 |
+
},
|
1097 |
+
},
|
1098 |
+
],
|
1099 |
+
{
|
1100 |
+
synchronousExecution: true,
|
1101 |
+
modalBehavior: 'execute',
|
1102 |
+
}
|
1103 |
+
)
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
await executeAsModal(async () => {
|
1107 |
+
await createClippingMaskCommand()
|
1108 |
+
})
|
1109 |
+
}
|
1110 |
+
//REFACTOR: delete and replace with getSelectionInfoExe()
|
1111 |
+
async function checkIfSelectionAreaIsActive() {
|
1112 |
+
try {
|
1113 |
+
let isSelectionAreaValid = await getSelectionInfoExe()
|
1114 |
+
return isSelectionAreaValid
|
1115 |
+
} catch (e) {
|
1116 |
+
console.warn(e)
|
1117 |
+
}
|
1118 |
+
}
|
1119 |
+
async function saveUniqueDocumentIdExe(new_id) {
|
1120 |
+
const batchPlay = require('photoshop').action.batchPlay
|
1121 |
+
|
1122 |
+
async function saveUniqueDocumentIdCommand() {
|
1123 |
+
const batchPlay = require('photoshop').action.batchPlay
|
1124 |
+
|
1125 |
+
const result = await batchPlay(
|
1126 |
+
[
|
1127 |
+
{
|
1128 |
+
_obj: 'set',
|
1129 |
+
_target: [
|
1130 |
+
{
|
1131 |
+
_ref: 'property',
|
1132 |
+
_property: 'fileInfo',
|
1133 |
+
},
|
1134 |
+
{
|
1135 |
+
_ref: 'document',
|
1136 |
+
_enum: 'ordinal',
|
1137 |
+
_value: 'targetEnum',
|
1138 |
+
},
|
1139 |
+
],
|
1140 |
+
to: {
|
1141 |
+
_obj: 'fileInfo',
|
1142 |
+
caption: new_id,
|
1143 |
+
keywords: [new_id],
|
1144 |
+
},
|
1145 |
+
_options: {
|
1146 |
+
dialogOptions: 'dontDisplay',
|
1147 |
+
},
|
1148 |
+
},
|
1149 |
+
],
|
1150 |
+
{
|
1151 |
+
synchronousExecution: true,
|
1152 |
+
modalBehavior: 'execute',
|
1153 |
+
}
|
1154 |
+
)
|
1155 |
+
}
|
1156 |
+
|
1157 |
+
await executeAsModal(async () => {
|
1158 |
+
await saveUniqueDocumentIdCommand()
|
1159 |
+
})
|
1160 |
+
}
|
1161 |
+
|
1162 |
+
async function readUniqueDocumentIdExe() {
|
1163 |
+
const batchPlay = require('photoshop').action.batchPlay
|
1164 |
+
|
1165 |
+
async function readUniqueDocumentIdCommand() {
|
1166 |
+
const batchPlay = require('photoshop').action.batchPlay
|
1167 |
+
|
1168 |
+
const result = await batchPlay(
|
1169 |
+
[
|
1170 |
+
{
|
1171 |
+
_obj: 'get',
|
1172 |
+
_target: [
|
1173 |
+
{
|
1174 |
+
_ref: 'property',
|
1175 |
+
_property: 'fileInfo',
|
1176 |
+
},
|
1177 |
+
{
|
1178 |
+
_ref: 'document',
|
1179 |
+
_enum: 'ordinal',
|
1180 |
+
_value: 'targetEnum',
|
1181 |
+
},
|
1182 |
+
],
|
1183 |
+
// to: {
|
1184 |
+
// _obj: 'fileInfo',
|
1185 |
+
// caption: new_id,
|
1186 |
+
// keywords: [new_id]
|
1187 |
+
// },
|
1188 |
+
_options: {
|
1189 |
+
dialogOptions: 'dontDisplay',
|
1190 |
+
},
|
1191 |
+
},
|
1192 |
+
],
|
1193 |
+
{
|
1194 |
+
synchronousExecution: true,
|
1195 |
+
modalBehavior: 'execute',
|
1196 |
+
}
|
1197 |
+
)
|
1198 |
+
console.log('readUniqueDocumentIdCommand: result ', result)
|
1199 |
+
return result
|
1200 |
+
}
|
1201 |
+
|
1202 |
+
let uniqueDocumentId = ''
|
1203 |
+
try {
|
1204 |
+
await executeAsModal(async () => {
|
1205 |
+
uniqueDocumentId = (await readUniqueDocumentIdCommand())[0].fileInfo
|
1206 |
+
.caption
|
1207 |
+
if (typeof uniqueDocumentId === 'string') {
|
1208 |
+
uniqueDocumentId = uniqueDocumentId.trim()
|
1209 |
+
}
|
1210 |
+
})
|
1211 |
+
} catch (e) {
|
1212 |
+
console.warn('readUniqueDocumentIdExe: ', e)
|
1213 |
+
uniqueDocumentId = ''
|
1214 |
+
}
|
1215 |
+
|
1216 |
+
return uniqueDocumentId
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
const readPng = async (image_name) => {
|
1220 |
+
//it will save the document then read it. store it in memory
|
1221 |
+
// image_name = 'test.png'
|
1222 |
+
try {
|
1223 |
+
let img_buffer
|
1224 |
+
await executeAsModal(
|
1225 |
+
async (control) => {
|
1226 |
+
const folder = await fs.getTemporaryFolder()
|
1227 |
+
// const pluginFolder = await fs.getPluginFolder()
|
1228 |
+
|
1229 |
+
// let init_images_dir = await pluginFolder.getEntry(
|
1230 |
+
// './server/python_server/init_images'
|
1231 |
+
// )
|
1232 |
+
|
1233 |
+
const file = await folder.createFile(image_name, {
|
1234 |
+
overwrite: true,
|
1235 |
+
})
|
1236 |
+
|
1237 |
+
const currentDocument = app.activeDocument
|
1238 |
+
await currentDocument.saveAs.png(
|
1239 |
+
file,
|
1240 |
+
// {
|
1241 |
+
// compression: 6,
|
1242 |
+
// },
|
1243 |
+
null,
|
1244 |
+
true
|
1245 |
+
)
|
1246 |
+
|
1247 |
+
const arrayBuffer = await file.read({ format: formats.binary })
|
1248 |
+
// console.log(arrayBuffer, 'arrayBuffer') ;
|
1249 |
+
img_buffer = arrayBuffer
|
1250 |
+
},
|
1251 |
+
|
1252 |
+
{ commandName: 'readPng' }
|
1253 |
+
)
|
1254 |
+
|
1255 |
+
return img_buffer
|
1256 |
+
} catch (e) {
|
1257 |
+
console.warn(e)
|
1258 |
+
}
|
1259 |
+
}
|
1260 |
+
|
1261 |
+
async function selectCanvasCommand() {
|
1262 |
+
// const result = await batchPlay(
|
1263 |
+
// [
|
1264 |
+
// {
|
1265 |
+
// _obj: "historyStateChanged",
|
1266 |
+
// documentID: 1044,
|
1267 |
+
// ID: 1058,
|
1268 |
+
// name: "Select Canvas",
|
1269 |
+
// hasEnglish: true,
|
1270 |
+
// itemIndex: 7,
|
1271 |
+
// commandID: 1017,
|
1272 |
+
// _options: {
|
1273 |
+
// dialogOptions: "dontDisplay"
|
1274 |
+
// }
|
1275 |
+
// }
|
1276 |
+
// ],{
|
1277 |
+
// synchronousExecution: true,
|
1278 |
+
// modalBehavior: "execute"
|
1279 |
+
// });
|
1280 |
+
|
1281 |
+
const result = await batchPlay(
|
1282 |
+
[
|
1283 |
+
{
|
1284 |
+
_obj: 'set',
|
1285 |
+
_target: [
|
1286 |
+
{
|
1287 |
+
_ref: 'channel',
|
1288 |
+
_property: 'selection',
|
1289 |
+
},
|
1290 |
+
],
|
1291 |
+
to: {
|
1292 |
+
_enum: 'ordinal',
|
1293 |
+
_value: 'allEnum',
|
1294 |
+
},
|
1295 |
+
_options: {
|
1296 |
+
dialogOptions: 'dontDisplay',
|
1297 |
+
},
|
1298 |
+
},
|
1299 |
+
],
|
1300 |
+
{
|
1301 |
+
synchronousExecution: true,
|
1302 |
+
modalBehavior: 'execute',
|
1303 |
+
}
|
1304 |
+
)
|
1305 |
+
|
1306 |
+
return result
|
1307 |
+
}
|
1308 |
+
async function selectCanvasExe() {
|
1309 |
+
await executeAsModal(
|
1310 |
+
async () => {
|
1311 |
+
await selectCanvasCommand()
|
1312 |
+
},
|
1313 |
+
{ commandName: 'selectCanvasExe' }
|
1314 |
+
)
|
1315 |
+
}
|
1316 |
+
async function newExportPng(layer, image_name, width, height) {
|
1317 |
+
//store layers we want to export in variables
|
1318 |
+
// let layerToExports =
|
1319 |
+
// create new document
|
1320 |
+
// duplicate the layers to the new documnet
|
1321 |
+
//select the layer channel selectLayerChannelCommand
|
1322 |
+
//document.crop
|
1323 |
+
//export using readPng()
|
1324 |
+
|
1325 |
+
try {
|
1326 |
+
//get the active layers
|
1327 |
+
// const layersToExport = app.activeDocument.activeLayers
|
1328 |
+
|
1329 |
+
//create new document
|
1330 |
+
// let exportDoc = await executeAsModal(app.documents.add)
|
1331 |
+
let exportDoc
|
1332 |
+
const makeDoc = async () => {
|
1333 |
+
let exportDoc = await app.documents.add({
|
1334 |
+
width: width,
|
1335 |
+
height: height,
|
1336 |
+
resolution: await app.activeDocument.resolution,
|
1337 |
+
mode: 'RGBColorMode',
|
1338 |
+
fill: 'transparent',
|
1339 |
+
})
|
1340 |
+
}
|
1341 |
+
let image_buffer
|
1342 |
+
await executeAsModal(
|
1343 |
+
async () => {
|
1344 |
+
// await app.documents.add()
|
1345 |
+
await makeDoc()
|
1346 |
+
exportDoc = app.activeDocument
|
1347 |
+
|
1348 |
+
console.log('exportDoc.id: ', exportDoc.id)
|
1349 |
+
// for (layer of layersToExport) {
|
1350 |
+
|
1351 |
+
console.log(layer.id)
|
1352 |
+
const dupLayer = await layer.duplicate(exportDoc)
|
1353 |
+
await selectLayers([dupLayer])
|
1354 |
+
// await selectLayerChannelCommand()
|
1355 |
+
await selectCanvasExe()
|
1356 |
+
const canvas_selection_info = await getSelectionInfoExe()
|
1357 |
+
await layerToSelection(canvas_selection_info)
|
1358 |
+
// const selection_info = await getSelectionInfoExe()
|
1359 |
+
// await exportDoc.crop(selection_info)
|
1360 |
+
// export_image_name = `${layer.name}.png`
|
1361 |
+
image_buffer = await readPng(image_name)
|
1362 |
+
await exportDoc.closeWithoutSaving()
|
1363 |
+
},
|
1364 |
+
{ commandName: 'NewExportPng' }
|
1365 |
+
)
|
1366 |
+
return image_buffer
|
1367 |
+
// }
|
1368 |
+
} catch (e) {
|
1369 |
+
console.error(`newExportPng error: ,${e}`)
|
1370 |
+
}
|
1371 |
+
}
|
1372 |
+
|
1373 |
+
async function tempExportPng(layer, image_name, width, height) {
|
1374 |
+
//store layers we want to export in variables
|
1375 |
+
// let layerToExports =
|
1376 |
+
// create new document
|
1377 |
+
// duplicate the layers to the new documnet
|
1378 |
+
//select the layer channel selectLayerChannelCommand
|
1379 |
+
//document.crop
|
1380 |
+
//export using readPng()
|
1381 |
+
|
1382 |
+
try {
|
1383 |
+
//get the active layers
|
1384 |
+
// const layersToExport = app.activeDocument.activeLayers
|
1385 |
+
|
1386 |
+
//create new document
|
1387 |
+
// let exportDoc = await executeAsModal(app.documents.add)
|
1388 |
+
let exportDoc
|
1389 |
+
const makeDoc = async () => {
|
1390 |
+
let exportDoc = await app.documents.add({
|
1391 |
+
width: width,
|
1392 |
+
height: height,
|
1393 |
+
resolution: await app.activeDocument.resolution,
|
1394 |
+
mode: 'RGBColorMode',
|
1395 |
+
fill: 'transparent',
|
1396 |
+
})
|
1397 |
+
}
|
1398 |
+
await executeAsModal(
|
1399 |
+
async () => {
|
1400 |
+
// await app.documents.add()
|
1401 |
+
await makeDoc()
|
1402 |
+
exportDoc = app.activeDocument
|
1403 |
+
|
1404 |
+
console.log('exportDoc.id: ', exportDoc.id)
|
1405 |
+
// for (layer of layersToExport) {
|
1406 |
+
|
1407 |
+
console.log(layer.id)
|
1408 |
+
const dupLayer = await layer.duplicate(exportDoc)
|
1409 |
+
await selectLayers([dupLayer])
|
1410 |
+
// await selectLayerChannelCommand()
|
1411 |
+
await selectCanvasExe()
|
1412 |
+
const canvas_selection_info = await getSelectionInfoExe()
|
1413 |
+
await layerToSelection(canvas_selection_info)
|
1414 |
+
// const selection_info = await getSelectionInfoExe()
|
1415 |
+
// await exportDoc.crop(selection_info)
|
1416 |
+
// export_image_name = `${layer.name}.png`
|
1417 |
+
await readPng(image_name)
|
1418 |
+
await exportDoc.closeWithoutSaving()
|
1419 |
+
},
|
1420 |
+
{ commandName: 'tempExportPng' }
|
1421 |
+
)
|
1422 |
+
// }
|
1423 |
+
} catch (e) {
|
1424 |
+
console.error(`newExportPng error: ,${e}`)
|
1425 |
+
}
|
1426 |
+
}
|
1427 |
+
async function mergeVisibleCommand() {
|
1428 |
+
const result = await batchPlay(
|
1429 |
+
[
|
1430 |
+
{
|
1431 |
+
_obj: 'mergeVisible',
|
1432 |
+
duplicate: true,
|
1433 |
+
_isCommand: true,
|
1434 |
+
// "_options": {
|
1435 |
+
// // "dialogOptions": "dontDisplay"
|
1436 |
+
// }
|
1437 |
+
},
|
1438 |
+
],
|
1439 |
+
{
|
1440 |
+
synchronousExecution: true,
|
1441 |
+
modalBehavior: 'execute',
|
1442 |
+
}
|
1443 |
+
)
|
1444 |
+
|
1445 |
+
return result
|
1446 |
+
}
|
1447 |
+
|
1448 |
+
async function mergeVisibleExe() {
|
1449 |
+
await executeAsModal(async () => {
|
1450 |
+
await mergeVisibleCommand()
|
1451 |
+
})
|
1452 |
+
}
|
1453 |
+
|
1454 |
+
async function layerToSelection(selection_info) {
|
1455 |
+
//store active layer for later
|
1456 |
+
|
1457 |
+
try {
|
1458 |
+
//Store selection info
|
1459 |
+
//unSelect
|
1460 |
+
//move layer
|
1461 |
+
//scale layer
|
1462 |
+
//Select from selection info
|
1463 |
+
// let selection_info = await getSelectionInfo()
|
1464 |
+
|
1465 |
+
console.log('selection_info:', selection_info)
|
1466 |
+
|
1467 |
+
console.log('unSelect')
|
1468 |
+
|
1469 |
+
function getLayerSize(layer) {
|
1470 |
+
console.log('layer.bounds:')
|
1471 |
+
console.dir(layer.bounds)
|
1472 |
+
const bounds = layer.bounds
|
1473 |
+
const height = bounds.bottom - bounds.top
|
1474 |
+
const width = bounds.right - bounds.left
|
1475 |
+
return {
|
1476 |
+
height: height,
|
1477 |
+
width: width,
|
1478 |
+
left: bounds.left,
|
1479 |
+
right: bounds.right,
|
1480 |
+
top: bounds.top,
|
1481 |
+
bottom: bounds.bottom,
|
1482 |
+
}
|
1483 |
+
}
|
1484 |
+
//scale layer
|
1485 |
+
async function scaleLayer(layer, selection_info) {
|
1486 |
+
console.log('scaleLayer got called')
|
1487 |
+
// const activeLayer = getActiveLayer()
|
1488 |
+
// const activeLayer = await app.activeDocument.activeLayers[0]
|
1489 |
+
|
1490 |
+
let layer_info = getLayerSize(layer)
|
1491 |
+
scale_x_ratio = (selection_info.width / layer_info.width) * 100
|
1492 |
+
scale_y_ratio = (selection_info.height / layer_info.height) * 100
|
1493 |
+
console.log('scale_x_y_ratio:', scale_x_ratio, scale_y_ratio)
|
1494 |
+
await layer.scale(scale_x_ratio, scale_y_ratio)
|
1495 |
+
}
|
1496 |
+
|
1497 |
+
async function moveLayerExe(layerToMove, selection_info) {
|
1498 |
+
let layer_info = getLayerSize(layerToMove)
|
1499 |
+
top_dist = layer_info.top - selection_info.top
|
1500 |
+
left_dist = layer_info.left - selection_info.left
|
1501 |
+
await layerToMove.translate(-left_dist, -top_dist)
|
1502 |
+
}
|
1503 |
+
// const activeLayer = await getActiveLayer()
|
1504 |
+
|
1505 |
+
//store all active layers
|
1506 |
+
const activeLayers = await app.activeDocument.activeLayers
|
1507 |
+
await unSelectMarqueeExe()
|
1508 |
+
// await executeAsModal(unSelect, {'commandName': 'unSelect'})
|
1509 |
+
// await executeAsModal(scaleLayer, {'commandName': 'scaleLayer'})
|
1510 |
+
|
1511 |
+
await executeAsModal(
|
1512 |
+
async () => {
|
1513 |
+
for (let layer of activeLayers) {
|
1514 |
+
await selectLayers([layer]) // make sure only one layer is selected
|
1515 |
+
await scaleLayer(layer, selection_info) //scale to selection size
|
1516 |
+
await moveLayerExe(layer, selection_info) //move to selection
|
1517 |
+
}
|
1518 |
+
},
|
1519 |
+
{ commandName: 'moveLayerExe' }
|
1520 |
+
)
|
1521 |
+
|
1522 |
+
// await reselect(selection_info)
|
1523 |
+
} catch (e) {
|
1524 |
+
console.warn(e)
|
1525 |
+
}
|
1526 |
+
}
|
1527 |
+
function executeCommandExe(commandFunc) {
|
1528 |
+
try {
|
1529 |
+
;(async () => {
|
1530 |
+
await executeAsModal(async () => {
|
1531 |
+
await commandFunc()
|
1532 |
+
})
|
1533 |
+
})()
|
1534 |
+
} catch (e) {
|
1535 |
+
console.warn(e)
|
1536 |
+
}
|
1537 |
+
}
|
1538 |
+
async function executeDescExe(Desc) {
|
1539 |
+
try {
|
1540 |
+
await executeAsModal(async () => {
|
1541 |
+
const result = await batchPlay([Desc], {
|
1542 |
+
synchronousExecution: true,
|
1543 |
+
modalBehavior: 'execute',
|
1544 |
+
})
|
1545 |
+
console.log(result)
|
1546 |
+
})
|
1547 |
+
} catch (e) {
|
1548 |
+
console.warn(e)
|
1549 |
+
}
|
1550 |
+
}
|
1551 |
+
module.exports = {
|
1552 |
+
createSolidLayer,
|
1553 |
+
createEmptyGroup,
|
1554 |
+
getLayerIndex,
|
1555 |
+
collapseGroup,
|
1556 |
+
moveToGroupCommand,
|
1557 |
+
MoveToGroupExe,
|
1558 |
+
selectLayers,
|
1559 |
+
selectLayersExe,
|
1560 |
+
unselectActiveLayers,
|
1561 |
+
unselectActiveLayersExe,
|
1562 |
+
createMaskExe,
|
1563 |
+
getSelectionInfoExe,
|
1564 |
+
unSelectMarqueeCommand,
|
1565 |
+
unSelectMarqueeExe,
|
1566 |
+
reSelectMarqueeExe,
|
1567 |
+
selectLayerChannelCommand,
|
1568 |
+
snapshot_layer,
|
1569 |
+
snapshot_layerExe,
|
1570 |
+
fillAndGroupExe,
|
1571 |
+
fastSnapshot,
|
1572 |
+
setInitImage,
|
1573 |
+
setInitImageMask,
|
1574 |
+
|
1575 |
+
layerToFileName,
|
1576 |
+
layerNameToFileName,
|
1577 |
+
// cleanLayersOutpaint,
|
1578 |
+
// cleanLayersInpaint,
|
1579 |
+
// cleanSnapAndFill,
|
1580 |
+
cleanLayers,
|
1581 |
+
createClippingMaskExe,
|
1582 |
+
checkIfSelectionAreaIsActive,
|
1583 |
+
selectMarqueeRectangularToolExe,
|
1584 |
+
promptForMarqueeTool,
|
1585 |
+
saveUniqueDocumentIdExe,
|
1586 |
+
readUniqueDocumentIdExe,
|
1587 |
+
newExportPng,
|
1588 |
+
mergeVisibleExe,
|
1589 |
+
selectCanvasExe,
|
1590 |
+
layerToSelection,
|
1591 |
+
isSelectionValid,
|
1592 |
+
snapshot_layer_no_slide_Exe,
|
1593 |
+
setVisibleExe,
|
1594 |
+
silentSetInitImage,
|
1595 |
+
silentSetInitImageMask,
|
1596 |
+
executeCommandExe,
|
1597 |
+
executeDescExe,
|
1598 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/requirements.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
anyio==3.6.2
|
2 |
+
asyncio==3.4.3
|
3 |
+
certifi==2022.12.7
|
4 |
+
charset-normalizer==2.1.1
|
5 |
+
click==8.1.3
|
6 |
+
fastapi==0.88.0
|
7 |
+
h11==0.14.0
|
8 |
+
httpcore==0.16.3
|
9 |
+
httptools==0.5.0
|
10 |
+
httpx==0.23.1
|
11 |
+
idna==3.4
|
12 |
+
Pillow==9.3.0
|
13 |
+
pydantic==1.10.2
|
14 |
+
python-dotenv==0.21.0
|
15 |
+
PyYAML==6.0
|
16 |
+
requests==2.28.1
|
17 |
+
rfc3986==1.5.0
|
18 |
+
sniffio==1.3.0
|
19 |
+
starlette==0.22.0
|
20 |
+
typing_extensions==4.4.0
|
21 |
+
urllib3==1.26.13
|
22 |
+
uvicorn==0.20.0
|
23 |
+
# uvloop==0.17.0
|
24 |
+
watchfiles==0.18.1
|
25 |
+
websockets==10.4
|
26 |
+
duckduckgo_search==3.7.1
|
Auto-Photoshop-StableDiffusion-Plugin/scripts/__pycache__/main.cpython-310.pyc
ADDED
Binary file (2.4 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/scripts/__pycache__/test.cpython-310.pyc
ADDED
Binary file (181 Bytes). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/scripts/main.py
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules import scripts, processing, shared, images, devices, ui, lowvram
|
2 |
+
import gradio
|
3 |
+
import requests
|
4 |
+
import time
|
5 |
+
import PIL.Image
|
6 |
+
import base64
|
7 |
+
import io
|
8 |
+
import os.path
|
9 |
+
import numpy
|
10 |
+
import itertools
|
11 |
+
import gradio as gr
|
12 |
+
import torch
|
13 |
+
from fastapi import FastAPI
|
14 |
+
from fastapi import APIRouter, Request
|
15 |
+
from fastapi.responses import StreamingResponse
|
16 |
+
from modules import script_callbacks, scripts, shared
|
17 |
+
|
18 |
+
|
19 |
+
import sys
|
20 |
+
python_server_dir = 'server/python_server'
|
21 |
+
extension_dir = scripts.basedir()
|
22 |
+
python_server_full_path = os.path.join(extension_dir,python_server_dir)
|
23 |
+
print("python_server_full_path: ",python_server_full_path)
|
24 |
+
sys.path.insert(0, python_server_full_path)
|
25 |
+
import search
|
26 |
+
import img2imgapi
|
27 |
+
import serverMain
|
28 |
+
|
29 |
+
router = APIRouter()
|
30 |
+
|
31 |
+
# @router.get("/config")
|
32 |
+
# async def get_state():
|
33 |
+
# print("hello get /config auto-photoshop-sd")
|
34 |
+
# res = "hello get /config auto-photoshop-sd"
|
35 |
+
# return {"res": res}
|
36 |
+
|
37 |
+
@router.post('/search/image/')
|
38 |
+
async def searchImage(request:Request):
|
39 |
+
try:
|
40 |
+
json = await request.json()
|
41 |
+
except:
|
42 |
+
json = {}
|
43 |
+
|
44 |
+
|
45 |
+
try:
|
46 |
+
keywords = json.get('keywords','cute cats')
|
47 |
+
images = await search.imageSearch(keywords)
|
48 |
+
print(images)
|
49 |
+
|
50 |
+
|
51 |
+
return {"images":images}
|
52 |
+
except:
|
53 |
+
print("keywords",keywords)
|
54 |
+
# print(f'{request}')
|
55 |
+
return {"error": "error message: can't preform an image search"}
|
56 |
+
|
57 |
+
|
58 |
+
@router.post('/mask/expansion/')
|
59 |
+
async def maskExpansionHandler(request:Request):
|
60 |
+
try:
|
61 |
+
json = await request.json()
|
62 |
+
except:
|
63 |
+
json = {}
|
64 |
+
|
65 |
+
# print("mask expansion json :",json)
|
66 |
+
try:
|
67 |
+
# keywords = json.get('keywords','cute dogs')
|
68 |
+
base64_mask_image = json['mask']
|
69 |
+
mask_expansion = json['mask_expansion']
|
70 |
+
#convert base64 to img
|
71 |
+
|
72 |
+
await img2imgapi.base64ToPng(base64_mask_image,"original_mask.png")#save a copy of the mask
|
73 |
+
|
74 |
+
mask_image = img2imgapi.b64_2_img(base64_mask_image)
|
75 |
+
|
76 |
+
expanded_mask_img = img2imgapi.maskExpansion(mask_image,mask_expansion)
|
77 |
+
base64_expanded_mask_image = img2imgapi.img_2_b64(expanded_mask_img)
|
78 |
+
await img2imgapi.base64ToPng(base64_expanded_mask_image,"expanded_mask.png")#save a copy of the mask
|
79 |
+
|
80 |
+
|
81 |
+
return {"mask":base64_expanded_mask_image}
|
82 |
+
|
83 |
+
except:
|
84 |
+
# print("request",request)
|
85 |
+
raise Exception(f"couldn't preform mask expansion",json)
|
86 |
+
# return response
|
87 |
+
return {"error": "error message: can't preform an mask expansion"}
|
88 |
+
|
89 |
+
|
90 |
+
|
91 |
+
def on_app_started(demo: gr.Blocks, app: FastAPI):
|
92 |
+
# print("hello on_app_started auto-photoshop-plugin")
|
93 |
+
|
94 |
+
if shared.cmd_opts.api:
|
95 |
+
app.include_router(serverMain.router, prefix="/sdapi/auto-photoshop-sd", tags=['Auto Photoshop SD Plugin API'])
|
96 |
+
# app.include_router(router, prefix="/sdapi/auto-photoshop-sd", tags=['Auto Photoshop SD Plugin API'])
|
97 |
+
|
98 |
+
|
99 |
+
else:
|
100 |
+
print("COMMANDLINE_ARGS does not contain --api, API won't be mounted.")
|
101 |
+
|
102 |
+
# logger.warning("COMMANDLINE_ARGS does not contain --api, API won't be mounted.")
|
103 |
+
# if you wanted to do anything massive to the UI, you could modify demo, but why?
|
104 |
+
|
105 |
+
script_callbacks.on_app_started(on_app_started)
|
Auto-Photoshop-StableDiffusion-Plugin/scripts/test.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import sys
|
2 |
+
# sys.path.insert(0, 'server/python_server')
|
3 |
+
# import search
|
4 |
+
|
5 |
+
# print("hello test.py")
|
Auto-Photoshop-StableDiffusion-Plugin/sdapi_py_re.js
ADDED
@@ -0,0 +1,814 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const { getDummyBase64, getDummyBase64_2 } = require('./utility/dummy')
|
2 |
+
const { base64ToBase64Url } = require('./utility/general')
|
3 |
+
const { getExtensionType } = require('./utility/html_manip')
|
4 |
+
const py_re = require('./utility/sdapi/python_replacement')
|
5 |
+
const Enum = require('./enum')
|
6 |
+
const control_net = require('./utility/tab/control_net')
|
7 |
+
const api = require('./utility/api')
|
8 |
+
//javascript plugin can't read images from local directory so we send a request to local server to read the image file and send it back to plugin as image string base64
|
9 |
+
|
10 |
+
async function getInitImage(init_image_name) {
|
11 |
+
console.log('getInitImage(): get Init Image from the server :')
|
12 |
+
const payload = {
|
13 |
+
init_image_name: init_image_name,
|
14 |
+
}
|
15 |
+
|
16 |
+
// const full_url = 'http://127.0.0.1:8000/getInitImage/'
|
17 |
+
// console.log(full_url)
|
18 |
+
// console.log('getInitImage payload:', payload)
|
19 |
+
// let request = await fetch(full_url, {
|
20 |
+
// method: 'POST',
|
21 |
+
// headers: {
|
22 |
+
// Accept: 'application/json',
|
23 |
+
// 'Content-Type': 'application/json',
|
24 |
+
// },
|
25 |
+
// body: JSON.stringify(payload),
|
26 |
+
// // "body": payload
|
27 |
+
// })
|
28 |
+
|
29 |
+
// let json = await request.json()
|
30 |
+
|
31 |
+
// console.log('json:')
|
32 |
+
// console.dir(json)
|
33 |
+
// base64data = json.init_image_str
|
34 |
+
// image_src = `data:image/png;base64, ${base64data}`
|
35 |
+
console.warn('this function is deprecated!')
|
36 |
+
const image_src =
|
37 |
+
'https://im ages.pexels.com/photos/1386604/pexels-photo-1386604.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1'
|
38 |
+
return image_src
|
39 |
+
|
40 |
+
// console.log(img.src)
|
41 |
+
|
42 |
+
// let img_blob = await (await fetch(img.src)).blob()
|
43 |
+
// console.log("img_blob:")
|
44 |
+
// console.dir(img_blob)
|
45 |
+
}
|
46 |
+
//REFACTOR: move this function to io.js
|
47 |
+
async function requestSavePng(base64_image, image_name) {
|
48 |
+
try {
|
49 |
+
console.log('requestSavePng():')
|
50 |
+
|
51 |
+
const uniqueDocumentId = await getUniqueDocumentId()
|
52 |
+
const folder = `${uniqueDocumentId}/init_images`
|
53 |
+
const init_entry = await getInitImagesDir()
|
54 |
+
saveFileInSubFolder(base64_image, folder, image_name)
|
55 |
+
console.warn('this function is deprecated')
|
56 |
+
} catch (e) {
|
57 |
+
console.warn(e)
|
58 |
+
return {}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
async function requestTxt2Img(payload) {
|
62 |
+
try {
|
63 |
+
console.log('requestTxt2Img(): about to send a fetch request')
|
64 |
+
|
65 |
+
// const full_url = 'http://127.0.0.1:8000/txt2img/'
|
66 |
+
// console.log(full_url)
|
67 |
+
|
68 |
+
// let request = await fetch(full_url, {
|
69 |
+
// method: 'POST',
|
70 |
+
// headers: {
|
71 |
+
// Accept: 'application/json',
|
72 |
+
// 'Content-Type': 'application/json',
|
73 |
+
// },
|
74 |
+
// body: JSON.stringify(payload),
|
75 |
+
// // "body": payload
|
76 |
+
// })
|
77 |
+
|
78 |
+
// let json = await request.json()
|
79 |
+
let json = await py_re.txt2ImgRequest(payload)
|
80 |
+
console.log('requestTxt2Img json:', json)
|
81 |
+
|
82 |
+
return json
|
83 |
+
} catch (e) {
|
84 |
+
console.warn(e)
|
85 |
+
return {}
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
async function requestImg2Img(payload) {
|
90 |
+
console.log('requestImg2Img(): about to send a fetch request')
|
91 |
+
try {
|
92 |
+
// const full_url = 'http://127.0.0.1:8000/img2img/'
|
93 |
+
// console.log(full_url)
|
94 |
+
// console.log('requestImg2Img payload is: ', payload)
|
95 |
+
// let request = await fetch(full_url, {
|
96 |
+
// method: 'POST',
|
97 |
+
// headers: {
|
98 |
+
// Accept: 'application/json',
|
99 |
+
// 'Content-Type': 'application/json',
|
100 |
+
// },
|
101 |
+
// body: JSON.stringify(payload),
|
102 |
+
// // "body": payload
|
103 |
+
// })
|
104 |
+
|
105 |
+
// let json = await request.json()
|
106 |
+
let json = await py_re.img2ImgRequest(g_sd_url, payload)
|
107 |
+
console.log('requestImg2Img json:')
|
108 |
+
console.dir(json)
|
109 |
+
|
110 |
+
return json
|
111 |
+
} catch (e) {
|
112 |
+
console.warn(e)
|
113 |
+
return {}
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
async function requestProgress() {
|
118 |
+
let json = {}
|
119 |
+
try {
|
120 |
+
console.log('requestProgress: ')
|
121 |
+
|
122 |
+
const full_url = `${g_sd_url}/sdapi/v1/progress?skip_current_image=false`
|
123 |
+
let request = await fetch(full_url)
|
124 |
+
json = await request.json()
|
125 |
+
console.log('progress json:', json)
|
126 |
+
|
127 |
+
return json
|
128 |
+
} catch (e) {
|
129 |
+
console.warn(e)
|
130 |
+
// console.log('json: ', json)
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
async function requestGetModels() {
|
135 |
+
console.log('requestGetModels: ')
|
136 |
+
let json = []
|
137 |
+
const full_url = `${g_sd_url}/sdapi/v1/sd-models`
|
138 |
+
try {
|
139 |
+
let request = await fetch(full_url)
|
140 |
+
json = await request.json()
|
141 |
+
console.log('models json:')
|
142 |
+
console.dir(json)
|
143 |
+
} catch (e) {
|
144 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
145 |
+
}
|
146 |
+
return json
|
147 |
+
}
|
148 |
+
|
149 |
+
async function requestGetSamplers() {
|
150 |
+
let json = null
|
151 |
+
try {
|
152 |
+
console.log('requestGetSamplers: ')
|
153 |
+
|
154 |
+
const full_url = `${g_sd_url}/sdapi/v1/samplers`
|
155 |
+
let request = await fetch(full_url)
|
156 |
+
json = await request.json()
|
157 |
+
console.log('samplers json:', json)
|
158 |
+
} catch (e) {
|
159 |
+
console.warn(e)
|
160 |
+
}
|
161 |
+
return json
|
162 |
+
}
|
163 |
+
|
164 |
+
async function requestSwapModel(model_title) {
|
165 |
+
console.log('requestSwapModel: ')
|
166 |
+
// const full_url = 'http://127.0.0.1:8000/swapModel'
|
167 |
+
|
168 |
+
const full_url = `${g_sd_url}/sdapi/v1/options`
|
169 |
+
payload = {
|
170 |
+
sd_model_checkpoint: model_title,
|
171 |
+
}
|
172 |
+
let request = await fetch(full_url, {
|
173 |
+
method: 'POST',
|
174 |
+
headers: {
|
175 |
+
Accept: 'application/json',
|
176 |
+
'Content-Type': 'application/json',
|
177 |
+
},
|
178 |
+
body: JSON.stringify(payload),
|
179 |
+
// "body": payload
|
180 |
+
})
|
181 |
+
|
182 |
+
let json = await request.json()
|
183 |
+
|
184 |
+
console.log('models json:')
|
185 |
+
console.dir(json)
|
186 |
+
|
187 |
+
return json
|
188 |
+
}
|
189 |
+
|
190 |
+
async function requestInterrupt() {
|
191 |
+
const full_url = `${g_sd_url}/sdapi/v1/interrupt`
|
192 |
+
try {
|
193 |
+
console.log('requestInterrupt: ')
|
194 |
+
|
195 |
+
payload = ''
|
196 |
+
let request = await fetch(full_url, {
|
197 |
+
method: 'POST',
|
198 |
+
headers: {
|
199 |
+
Accept: 'application/json',
|
200 |
+
'Content-Type': 'application/json',
|
201 |
+
},
|
202 |
+
// body: JSON.stringify(payload)
|
203 |
+
// "body": payload
|
204 |
+
})
|
205 |
+
|
206 |
+
console.log('interrupt request:', request)
|
207 |
+
let json = await request.json()
|
208 |
+
|
209 |
+
return json
|
210 |
+
} catch (e) {
|
211 |
+
console.warn(e)
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
async function getVersionRequest() {
|
216 |
+
// version = "v0.0.0"
|
217 |
+
console.log('requestGetSamplers: ')
|
218 |
+
const current_version = g_version
|
219 |
+
// try {
|
220 |
+
// const full_url = 'http://127.0.0.1:8000/version'
|
221 |
+
// let request = await fetch(full_url)
|
222 |
+
// let json = await request.json()
|
223 |
+
// console.log('version json:', json)
|
224 |
+
// version = json['version']
|
225 |
+
|
226 |
+
// return version
|
227 |
+
// } catch (e) {
|
228 |
+
// console.warn(e)
|
229 |
+
// version = 'v0.0.0'
|
230 |
+
|
231 |
+
// return version
|
232 |
+
// }
|
233 |
+
return current_version
|
234 |
+
}
|
235 |
+
|
236 |
+
async function changeSdUrl(new_sd_url) {
|
237 |
+
// version = "v0.0.0"
|
238 |
+
console.log('changeSdUrl: new_sd_url:', new_sd_url)
|
239 |
+
try {
|
240 |
+
payload = {
|
241 |
+
sd_url: new_sd_url,
|
242 |
+
}
|
243 |
+
|
244 |
+
// const full_url = `${g_sd_url}/sd_url/`
|
245 |
+
// console.log('changeSdUrl: payload: ', payload)
|
246 |
+
// let request = await fetch(full_url, {
|
247 |
+
// method: 'POST',
|
248 |
+
// headers: {
|
249 |
+
// Accept: 'application/json',
|
250 |
+
// 'Content-Type': 'application/json',
|
251 |
+
// },
|
252 |
+
// body: JSON.stringify(payload),
|
253 |
+
// })
|
254 |
+
|
255 |
+
g_sd_url = new_sd_url
|
256 |
+
// console.log('changeSdUrl: request: ', request)
|
257 |
+
} catch (e) {
|
258 |
+
console.warn(e)
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
// function printTheJSONInPrettyFormat(json) {
|
263 |
+
// // var badJSON = document.getElementById('prettyJSONFormat').value;
|
264 |
+
// // var parseJSON = JSON.parse(badJSON);
|
265 |
+
// // var JSONInPrettyFormat = JSON.stringify(json, undefined, 4);
|
266 |
+
// // return
|
267 |
+
// }
|
268 |
+
async function loadHistory(uniqueDocumentId) {
|
269 |
+
let json = {}
|
270 |
+
try {
|
271 |
+
payload = {
|
272 |
+
uniqueDocumentId: uniqueDocumentId,
|
273 |
+
}
|
274 |
+
json = await py_re.loadHistory(payload)
|
275 |
+
// const full_url = 'http://127.0.0.1:8000/history/load'
|
276 |
+
|
277 |
+
// let request = await fetch(full_url, {
|
278 |
+
// method: 'POST',
|
279 |
+
// headers: {
|
280 |
+
// Accept: 'application/json',
|
281 |
+
// 'Content-Type': 'application/json',
|
282 |
+
// },
|
283 |
+
// body: JSON.stringify(payload),
|
284 |
+
// })
|
285 |
+
|
286 |
+
// json = await request.json()
|
287 |
+
// console.log('loadHistory:', json)
|
288 |
+
|
289 |
+
// console.log('loadPromptShortcut: request: ',request)
|
290 |
+
} catch (e) {
|
291 |
+
console.warn(e)
|
292 |
+
}
|
293 |
+
|
294 |
+
return [json['image_paths'], json['metadata_jsons'], json['base64_images']]
|
295 |
+
}
|
296 |
+
async function loadPromptShortcut() {
|
297 |
+
// console.log('loadPromptShortcut:')
|
298 |
+
let prompt_shortcut_json = {}
|
299 |
+
try {
|
300 |
+
// payload = {}
|
301 |
+
|
302 |
+
// const full_url = 'http://127.0.0.1:8000/prompt_shortcut/load'
|
303 |
+
|
304 |
+
// let request = await fetch(full_url, {
|
305 |
+
// method: 'POST',
|
306 |
+
// headers: {
|
307 |
+
// Accept: 'application/json',
|
308 |
+
// 'Content-Type': 'application/json',
|
309 |
+
// },
|
310 |
+
// body: JSON.stringify(payload),
|
311 |
+
// })
|
312 |
+
|
313 |
+
// json = await request.json()
|
314 |
+
prompt_shortcut_json = await py_re.loadPromptShortcut(
|
315 |
+
'prompt_shortcut.json'
|
316 |
+
)
|
317 |
+
console.log('loadPromptShortcut:', prompt_shortcut_json)
|
318 |
+
// console.log('loadPromptShortcut: request: ',request)
|
319 |
+
} catch (e) {
|
320 |
+
console.warn(e)
|
321 |
+
prompt_shortcut_json = {}
|
322 |
+
}
|
323 |
+
return prompt_shortcut_json
|
324 |
+
// return json['prompt_shortcut']
|
325 |
+
}
|
326 |
+
|
327 |
+
async function savePromptShortcut(prompt_shortcut) {
|
328 |
+
// console.log('loadPromptShortcut:')
|
329 |
+
let json = prompt_shortcut
|
330 |
+
try {
|
331 |
+
// payload = { prompt_shortcut: prompt_shortcut }
|
332 |
+
|
333 |
+
// const full_url = 'http://127.0.0.1:8000/prompt_shortcut/save'
|
334 |
+
|
335 |
+
// let request = await fetch(full_url, {
|
336 |
+
// method: 'POST',
|
337 |
+
// headers: {
|
338 |
+
// Accept: 'application/json',
|
339 |
+
// 'Content-Type': 'application/json',
|
340 |
+
// },
|
341 |
+
// body: JSON.stringify(payload),
|
342 |
+
// })
|
343 |
+
|
344 |
+
// json = await request.json()
|
345 |
+
await py_re.savePromptShortcut(json, 'prompt_shortcut.json')
|
346 |
+
console.log('savePromptShortcut:', json)
|
347 |
+
// console.log('loadPromptShortcut: request: ',request)
|
348 |
+
} catch (e) {
|
349 |
+
console.warn(e)
|
350 |
+
}
|
351 |
+
|
352 |
+
return json['prompt_shortcut']
|
353 |
+
}
|
354 |
+
async function setInpaintMaskWeight(value) {
|
355 |
+
const full_url = `${g_sd_url}/sdapi/v1/options`
|
356 |
+
try {
|
357 |
+
const payload = {
|
358 |
+
inpainting_mask_weight: value,
|
359 |
+
}
|
360 |
+
await fetch(full_url, {
|
361 |
+
method: 'POST',
|
362 |
+
headers: {
|
363 |
+
Accept: 'application/json',
|
364 |
+
'Content-Type': 'application/json',
|
365 |
+
},
|
366 |
+
body: JSON.stringify(payload),
|
367 |
+
})
|
368 |
+
} catch (e) {
|
369 |
+
console.warn(e)
|
370 |
+
}
|
371 |
+
}
|
372 |
+
|
373 |
+
async function requestGetConfig() {
|
374 |
+
console.log('requestGetConfig: ')
|
375 |
+
let json = []
|
376 |
+
const full_url = `${g_sd_url}/config`
|
377 |
+
try {
|
378 |
+
let request = await fetch(full_url)
|
379 |
+
json = await request.json()
|
380 |
+
console.log('models json:')
|
381 |
+
console.dir(json)
|
382 |
+
} catch (e) {
|
383 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
384 |
+
}
|
385 |
+
return json
|
386 |
+
}
|
387 |
+
async function requestGetOptions() {
|
388 |
+
console.log('requestGetOptions: ')
|
389 |
+
let json = null
|
390 |
+
const full_url = `${g_sd_url}/sdapi/v1/options`
|
391 |
+
try {
|
392 |
+
let request = await fetch(full_url)
|
393 |
+
if (request.status === 404) {
|
394 |
+
return null
|
395 |
+
}
|
396 |
+
|
397 |
+
json = await request.json()
|
398 |
+
console.log('models json:')
|
399 |
+
console.dir(json)
|
400 |
+
} catch (e) {
|
401 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
402 |
+
}
|
403 |
+
return json
|
404 |
+
}
|
405 |
+
|
406 |
+
async function imageSearch(keywords) {
|
407 |
+
let json = {}
|
408 |
+
const extension_url = py_re.getExtensionUrl()
|
409 |
+
|
410 |
+
const full_url = `${extension_url}/search/image/`
|
411 |
+
try {
|
412 |
+
payload = {
|
413 |
+
keywords: keywords,
|
414 |
+
}
|
415 |
+
|
416 |
+
let request = await fetch(full_url, {
|
417 |
+
method: 'POST',
|
418 |
+
headers: {
|
419 |
+
Accept: 'application/json',
|
420 |
+
'Content-Type': 'application/json',
|
421 |
+
},
|
422 |
+
body: JSON.stringify(payload),
|
423 |
+
})
|
424 |
+
|
425 |
+
json = await request.json()
|
426 |
+
console.log('imageSearch:', json)
|
427 |
+
|
428 |
+
return json['images']
|
429 |
+
} catch (e) {
|
430 |
+
console.warn(e)
|
431 |
+
}
|
432 |
+
return []
|
433 |
+
}
|
434 |
+
|
435 |
+
// async function requestHorde(payload) {
|
436 |
+
// payload = {
|
437 |
+
// prompt: 'string',
|
438 |
+
// params: {
|
439 |
+
// sampler_name: 'k_lms',
|
440 |
+
// toggles: [1, 4],
|
441 |
+
// cfg_scale: 5,
|
442 |
+
// denoising_strength: 0.75,
|
443 |
+
// seed: 'string',
|
444 |
+
// height: 512,
|
445 |
+
// width: 512,
|
446 |
+
// seed_variation: 1,
|
447 |
+
// post_processing: ['GFPGAN'],
|
448 |
+
// karras: false,
|
449 |
+
// tiling: false,
|
450 |
+
// steps: 30,
|
451 |
+
// n: 1,
|
452 |
+
// },
|
453 |
+
// nsfw: false,
|
454 |
+
// trusted_workers: true,
|
455 |
+
// censor_nsfw: false,
|
456 |
+
// workers: ['4c79ab19-8e6c-4054-83b3-773b7ce71ece'],
|
457 |
+
// models: ['stable_diffusion'],
|
458 |
+
// // source_image: 'string',
|
459 |
+
// // source_processing: 'img2img',
|
460 |
+
// // source_mask: 'string',
|
461 |
+
// r2: true,
|
462 |
+
// shared: false,
|
463 |
+
// }
|
464 |
+
// try {
|
465 |
+
// console.log('requestHorde():')
|
466 |
+
|
467 |
+
// const full_url = 'https://stablehorde.net/api/v2/generate/async'
|
468 |
+
// // const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
469 |
+
// console.log(full_url)
|
470 |
+
|
471 |
+
// let request = await fetch(full_url, {
|
472 |
+
// method: 'POST',
|
473 |
+
// headers: {
|
474 |
+
// Accept: 'application/json',
|
475 |
+
// 'Content-Type': 'application/json',
|
476 |
+
// apikey: '0000000000',
|
477 |
+
// // 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
478 |
+
// 'Client-Agent': 'unknown:0:unknown',
|
479 |
+
// },
|
480 |
+
// body: JSON.stringify(payload),
|
481 |
+
// })
|
482 |
+
|
483 |
+
// let json = await request.json()
|
484 |
+
// console.log('requestHorde json:', json)
|
485 |
+
|
486 |
+
// return json
|
487 |
+
// } catch (e) {
|
488 |
+
// console.warn(e)
|
489 |
+
// return {}
|
490 |
+
// }
|
491 |
+
// }
|
492 |
+
// async function requestHordeCheck(id) {
|
493 |
+
// try {
|
494 |
+
// console.log('requestHordeCheck():')
|
495 |
+
// const base_url = 'https://stablehorde.net/api/v2/generate/check'
|
496 |
+
|
497 |
+
// const full_url = `${base_url}/${id}`
|
498 |
+
// // const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
499 |
+
// console.log(full_url)
|
500 |
+
// const payload = {}
|
501 |
+
// let request = await fetch(full_url, {
|
502 |
+
// method: 'GET',
|
503 |
+
// headers: {
|
504 |
+
// Accept: 'application/json',
|
505 |
+
// 'Content-Type': 'application/json',
|
506 |
+
// // 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
507 |
+
// 'Client-Agent': 'unknown:0:unknown',
|
508 |
+
// },
|
509 |
+
// })
|
510 |
+
|
511 |
+
// let json = await request.json()
|
512 |
+
// console.log('requestHordeCheck json:', json)
|
513 |
+
|
514 |
+
// return json
|
515 |
+
// } catch (e) {
|
516 |
+
// console.warn(e)
|
517 |
+
// return {}
|
518 |
+
// }
|
519 |
+
// }
|
520 |
+
|
521 |
+
// async function requestHordeStatus(id) {
|
522 |
+
// try {
|
523 |
+
// console.log('requestHordeStatus():')
|
524 |
+
// const base_url = 'https://stablehorde.net/api/v2/generate/status'
|
525 |
+
|
526 |
+
// const full_url = `${base_url}/${id}`
|
527 |
+
// // const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
528 |
+
// console.log(full_url)
|
529 |
+
// const payload = {}
|
530 |
+
// let request = await fetch(full_url, {
|
531 |
+
// method: 'GET',
|
532 |
+
// headers: {
|
533 |
+
// Accept: 'application/json',
|
534 |
+
// 'Content-Type': 'application/json',
|
535 |
+
// // 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
536 |
+
// 'Client-Agent': 'unknown:0:unknown',
|
537 |
+
// },
|
538 |
+
// })
|
539 |
+
|
540 |
+
// let json = await request.json()
|
541 |
+
// console.log('requestHordeStatus json:', json)
|
542 |
+
|
543 |
+
// return json
|
544 |
+
// } catch (e) {
|
545 |
+
// console.warn(e)
|
546 |
+
// return {}
|
547 |
+
// }
|
548 |
+
// }
|
549 |
+
|
550 |
+
async function requestExtraSingleImage(payload) {
|
551 |
+
console.log('requestExtraSingleImage(): about to send a fetch request')
|
552 |
+
try {
|
553 |
+
let json = await py_re.extraSingleImageRequest(g_sd_url, payload)
|
554 |
+
console.log('requestExtraSingleImage json:')
|
555 |
+
console.dir(json)
|
556 |
+
|
557 |
+
return json
|
558 |
+
} catch (e) {
|
559 |
+
console.warn(e)
|
560 |
+
return {}
|
561 |
+
}
|
562 |
+
}
|
563 |
+
|
564 |
+
async function requestGetUpscalers() {
|
565 |
+
console.log('requestGetUpscalers: ')
|
566 |
+
let json = []
|
567 |
+
const full_url = `${g_sd_url}/sdapi/v1/upscalers`
|
568 |
+
try {
|
569 |
+
let request = await fetch(full_url)
|
570 |
+
json = await request.json()
|
571 |
+
console.log('upscalers json:')
|
572 |
+
console.dir(json)
|
573 |
+
} catch (e) {
|
574 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
575 |
+
}
|
576 |
+
return json
|
577 |
+
}
|
578 |
+
|
579 |
+
//REFACTOR: reuse the same code for (requestControlNetTxt2Img,requestControlNetImg2Img)
|
580 |
+
async function requestControlNetTxt2Img(plugin_settings) {
|
581 |
+
console.log('requestControlNetTxt2Img: ')
|
582 |
+
|
583 |
+
// const full_url = `${g_sd_url}/controlnet/txt2img`
|
584 |
+
const full_url = `${g_sd_url}/sdapi/v1/txt2img`
|
585 |
+
// debugger
|
586 |
+
const control_net_settings =
|
587 |
+
control_net.mapPluginSettingsToControlNet(plugin_settings)
|
588 |
+
let control_networks = []
|
589 |
+
// let active_control_networks = 0
|
590 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
591 |
+
if (!control_net.getEnableControlNet(index)) {
|
592 |
+
control_networks[index] = false
|
593 |
+
continue
|
594 |
+
}
|
595 |
+
control_networks[index] = true
|
596 |
+
// debugger
|
597 |
+
if (!control_net_settings['controlnet_units'][index]['input_image']) {
|
598 |
+
app.showAlert('you need to add a valid ControlNet input image')
|
599 |
+
throw 'you need to add a valid ControlNet input image'
|
600 |
+
}
|
601 |
+
|
602 |
+
if (!control_net_settings['controlnet_units'][index]['module']) {
|
603 |
+
app.showAlert('you need to select a valid ControlNet Module')
|
604 |
+
throw 'you need to select a valid ControlNet Module'
|
605 |
+
}
|
606 |
+
if (
|
607 |
+
!control_net_settings['controlnet_units'][index]['model'] &&
|
608 |
+
!control_net.getModuleDetail()[
|
609 |
+
control_net_settings['controlnet_units'][index]['module']
|
610 |
+
].model_free
|
611 |
+
) {
|
612 |
+
app.showAlert('you need to select a valid ControlNet Model')
|
613 |
+
throw 'you need to select a valid ControlNet Model'
|
614 |
+
}
|
615 |
+
// active_control_networks++
|
616 |
+
}
|
617 |
+
|
618 |
+
let request = await fetch(full_url, {
|
619 |
+
method: 'POST',
|
620 |
+
headers: {
|
621 |
+
Accept: 'application/json',
|
622 |
+
'Content-Type': 'application/json',
|
623 |
+
},
|
624 |
+
body: JSON.stringify(control_net_settings),
|
625 |
+
})
|
626 |
+
|
627 |
+
let json = await request.json()
|
628 |
+
console.log('json:', json)
|
629 |
+
|
630 |
+
//update the mask in controlNet tab
|
631 |
+
const numOfImages = json['images'].length
|
632 |
+
let numberOfAnnotations =
|
633 |
+
numOfImages - g_generation_session.last_settings.batch_size
|
634 |
+
if (numberOfAnnotations < 0) numberOfAnnotations = 0
|
635 |
+
|
636 |
+
const base64_mask = json['images'].slice(numOfImages - numberOfAnnotations)
|
637 |
+
|
638 |
+
let mask_index = 0
|
639 |
+
|
640 |
+
for (let index = 0; index < control_networks.length; index++) {
|
641 |
+
if (
|
642 |
+
control_networks[index] == false ||
|
643 |
+
mask_index >= numberOfAnnotations
|
644 |
+
)
|
645 |
+
continue
|
646 |
+
html_manip.setControlMaskSrc(
|
647 |
+
base64ToBase64Url(base64_mask[mask_index]),
|
648 |
+
index
|
649 |
+
)
|
650 |
+
g_generation_session.controlNetMask[index] = base64_mask[mask_index]
|
651 |
+
mask_index++
|
652 |
+
}
|
653 |
+
// g_generation_session.controlNetMask = base64_mask
|
654 |
+
|
655 |
+
const standard_response = await py_re.convertToStandardResponse(
|
656 |
+
control_net_settings,
|
657 |
+
json['images'].slice(0, numOfImages - numberOfAnnotations),
|
658 |
+
plugin_settings['uniqueDocumentId']
|
659 |
+
)
|
660 |
+
console.log('standard_response:', standard_response)
|
661 |
+
|
662 |
+
return standard_response
|
663 |
+
}
|
664 |
+
|
665 |
+
//REFACTOR: reuse the same code for (requestControlNetTxt2Img,requestControlNetImg2Img)
|
666 |
+
async function requestControlNetImg2Img(plugin_settings) {
|
667 |
+
console.log('requestControlNetImg2Img: ')
|
668 |
+
// const full_url = 'http://127.0.0.1:8000/swapModel'
|
669 |
+
|
670 |
+
// const full_url = `${g_sd_url}/controlnet/img2img`
|
671 |
+
const full_url = `${g_sd_url}/sdapi/v1/img2img`
|
672 |
+
const control_net_settings =
|
673 |
+
control_net.mapPluginSettingsToControlNet(plugin_settings)
|
674 |
+
|
675 |
+
// let control_networks = 0
|
676 |
+
let control_networks = []
|
677 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
678 |
+
if (!control_net.getEnableControlNet(index)) {
|
679 |
+
control_networks[index] = false
|
680 |
+
continue
|
681 |
+
}
|
682 |
+
control_networks[index] = true
|
683 |
+
if (!control_net_settings['controlnet_units'][index]['input_image']) {
|
684 |
+
app.showAlert('you need to add a valid ControlNet input image')
|
685 |
+
throw 'you need to add a valid ControlNet input image'
|
686 |
+
}
|
687 |
+
|
688 |
+
if (!control_net_settings['controlnet_units'][index]['module']) {
|
689 |
+
app.showAlert('you need to select a valid ControlNet Module')
|
690 |
+
throw 'you need to select a valid ControlNet Module'
|
691 |
+
}
|
692 |
+
if (
|
693 |
+
!control_net_settings['controlnet_units'][index]['model'] &&
|
694 |
+
!control_net.getModuleDetail()[
|
695 |
+
control_net_settings['controlnet_units'][index]['module']
|
696 |
+
].model_free
|
697 |
+
) {
|
698 |
+
app.showAlert('you need to select a valid ControlNet Model')
|
699 |
+
throw 'you need to select a valid ControlNet Model'
|
700 |
+
}
|
701 |
+
}
|
702 |
+
|
703 |
+
let request = await fetch(full_url, {
|
704 |
+
method: 'POST',
|
705 |
+
headers: {
|
706 |
+
Accept: 'application/json',
|
707 |
+
'Content-Type': 'application/json',
|
708 |
+
},
|
709 |
+
body: JSON.stringify(control_net_settings),
|
710 |
+
// body: JSON.stringify(payload),
|
711 |
+
})
|
712 |
+
|
713 |
+
let json = await request.json()
|
714 |
+
console.log('json:', json)
|
715 |
+
|
716 |
+
//update the mask in controlNet tab
|
717 |
+
const numOfImages = json['images'].length
|
718 |
+
let numberOfAnnotations =
|
719 |
+
numOfImages - g_generation_session.last_settings.batch_size
|
720 |
+
if (numberOfAnnotations < 0) numberOfAnnotations = 0
|
721 |
+
|
722 |
+
// To fix a bug: when Ultimate SD Upscale is active and running, the detection maps won’t be retrieved.
|
723 |
+
// So set its value to 0 to avoid the result images being loaded in the annotation map interface.
|
724 |
+
if (
|
725 |
+
scripts.script_store.is_active &&
|
726 |
+
scripts.script_store.selected_script_name !== 'None' &&
|
727 |
+
scripts.script_store.is_selected_script_available
|
728 |
+
) {
|
729 |
+
numberOfAnnotations = 0
|
730 |
+
}
|
731 |
+
const base64_mask = json['images'].slice(numOfImages - numberOfAnnotations)
|
732 |
+
|
733 |
+
let mask_index = 0
|
734 |
+
for (let index = 0; index < control_networks.length; index++) {
|
735 |
+
if (
|
736 |
+
control_networks[index] == false ||
|
737 |
+
mask_index >= numberOfAnnotations
|
738 |
+
)
|
739 |
+
continue
|
740 |
+
html_manip.setControlMaskSrc(
|
741 |
+
base64ToBase64Url(base64_mask[mask_index]),
|
742 |
+
index
|
743 |
+
)
|
744 |
+
g_generation_session.controlNetMask[index] = base64_mask[mask_index]
|
745 |
+
mask_index++
|
746 |
+
}
|
747 |
+
|
748 |
+
// g_generation_session.controlNetMask = base64_mask
|
749 |
+
|
750 |
+
const standard_response = await py_re.convertToStandardResponse(
|
751 |
+
control_net_settings,
|
752 |
+
json['images'].slice(0, numOfImages - numberOfAnnotations),
|
753 |
+
plugin_settings['uniqueDocumentId']
|
754 |
+
)
|
755 |
+
console.log('standard_response:', standard_response)
|
756 |
+
|
757 |
+
// //get all images except last because it's the mask
|
758 |
+
// for (const image of json['images'].slice(0, -1)) {
|
759 |
+
// await io.IO.base64ToLayer(image)
|
760 |
+
// }
|
761 |
+
|
762 |
+
return standard_response
|
763 |
+
}
|
764 |
+
|
765 |
+
async function isWebuiRunning() {
|
766 |
+
console.log('isWebuiRunning: ')
|
767 |
+
let json = []
|
768 |
+
const full_url = `${g_sd_url}/user`
|
769 |
+
try {
|
770 |
+
let request = await fetch(full_url)
|
771 |
+
json = await request.json()
|
772 |
+
console.log('json:')
|
773 |
+
console.dir(json)
|
774 |
+
} catch (e) {
|
775 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
776 |
+
return false
|
777 |
+
}
|
778 |
+
return true
|
779 |
+
}
|
780 |
+
async function requestLoraModels() {
|
781 |
+
const extension_url = py_re.getExtensionUrl()
|
782 |
+
const full_url = `${extension_url}/lora/list`
|
783 |
+
const lora_models = await api.requestGet(full_url)
|
784 |
+
return lora_models
|
785 |
+
}
|
786 |
+
module.exports = {
|
787 |
+
requestTxt2Img,
|
788 |
+
requestImg2Img,
|
789 |
+
getInitImage,
|
790 |
+
requestProgress,
|
791 |
+
requestGetModels,
|
792 |
+
requestSwapModel,
|
793 |
+
requestInterrupt,
|
794 |
+
requestGetSamplers,
|
795 |
+
getVersionRequest,
|
796 |
+
changeSdUrl,
|
797 |
+
loadPromptShortcut,
|
798 |
+
savePromptShortcut,
|
799 |
+
loadHistory,
|
800 |
+
setInpaintMaskWeight,
|
801 |
+
requestGetConfig,
|
802 |
+
requestGetOptions,
|
803 |
+
imageSearch,
|
804 |
+
requestSavePng,
|
805 |
+
// requestHorde,
|
806 |
+
// requestHordeCheck,
|
807 |
+
// requestHordeStatus,
|
808 |
+
requestExtraSingleImage,
|
809 |
+
requestGetUpscalers,
|
810 |
+
requestControlNetTxt2Img,
|
811 |
+
requestControlNetImg2Img,
|
812 |
+
isWebuiRunning,
|
813 |
+
requestLoraModels,
|
814 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/selection.js
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const psapi = require('./psapi')
|
2 |
+
const html_manip = require('./utility/html_manip')
|
3 |
+
function finalWidthHeight(
|
4 |
+
selectionWidth,
|
5 |
+
selectionHeight,
|
6 |
+
minWidth,
|
7 |
+
minHeight
|
8 |
+
) {
|
9 |
+
// const minWidth = 512
|
10 |
+
// const minHeight = 512
|
11 |
+
|
12 |
+
// const selectionWidth = 256
|
13 |
+
// const selectionHeight = 1000
|
14 |
+
|
15 |
+
let finalWidth = 0
|
16 |
+
let finalHeight = 0
|
17 |
+
|
18 |
+
if (selectionWidth <= selectionHeight) {
|
19 |
+
//do operation on the smaller dimension
|
20 |
+
const scaleRatio = selectionWidth / minWidth
|
21 |
+
|
22 |
+
finalWidth = minWidth
|
23 |
+
finalHeight = selectionHeight / scaleRatio
|
24 |
+
} else {
|
25 |
+
const scaleRatio = selectionHeight / minHeight
|
26 |
+
|
27 |
+
finalHeight = minHeight
|
28 |
+
finalWidth = selectionWidth / scaleRatio
|
29 |
+
}
|
30 |
+
return [finalWidth, finalHeight]
|
31 |
+
}
|
32 |
+
|
33 |
+
async function selectionToFinalWidthHeight() {
|
34 |
+
// const { getSelectionInfoExe } = require('./psapi')
|
35 |
+
try {
|
36 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
37 |
+
const [finalWidth, finalHeight] = finalWidthHeight(
|
38 |
+
selectionInfo.width,
|
39 |
+
selectionInfo.height,
|
40 |
+
512,
|
41 |
+
512
|
42 |
+
)
|
43 |
+
|
44 |
+
return [
|
45 |
+
parseInt(finalWidth),
|
46 |
+
parseInt(finalHeight),
|
47 |
+
selectionInfo.width,
|
48 |
+
selectionInfo.height,
|
49 |
+
]
|
50 |
+
} catch (e) {
|
51 |
+
console.warn('you need a rectangular selection', e)
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
async function selectBoundingBox() {
|
56 |
+
let l = await app.activeDocument.activeLayers[0]
|
57 |
+
let bounds = await l.boundsNoEffects
|
58 |
+
let selectionInfo = convertSelectionObjectToSelectionInfo(bounds)
|
59 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
60 |
+
return selectionInfo
|
61 |
+
}
|
62 |
+
function convertSelectionObjectToSelectionInfo(selection_obj) {
|
63 |
+
let selection_info = {
|
64 |
+
left: selection_obj._left,
|
65 |
+
right: selection_obj._right,
|
66 |
+
bottom: selection_obj._bottom,
|
67 |
+
top: selection_obj._top,
|
68 |
+
height: selection_obj._bottom - selection_obj._top,
|
69 |
+
width: selection_obj._right - selection_obj._left,
|
70 |
+
}
|
71 |
+
return selection_info
|
72 |
+
}
|
73 |
+
|
74 |
+
const SelectionInfoDesc = () => ({
|
75 |
+
_obj: 'get',
|
76 |
+
_target: [
|
77 |
+
{
|
78 |
+
_property: 'selection',
|
79 |
+
},
|
80 |
+
{
|
81 |
+
_ref: 'document',
|
82 |
+
_id: app.activeDocument._id,
|
83 |
+
},
|
84 |
+
],
|
85 |
+
_options: {
|
86 |
+
dialogOptions: 'dontDisplay',
|
87 |
+
},
|
88 |
+
})
|
89 |
+
class Selection {
|
90 |
+
static async getSelectionInfoExe() {
|
91 |
+
//return a selectionInfo object or undefined
|
92 |
+
try {
|
93 |
+
const selection = await executeAsModal(async () => {
|
94 |
+
const result = await batchPlay([SelectionInfoDesc()], {
|
95 |
+
synchronousExecution: true,
|
96 |
+
modalBehavior: 'execute',
|
97 |
+
})
|
98 |
+
|
99 |
+
return result[0]?.selection
|
100 |
+
})
|
101 |
+
|
102 |
+
if (this.isSelectionValid(selection)) {
|
103 |
+
let selection_info = {
|
104 |
+
left: selection.left._value,
|
105 |
+
right: selection.right._value,
|
106 |
+
bottom: selection.bottom._value,
|
107 |
+
top: selection.top._value,
|
108 |
+
height: selection.bottom._value - selection.top._value,
|
109 |
+
width: selection.right._value - selection.left._value,
|
110 |
+
}
|
111 |
+
// console.dir({selection_info})
|
112 |
+
return selection_info
|
113 |
+
}
|
114 |
+
} catch (e) {
|
115 |
+
console.warn('selection info error', e)
|
116 |
+
}
|
117 |
+
}
|
118 |
+
|
119 |
+
static isSelectionValid(selection) {
|
120 |
+
console.warn(
|
121 |
+
'isSelectionValid is deprecated use selection.isSelectionValid instead'
|
122 |
+
)
|
123 |
+
if (
|
124 |
+
selection && // check if the selection is defined
|
125 |
+
selection.hasOwnProperty('left') &&
|
126 |
+
selection.hasOwnProperty('right') &&
|
127 |
+
selection.hasOwnProperty('top') &&
|
128 |
+
selection.hasOwnProperty('bottom')
|
129 |
+
) {
|
130 |
+
return true
|
131 |
+
}
|
132 |
+
|
133 |
+
return false
|
134 |
+
}
|
135 |
+
static reselectArea(selection_info) {}
|
136 |
+
static isSameSelection(selection_info_1, selection_info_2) {}
|
137 |
+
static async getImageToSelectionDifference() {
|
138 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
139 |
+
|
140 |
+
const width = html_manip.getWidth()
|
141 |
+
const height = html_manip.getHeight()
|
142 |
+
const scale_info_str = `${parseInt(width)}x${parseInt(
|
143 |
+
height
|
144 |
+
)} => ${parseInt(selectionInfo.width)}x${parseInt(
|
145 |
+
selectionInfo.height
|
146 |
+
)} `
|
147 |
+
let ratio =
|
148 |
+
(width * height) / (selectionInfo.width * selectionInfo.height)
|
149 |
+
|
150 |
+
// const arrow = percentage >= 1 ? '↑' : '↓'
|
151 |
+
// percentage = percentage >= 1 ? percentage : 1 / percentage
|
152 |
+
|
153 |
+
// const percentage_str = `${arrow}X${percentage.toFixed(2)}`
|
154 |
+
|
155 |
+
// console.log('scale_info_str: ', scale_info_str)
|
156 |
+
// console.log('percentage_str: ', percentage_str)
|
157 |
+
return ratio
|
158 |
+
}
|
159 |
+
static {}
|
160 |
+
}
|
161 |
+
module.exports = {
|
162 |
+
finalWidthHeight,
|
163 |
+
selectionToFinalWidthHeight,
|
164 |
+
selectBoundingBox,
|
165 |
+
convertSelectionObjectToSelectionInfo,
|
166 |
+
Selection,
|
167 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/img2imgapi.cpython-310.pyc
ADDED
Binary file (4.1 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/metadata_to_json.cpython-310.pyc
ADDED
Binary file (1.93 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/prompt_shortcut.cpython-310.pyc
ADDED
Binary file (2.02 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/search.cpython-310.pyc
ADDED
Binary file (1.03 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/serverHelper.cpython-310.pyc
ADDED
Binary file (1.82 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/__pycache__/serverMain.cpython-310.pyc
ADDED
Binary file (10 kB). View file
|
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/control_net.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
# controlnet original + txt2img
|
3 |
+
import requests
|
4 |
+
import cv2
|
5 |
+
import numpy as np
|
6 |
+
from base64 import b64encode , b64decode
|
7 |
+
from PIL import Image
|
8 |
+
import io
|
9 |
+
|
10 |
+
def readImage(path):
|
11 |
+
img = cv2.imread(path)
|
12 |
+
retval, buffer = cv2.imencode('.jpg', img)
|
13 |
+
b64img = b64encode(buffer).decode("utf-8")
|
14 |
+
return b64img
|
15 |
+
|
16 |
+
def readb64(uri):
|
17 |
+
nparr = np.fromstring(b64decode(uri), np.uint8)
|
18 |
+
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
|
19 |
+
return img
|
20 |
+
|
21 |
+
b64img = readImage("output_image.png")
|
22 |
+
|
23 |
+
class controlnetRequest():
|
24 |
+
def __init__(self, prompt):
|
25 |
+
self.url = "http://127.0.0.1:7860/controlnet/txt2img" #openpose
|
26 |
+
self.body = {
|
27 |
+
"prompt": prompt,
|
28 |
+
"negative_prompt": "",
|
29 |
+
"seed": -1,
|
30 |
+
"subseed": -1,
|
31 |
+
"subseed_strength": 0,
|
32 |
+
"batch_size": 1,
|
33 |
+
"n_iter": 1,
|
34 |
+
"steps": 30,
|
35 |
+
"cfg_scale": 14,
|
36 |
+
"width": 512,
|
37 |
+
"height": 512,
|
38 |
+
"restore_faces": True,
|
39 |
+
"eta": 0,
|
40 |
+
"sampler_index": "DDIM",
|
41 |
+
"controlnet_model": "Test_ziva",
|
42 |
+
"controlnet_input_image": [b64img],
|
43 |
+
"controlnet_module": 'depth',
|
44 |
+
"ControlNet Weight": 1,
|
45 |
+
"controlnet_model": 'control_sd15_depth [fef5e48e]',
|
46 |
+
"controlnet_guidance": 1
|
47 |
+
}
|
48 |
+
|
49 |
+
def sendRequest(self):
|
50 |
+
# print(self.simple_txt2img)
|
51 |
+
r = requests.post(self.url, json=self.body)
|
52 |
+
print(r)
|
53 |
+
return r.json()
|
54 |
+
|
55 |
+
js = controlnetRequest("clothed busty bird").sendRequest()
|
56 |
+
|
57 |
+
|
58 |
+
for x,i in enumerate(js['images']):
|
59 |
+
image = Image.open(io.BytesIO(b64decode(i.split(",",1)[0])))
|
60 |
+
image.save(str(x)+'output.png')
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
len(js['images'])
|
65 |
+
print(js)
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/img2imgapi.py
ADDED
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import requests
|
3 |
+
import io
|
4 |
+
import base64
|
5 |
+
from PIL import Image, PngImagePlugin
|
6 |
+
# from serverMain import sd_url
|
7 |
+
import asyncio
|
8 |
+
import httpx
|
9 |
+
|
10 |
+
|
11 |
+
from io import BytesIO
|
12 |
+
import prompt_shortcut
|
13 |
+
|
14 |
+
# Convert Image to Base64
|
15 |
+
def img_2_b64(image):
|
16 |
+
buff = BytesIO()
|
17 |
+
image.save(buff, format="PNG")
|
18 |
+
img_byte = base64.b64encode(buff.getvalue())
|
19 |
+
img_str = img_byte.decode("utf-8")
|
20 |
+
return img_str
|
21 |
+
|
22 |
+
import time
|
23 |
+
import serverHelper
|
24 |
+
import metadata_to_json
|
25 |
+
|
26 |
+
def b64_2_img(base64_image):
|
27 |
+
image = Image.open(io.BytesIO(base64.b64decode(base64_image.split(",",1)[0])))
|
28 |
+
return image
|
29 |
+
|
30 |
+
def reserveBorderPixels(img,dilation_img):
|
31 |
+
pixels = img.load() # this is not a list, nor is it list()'able
|
32 |
+
width, height = img.size
|
33 |
+
dilation_pixels = dilation_img.load()
|
34 |
+
all_pixels = []
|
35 |
+
depth = 20 # five pixel depth
|
36 |
+
for x in range(width):
|
37 |
+
for d in range(depth):
|
38 |
+
dilation_pixels[x,d] = pixels[x, d]
|
39 |
+
dilation_pixels[x,height-(d+1)] = pixels[x, height-(d+1)]
|
40 |
+
# all_pixels.append(cpixel)
|
41 |
+
for y in range(height):
|
42 |
+
for d in range(depth):
|
43 |
+
dilation_pixels[d,y] = pixels[d,y] # d = 0
|
44 |
+
dilation_pixels[width-(d+1),y] = pixels[width-(d+1), y]
|
45 |
+
return dilation_img
|
46 |
+
|
47 |
+
def maskExpansion(mask_img,mask_expansion):
|
48 |
+
#only if image exist then try to open it
|
49 |
+
|
50 |
+
|
51 |
+
# init_img_mask = Image.open(f"{init_img_dir}/{init_img_mask_name}")
|
52 |
+
|
53 |
+
# if(payload['use_sharp_mask'] == False):# use blurry mask
|
54 |
+
iteration = mask_expansion
|
55 |
+
dilated_img = applyDilation(mask_img,iteration)
|
56 |
+
mask_with_border = reserveBorderPixels(mask_img,dilated_img)
|
57 |
+
mask_with_border = mask_with_border.filter(ImageFilter.GaussianBlur(radius = 10))
|
58 |
+
return mask_with_border
|
59 |
+
|
60 |
+
async def base64ToPng(base64_image,image_path):
|
61 |
+
base64_img_bytes = base64_image.encode('utf-8')
|
62 |
+
with open(image_path, 'wb') as file_to_save:
|
63 |
+
decoded_image_data = base64.decodebytes(base64_img_bytes)
|
64 |
+
file_to_save.write(decoded_image_data)
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
|
69 |
+
from PIL import Image, ImageFilter
|
70 |
+
def applyDilation(img,iteration=20,max_filter=3):
|
71 |
+
# img = Image.open("test_image_2.png")
|
72 |
+
dilation_img = img.copy()
|
73 |
+
# for i in range(20):
|
74 |
+
# dilation_img = dilation_img.filter(ImageFilter.MaxFilter(3))
|
75 |
+
for i in range(iteration):
|
76 |
+
dilation_img = dilation_img.filter(ImageFilter.MaxFilter(max_filter))
|
77 |
+
return dilation_img
|
78 |
+
|
79 |
+
|
80 |
+
|
81 |
+
async def img2ImgRequest(sd_url,payload):
|
82 |
+
# init_img = Image.open(r"C:/Users/abdul/Desktop/photoshop_plugins/my_plugin_1/server/python_server/output- 1670544300.95411.png")
|
83 |
+
print("payload debug:",payload)
|
84 |
+
|
85 |
+
if(payload['use_prompt_shortcut']): # use edit prompt
|
86 |
+
#edit prompt, replaceShortcut(prompt)
|
87 |
+
prompt_shortcut_dict = prompt_shortcut.load()
|
88 |
+
prompt_shortcut_dict.update(payload["prompt_shortcut_ui_dict"])
|
89 |
+
payload['prompt'] = prompt_shortcut.replaceShortcut(payload['prompt'],prompt_shortcut_dict)
|
90 |
+
# edit negative prompt, replaceShortcut(negative_prompt)
|
91 |
+
payload['negative_prompt'] = prompt_shortcut.replaceShortcut(payload['negative_prompt'],prompt_shortcut_dict)
|
92 |
+
|
93 |
+
init_img_dir = "./init_images"
|
94 |
+
init_img_name = payload['init_image_name']
|
95 |
+
init_img = Image.open(f"{init_img_dir}/{init_img_name}")
|
96 |
+
init_img_str = img_2_b64(init_img)
|
97 |
+
payload['init_images'] = [init_img_str]
|
98 |
+
|
99 |
+
# mask
|
100 |
+
|
101 |
+
init_img_mask_name = payload.get('init_image_mask_name',"")
|
102 |
+
|
103 |
+
|
104 |
+
#only if image exist then try to open it
|
105 |
+
if(len(init_img_mask_name) > 0):
|
106 |
+
init_img_mask = Image.open(f"{init_img_dir}/{init_img_mask_name}")
|
107 |
+
|
108 |
+
if(payload['use_sharp_mask'] == False):# use blurry mask
|
109 |
+
iteration = payload['mask_expansion']
|
110 |
+
init_img_mask = applyDilation(init_img_mask,iteration)
|
111 |
+
|
112 |
+
init_img_mask_str = img_2_b64(init_img_mask)
|
113 |
+
payload['mask'] = init_img_mask_str #there is only one mask, unlike 'init_images' which is of type array
|
114 |
+
|
115 |
+
|
116 |
+
# payload = {
|
117 |
+
# "prompt": "cute dog",
|
118 |
+
# "steps": 10,
|
119 |
+
# "init_images":[init_img_str],
|
120 |
+
# "n_iter":3
|
121 |
+
# }
|
122 |
+
# print("payload:",payload)
|
123 |
+
print(type(init_img_str))
|
124 |
+
#request the images to be generated
|
125 |
+
async with httpx.AsyncClient() as client:
|
126 |
+
response = await client.post(url=f'{sd_url}/sdapi/v1/img2img', json=payload, timeout=None)
|
127 |
+
|
128 |
+
r = response.json()
|
129 |
+
|
130 |
+
#create a directory to store the images at
|
131 |
+
# dirName = f'{time.time()}'
|
132 |
+
# dir_fullpath,dirName = serverHelper.makeDirPathName()
|
133 |
+
uniqueDocumentId = payload['uniqueDocumentId']
|
134 |
+
dir_fullpath,dirName = serverHelper.getUniqueDocumentDirPathName(uniqueDocumentId)
|
135 |
+
serverHelper.createFolder(dir_fullpath)
|
136 |
+
image_paths = []
|
137 |
+
metadata = []
|
138 |
+
images_info = []
|
139 |
+
#for each image store the prompt and settings in the meta data
|
140 |
+
for i in r['images']:
|
141 |
+
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
|
142 |
+
|
143 |
+
png_payload = {
|
144 |
+
"image": "data:image/png;base64," + i
|
145 |
+
}
|
146 |
+
response2 = await client.post(url=f'{sd_url}/sdapi/v1/png-info', json=png_payload, timeout=None)
|
147 |
+
pnginfo = PngImagePlugin.PngInfo()
|
148 |
+
pnginfo.add_text("parameters", response2.json().get("info"))
|
149 |
+
image_name = f'output- {time.time()}.png'
|
150 |
+
image_path = f'output/{dirName}/{image_name}'
|
151 |
+
image_paths.append(image_path)
|
152 |
+
image.save(f'./{image_path}', pnginfo=pnginfo)
|
153 |
+
|
154 |
+
metadata_info = response2.json().get("info")
|
155 |
+
metadata_json = metadata_to_json.convertMetadataToJson(metadata_info)
|
156 |
+
metadata.append(metadata_json)
|
157 |
+
images_info.append({"base64":i,"path":image_path})
|
158 |
+
print("metadata_json: ", metadata_json)
|
159 |
+
|
160 |
+
return dirName,images_info,metadata
|
161 |
+
|
162 |
+
if __name__=="__main__":
|
163 |
+
img2ImgRequest()
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/init_images/.gitignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ignore everything in this directory
|
2 |
+
*
|
3 |
+
# Except this file
|
4 |
+
!.gitignore
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/metadata_to_json.py
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from pathlib import Path
|
3 |
+
from PIL import Image
|
4 |
+
import json
|
5 |
+
|
6 |
+
import serverHelper
|
7 |
+
# metadata_str = 'cute cat\nSteps: 20, Sampler: Euler a, CFG scale: 7.0, Seed: 2253354038, Size: 512x512, Model hash: 3e16efc8, Seed resize from: -1x-1, Denoising strength: 0, Conditional mask weight: 1.0'
|
8 |
+
def convertMetadataToJson(metadata_str):
|
9 |
+
print(metadata_str)
|
10 |
+
last_new_line_index = metadata_str.rindex('\n')
|
11 |
+
prompt = metadata_str[:last_new_line_index]
|
12 |
+
other_settings = metadata_str[last_new_line_index+1:]
|
13 |
+
|
14 |
+
print("prompt:", prompt)
|
15 |
+
print("other_settings:", other_settings)
|
16 |
+
sub_settings = other_settings.split(",")
|
17 |
+
print("sub_settings: ",sub_settings)
|
18 |
+
|
19 |
+
settings_dict = {}
|
20 |
+
settings_dict['prompt'] = prompt
|
21 |
+
|
22 |
+
for setting in sub_settings:
|
23 |
+
[key,value]= setting.split(":")
|
24 |
+
key = key.lstrip(' ')
|
25 |
+
value = value.lstrip(' ')
|
26 |
+
settings_dict[key] = value
|
27 |
+
import json
|
28 |
+
settings_json = json.dumps(settings_dict)
|
29 |
+
print("settings_dict: ",settings_dict)
|
30 |
+
print("settings_json ",settings_json)
|
31 |
+
return settings_json
|
32 |
+
|
33 |
+
|
34 |
+
|
35 |
+
|
36 |
+
def getMetadataFromPng(image_path):
|
37 |
+
# image_path = "./output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png"
|
38 |
+
# image_path = "C:/Users/abdul/Desktop/auto-photoshop/Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png"
|
39 |
+
im = Image.open(image_path)
|
40 |
+
# im.load() # Needed only for .png EXIF data (see citation above)
|
41 |
+
# print(im.info['parameters'])
|
42 |
+
metadata_string = im.info['parameters']
|
43 |
+
metadata_json_string = convertMetadataToJson(metadata_string)
|
44 |
+
metadata_dict = json.loads(metadata_json_string)
|
45 |
+
print("metadata_dict: ", metadata_dict)
|
46 |
+
# print(im.info['meta_to_read'])
|
47 |
+
return metadata_dict
|
48 |
+
|
49 |
+
|
50 |
+
def createMetadataJsonFileIfNotExist(image_path):
|
51 |
+
|
52 |
+
# image_name = os.path.splitext(image_path)
|
53 |
+
image_name = Path(image_path).stem
|
54 |
+
# parent_dir_path = Path(image_path)
|
55 |
+
# parent_dir_path = image_path.split(image_name)[0]
|
56 |
+
# os.path.join()
|
57 |
+
head = os.path.split(image_path)[0]
|
58 |
+
json_file_tail = f'{image_name}.json'
|
59 |
+
json_full_path = os.path.join(head,json_file_tail)
|
60 |
+
print("image_name: ",image_name)
|
61 |
+
print("json_full_path: ",json_full_path)
|
62 |
+
isExist = os.path.exists(json_full_path)
|
63 |
+
if(isExist):
|
64 |
+
#read metadata from json
|
65 |
+
metadata_dict = serverHelper.readJson(json_full_path)
|
66 |
+
|
67 |
+
else:
|
68 |
+
#read metadata from image
|
69 |
+
#save the metadata to a json file
|
70 |
+
metadata_dict = getMetadataFromPng(image_path)
|
71 |
+
serverHelper.writeJson(json_full_path,metadata_dict)
|
72 |
+
return metadata_dict
|
73 |
+
|
74 |
+
|
75 |
+
if __name__ == "__main__":
|
76 |
+
image_path = "C:/Users/abdul/Desktop/auto-photoshop/Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png"
|
77 |
+
# getMetadataFromPng(image_path)
|
78 |
+
createMetadataJsonFileIfNotExist(image_path)
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/output/.gitignore
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Ignore everything in this directory
|
2 |
+
*
|
3 |
+
# Except this file
|
4 |
+
!.gitignore
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/prompt_shortcut - Copy.json
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"painterly_style_1": "A full portrait of a beautiful post apocalyptic offworld arctic explorer, intricate, elegant, highly detailed, digital painting, artstation, concept art, smooth, sharp focus, illustration",
|
3 |
+
"ugly": " ((((ugly)))), (((duplicate))), ((morbid)), ((mutilated)), out of frame, extra fingers, mutated hands, ((poorly drawn hands)), ((poorly drawn face)), (((mutation))), (((deformed))), ((ugly)), blurry, ((bad anatomy)), (((bad proportions))), ((extra limbs)), cloned face, (((disfigured))), out of frame, ugly, extra limbs, (bad anatomy), gross proportions, (malformed limbs), ((missing arms)), ((missing legs)), (((extra arms))), (((extra legs))), mutated hands, (fused fingers), (too many fingers), (((long neck)))",
|
4 |
+
"art_style": "(SPACE1999:1.0),(dreamlikeart style:1.0), ( redshift style:1.0), (analog style:1.2), (studio_ghibli_anime_style style:0.7), (copeseethemald style:0.8)",
|
5 |
+
"woman_style": "woman, 1girls, solo, detailed face, lips, realistic pupils, closeup, centered, standing, centered, skin pores, subsurface scattering, detailed skin",
|
6 |
+
"environment_style": "detailed background, items, realistic proportions, blushing, masterpiece, best quality, realistic, hyperrealistic, sharp focus, absurdres, good anatomy",
|
7 |
+
"uniform_style": "space uniform, red, smooth, black belt, black boots",
|
8 |
+
"man_style": "man, solo, detailed face, lips, realistic pupils, closeup, centered, standing, centered, skin pores, subsurface scattering, detailed skin",
|
9 |
+
"neg_person": "(glossy:1.0), freckles, nipples, small waist, lowres, large head, long neck, blurry, bad anatomy, bad hands, extra limbs, extra hands, mutated hands, mutated fingers, missing hand, missing finger, text, error, missing fingers, extra digit, fewer digits,",
|
10 |
+
"neg_general": "cropped, worst quality, low quality, normal quality, jpeg artifacts, text, signature, watermark, artist name, logo,",
|
11 |
+
"nova_green": "[Julianne Hough:Jaime King:0.5]"
|
12 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/prompt_shortcut.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
import json
|
3 |
+
prompt_shortcut_dict ={}
|
4 |
+
|
5 |
+
|
6 |
+
def readToJson():
|
7 |
+
return load()
|
8 |
+
|
9 |
+
def writeToJson(file_name,data_dict):
|
10 |
+
with open(file_name, "w") as outfile:
|
11 |
+
json.dump(data_dict, outfile,indent=4)
|
12 |
+
|
13 |
+
|
14 |
+
def load():
|
15 |
+
global prompt_shortcut_dict
|
16 |
+
try:
|
17 |
+
with open('prompt_shortcut.json') as f_obj:
|
18 |
+
data = json.load(f_obj)
|
19 |
+
prompt_shortcut_dict = data
|
20 |
+
print(data)
|
21 |
+
except IOError:
|
22 |
+
print("prompt_shortcut.json is not found")
|
23 |
+
return prompt_shortcut_dict
|
24 |
+
def find_words_inside_braces(string):
|
25 |
+
result = ""
|
26 |
+
pattern ="\{(.*?)\}"
|
27 |
+
keywords = []
|
28 |
+
for match in re.findall(pattern, string):
|
29 |
+
keywords.append(match)
|
30 |
+
result += match
|
31 |
+
return keywords
|
32 |
+
|
33 |
+
# text = "a beautiful girl holding a cute cat {style_1} on sunny day"
|
34 |
+
# text = "a beautiful girl holding a cute cat { style_1 } on sunny day"
|
35 |
+
text = "a beautiful girl{ }, {char1}, {painterly_style} holding a cute cat { style_1 } on sunny day"
|
36 |
+
# text = "a beautiful girl {char1 } holding a cute cat on sunny day"
|
37 |
+
|
38 |
+
|
39 |
+
|
40 |
+
def replaceShortcut(text,prompt_shortcut_dict):
|
41 |
+
raw_keywords = find_words_inside_braces(text)
|
42 |
+
strip_keywords = list(map(lambda s: s.strip(),raw_keywords))
|
43 |
+
|
44 |
+
original_substrings = list(map(lambda s: '{'+s+'}',raw_keywords))
|
45 |
+
|
46 |
+
print("raw_keywords: ", raw_keywords)
|
47 |
+
print("strip_keywords: ", strip_keywords)
|
48 |
+
print("original_substrings: ",original_substrings)
|
49 |
+
# print ("text:",text)
|
50 |
+
|
51 |
+
for i, word in enumerate(strip_keywords):
|
52 |
+
# word = word.strip()
|
53 |
+
print("word: ",word)
|
54 |
+
if len(word) > 0 and word in prompt_shortcut_dict:
|
55 |
+
prompt = prompt_shortcut_dict[word]
|
56 |
+
print("prompt: ",prompt)
|
57 |
+
text = text.replace(original_substrings[i],prompt)
|
58 |
+
# else:
|
59 |
+
# text = text.replace(word,word.strip())
|
60 |
+
print ("final text: ",text)
|
61 |
+
return text
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/search.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from itertools import islice
|
2 |
+
|
3 |
+
try:
|
4 |
+
from duckduckgo_search import DDGS
|
5 |
+
except ImportError:
|
6 |
+
raise ImportError(
|
7 |
+
"duckduckgo_search is required to image search. Please install it with `pip install --upgrade duckduckgo_search`."
|
8 |
+
)
|
9 |
+
|
10 |
+
|
11 |
+
async def imageSearch(keywords="cute cats"):
|
12 |
+
with DDGS() as ddgs:
|
13 |
+
return [x for x in islice(ddgs.images(keywords), 30)]
|
14 |
+
|
15 |
+
|
16 |
+
if __name__ == "__main__":
|
17 |
+
|
18 |
+
async def main():
|
19 |
+
result = await imageSearch()
|
20 |
+
print(result)
|
21 |
+
|
22 |
+
import asyncio
|
23 |
+
|
24 |
+
asyncio.run(main())
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/serverHelper.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import os
|
3 |
+
import datetime
|
4 |
+
import uuid
|
5 |
+
import json
|
6 |
+
|
7 |
+
# this function should be used whenever we need to write to json file
|
8 |
+
def writeJson(file_name,data_dict):
|
9 |
+
with open(file_name, 'w', encoding='utf-8') as outfile:
|
10 |
+
json.dump(data_dict, outfile, ensure_ascii=False, indent=4)
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# this function should be used whenever we need to read from json file
|
16 |
+
def readJson(file_name):
|
17 |
+
data_dict = {}
|
18 |
+
try:
|
19 |
+
with open(file_name) as f_obj:
|
20 |
+
data_dict = json.load(f_obj)
|
21 |
+
|
22 |
+
print("readJson: data_dict: ", data_dict)
|
23 |
+
except IOError:
|
24 |
+
print(f"{file_name} is not found")
|
25 |
+
return data_dict
|
26 |
+
|
27 |
+
def createFolder(fullpath):
|
28 |
+
print("fullpath:",fullpath)
|
29 |
+
|
30 |
+
if not os.path.exists(fullpath):
|
31 |
+
os.mkdir(fullpath)
|
32 |
+
#create string dir path name based on the current time
|
33 |
+
def makeDirPathName():
|
34 |
+
# dirName = f'{time.time()}'
|
35 |
+
currentDirPath = os.getcwd()
|
36 |
+
now = datetime.datetime.now()
|
37 |
+
daily_folder = now.strftime("%Y-%m-%d")
|
38 |
+
output_path = os.path.join(currentDirPath,"output")
|
39 |
+
fullpath = os.path.join(output_path,daily_folder)
|
40 |
+
# fullpath = os.path.join(currentDirPath,dirName)
|
41 |
+
return fullpath,daily_folder
|
42 |
+
|
43 |
+
#create string dir path name based on the uniqueDocumentId
|
44 |
+
def getUniqueDocumentDirPathName(uniqueDocumentId):
|
45 |
+
|
46 |
+
currentDirPath = os.getcwd()
|
47 |
+
output_path = os.path.join(currentDirPath,"output")
|
48 |
+
fullpath = os.path.join(output_path,uniqueDocumentId)
|
49 |
+
|
50 |
+
return fullpath,uniqueDocumentId
|
51 |
+
|
52 |
+
def makeUniqueID():
|
53 |
+
myuuid = uuid.uuid4()
|
54 |
+
print('Your UUID is: ' + str(myuuid))
|
55 |
+
return myuuid
|
56 |
+
|
57 |
+
|
58 |
+
if __name__ == "__main__":
|
59 |
+
# currentDirPath = os.getcwd()
|
60 |
+
# dirName = f'{time.time()}'
|
61 |
+
# fullpath = os.path.join(currentDirPath,dirName)
|
62 |
+
# createFolder(fullpath)
|
63 |
+
id = makeUniqueID()
|
64 |
+
print("id: ",id)
|
Auto-Photoshop-StableDiffusion-Plugin/server/python_server/serverMain.py
ADDED
@@ -0,0 +1,495 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import json
|
3 |
+
import requests
|
4 |
+
import io
|
5 |
+
import base64
|
6 |
+
from PIL import Image, PngImagePlugin
|
7 |
+
import asyncio
|
8 |
+
import httpx
|
9 |
+
|
10 |
+
|
11 |
+
import os
|
12 |
+
import time
|
13 |
+
import serverHelper
|
14 |
+
import prompt_shortcut
|
15 |
+
import metadata_to_json
|
16 |
+
import search
|
17 |
+
sd_url = os.environ.get('SD_URL', 'http://127.0.0.1:7860')
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
async def txt2ImgRequest(payload):
|
23 |
+
# payload = {
|
24 |
+
# "prompt": "cute cat, kitten",
|
25 |
+
# "steps": 10
|
26 |
+
# }
|
27 |
+
print("payload: ",payload)
|
28 |
+
|
29 |
+
if(payload['use_prompt_shortcut']): # use edit prompt
|
30 |
+
#edit prompt, replaceShortcut(prompt)
|
31 |
+
prompt_shortcut_dict = prompt_shortcut.load()
|
32 |
+
prompt_shortcut_dict.update(payload["prompt_shortcut_ui_dict"])
|
33 |
+
payload['prompt'] = prompt_shortcut.replaceShortcut(payload['prompt'],prompt_shortcut_dict)
|
34 |
+
# edit negative prompt, replaceShortcut(negative_prompt)
|
35 |
+
payload['negative_prompt'] = prompt_shortcut.replaceShortcut(payload['negative_prompt'],prompt_shortcut_dict)
|
36 |
+
|
37 |
+
|
38 |
+
#request the images to be generated
|
39 |
+
request_path = "/sdapi/v1/txt2img"
|
40 |
+
|
41 |
+
async with httpx.AsyncClient() as client:
|
42 |
+
response = await client.post(url=f'{sd_url}/sdapi/v1/txt2img', json=payload, timeout=None)
|
43 |
+
r = response.json()
|
44 |
+
|
45 |
+
#create a directory to store the images at
|
46 |
+
# dirName = f'{time.time()}'
|
47 |
+
# dir_fullpath,dirName = serverHelper.makeDirPathName()
|
48 |
+
uniqueDocumentId = payload['uniqueDocumentId']
|
49 |
+
dir_fullpath,dirName = serverHelper.getUniqueDocumentDirPathName(uniqueDocumentId)
|
50 |
+
serverHelper.createFolder(dir_fullpath)
|
51 |
+
image_paths = []
|
52 |
+
#for each image store the prompt and settings in the meta data
|
53 |
+
metadata = []
|
54 |
+
images_info = []
|
55 |
+
for i in r['images']:
|
56 |
+
image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
|
57 |
+
|
58 |
+
png_payload = {
|
59 |
+
"image": "data:image/png;base64," + i
|
60 |
+
}
|
61 |
+
response2 = await client.post(url=f'{sd_url}/sdapi/v1/png-info', json=png_payload)
|
62 |
+
pnginfo = PngImagePlugin.PngInfo()
|
63 |
+
pnginfo.add_text("parameters", response2.json().get("info"))
|
64 |
+
image_name = f'output- {time.time()}.png'
|
65 |
+
|
66 |
+
image_path = f'output/{dirName}/{image_name}'
|
67 |
+
image_paths.append(image_path)
|
68 |
+
image.save(f'./{image_path}', pnginfo=pnginfo)
|
69 |
+
|
70 |
+
metadata_info = response2.json().get("info")
|
71 |
+
metadata_json = metadata_to_json.convertMetadataToJson(metadata_info)
|
72 |
+
metadata.append(metadata_json)
|
73 |
+
images_info.append({"base64":i,"path":image_path})
|
74 |
+
print("metadata_json: ", metadata_json)
|
75 |
+
|
76 |
+
|
77 |
+
return dirName,images_info,metadata
|
78 |
+
|
79 |
+
import base64
|
80 |
+
from io import BytesIO
|
81 |
+
|
82 |
+
|
83 |
+
def img_2_b64(image):
|
84 |
+
buff = BytesIO()
|
85 |
+
image.save(buff, format="PNG")
|
86 |
+
img_byte = base64.b64encode(buff.getvalue())
|
87 |
+
img_str = img_byte.decode("utf-8")
|
88 |
+
return img_str
|
89 |
+
|
90 |
+
|
91 |
+
from typing import Union
|
92 |
+
|
93 |
+
from fastapi import FastAPI
|
94 |
+
from fastapi import APIRouter, Request
|
95 |
+
|
96 |
+
|
97 |
+
|
98 |
+
router = APIRouter()
|
99 |
+
|
100 |
+
|
101 |
+
@router.get("/")
|
102 |
+
def read_root():
|
103 |
+
return {"Hello": "World"}
|
104 |
+
|
105 |
+
|
106 |
+
@router.get("/version")
|
107 |
+
def getVersion():
|
108 |
+
manifest_dir = "..\..\manifest.json"
|
109 |
+
|
110 |
+
manifest = {'version': '0.0.0'}
|
111 |
+
version = "0.0.0"
|
112 |
+
try:
|
113 |
+
|
114 |
+
with open(manifest_dir, 'r') as f:
|
115 |
+
manifest = json.load(f)
|
116 |
+
version = manifest['version']
|
117 |
+
except:
|
118 |
+
print("couldn't read the manifest.json")
|
119 |
+
return {"version": f"v{version}"}
|
120 |
+
|
121 |
+
|
122 |
+
|
123 |
+
|
124 |
+
|
125 |
+
|
126 |
+
# @router.post("/txt2img/")
|
127 |
+
# async def txt2ImgHandle(payload:Payload):
|
128 |
+
# print("txt2ImgHandle: \n")
|
129 |
+
# txt2ImgRequest(payload)
|
130 |
+
# return {"prompt":payload.prompt,"images": ""}
|
131 |
+
|
132 |
+
|
133 |
+
from fastapi import Request, Response
|
134 |
+
import img2imgapi
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
|
139 |
+
|
140 |
+
|
141 |
+
@router.post("/sd_url/")
|
142 |
+
async def changeSdUrl(request:Request):
|
143 |
+
global sd_url
|
144 |
+
try:
|
145 |
+
|
146 |
+
payload = await request.json()
|
147 |
+
print("changeSdUrl: payload:",payload)
|
148 |
+
print(f"change sd url from {sd_url} to {payload['sd_url']} \n")
|
149 |
+
sd_url = payload['sd_url']
|
150 |
+
except:
|
151 |
+
print("error occurred in changeSdUrl()")
|
152 |
+
# response.body = resp.content
|
153 |
+
# return {}
|
154 |
+
return {"sd_url":sd_url}
|
155 |
+
|
156 |
+
|
157 |
+
|
158 |
+
|
159 |
+
|
160 |
+
|
161 |
+
|
162 |
+
|
163 |
+
|
164 |
+
@router.post("/txt2img/")
|
165 |
+
async def txt2ImgHandle(request:Request):
|
166 |
+
print("txt2ImgHandle: \n")
|
167 |
+
payload = await request.json()
|
168 |
+
dir_name,images_info,metadata, = await txt2ImgRequest(payload)
|
169 |
+
# return {"prompt":payload.prompt,"images": ""}
|
170 |
+
return {"payload": payload,"dir_name": dir_name,"images_info":images_info,"metadata":metadata}
|
171 |
+
|
172 |
+
@router.post("/img2img/")
|
173 |
+
async def img2ImgHandle(request:Request):
|
174 |
+
print("img2ImgHandle: \n")
|
175 |
+
payload = await request.json()
|
176 |
+
dir_name,images_info,metadata = await img2imgapi.img2ImgRequest(sd_url,payload)
|
177 |
+
# return {"prompt":payload.prompt,"images": ""}
|
178 |
+
return {"payload": payload,"dir_name": dir_name,"images_info":images_info,"metadata":metadata}
|
179 |
+
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
|
184 |
+
|
185 |
+
@router.post("/getInitImage/")
|
186 |
+
async def getInitImageHandle(request:Request):
|
187 |
+
print("getInitImageHandle: \n")
|
188 |
+
payload = await request.json()
|
189 |
+
print("payload:",payload)
|
190 |
+
init_img_dir = "./init_images"
|
191 |
+
init_img_name = payload["init_image_name"]# change this to "image_name"
|
192 |
+
|
193 |
+
numOfAttempts = 3
|
194 |
+
init_img_str = ""
|
195 |
+
for i in range(numOfAttempts):
|
196 |
+
try:
|
197 |
+
image_path = f"{init_img_dir}/{init_img_name}"
|
198 |
+
init_img = Image.open(image_path)
|
199 |
+
init_img_str = img_2_b64(init_img)
|
200 |
+
|
201 |
+
|
202 |
+
# # If file exists, delete it.
|
203 |
+
# if os.path.isfile(image_path):
|
204 |
+
# os.remove(image_path)
|
205 |
+
except:
|
206 |
+
print(f"exception:fail to read an image file {image_path}, will try again {i} of {numOfAttempts}")
|
207 |
+
#sleep for one second every time you try to read an image and fail
|
208 |
+
time.sleep(1)
|
209 |
+
continue;
|
210 |
+
|
211 |
+
|
212 |
+
|
213 |
+
return {"payload": payload,"init_image_str":init_img_str}
|
214 |
+
|
215 |
+
@router.get('/config')
|
216 |
+
async def sdapi(request: Request, response: Response):
|
217 |
+
try:
|
218 |
+
|
219 |
+
resp = requests.get(url=f'{sd_url}/config', params=request.query_params)
|
220 |
+
response.status_code = resp.status_code
|
221 |
+
response.body = resp.content
|
222 |
+
except:
|
223 |
+
print(f'exception: fail to send request to {sd_url}/config')
|
224 |
+
print(f'{request}')
|
225 |
+
return response
|
226 |
+
|
227 |
+
@router.get('/sdapi/v1/{path:path}')
|
228 |
+
async def sdapi(path: str, request: Request, response: Response):
|
229 |
+
try:
|
230 |
+
|
231 |
+
resp = requests.get(url=f'{sd_url}/sdapi/v1/{path}', params=request.query_params)
|
232 |
+
response.status_code = resp.status_code
|
233 |
+
response.body = resp.content
|
234 |
+
except:
|
235 |
+
print(f'exception: fail to send request to {sd_url}/sdapi/v1/{path}')
|
236 |
+
print(f'{request}')
|
237 |
+
return response
|
238 |
+
|
239 |
+
@router.post('/sdapi/v1/{path:path}')
|
240 |
+
async def sdapi(path: str, request: Request, response: Response):
|
241 |
+
try:
|
242 |
+
json = await request.json()
|
243 |
+
except:
|
244 |
+
json = {}
|
245 |
+
|
246 |
+
try:
|
247 |
+
# if(path =="interrupt"):
|
248 |
+
# resp = requests.post(url=f'{sd_url}/sdapi/v1/{path}', params=request.query_params)
|
249 |
+
|
250 |
+
# else:
|
251 |
+
# resp = requests.post(url=f'{sd_url}/sdapi/v1/{path}', params=request.query_params, json=await request.json())
|
252 |
+
resp = requests.post(url=f'{sd_url}/sdapi/v1/{path}', params=request.query_params, json=json)
|
253 |
+
|
254 |
+
response.status_code = resp.status_code
|
255 |
+
response.body = resp.content
|
256 |
+
except:
|
257 |
+
print(f'exception: fail to send request to {sd_url}/sdapi/v1/{path}')
|
258 |
+
print(f'{request}')
|
259 |
+
return response
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
# async def base64ToPng(base64_image,image_path):
|
264 |
+
# base64_img_bytes = base64_image.encode('utf-8')
|
265 |
+
# with open(image_path, 'wb') as file_to_save:
|
266 |
+
# decoded_image_data = base64.decodebytes(base64_img_bytes)
|
267 |
+
# file_to_save.write(decoded_image_data)
|
268 |
+
|
269 |
+
|
270 |
+
@router.post('/save/png/')
|
271 |
+
async def savePng(request:Request):
|
272 |
+
print("savePng()")
|
273 |
+
try:
|
274 |
+
json = await request.json()
|
275 |
+
|
276 |
+
except:
|
277 |
+
json = {}
|
278 |
+
|
279 |
+
print("json:",json)
|
280 |
+
try:
|
281 |
+
folder = './init_images'
|
282 |
+
image_path = f"{folder}/{json['image_name']}"
|
283 |
+
await img2imgapi.base64ToPng(json['base64'],image_path)
|
284 |
+
|
285 |
+
|
286 |
+
|
287 |
+
|
288 |
+
return {"status":f"{json['image_name']} has been saved"}
|
289 |
+
except:
|
290 |
+
print(f'{request}')
|
291 |
+
return {"error": "error message: could not save the image file"}
|
292 |
+
|
293 |
+
|
294 |
+
@router.post('/search/image/')
|
295 |
+
async def searchImage(request:Request):
|
296 |
+
try:
|
297 |
+
json = await request.json()
|
298 |
+
except:
|
299 |
+
json = {}
|
300 |
+
|
301 |
+
|
302 |
+
try:
|
303 |
+
keywords = json.get('keywords','cute dogs')
|
304 |
+
images = await search.imageSearch(keywords)
|
305 |
+
print(images)
|
306 |
+
|
307 |
+
|
308 |
+
return {"images":images}
|
309 |
+
except:
|
310 |
+
print("keywords",keywords)
|
311 |
+
# print(f'{request}')
|
312 |
+
return {"error": "error message: can't preform an image search"}
|
313 |
+
|
314 |
+
@router.post('/mask/expansion/')
|
315 |
+
async def maskExpansionHandler(request:Request):
|
316 |
+
try:
|
317 |
+
json = await request.json()
|
318 |
+
except:
|
319 |
+
json = {}
|
320 |
+
|
321 |
+
|
322 |
+
try:
|
323 |
+
# keywords = json.get('keywords','cute dogs')
|
324 |
+
base64_mask_image = json['mask']
|
325 |
+
mask_expansion = json['mask_expansion']
|
326 |
+
#convert base64 to img
|
327 |
+
|
328 |
+
await img2imgapi.base64ToPng(base64_mask_image,"original_mask.png")#save a copy of the mask for debugging
|
329 |
+
|
330 |
+
mask_image = img2imgapi.b64_2_img(base64_mask_image)
|
331 |
+
|
332 |
+
expanded_mask_img = img2imgapi.maskExpansion(mask_image,mask_expansion)
|
333 |
+
base64_expanded_mask_image = img2imgapi.img_2_b64(expanded_mask_img)
|
334 |
+
await img2imgapi.base64ToPng(base64_expanded_mask_image,"expanded_mask.png")#save a copy of the mask of the expanded_mask for debugging
|
335 |
+
|
336 |
+
print("successful mask expansion operation")
|
337 |
+
return {"mask":base64_expanded_mask_image}
|
338 |
+
|
339 |
+
except:
|
340 |
+
print("request",request)
|
341 |
+
raise Exception(f"couldn't preform mask expansion")
|
342 |
+
# return response
|
343 |
+
return {"error": "error message: can't preform an mask expansion"}
|
344 |
+
|
345 |
+
|
346 |
+
@router.post('/history/load')
|
347 |
+
async def loadHistory(request: Request):
|
348 |
+
# {'image_paths','metadata_setting'}
|
349 |
+
history = {}
|
350 |
+
try:
|
351 |
+
json = await request.json()
|
352 |
+
except:
|
353 |
+
json = {}
|
354 |
+
|
355 |
+
try:
|
356 |
+
|
357 |
+
uniqueDocumentId = json['uniqueDocumentId']
|
358 |
+
|
359 |
+
import glob
|
360 |
+
|
361 |
+
image_paths = glob.glob(f'./output/{uniqueDocumentId}/*.png')
|
362 |
+
settings_paths = glob.glob(f'./output/{uniqueDocumentId}/*.json')#note: why is we are not using settings_paths?
|
363 |
+
print("loadHistory: image_paths:", image_paths)
|
364 |
+
|
365 |
+
|
366 |
+
history['image_paths'] = image_paths
|
367 |
+
history['metadata_jsons'] = []
|
368 |
+
history['base64_images'] = []
|
369 |
+
for image_path in image_paths:
|
370 |
+
print("image_path: ", image_path)
|
371 |
+
metadata_dict = metadata_to_json.createMetadataJsonFileIfNotExist(image_path)
|
372 |
+
history['metadata_jsons'].routerend(metadata_dict)
|
373 |
+
|
374 |
+
|
375 |
+
img = Image.open(image_path)
|
376 |
+
base64_image = img_2_b64(img)
|
377 |
+
history['base64_images'].routerend(base64_image)
|
378 |
+
|
379 |
+
except:
|
380 |
+
|
381 |
+
print(f'{request}')
|
382 |
+
|
383 |
+
#reverse the order so that newer generated images path will be shown first
|
384 |
+
|
385 |
+
|
386 |
+
history['image_paths'].reverse()
|
387 |
+
history['metadata_jsons'].reverse()
|
388 |
+
history['base64_images'].reverse()
|
389 |
+
return {"image_paths":history['image_paths'], "metadata_jsons":history['metadata_jsons'],"base64_images": history['base64_images']}
|
390 |
+
|
391 |
+
|
392 |
+
@router.post('/prompt_shortcut/load')
|
393 |
+
async def loadPromptShortcut(request: Request):
|
394 |
+
prompt_shortcut_json = {}
|
395 |
+
try:
|
396 |
+
json = await request.json()
|
397 |
+
except:
|
398 |
+
json = {}
|
399 |
+
|
400 |
+
try:
|
401 |
+
|
402 |
+
prompt_shortcut_json = prompt_shortcut.load()
|
403 |
+
# response.body = {"prompt_shortcut":prompt_shortcut}
|
404 |
+
# response.status_code = 200
|
405 |
+
except:
|
406 |
+
# print(f'exception: fail to send request to {sd_url}/sdapi/v1/{path}')
|
407 |
+
print(f'{request}')
|
408 |
+
|
409 |
+
# return response
|
410 |
+
return {"prompt_shortcut":prompt_shortcut_json}
|
411 |
+
@router.post('/prompt_shortcut/save')
|
412 |
+
async def loadPromptShortcut(request: Request):
|
413 |
+
prompt_shortcut_json = {}
|
414 |
+
try:
|
415 |
+
json = await request.json()
|
416 |
+
except:
|
417 |
+
json = {}
|
418 |
+
|
419 |
+
try:
|
420 |
+
print("json: ",json)
|
421 |
+
print("json['prompt_shortcut']: ",json['prompt_shortcut'])
|
422 |
+
# save the prompt shortcut to the prompt_shortcut.json
|
423 |
+
prompt_shortcut_json = json['prompt_shortcut']
|
424 |
+
# response.body = {"prompt_shortcut":prompt_shortcut}
|
425 |
+
# response.body = {"prompt_shortcut":prompt_shortcut}
|
426 |
+
prompt_shortcut.writeToJson("prompt_shortcut.json",prompt_shortcut_json)
|
427 |
+
except:
|
428 |
+
# print(f'exception: fail to send request to {sd_url}/sdapi/v1/{path}')
|
429 |
+
print(f'error occurred durning reading the request {request}')
|
430 |
+
# return response
|
431 |
+
return {"prompt_shortcut":prompt_shortcut_json}
|
432 |
+
|
433 |
+
@router.post("/swapModel")
|
434 |
+
async def swapModel(request:Request):
|
435 |
+
print("swapModel: \n")
|
436 |
+
payload = await request.json()
|
437 |
+
print("payload:",payload)
|
438 |
+
model_title = payload.title
|
439 |
+
option_payload = {
|
440 |
+
# "sd_model_checkpoint": "Anything-V3.0-pruned.ckpt [2700c435]"
|
441 |
+
"sd_model_checkpoint": model_title
|
442 |
+
|
443 |
+
}
|
444 |
+
response = requests.post(url=f'{sd_url}/sdapi/v1/options', json=option_payload)
|
445 |
+
|
446 |
+
|
447 |
+
import webbrowser
|
448 |
+
@router.post("/open/url/")
|
449 |
+
async def openUrl(request:Request):
|
450 |
+
try:
|
451 |
+
json = await request.json()
|
452 |
+
except:
|
453 |
+
json = {}
|
454 |
+
|
455 |
+
url = ""
|
456 |
+
print("json: ",json)
|
457 |
+
try:
|
458 |
+
url = json['url']
|
459 |
+
webbrowser.open(url) # Go to example.com
|
460 |
+
except:
|
461 |
+
# print(f'exception: fail to send request to {sd_url}/sdapi/v1/{path}')
|
462 |
+
print(f'an error has occurred durning processing the request {request}')
|
463 |
+
# return response
|
464 |
+
return {"url":url}
|
465 |
+
|
466 |
+
|
467 |
+
@router.get('/lora/list')
|
468 |
+
async def list_available_loras():
|
469 |
+
lora_dict = {}
|
470 |
+
try:
|
471 |
+
from modules import shared
|
472 |
+
import glob
|
473 |
+
|
474 |
+
os.makedirs(shared.cmd_opts.lora_dir, exist_ok=True)
|
475 |
+
|
476 |
+
candidates = \
|
477 |
+
glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.pt'), recursive=True) + \
|
478 |
+
glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.safetensors'), recursive=True) + \
|
479 |
+
glob.glob(os.path.join(shared.cmd_opts.lora_dir, '**/*.ckpt'), recursive=True)
|
480 |
+
|
481 |
+
for filename in sorted(candidates, key=str.lower):
|
482 |
+
if os.path.isdir(filename):
|
483 |
+
continue
|
484 |
+
|
485 |
+
name = os.path.splitext(os.path.basename(filename))[0]
|
486 |
+
print("lora name: ",name)
|
487 |
+
# available_loras[name] = LoraOnDisk(name, filename)
|
488 |
+
lora_dict[name] = name
|
489 |
+
|
490 |
+
except Exception as e:
|
491 |
+
print("list_available_loras() error ",repr(e),e)
|
492 |
+
return lora_dict
|
493 |
+
|
494 |
+
app = FastAPI()
|
495 |
+
app.include_router(router)
|
Auto-Photoshop-StableDiffusion-Plugin/start_server.bat
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@REM @echo off
|
2 |
+
git pull
|
3 |
+
|
4 |
+
set SD_URL=http://127.0.0.1:7860
|
5 |
+
|
6 |
+
echo does server_env\ exist
|
7 |
+
if exist server_env\ (
|
8 |
+
echo Yes
|
9 |
+
goto :activate_server_env
|
10 |
+
) else (
|
11 |
+
echo No
|
12 |
+
goto :create_server_env
|
13 |
+
)
|
14 |
+
|
15 |
+
:create_server_env
|
16 |
+
python -m venv server_env
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
@REM pause
|
22 |
+
|
23 |
+
|
24 |
+
:activate_server_env
|
25 |
+
|
26 |
+
::run a server
|
27 |
+
echo my_path: %~dp0
|
28 |
+
@REM set current_dir=
|
29 |
+
set VENV_DIR=%~dp0server_env
|
30 |
+
@REM cd ./server_env/Scripts/
|
31 |
+
set PYTHON="%VENV_DIR%\Scripts\Python.exe"
|
32 |
+
%PYTHON% -m pip install -r requirements.txt
|
33 |
+
|
34 |
+
cd ./server/python_server
|
35 |
+
echo python path: %PYTHON%
|
36 |
+
dir
|
37 |
+
echo %PYTHON% uvicorn serverMain:app --reload
|
38 |
+
%PYTHON% -m uvicorn serverMain:app --reload
|
39 |
+
pause
|
40 |
+
@REM exit /b
|
41 |
+
@REM %PYTHON% uvicorn serverMain:app --reload
|
42 |
+
pause
|
43 |
+
|
44 |
+
@REM %PYTHON% img2imgapi.py
|
45 |
+
@REM activate
|
46 |
+
@REM echo server_env %PYTHON%
|
47 |
+
@REM cd ./server/python_server
|
48 |
+
@REM %PYTHON% img2imgapi.py
|
49 |
+
@REM uvicorn serverMain:app --reload
|
50 |
+
@REM dir .
|
51 |
+
@REM call webui.bat
|
Auto-Photoshop-StableDiffusion-Plugin/start_server.sh
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
git pull
|
3 |
+
# Set the desired remote host where the "<>" is
|
4 |
+
export SD_URL=http://127.0.0.1:7860
|
5 |
+
|
6 |
+
# Check python was installed
|
7 |
+
if ! hash python; then
|
8 |
+
echo "Python is not installed"
|
9 |
+
exit 1
|
10 |
+
fi
|
11 |
+
|
12 |
+
# Check the default python version
|
13 |
+
orig_ver=$(python -V 2>&1)
|
14 |
+
major_version=$(echo "$orig_ver" | sed 's/[^0-9]*\([0-9]*\)\..*/\1/')
|
15 |
+
minor_subversion=$(echo "$orig_ver" | sed -E 's/^[^.]*\.([^.]*).*$/\1/')
|
16 |
+
if [[ "$major_version" -ge "3" ]] && [[ "$minor_subversion" -ge "7" ]] # Because of uvicorn==0.20.0 in requirements
|
17 |
+
then
|
18 |
+
echo "You have valid version of $orig_ver"
|
19 |
+
else
|
20 |
+
echo "Your version $orig_ver not valid, should be >=3.7"
|
21 |
+
exit 1
|
22 |
+
fi
|
23 |
+
|
24 |
+
|
25 |
+
# Check if the desired environment exists
|
26 |
+
if [ ! -d "server_env" ]; then
|
27 |
+
# Create the environment if it doesn't exist
|
28 |
+
python -m venv server_env
|
29 |
+
source ./server_env/bin/activate
|
30 |
+
python -m pip install -r requirements.txt
|
31 |
+
else
|
32 |
+
source ./server_env/bin/activate
|
33 |
+
fi
|
34 |
+
|
35 |
+
cd ./server/python_server
|
36 |
+
python -m uvicorn serverMain:app --reload
|
Auto-Photoshop-StableDiffusion-Plugin/start_server_MacOS.sh
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
git pull
|
3 |
+
# Set the desired remote host where the "<>" is
|
4 |
+
export SD_URL=http://127.0.0.1:7860
|
5 |
+
|
6 |
+
# Check if the desired environment exists
|
7 |
+
if [ ! -d "server_env" ]; then
|
8 |
+
# Create the environment if it doesn't exist
|
9 |
+
python3 -m venv server_env
|
10 |
+
source ./server_env/bin/activate
|
11 |
+
python3 -m pip install -r requirements.txt
|
12 |
+
else
|
13 |
+
source ./server_env/bin/activate
|
14 |
+
fi
|
15 |
+
|
16 |
+
cd ./server/python_server
|
17 |
+
python3 -m uvicorn serverMain:app --reload
|