a34e80e8b4b20b9452d240a5dfb1810a082bf12e800fb36d96f61768dfebfe44
Browse files- Auto-Photoshop-StableDiffusion-Plugin/thumbnail.js +40 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/.gitignore +1 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/config.ts +134 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/elements.tsx +255 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/scripts.tsx +165 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/ultimate_sd_upscaler.tsx +292 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/tsconfig.json +109 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/types/sdapi_py_re.d.ts +5 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/types/uxp.d.ts +5 -0
- Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/webpack.config.js +65 -0
- Auto-Photoshop-StableDiffusion-Plugin/update_plugin.bat +1 -0
- Auto-Photoshop-StableDiffusion-Plugin/update_plugin.sh +2 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/api.js +80 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/dummy.js +0 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/event.js +13 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/general.js +160 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/html_manip.js +1177 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/io.js +836 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/layer.js +357 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/notification.js +102 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/online_data.json +4 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/presets/controlnet_preset.js +198 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/presets/preset.js +408 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sampler.js +117 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sd_scripts/horde.js +107 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/config.js +83 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/horde_native.js +731 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/metadata_to_json.js +76 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/options.js +37 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/prompt_shortcut.js +42 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/python_replacement.js +594 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/session.js +270 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/control_net.js +1144 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/history_tab.js +101 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/image_search_tab.js +51 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/lexica_tab.js +239 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/sd.js +370 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/settings.js +137 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tab/share_tab.js +17 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/tips.js +40 -0
- Auto-Photoshop-StableDiffusion-Plugin/utility/ui.js +404 -0
- Auto-Photoshop-StableDiffusion-Plugin/viewer.js +861 -0
- Stable-Diffusion-Webui-Civitai-Helper/.github/ISSUE_TEMPLATE/simple-issue-template.md +20 -0
- Stable-Diffusion-Webui-Civitai-Helper/.gitignore +3 -0
- Stable-Diffusion-Webui-Civitai-Helper/README.cn.md +241 -0
- Stable-Diffusion-Webui-Civitai-Helper/README.jp.md +224 -0
- Stable-Diffusion-Webui-Civitai-Helper/README.kr.md +206 -0
- Stable-Diffusion-Webui-Civitai-Helper/README.md +329 -0
- Stable-Diffusion-Webui-Civitai-Helper/claim_wall.md +91 -0
- Stable-Diffusion-Webui-Civitai-Helper/icon/.keep +0 -0
Auto-Photoshop-StableDiffusion-Plugin/thumbnail.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class Thumbnail {
|
| 2 |
+
static wrapImgInContainer(img, container_style_class) {
|
| 3 |
+
const container = document.createElement('div')
|
| 4 |
+
container.className = container_style_class
|
| 5 |
+
container.appendChild(img)
|
| 6 |
+
return container
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
static addSPButtonToContainer(
|
| 10 |
+
container,
|
| 11 |
+
button_id,
|
| 12 |
+
title,
|
| 13 |
+
callbackFunction,
|
| 14 |
+
param1
|
| 15 |
+
) {
|
| 16 |
+
const elem = document.getElementById(button_id)
|
| 17 |
+
const clone = elem.cloneNode(true)
|
| 18 |
+
const button = clone
|
| 19 |
+
button.style.display = null
|
| 20 |
+
button.removeAttribute('id')
|
| 21 |
+
button.setAttribute('title', title)
|
| 22 |
+
|
| 23 |
+
// Create button element
|
| 24 |
+
button.className = 'thumbnail-image-button'
|
| 25 |
+
if (callbackFunction.constructor.name === 'AsyncFunction') {
|
| 26 |
+
button.addEventListener(
|
| 27 |
+
'click',
|
| 28 |
+
async () => await callbackFunction(param1)
|
| 29 |
+
)
|
| 30 |
+
} else {
|
| 31 |
+
button.addEventListener('click', () => callbackFunction(param1))
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
container.appendChild(button)
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
module.exports = {
|
| 39 |
+
Thumbnail,
|
| 40 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# dist/*.bundle.js
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/config.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export let ui_config = {
|
| 2 |
+
tile_width: {
|
| 3 |
+
minimum: 0,
|
| 4 |
+
maximum: 2048,
|
| 5 |
+
step: 64,
|
| 6 |
+
label: 'Tile width',
|
| 7 |
+
value: 512,
|
| 8 |
+
},
|
| 9 |
+
tile_height: {
|
| 10 |
+
minimum: 0,
|
| 11 |
+
maximum: 2048,
|
| 12 |
+
step: 64,
|
| 13 |
+
label: 'Tile height',
|
| 14 |
+
value: 0,
|
| 15 |
+
},
|
| 16 |
+
mask_blur: {
|
| 17 |
+
minimum: 0,
|
| 18 |
+
maximum: 64,
|
| 19 |
+
step: 1,
|
| 20 |
+
label: 'Mask blur',
|
| 21 |
+
value: 8,
|
| 22 |
+
},
|
| 23 |
+
padding: { minimum: 0, maximum: 128, step: 1, label: 'Padding', value: 32 },
|
| 24 |
+
|
| 25 |
+
seams_fix_denoise: {
|
| 26 |
+
label: 'Denoise',
|
| 27 |
+
minimum: 0,
|
| 28 |
+
maximum: 1,
|
| 29 |
+
step: 0.01,
|
| 30 |
+
value: 0.35,
|
| 31 |
+
visible: false,
|
| 32 |
+
interactive: true,
|
| 33 |
+
},
|
| 34 |
+
|
| 35 |
+
seams_fix_width: {
|
| 36 |
+
label: 'Width',
|
| 37 |
+
minimum: 0,
|
| 38 |
+
maximum: 128,
|
| 39 |
+
step: 1,
|
| 40 |
+
value: 64,
|
| 41 |
+
visible: false,
|
| 42 |
+
interactive: true,
|
| 43 |
+
},
|
| 44 |
+
seams_fix_mask_blur: {
|
| 45 |
+
label: 'Mask blur',
|
| 46 |
+
minimum: 0,
|
| 47 |
+
maximum: 64,
|
| 48 |
+
step: 1,
|
| 49 |
+
value: 4,
|
| 50 |
+
visible: false,
|
| 51 |
+
interactive: true,
|
| 52 |
+
},
|
| 53 |
+
seams_fix_padding: {
|
| 54 |
+
label: 'Padding',
|
| 55 |
+
minimum: 0,
|
| 56 |
+
maximum: 128,
|
| 57 |
+
step: 1,
|
| 58 |
+
value: 16,
|
| 59 |
+
visible: false,
|
| 60 |
+
interactive: true,
|
| 61 |
+
},
|
| 62 |
+
redraw_mode: {
|
| 63 |
+
label: 'Type',
|
| 64 |
+
choices: ['Linear', 'Chess', 'None'],
|
| 65 |
+
type: 'index',
|
| 66 |
+
value: 0,
|
| 67 |
+
},
|
| 68 |
+
save_upscaled_image: {
|
| 69 |
+
label: 'Upscaled',
|
| 70 |
+
value: true,
|
| 71 |
+
},
|
| 72 |
+
save_seams_fix_image: {
|
| 73 |
+
label: 'Seams fix',
|
| 74 |
+
value: false,
|
| 75 |
+
},
|
| 76 |
+
|
| 77 |
+
seams_fix_type: {
|
| 78 |
+
label: 'Type',
|
| 79 |
+
choices: [
|
| 80 |
+
'None',
|
| 81 |
+
'Band pass',
|
| 82 |
+
'Half tile offset pass',
|
| 83 |
+
'Half tile offset pass + intersections',
|
| 84 |
+
],
|
| 85 |
+
type: 'index',
|
| 86 |
+
value: 3,
|
| 87 |
+
},
|
| 88 |
+
|
| 89 |
+
target_size_type: {
|
| 90 |
+
label: 'Target size type',
|
| 91 |
+
choices: [
|
| 92 |
+
'From img2img2 settings',
|
| 93 |
+
'Custom size',
|
| 94 |
+
'Scale from image size',
|
| 95 |
+
],
|
| 96 |
+
type: 'index',
|
| 97 |
+
value: 2,
|
| 98 |
+
},
|
| 99 |
+
|
| 100 |
+
custom_width: {
|
| 101 |
+
label: 'Custom width',
|
| 102 |
+
minimum: 64,
|
| 103 |
+
maximum: 8192,
|
| 104 |
+
step: 64,
|
| 105 |
+
value: 2048,
|
| 106 |
+
visible: false,
|
| 107 |
+
interactive: true,
|
| 108 |
+
},
|
| 109 |
+
custom_height: {
|
| 110 |
+
label: 'Custom height',
|
| 111 |
+
minimum: 64,
|
| 112 |
+
maximum: 8192,
|
| 113 |
+
step: 64,
|
| 114 |
+
value: 2048,
|
| 115 |
+
visible: false,
|
| 116 |
+
interactive: true,
|
| 117 |
+
},
|
| 118 |
+
custom_scale: {
|
| 119 |
+
label: 'Scale',
|
| 120 |
+
minimum: 1,
|
| 121 |
+
maximum: 16,
|
| 122 |
+
step: 0.01,
|
| 123 |
+
value: 2,
|
| 124 |
+
visible: false,
|
| 125 |
+
interactive: true,
|
| 126 |
+
},
|
| 127 |
+
|
| 128 |
+
upscaler_index: {
|
| 129 |
+
label: 'Upscaler',
|
| 130 |
+
choices: [],
|
| 131 |
+
type: 'index',
|
| 132 |
+
value: 0,
|
| 133 |
+
},
|
| 134 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/elements.tsx
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { ReactEventHandler, useState } from 'react'
|
| 2 |
+
// import ReactDOM from 'react-dom'
|
| 3 |
+
import ReactDOM from 'react-dom/client'
|
| 4 |
+
import { versions } from 'uxp'
|
| 5 |
+
declare global {
|
| 6 |
+
namespace JSX {
|
| 7 |
+
interface IntrinsicElements {
|
| 8 |
+
'sp-picker': any
|
| 9 |
+
'sp-menu': any
|
| 10 |
+
'sp-menu-item': any
|
| 11 |
+
'sp-label': any
|
| 12 |
+
'sp-checkbox': any
|
| 13 |
+
'sp-slider': any
|
| 14 |
+
'sp-radio-group': any
|
| 15 |
+
'sp-radio': any
|
| 16 |
+
'sp-divider': any
|
| 17 |
+
'sp-detail': any
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
function mapRange(
|
| 22 |
+
x: number,
|
| 23 |
+
in_min: number,
|
| 24 |
+
in_max: number,
|
| 25 |
+
out_min: number,
|
| 26 |
+
out_max: number
|
| 27 |
+
) {
|
| 28 |
+
const mappedValue =
|
| 29 |
+
((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
|
| 30 |
+
return mappedValue
|
| 31 |
+
}
|
| 32 |
+
export enum SliderType {
|
| 33 |
+
Integer = 'integer',
|
| 34 |
+
Float = 'float',
|
| 35 |
+
}
|
| 36 |
+
export class SpSliderWithLabel extends React.Component<{
|
| 37 |
+
onSliderChange?: any
|
| 38 |
+
id?: string
|
| 39 |
+
'show-value'?: boolean
|
| 40 |
+
steps?: number
|
| 41 |
+
in_min?: number
|
| 42 |
+
in_max?: number
|
| 43 |
+
out_min: number
|
| 44 |
+
out_max: number
|
| 45 |
+
// value?: number
|
| 46 |
+
title?: string
|
| 47 |
+
label?: string
|
| 48 |
+
output_value?: number // can be use to represent sd value
|
| 49 |
+
// slider_value?: number // it's slider value can be from 1 to 100
|
| 50 |
+
slider_type?: SliderType
|
| 51 |
+
}> {
|
| 52 |
+
// const [sliderValue,setSliderValue] = useState<number>(0)
|
| 53 |
+
state = { output_value: this.props.output_value || 0, slider_value: 0 }
|
| 54 |
+
steps: number
|
| 55 |
+
in_min: number
|
| 56 |
+
in_max: number
|
| 57 |
+
out_min: number
|
| 58 |
+
out_max: number
|
| 59 |
+
slider_type: SliderType
|
| 60 |
+
constructor(props: any) {
|
| 61 |
+
super(props)
|
| 62 |
+
this.steps = this.props.steps || 1
|
| 63 |
+
// this.out_min = this.props.out_min || this.in_min
|
| 64 |
+
this.out_min = this.props.out_min
|
| 65 |
+
this.out_max = this.props.out_max
|
| 66 |
+
|
| 67 |
+
// const temp_out_max = this.props.out_max || this.props.in_max || 99
|
| 68 |
+
this.in_min = this.props.in_min || 0
|
| 69 |
+
this.in_max = Math.round((this.out_max - this.out_min) / this.steps)
|
| 70 |
+
this.slider_type = this.props.slider_type || SliderType.Integer
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
componentDidMount(): void {
|
| 74 |
+
const slider_value = this.outputValueToStep(this.state.output_value)
|
| 75 |
+
this.setState({ slider_value: slider_value })
|
| 76 |
+
}
|
| 77 |
+
stepToOutputValue(slider_step: number) {
|
| 78 |
+
let to_value = mapRange(
|
| 79 |
+
slider_step,
|
| 80 |
+
this.in_min,
|
| 81 |
+
this.in_max,
|
| 82 |
+
this.out_min,
|
| 83 |
+
this.out_max
|
| 84 |
+
)
|
| 85 |
+
if (this.slider_type === SliderType.Integer)
|
| 86 |
+
to_value = Math.round(to_value)
|
| 87 |
+
|
| 88 |
+
return to_value
|
| 89 |
+
}
|
| 90 |
+
outputValueToStep(output_value: number) {
|
| 91 |
+
let slider_step = mapRange(
|
| 92 |
+
output_value,
|
| 93 |
+
this.out_min,
|
| 94 |
+
this.out_max,
|
| 95 |
+
this.in_min,
|
| 96 |
+
this.in_max
|
| 97 |
+
)
|
| 98 |
+
// if (this.slider_type === SliderType.Integer)
|
| 99 |
+
slider_step = Math.round(slider_step)
|
| 100 |
+
return slider_step
|
| 101 |
+
}
|
| 102 |
+
setSliderValue(newValue: any) {
|
| 103 |
+
let to_value = mapRange(
|
| 104 |
+
newValue,
|
| 105 |
+
this.in_min,
|
| 106 |
+
this.in_max,
|
| 107 |
+
this.out_min,
|
| 108 |
+
this.out_max
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
if (this.slider_type === SliderType.Integer)
|
| 112 |
+
to_value = Math.round(to_value)
|
| 113 |
+
|
| 114 |
+
this.setState({ output_value: to_value })
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
onSliderValueChangeHandler(event: React.ChangeEvent<HTMLInputElement>) {
|
| 118 |
+
const newValue: string = event.target.value
|
| 119 |
+
console.log('onSliderValueChangeHandler value: ', newValue)
|
| 120 |
+
this.setState({ output_value: newValue })
|
| 121 |
+
|
| 122 |
+
console.log({
|
| 123 |
+
in_min: this.in_min,
|
| 124 |
+
in_max: this.in_max,
|
| 125 |
+
out_min: this.out_min,
|
| 126 |
+
out_max: this.out_max,
|
| 127 |
+
})
|
| 128 |
+
|
| 129 |
+
let output_value = this.stepToOutputValue(parseInt(newValue))
|
| 130 |
+
this.setState({ output_value: output_value })
|
| 131 |
+
if (this.props.onSliderChange && this.props.id) {
|
| 132 |
+
this.props.onSliderChange(this.props.id, output_value)
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
handleNum2Change = (event: React.ChangeEvent<HTMLInputElement>) => {}
|
| 137 |
+
|
| 138 |
+
render() {
|
| 139 |
+
return (
|
| 140 |
+
// <div>
|
| 141 |
+
// <
|
| 142 |
+
// <sp-detail>VERSIONS</sp-detail>
|
| 143 |
+
// <div>{versions.plugin}</div>
|
| 144 |
+
// </div>
|
| 145 |
+
<div>
|
| 146 |
+
<sp-slider
|
| 147 |
+
show-value="false"
|
| 148 |
+
// id="slControlNetWeight_0"
|
| 149 |
+
class="slControlNetWeight_"
|
| 150 |
+
min={this.in_min}
|
| 151 |
+
max={this.in_max}
|
| 152 |
+
value={this.state.slider_value}
|
| 153 |
+
title="2 will keep the composition; 0 will allow composition to change"
|
| 154 |
+
onInput={this.onSliderValueChangeHandler.bind(this)}
|
| 155 |
+
>
|
| 156 |
+
<sp-label slot="label">{this.props.label}:</sp-label>
|
| 157 |
+
<sp-label
|
| 158 |
+
slot="label"
|
| 159 |
+
// id="lControlNetWeight_0"
|
| 160 |
+
class="lControlNetWeight_"
|
| 161 |
+
>
|
| 162 |
+
{this.state.output_value}
|
| 163 |
+
</sp-label>
|
| 164 |
+
</sp-slider>
|
| 165 |
+
</div>
|
| 166 |
+
)
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
export class SpMenu extends React.Component<{
|
| 171 |
+
id?: string
|
| 172 |
+
|
| 173 |
+
title?: string
|
| 174 |
+
style?: string
|
| 175 |
+
items?: string[]
|
| 176 |
+
disabled?: boolean[]
|
| 177 |
+
label_item?: string
|
| 178 |
+
onChange?: any
|
| 179 |
+
selected_index?: number
|
| 180 |
+
}> {
|
| 181 |
+
state = {
|
| 182 |
+
selectedItem: this.props.items ? this.props.items[0] : undefined,
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
componentDidUpdate(prevProps: any) {
|
| 186 |
+
// console.log('prevProps.items: ', prevProps.items)
|
| 187 |
+
// console.log('this.props.items: ', this.props.items)
|
| 188 |
+
// if (prevProps.items !== this.props.items) {
|
| 189 |
+
// const spMenu = this.spMenuRef.current
|
| 190 |
+
// if (spMenu) {
|
| 191 |
+
// spMenu.innerHTML = ''
|
| 192 |
+
// }
|
| 193 |
+
// }
|
| 194 |
+
}
|
| 195 |
+
handleItemClick = (item: string, index: number) => {
|
| 196 |
+
console.log('clicked item: ', item)
|
| 197 |
+
console.log('clicked index: ', index)
|
| 198 |
+
this.setState({ selectedItem: item })
|
| 199 |
+
if (this.props.onChange && this.props.id) {
|
| 200 |
+
this.props.onChange(this.props.id, { index: index, item: item })
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
handleMakeSelection = (item: string) => {
|
| 204 |
+
console.log('handleMakeSelection: item ', item)
|
| 205 |
+
this.setState({ selectedItem: item })
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
render() {
|
| 209 |
+
return (
|
| 210 |
+
<div>
|
| 211 |
+
<sp-picker
|
| 212 |
+
title={this.props.title}
|
| 213 |
+
size="m"
|
| 214 |
+
style={{ width: '199px', marginRight: '5px' }}
|
| 215 |
+
>
|
| 216 |
+
<sp-menu id={this.props.id} slot="options">
|
| 217 |
+
{this.props.label_item && (
|
| 218 |
+
<sp-menu-item
|
| 219 |
+
disabled="disabled"
|
| 220 |
+
key={-1}
|
| 221 |
+
data-index={-1}
|
| 222 |
+
selected
|
| 223 |
+
>
|
| 224 |
+
{this.props.label_item}
|
| 225 |
+
</sp-menu-item>
|
| 226 |
+
)}
|
| 227 |
+
{this.props.items?.map((item, index: number) => (
|
| 228 |
+
<sp-menu-item
|
| 229 |
+
key={item}
|
| 230 |
+
data-index={index}
|
| 231 |
+
selected={
|
| 232 |
+
this.props.selected_index !== undefined &&
|
| 233 |
+
this.props.selected_index !== null &&
|
| 234 |
+
this.props.selected_index === index
|
| 235 |
+
? 'selected'
|
| 236 |
+
: undefined
|
| 237 |
+
}
|
| 238 |
+
disabled={
|
| 239 |
+
this.props.disabled?.[index]
|
| 240 |
+
? 'disabled'
|
| 241 |
+
: undefined
|
| 242 |
+
}
|
| 243 |
+
onClick={() => {
|
| 244 |
+
this.handleItemClick(item, index)
|
| 245 |
+
}}
|
| 246 |
+
>
|
| 247 |
+
{item}
|
| 248 |
+
</sp-menu-item>
|
| 249 |
+
))}
|
| 250 |
+
</sp-menu>
|
| 251 |
+
</sp-picker>
|
| 252 |
+
</div>
|
| 253 |
+
)
|
| 254 |
+
}
|
| 255 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/scripts.tsx
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { ReactEventHandler, useState } from 'react'
|
| 2 |
+
import ReactDOM from 'react-dom/client'
|
| 3 |
+
|
| 4 |
+
import { action, makeAutoObservable, reaction, toJS } from 'mobx'
|
| 5 |
+
import { Provider, inject, observer } from 'mobx-react'
|
| 6 |
+
|
| 7 |
+
import { SpMenu } from './elements'
|
| 8 |
+
import * as ultimate_sd_upscale_script from './ultimate_sd_upscaler'
|
| 9 |
+
import { ScriptMode } from './ultimate_sd_upscaler'
|
| 10 |
+
export function toJsFunc(store: any) {
|
| 11 |
+
return toJS(store)
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
class ScriptStore {
|
| 15 |
+
scripts_list
|
| 16 |
+
disabled: boolean[]
|
| 17 |
+
selected_script_name
|
| 18 |
+
is_selected_script_available: boolean
|
| 19 |
+
selected_store: any
|
| 20 |
+
is_active: boolean
|
| 21 |
+
selected_args_name: string[]
|
| 22 |
+
mode: ScriptMode
|
| 23 |
+
scripts: any = {
|
| 24 |
+
None: { store: null, args_names: [], mode: [] },
|
| 25 |
+
'Ultimate SD upscale': {
|
| 26 |
+
store: ultimate_sd_upscale_script.ultimate_sd_upscaler_store,
|
| 27 |
+
args_names: ultimate_sd_upscale_script.script_args_ordered,
|
| 28 |
+
mode: ultimate_sd_upscale_script.script_mode,
|
| 29 |
+
},
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
constructor() {
|
| 33 |
+
this.scripts_list = ['None', ultimate_sd_upscale_script.script_name]
|
| 34 |
+
this.disabled = [false, true]
|
| 35 |
+
this.selected_script_name = 'None'
|
| 36 |
+
this.is_selected_script_available = true
|
| 37 |
+
this.selected_store = null
|
| 38 |
+
this.is_active = true
|
| 39 |
+
this.selected_args_name = []
|
| 40 |
+
this.mode = ScriptMode.Txt2Img
|
| 41 |
+
makeAutoObservable(this)
|
| 42 |
+
}
|
| 43 |
+
setSelectedScript(name: string) {
|
| 44 |
+
this.selected_script_name = name
|
| 45 |
+
this.selected_store = this.scripts[name].store
|
| 46 |
+
this.selected_args_name = this.scripts[name].args_names
|
| 47 |
+
this.is_selected_script_available = true
|
| 48 |
+
}
|
| 49 |
+
setIsActive(new_value: boolean) {
|
| 50 |
+
this.is_active = new_value
|
| 51 |
+
}
|
| 52 |
+
updateProperty(id: any, value: any) {}
|
| 53 |
+
|
| 54 |
+
orderedValues() {
|
| 55 |
+
const values: any = []
|
| 56 |
+
if (!this.selected_store) return values
|
| 57 |
+
|
| 58 |
+
for (const key of this.selected_args_name) {
|
| 59 |
+
// console.log(key, this.data[key])
|
| 60 |
+
values.push((this.selected_store.data as any)[key])
|
| 61 |
+
}
|
| 62 |
+
return values
|
| 63 |
+
}
|
| 64 |
+
setDisabled(newDisabled: boolean[]) {
|
| 65 |
+
console.log('this.disabled:', this.disabled)
|
| 66 |
+
console.log('newDisabled:', newDisabled)
|
| 67 |
+
|
| 68 |
+
this.disabled = newDisabled
|
| 69 |
+
}
|
| 70 |
+
setMode(newMode: ScriptMode) {
|
| 71 |
+
this.mode = newMode
|
| 72 |
+
|
| 73 |
+
// let index = 0
|
| 74 |
+
// Object.keys(this.scripts).forEach((key, index) => {
|
| 75 |
+
// const script = this.scripts[key]
|
| 76 |
+
// this.disabled[index] = script.mode.includes(newMode) ? false : true
|
| 77 |
+
|
| 78 |
+
// // console.log(key, script)
|
| 79 |
+
// })
|
| 80 |
+
const names = Object.keys(this.scripts)
|
| 81 |
+
let index = 0
|
| 82 |
+
for (let name of names) {
|
| 83 |
+
const script = this.scripts[name]
|
| 84 |
+
this.disabled[index] = script.mode.includes(newMode) ? false : true
|
| 85 |
+
index += 1
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
this.disabled[0] = false // None is always enabled
|
| 89 |
+
const selected_index = this.scripts_list.indexOf(
|
| 90 |
+
this.selected_script_name
|
| 91 |
+
)
|
| 92 |
+
this.is_selected_script_available = !this.disabled?.[selected_index]
|
| 93 |
+
this.setDisabled([...this.disabled])
|
| 94 |
+
}
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
export const script_store = new ScriptStore()
|
| 98 |
+
@observer
|
| 99 |
+
class ScriptComponent extends React.Component<{}> {
|
| 100 |
+
render(): React.ReactNode {
|
| 101 |
+
// const script_message = index !== -1 ? script_store.disabled[index] : undefined;
|
| 102 |
+
const script_message =
|
| 103 |
+
script_store.is_selected_script_available ? undefined : (
|
| 104 |
+
<span style={{ color: '#ff595e' }}>
|
| 105 |
+
{'the script is not available in the current Mode'}
|
| 106 |
+
</span>
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
return (
|
| 110 |
+
<>
|
| 111 |
+
<SpMenu
|
| 112 |
+
title="Scripts"
|
| 113 |
+
items={script_store.scripts_list}
|
| 114 |
+
disabled={script_store.disabled}
|
| 115 |
+
// style="width: 199px; margin-right: 5px"
|
| 116 |
+
label_item="Select A Script"
|
| 117 |
+
id={'script_list'}
|
| 118 |
+
onChange={(id: any, value: any) => {
|
| 119 |
+
script_store.setSelectedScript(value.item)
|
| 120 |
+
}}
|
| 121 |
+
/>
|
| 122 |
+
<div>
|
| 123 |
+
{script_message}
|
| 124 |
+
|
| 125 |
+
{/* {script_store.disabled.map((value, index) => (
|
| 126 |
+
<li key={index}> {value ? 'true' : 'false'}</li>
|
| 127 |
+
))} */}
|
| 128 |
+
</div>
|
| 129 |
+
<sp-checkbox
|
| 130 |
+
checked={script_store.is_active ? true : undefined}
|
| 131 |
+
onClick={(event: React.ChangeEvent<HTMLInputElement>) => {
|
| 132 |
+
script_store.setIsActive(event.target.checked)
|
| 133 |
+
}}
|
| 134 |
+
>
|
| 135 |
+
{'Activate'}
|
| 136 |
+
</sp-checkbox>
|
| 137 |
+
<>
|
| 138 |
+
{script_store.selected_script_name === 'None' && <></>}
|
| 139 |
+
{script_store.selected_script_name ===
|
| 140 |
+
ultimate_sd_upscale_script.script_name && (
|
| 141 |
+
<ultimate_sd_upscale_script.UltimateSDUpscalerForm
|
| 142 |
+
store={
|
| 143 |
+
// ultimate_sd_upscale_script.ultimate_sd_upscaler_store
|
| 144 |
+
script_store.scripts[
|
| 145 |
+
script_store.selected_script_name
|
| 146 |
+
].store
|
| 147 |
+
}
|
| 148 |
+
/>
|
| 149 |
+
)}
|
| 150 |
+
{/* ... other conditions for other components */}
|
| 151 |
+
</>
|
| 152 |
+
</>
|
| 153 |
+
)
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
const domNode = document.getElementById('scriptsContainer')!
|
| 157 |
+
const root = ReactDOM.createRoot(domNode)
|
| 158 |
+
|
| 159 |
+
root.render(
|
| 160 |
+
<React.StrictMode>
|
| 161 |
+
<ScriptComponent></ScriptComponent>
|
| 162 |
+
|
| 163 |
+
{/* <SliderValuesDisplay /> */}
|
| 164 |
+
</React.StrictMode>
|
| 165 |
+
)
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/src/ultimate_sd_upscaler.tsx
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { ReactEventHandler } from 'react'
|
| 2 |
+
import ReactDOM from 'react-dom/client'
|
| 3 |
+
|
| 4 |
+
import { action, makeAutoObservable, reaction, toJS } from 'mobx'
|
| 5 |
+
import { Provider, inject, observer } from 'mobx-react'
|
| 6 |
+
|
| 7 |
+
import { SliderType, SpMenu, SpSliderWithLabel } from './elements'
|
| 8 |
+
|
| 9 |
+
import * as sdapi from '../../sdapi_py_re'
|
| 10 |
+
|
| 11 |
+
import { ui_config } from './config'
|
| 12 |
+
|
| 13 |
+
export let script_name: string = 'Ultimate SD upscale'
|
| 14 |
+
export enum ScriptMode {
|
| 15 |
+
Txt2Img = 'txt2img',
|
| 16 |
+
Img2Img = 'img2img',
|
| 17 |
+
Inpaint = 'inpaint',
|
| 18 |
+
Outpaint = 'outpaint',
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
export let script_mode = [
|
| 22 |
+
ScriptMode.Img2Img,
|
| 23 |
+
ScriptMode.Inpaint,
|
| 24 |
+
ScriptMode.Outpaint,
|
| 25 |
+
]
|
| 26 |
+
interface UltimateSDUpscalerData {
|
| 27 |
+
_: string
|
| 28 |
+
tile_width: number
|
| 29 |
+
tile_height: number
|
| 30 |
+
mask_blur: number
|
| 31 |
+
padding: number
|
| 32 |
+
seams_fix_width: number
|
| 33 |
+
seams_fix_denoise: number
|
| 34 |
+
seams_fix_padding: number
|
| 35 |
+
upscaler_index: number
|
| 36 |
+
save_upscaled_image: boolean
|
| 37 |
+
redraw_mode: number
|
| 38 |
+
save_seams_fix_image: boolean
|
| 39 |
+
seams_fix_mask_blur: number
|
| 40 |
+
seams_fix_type: number
|
| 41 |
+
target_size_type: number
|
| 42 |
+
custom_width: number
|
| 43 |
+
custom_height: number
|
| 44 |
+
custom_scale: number
|
| 45 |
+
}
|
| 46 |
+
export const script_args_ordered = [
|
| 47 |
+
'_',
|
| 48 |
+
'tile_width',
|
| 49 |
+
'tile_height',
|
| 50 |
+
'mask_blur',
|
| 51 |
+
'padding',
|
| 52 |
+
'seams_fix_width',
|
| 53 |
+
'seams_fix_denoise',
|
| 54 |
+
'seams_fix_padding',
|
| 55 |
+
'upscaler_index',
|
| 56 |
+
'save_upscaled_image',
|
| 57 |
+
'redraw_mode',
|
| 58 |
+
'save_seams_fix_image',
|
| 59 |
+
'seams_fix_mask_blur',
|
| 60 |
+
'seams_fix_type',
|
| 61 |
+
'target_size_type',
|
| 62 |
+
'custom_width',
|
| 63 |
+
'custom_height',
|
| 64 |
+
'custom_scale',
|
| 65 |
+
]
|
| 66 |
+
|
| 67 |
+
class UltimateSDUpscalerStore {
|
| 68 |
+
data: UltimateSDUpscalerData
|
| 69 |
+
// test_value: number = 10
|
| 70 |
+
// test_value_2: number = 2
|
| 71 |
+
test_value: number
|
| 72 |
+
test_value_2: number
|
| 73 |
+
is_active: boolean
|
| 74 |
+
constructor(data: UltimateSDUpscalerData) {
|
| 75 |
+
this.data = data
|
| 76 |
+
this.test_value = 10
|
| 77 |
+
this.test_value_2 = 2
|
| 78 |
+
this.is_active = false
|
| 79 |
+
makeAutoObservable(this)
|
| 80 |
+
|
| 81 |
+
// reaction(
|
| 82 |
+
// () => [this.test_value],
|
| 83 |
+
// () => {
|
| 84 |
+
// this.test_value_2 = this.test_value * 2
|
| 85 |
+
// console.log('reaction to test_value change:', this.test_value)
|
| 86 |
+
// console.log('this.test_value_2:', this.test_value_2)
|
| 87 |
+
// }
|
| 88 |
+
// )
|
| 89 |
+
}
|
| 90 |
+
setIsActive(b_value: boolean) {
|
| 91 |
+
this.is_active = b_value
|
| 92 |
+
}
|
| 93 |
+
setTestValue(new_value: number) {
|
| 94 |
+
this.test_value = new_value
|
| 95 |
+
console.log('setTestValue: new_value ', new_value)
|
| 96 |
+
console.log('setTestValue: this.test_value: ', this.test_value)
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
updateProperty(key: keyof UltimateSDUpscalerData, value: any) {
|
| 100 |
+
;(this.data as any)[key] = value
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
toJsFunc() {
|
| 104 |
+
return toJS(this)
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
const configValues = Object.entries(ui_config).reduce(
|
| 109 |
+
(acc, [key, value]) => ({ ...acc, [key]: value.value }),
|
| 110 |
+
{}
|
| 111 |
+
)
|
| 112 |
+
const default_values: any = {
|
| 113 |
+
_: '',
|
| 114 |
+
...configValues,
|
| 115 |
+
}
|
| 116 |
+
export const ultimate_sd_upscaler_store = new UltimateSDUpscalerStore(
|
| 117 |
+
default_values
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
@observer
|
| 121 |
+
export class UltimateSDUpscalerForm extends React.Component<{
|
| 122 |
+
store: UltimateSDUpscalerStore
|
| 123 |
+
}> {
|
| 124 |
+
// slider1Ref = React.createRef<SpSliderWithLabel>()
|
| 125 |
+
// slider2Ref = React.createRef<SpSliderWithLabel>()
|
| 126 |
+
state = {
|
| 127 |
+
items: ['Item 1', 'Item 2', 'Item 3'],
|
| 128 |
+
sd_upscalers: [],
|
| 129 |
+
}
|
| 130 |
+
componentDidMount(): void {
|
| 131 |
+
this.getUpscalers()
|
| 132 |
+
}
|
| 133 |
+
handleUpdateItems = () => {
|
| 134 |
+
this.setState({
|
| 135 |
+
items: ['New Item 1', 'New Item 2', 'New Item 3'],
|
| 136 |
+
})
|
| 137 |
+
}
|
| 138 |
+
handleSlider1ValueChange = (newValue: any) => {
|
| 139 |
+
// this.props.store.setTestValue(newValue)
|
| 140 |
+
this.props.store.test_value = newValue
|
| 141 |
+
|
| 142 |
+
// this.props.store.
|
| 143 |
+
console.log('store.test_value: ', this.props.store.test_value)
|
| 144 |
+
console.log('newValue: ', newValue)
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
handleSlider2ValueChange = (newValue: any) => {
|
| 148 |
+
// scriptFormStore.setSlider2Value(newValue)
|
| 149 |
+
}
|
| 150 |
+
handleSliderChange = (key: any, newValue: any) => {
|
| 151 |
+
this.props.store.updateProperty(key, newValue)
|
| 152 |
+
}
|
| 153 |
+
handleMenuChange = (key: any, new_index_value_pair: any) => {
|
| 154 |
+
let config = ui_config[key as keyof typeof ui_config] as any
|
| 155 |
+
if ('type' in config) {
|
| 156 |
+
let value =
|
| 157 |
+
config.type === 'index'
|
| 158 |
+
? new_index_value_pair['index']
|
| 159 |
+
: new_index_value_pair['item']
|
| 160 |
+
this.props.store.updateProperty(key, value)
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
async getUpscalers() {
|
| 165 |
+
const sd_upscalers_json = await sdapi.requestGetUpscalers()
|
| 166 |
+
const sd_upscalers = sd_upscalers_json.map(
|
| 167 |
+
(upscaler: any) => upscaler.name
|
| 168 |
+
)
|
| 169 |
+
this.setState({ sd_upscalers: sd_upscalers })
|
| 170 |
+
return sd_upscalers
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
render() {
|
| 174 |
+
const ids = [
|
| 175 |
+
'tile_width',
|
| 176 |
+
'tile_height',
|
| 177 |
+
'mask_blur',
|
| 178 |
+
'padding',
|
| 179 |
+
] as const
|
| 180 |
+
// let config = ui_config[ids as keyof typeof ui_config] as any
|
| 181 |
+
const group_1_sliders = ids.map((id) => (
|
| 182 |
+
<SpSliderWithLabel
|
| 183 |
+
key={id}
|
| 184 |
+
id={id}
|
| 185 |
+
show-value={false}
|
| 186 |
+
steps={ui_config[id].step}
|
| 187 |
+
out_min={ui_config[id].minimum}
|
| 188 |
+
out_max={ui_config[id].maximum}
|
| 189 |
+
output_value={this.props.store.data[id]}
|
| 190 |
+
title={ui_config[id].label}
|
| 191 |
+
label={ui_config[id].label}
|
| 192 |
+
onSliderChange={this.handleSliderChange}
|
| 193 |
+
/>
|
| 194 |
+
))
|
| 195 |
+
const seamfix_ids = [
|
| 196 |
+
'seams_fix_denoise',
|
| 197 |
+
'seams_fix_width',
|
| 198 |
+
'seams_fix_mask_blur',
|
| 199 |
+
'seams_fix_padding',
|
| 200 |
+
] as const
|
| 201 |
+
const seamfix_sliders = seamfix_ids.map((id) => (
|
| 202 |
+
<SpSliderWithLabel
|
| 203 |
+
key={id}
|
| 204 |
+
id={id}
|
| 205 |
+
show-value={false}
|
| 206 |
+
steps={ui_config[id].step}
|
| 207 |
+
out_min={ui_config[id].minimum}
|
| 208 |
+
out_max={ui_config[id].maximum}
|
| 209 |
+
output_value={this.props.store.data[id]}
|
| 210 |
+
title={ui_config[id].label}
|
| 211 |
+
label={ui_config[id].label}
|
| 212 |
+
onSliderChange={this.handleSliderChange}
|
| 213 |
+
slider_type={
|
| 214 |
+
Number.isInteger(ui_config[id].step)
|
| 215 |
+
? SliderType.Integer
|
| 216 |
+
: SliderType.Float
|
| 217 |
+
}
|
| 218 |
+
/>
|
| 219 |
+
))
|
| 220 |
+
return (
|
| 221 |
+
<div>
|
| 222 |
+
<SpMenu
|
| 223 |
+
title="Stable Diffusion Upscalers"
|
| 224 |
+
items={this.state.sd_upscalers}
|
| 225 |
+
label_item="Select Upscaler"
|
| 226 |
+
id={'upscaler_index'}
|
| 227 |
+
onChange={this.handleMenuChange}
|
| 228 |
+
selected_index={this.props.store.data.upscaler_index}
|
| 229 |
+
/>
|
| 230 |
+
<SpMenu
|
| 231 |
+
title={ui_config.target_size_type.label}
|
| 232 |
+
id={'target_size_type'}
|
| 233 |
+
items={ui_config.target_size_type.choices}
|
| 234 |
+
label_item={'Select ' + ui_config.target_size_type.label}
|
| 235 |
+
onChange={this.handleMenuChange}
|
| 236 |
+
selected_index={this.props.store.data.target_size_type}
|
| 237 |
+
/>
|
| 238 |
+
<SpSliderWithLabel
|
| 239 |
+
label={ui_config.custom_scale.label}
|
| 240 |
+
output_value={this.props.store.data.custom_scale}
|
| 241 |
+
id={'custom_scale'}
|
| 242 |
+
out_min={ui_config.custom_scale.minimum}
|
| 243 |
+
out_max={ui_config.custom_scale.maximum}
|
| 244 |
+
onSliderChange={this.handleSliderChange}
|
| 245 |
+
steps={0.01}
|
| 246 |
+
slider_type={SliderType.Float}
|
| 247 |
+
/>
|
| 248 |
+
|
| 249 |
+
<sp-checkbox
|
| 250 |
+
checked={
|
| 251 |
+
this.props.store.data.save_upscaled_image
|
| 252 |
+
? true
|
| 253 |
+
: undefined
|
| 254 |
+
}
|
| 255 |
+
onClick={(event: React.ChangeEvent<HTMLInputElement>) => {
|
| 256 |
+
this.props.store.updateProperty(
|
| 257 |
+
'save_upscaled_image',
|
| 258 |
+
event.target.checked
|
| 259 |
+
)
|
| 260 |
+
}}
|
| 261 |
+
>
|
| 262 |
+
{ui_config.save_upscaled_image.label}
|
| 263 |
+
</sp-checkbox>
|
| 264 |
+
<sp-checkbox
|
| 265 |
+
checked={
|
| 266 |
+
this.props.store.data.save_seams_fix_image
|
| 267 |
+
? true
|
| 268 |
+
: undefined
|
| 269 |
+
}
|
| 270 |
+
onClick={(event: React.ChangeEvent<HTMLInputElement>) => {
|
| 271 |
+
this.props.store.updateProperty(
|
| 272 |
+
'save_seams_fix_image',
|
| 273 |
+
event.target.checked
|
| 274 |
+
)
|
| 275 |
+
}}
|
| 276 |
+
>
|
| 277 |
+
{ui_config.save_seams_fix_image.label}
|
| 278 |
+
</sp-checkbox>
|
| 279 |
+
{group_1_sliders}
|
| 280 |
+
<SpMenu
|
| 281 |
+
title={'Seams Fix Type'}
|
| 282 |
+
id={'seams_fix_type'}
|
| 283 |
+
items={ui_config.seams_fix_type.choices}
|
| 284 |
+
label_item="Select Seams Fix Type"
|
| 285 |
+
onChange={this.handleMenuChange}
|
| 286 |
+
selected_index={this.props.store.data.seams_fix_type}
|
| 287 |
+
/>
|
| 288 |
+
{seamfix_sliders}
|
| 289 |
+
</div>
|
| 290 |
+
)
|
| 291 |
+
}
|
| 292 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/tsconfig.json
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
/* Visit https://aka.ms/tsconfig to read more about this file */
|
| 4 |
+
|
| 5 |
+
/* Projects */
|
| 6 |
+
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
| 7 |
+
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
| 8 |
+
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
| 9 |
+
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
| 10 |
+
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
| 11 |
+
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
| 12 |
+
|
| 13 |
+
/* Language and Environment */
|
| 14 |
+
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
| 15 |
+
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
| 16 |
+
"jsx": "react", /* Specify what JSX code is generated. */
|
| 17 |
+
"experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
|
| 18 |
+
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
| 19 |
+
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
| 20 |
+
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
| 21 |
+
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
| 22 |
+
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
| 23 |
+
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
| 24 |
+
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
| 25 |
+
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
| 26 |
+
|
| 27 |
+
/* Modules */
|
| 28 |
+
"module": "commonjs", /* Specify what module code is generated. */
|
| 29 |
+
// "rootDir": "./", /* Specify the root folder within your source files. */
|
| 30 |
+
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
| 31 |
+
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
| 32 |
+
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
| 33 |
+
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
| 34 |
+
"typeRoots": ["./types", "../node_modules/@types"], /* Specify multiple folders that act like './node_modules/@types'. */
|
| 35 |
+
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
| 36 |
+
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
| 37 |
+
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
| 38 |
+
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
|
| 39 |
+
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
|
| 40 |
+
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
|
| 41 |
+
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
|
| 42 |
+
// "resolveJsonModule": true, /* Enable importing .json files. */
|
| 43 |
+
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
|
| 44 |
+
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
| 45 |
+
|
| 46 |
+
/* JavaScript Support */
|
| 47 |
+
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
| 48 |
+
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
| 49 |
+
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
| 50 |
+
|
| 51 |
+
/* Emit */
|
| 52 |
+
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
| 53 |
+
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
| 54 |
+
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
| 55 |
+
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
| 56 |
+
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
| 57 |
+
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
| 58 |
+
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
| 59 |
+
// "removeComments": true, /* Disable emitting comments. */
|
| 60 |
+
// "noEmit": true, /* Disable emitting files from a compilation. */
|
| 61 |
+
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
| 62 |
+
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
| 63 |
+
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
| 64 |
+
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
| 65 |
+
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
| 66 |
+
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
| 67 |
+
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
| 68 |
+
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
| 69 |
+
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
| 70 |
+
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
| 71 |
+
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
| 72 |
+
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
| 73 |
+
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
| 74 |
+
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
| 75 |
+
|
| 76 |
+
/* Interop Constraints */
|
| 77 |
+
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
| 78 |
+
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
|
| 79 |
+
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
| 80 |
+
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
| 81 |
+
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
| 82 |
+
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
| 83 |
+
|
| 84 |
+
/* Type Checking */
|
| 85 |
+
"strict": true, /* Enable all strict type-checking options. */
|
| 86 |
+
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
| 87 |
+
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
| 88 |
+
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
| 89 |
+
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
| 90 |
+
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
| 91 |
+
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
| 92 |
+
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
| 93 |
+
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
| 94 |
+
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
| 95 |
+
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
| 96 |
+
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
| 97 |
+
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
| 98 |
+
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
| 99 |
+
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
| 100 |
+
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
| 101 |
+
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
| 102 |
+
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
| 103 |
+
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
| 104 |
+
|
| 105 |
+
/* Completeness */
|
| 106 |
+
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
| 107 |
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
| 108 |
+
}
|
| 109 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/types/sdapi_py_re.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
declare module 'sdapi_py_re' {
|
| 3 |
+
const exports: any;
|
| 4 |
+
export = exports;
|
| 5 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/types/uxp.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
declare module 'uxp' {
|
| 2 |
+
// Add type declarations for the uxp module here
|
| 3 |
+
export const storage: any;
|
| 4 |
+
export const versions: any;
|
| 5 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/ultimate_sd_upscaler/webpack.config.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const path = require('path')
|
| 2 |
+
// const CleanWebpackPlugin = require('clean-webpack-plugin')
|
| 3 |
+
const CopyPlugin = require('copy-webpack-plugin')
|
| 4 |
+
|
| 5 |
+
module.exports = {
|
| 6 |
+
entry: {
|
| 7 |
+
ultimate_sd_upscaler: './src/ultimate_sd_upscaler.tsx',
|
| 8 |
+
scripts: './src/scripts.tsx',
|
| 9 |
+
},
|
| 10 |
+
output: {
|
| 11 |
+
path: path.resolve(__dirname, 'dist'),
|
| 12 |
+
filename: '[name].bundle.js',
|
| 13 |
+
libraryTarget: 'commonjs2',
|
| 14 |
+
},
|
| 15 |
+
// mode: 'development',
|
| 16 |
+
mode: 'production',
|
| 17 |
+
devtool: 'inline-source-map', // won't work on XD due to lack of eval
|
| 18 |
+
externals: {
|
| 19 |
+
uxp: 'commonjs2 uxp',
|
| 20 |
+
photoshop: 'commonjs2 photoshop',
|
| 21 |
+
os: 'commonjs2 os',
|
| 22 |
+
},
|
| 23 |
+
resolve: {
|
| 24 |
+
extensions: ['.tsx', '.ts', '.js', '.jsx'],
|
| 25 |
+
},
|
| 26 |
+
module: {
|
| 27 |
+
rules: [
|
| 28 |
+
{
|
| 29 |
+
test: /\.tsx?$/,
|
| 30 |
+
loader: 'ts-loader',
|
| 31 |
+
exclude: /node_modules/,
|
| 32 |
+
options: {
|
| 33 |
+
configFile: 'tsconfig.json',
|
| 34 |
+
},
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
test: /\.jsx?$/,
|
| 38 |
+
exclude: /node_modules/,
|
| 39 |
+
loader: 'babel-loader',
|
| 40 |
+
options: {
|
| 41 |
+
plugins: [
|
| 42 |
+
'@babel/transform-react-jsx',
|
| 43 |
+
'@babel/proposal-object-rest-spread',
|
| 44 |
+
'@babel/plugin-syntax-class-properties',
|
| 45 |
+
],
|
| 46 |
+
},
|
| 47 |
+
},
|
| 48 |
+
{
|
| 49 |
+
test: /\.png$/,
|
| 50 |
+
exclude: /node_modules/,
|
| 51 |
+
loader: 'file-loader',
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
test: /\.css$/,
|
| 55 |
+
use: ['style-loader', 'css-loader'],
|
| 56 |
+
},
|
| 57 |
+
],
|
| 58 |
+
},
|
| 59 |
+
plugins: [
|
| 60 |
+
//new CleanWebpackPlugin(),
|
| 61 |
+
// new CopyPlugin(['plugin'], {
|
| 62 |
+
// copyUnmodified: true,
|
| 63 |
+
// }),
|
| 64 |
+
],
|
| 65 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/update_plugin.bat
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
git pull
|
Auto-Photoshop-StableDiffusion-Plugin/update_plugin.sh
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
git pull
|
Auto-Photoshop-StableDiffusion-Plugin/utility/api.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function requestGet(url) {
|
| 2 |
+
let json = null
|
| 3 |
+
|
| 4 |
+
const full_url = url
|
| 5 |
+
try {
|
| 6 |
+
let request = await fetch(full_url)
|
| 7 |
+
if (request.status === 404) {
|
| 8 |
+
return null
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
json = await request.json()
|
| 12 |
+
|
| 13 |
+
console.log('json: ', json)
|
| 14 |
+
} catch (e) {
|
| 15 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
| 16 |
+
}
|
| 17 |
+
return json
|
| 18 |
+
}
|
| 19 |
+
async function requestPost(url, payload) {
|
| 20 |
+
let json = null
|
| 21 |
+
|
| 22 |
+
const full_url = url
|
| 23 |
+
try {
|
| 24 |
+
let request = await fetch(full_url, {
|
| 25 |
+
method: 'POST',
|
| 26 |
+
headers: {
|
| 27 |
+
Accept: 'application/json',
|
| 28 |
+
'Content-Type': 'application/json',
|
| 29 |
+
},
|
| 30 |
+
body: JSON.stringify(payload),
|
| 31 |
+
})
|
| 32 |
+
|
| 33 |
+
if (request.status === 404) {
|
| 34 |
+
return null
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
json = await request.json()
|
| 38 |
+
|
| 39 |
+
console.log('json: ', json)
|
| 40 |
+
} catch (e) {
|
| 41 |
+
console.warn(`issues requesting from ${full_url}`, e)
|
| 42 |
+
}
|
| 43 |
+
return json
|
| 44 |
+
}
|
| 45 |
+
async function requestFormDataPost(url, payload) {
|
| 46 |
+
try {
|
| 47 |
+
var myHeaders = new Headers()
|
| 48 |
+
myHeaders.append('Cookie', 'PHPSESSID=n70fa2vmvm6tfmktf4jmstmd1i')
|
| 49 |
+
|
| 50 |
+
var formdata = new FormData()
|
| 51 |
+
|
| 52 |
+
for ([key, value] of Object.entries(payload)) {
|
| 53 |
+
formdata.append(key, value)
|
| 54 |
+
}
|
| 55 |
+
// formdata.append(
|
| 56 |
+
// 'source',
|
| 57 |
+
// 'iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII='
|
| 58 |
+
// )
|
| 59 |
+
// formdata.append('key', '6d207e02198a847aa98d0a2a901485a5')
|
| 60 |
+
|
| 61 |
+
var requestOptions = {
|
| 62 |
+
method: 'POST',
|
| 63 |
+
headers: myHeaders,
|
| 64 |
+
body: formdata,
|
| 65 |
+
redirect: 'follow',
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
const response = await fetch(url, requestOptions)
|
| 69 |
+
const result_json = response.json()
|
| 70 |
+
return result_json
|
| 71 |
+
} catch (e) {
|
| 72 |
+
console.warn(e)
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
module.exports = {
|
| 77 |
+
requestGet,
|
| 78 |
+
requestPost,
|
| 79 |
+
requestFormDataPost,
|
| 80 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/dummy.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Auto-Photoshop-StableDiffusion-Plugin/utility/event.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const updatePresetMenuEvent = new CustomEvent('updatePresetMenuEvent', {
|
| 2 |
+
detail: {},
|
| 3 |
+
bubbles: true,
|
| 4 |
+
cancelable: true,
|
| 5 |
+
composed: false,
|
| 6 |
+
})
|
| 7 |
+
function triggerEvent(query_selector, event) {
|
| 8 |
+
document.querySelector(query_selector).dispatchEvent(event)
|
| 9 |
+
}
|
| 10 |
+
module.exports = {
|
| 11 |
+
updatePresetMenuEvent,
|
| 12 |
+
triggerEvent,
|
| 13 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/general.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { requestGet } = require('./api')
|
| 2 |
+
|
| 3 |
+
function newOutputImageName(format = 'png') {
|
| 4 |
+
const random_id = Math.floor(Math.random() * 100000000000 + 1) // Date.now() doesn't have enough resolution to avoid duplicate
|
| 5 |
+
const image_name = `output- ${Date.now()}-${random_id}.${format}`
|
| 6 |
+
console.log('generated image name:', image_name)
|
| 7 |
+
return image_name
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
function makeImagePath(format = 'png') {
|
| 11 |
+
const image_name = newOutputImageName(format)
|
| 12 |
+
const image_path = `${uniqueDocumentId}/${image_name}`
|
| 13 |
+
return image_path
|
| 14 |
+
}
|
| 15 |
+
function convertImageNameToPng(image_name) {
|
| 16 |
+
const image_png_name = image_name.split('.')[0] + '.png'
|
| 17 |
+
return image_png_name
|
| 18 |
+
}
|
| 19 |
+
function fixNativePath(native_path) {
|
| 20 |
+
const fixed_native_path = native_path.replaceAll('\\', '/')
|
| 21 |
+
|
| 22 |
+
return fixed_native_path
|
| 23 |
+
}
|
| 24 |
+
function base64ToBase64Url(base64_image) {
|
| 25 |
+
return 'data:image/png;base64,' + base64_image
|
| 26 |
+
}
|
| 27 |
+
function base64UrlToBase64(base64_url) {
|
| 28 |
+
const base64_image = base64_url.replace('data:image/png;base64,', '')
|
| 29 |
+
return base64_image
|
| 30 |
+
}
|
| 31 |
+
const timer = (ms) => new Promise((res) => setTimeout(res, ms)) //Todo: move this line to it's own utilit function
|
| 32 |
+
|
| 33 |
+
function scaleToClosestKeepRatio(
|
| 34 |
+
original_width,
|
| 35 |
+
original_height,
|
| 36 |
+
min_width,
|
| 37 |
+
min_height
|
| 38 |
+
) {
|
| 39 |
+
const { finalWidthHeight } = require('../selection')
|
| 40 |
+
//better naming than finalWidthHeight()
|
| 41 |
+
//scale an image to the closest dimension while keeping the ratio intact
|
| 42 |
+
const [final_width, final_height] = finalWidthHeight(
|
| 43 |
+
original_width,
|
| 44 |
+
original_height,
|
| 45 |
+
min_width,
|
| 46 |
+
min_height
|
| 47 |
+
)
|
| 48 |
+
return [final_width, final_height]
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
function mapRange(x, in_min, in_max, out_min, out_max) {
|
| 52 |
+
return ((x - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
|
| 53 |
+
}
|
| 54 |
+
function scaleToRatio(
|
| 55 |
+
new_value_1,
|
| 56 |
+
old_value_1,
|
| 57 |
+
new_value_2, //get ignored
|
| 58 |
+
old_value_2,
|
| 59 |
+
max_value,
|
| 60 |
+
min_value
|
| 61 |
+
) {
|
| 62 |
+
const ratio = new_value_1 / old_value_1 // 1000/500 = 2
|
| 63 |
+
let final_new_value_2 = old_value_2 * ratio // 500 * 2 = 1000
|
| 64 |
+
let final_new_value_1 = new_value_1
|
| 65 |
+
if (final_new_value_2 > max_value) {
|
| 66 |
+
;[_, final_new_value_1] = scaleToRatio(
|
| 67 |
+
max_value,
|
| 68 |
+
old_value_2,
|
| 69 |
+
new_value_1, //get ignored
|
| 70 |
+
old_value_1,
|
| 71 |
+
max_value,
|
| 72 |
+
min_value
|
| 73 |
+
)
|
| 74 |
+
final_new_value_2 = max_value
|
| 75 |
+
} else if (final_new_value_2 < min_value) {
|
| 76 |
+
;[_, final_new_value_1] = scaleToRatio(
|
| 77 |
+
min_value,
|
| 78 |
+
old_value_2,
|
| 79 |
+
new_value_1, //get ignored
|
| 80 |
+
old_value_1,
|
| 81 |
+
max_value,
|
| 82 |
+
min_value
|
| 83 |
+
)
|
| 84 |
+
final_new_value_2 = min_value
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
return [final_new_value_1, final_new_value_2]
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
function compareVersions(version_1, version_2) {
|
| 91 |
+
//remove the first character v
|
| 92 |
+
version_1 = version_1.slice(1)
|
| 93 |
+
const increments_1 = version_1.split('.').map((sn) => parseInt(sn))
|
| 94 |
+
|
| 95 |
+
version_2 = version_2.slice(1)
|
| 96 |
+
const increments_2 = version_2.split('.').map((sn) => parseInt(sn))
|
| 97 |
+
|
| 98 |
+
let b_older = false // true if version_1 is < than version_2, false if version_1 >= older
|
| 99 |
+
for (let i = 0; i < increments_1.length; ++i) {
|
| 100 |
+
if (increments_1[i] < increments_2[i]) {
|
| 101 |
+
b_older = true
|
| 102 |
+
break
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
return b_older
|
| 106 |
+
}
|
| 107 |
+
async function requestOnlineData() {
|
| 108 |
+
const { requestGet } = require('./api')
|
| 109 |
+
const online_data = await requestGet(g_online_data_url)
|
| 110 |
+
return online_data
|
| 111 |
+
}
|
| 112 |
+
function nearestMultiple(input, multiple) {
|
| 113 |
+
//use the following formula for finding the upper value instead of the lower.
|
| 114 |
+
//( ( x - 1 ) | ( m - 1 ) ) + 1
|
| 115 |
+
const nearest_multiple = input - (input % multiple)
|
| 116 |
+
return nearest_multiple
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
function sudoTimer(progress_text = 'Loading ControlNet...') {
|
| 120 |
+
//sudo timer that will count to 100 and update the progress bar.
|
| 121 |
+
//use it for controlNet since block api progress call
|
| 122 |
+
let current_time = 0
|
| 123 |
+
let max_time = 100
|
| 124 |
+
var timerId = setInterval(countdown, 1000)
|
| 125 |
+
|
| 126 |
+
function countdown() {
|
| 127 |
+
if (current_time > max_time) {
|
| 128 |
+
clearTimeout(timerId)
|
| 129 |
+
// doSomething()
|
| 130 |
+
// html_manip.updateProgressBarsHtml(0)
|
| 131 |
+
} else {
|
| 132 |
+
html_manip.updateProgressBarsHtml(current_time, progress_text)
|
| 133 |
+
console.log(current_time + ' seconds remaining')
|
| 134 |
+
current_time++
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
return timerId
|
| 138 |
+
}
|
| 139 |
+
function countNewLines(string) {
|
| 140 |
+
const count = (string.match(/\n/g) || []).length
|
| 141 |
+
// console.log(count)
|
| 142 |
+
return count
|
| 143 |
+
}
|
| 144 |
+
module.exports = {
|
| 145 |
+
newOutputImageName,
|
| 146 |
+
makeImagePath,
|
| 147 |
+
convertImageNameToPng,
|
| 148 |
+
fixNativePath,
|
| 149 |
+
base64ToBase64Url,
|
| 150 |
+
base64UrlToBase64,
|
| 151 |
+
timer,
|
| 152 |
+
scaleToClosestKeepRatio,
|
| 153 |
+
scaleToRatio,
|
| 154 |
+
mapRange,
|
| 155 |
+
compareVersions,
|
| 156 |
+
requestOnlineData,
|
| 157 |
+
nearestMultiple,
|
| 158 |
+
sudoTimer,
|
| 159 |
+
countNewLines,
|
| 160 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/html_manip.js
ADDED
|
@@ -0,0 +1,1177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
////// Start Prompt//////////
|
| 2 |
+
|
| 3 |
+
function getPrompt() {
|
| 4 |
+
const prompt = document.getElementById('taPrompt').value
|
| 5 |
+
return prompt
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
function autoFillInPrompt(prompt_value) {
|
| 9 |
+
document.getElementById('taPrompt').value = prompt_value
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
////// End Prompt//////////
|
| 13 |
+
|
| 14 |
+
////// Start Negative Prompt//////////
|
| 15 |
+
|
| 16 |
+
function getNegativePrompt() {
|
| 17 |
+
const negative_prompt = document.getElementById('taNegativePrompt').value
|
| 18 |
+
return negative_prompt
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
function autoFillInNegativePrompt(negative_prompt_value) {
|
| 22 |
+
document.getElementById('taNegativePrompt').value = negative_prompt_value
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
////// End Negative Prompt//////////
|
| 26 |
+
|
| 27 |
+
////// Start Width//////////
|
| 28 |
+
|
| 29 |
+
document.getElementById('slWidth').addEventListener('input', (evt) => {
|
| 30 |
+
const width = evt.target.value * 64
|
| 31 |
+
|
| 32 |
+
document.getElementById('lWidth').textContent = parseInt(width)
|
| 33 |
+
// widthSliderOnChangeEventHandler(evt)
|
| 34 |
+
updateResDifferenceLabel()
|
| 35 |
+
})
|
| 36 |
+
|
| 37 |
+
document.getElementById('slHeight').addEventListener('input', (evt) => {
|
| 38 |
+
const height = evt.target.value * 64
|
| 39 |
+
|
| 40 |
+
document.getElementById('lHeight').textContent = parseInt(height)
|
| 41 |
+
// heightSliderOnChangeEventHandler(evt)
|
| 42 |
+
updateResDifferenceLabel()
|
| 43 |
+
})
|
| 44 |
+
|
| 45 |
+
function widthSliderOnChangeEventHandler(evt) {
|
| 46 |
+
let new_width = evt.target.value * 64
|
| 47 |
+
const b_link = getLinkWidthHeightState()
|
| 48 |
+
let final_width = new_width
|
| 49 |
+
let final_height
|
| 50 |
+
if (b_link) {
|
| 51 |
+
const current_height = html_manip.getHeight()
|
| 52 |
+
;[final_width, final_height] = general.scaleToRatio(
|
| 53 |
+
new_width,
|
| 54 |
+
g_old_slider_width,
|
| 55 |
+
_,
|
| 56 |
+
current_height,
|
| 57 |
+
parseInt(evt.target.max * 64),
|
| 58 |
+
parseInt(evt.target.min * 64)
|
| 59 |
+
)
|
| 60 |
+
|
| 61 |
+
evt.target.value = parseInt(final_width / 64)
|
| 62 |
+
html_manip.autoFillInHeight(final_height)
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
g_old_slider_width = final_width // update the old value, so we can use it later
|
| 66 |
+
document.getElementById('lWidth').textContent = parseInt(final_width)
|
| 67 |
+
}
|
| 68 |
+
document.getElementById('slWidth').addEventListener('change', (evt) => {
|
| 69 |
+
widthSliderOnChangeEventHandler(evt)
|
| 70 |
+
})
|
| 71 |
+
// document.getElementById('slWidth').addEventListener('change', (evt) => {
|
| 72 |
+
// let new_width = evt.target.value * 64
|
| 73 |
+
// const b_link = getLinkWidthHeightState()
|
| 74 |
+
// let final_width = new_width
|
| 75 |
+
// let final_height
|
| 76 |
+
// if (b_link) {
|
| 77 |
+
// const current_height = html_manip.getHeight()
|
| 78 |
+
// ;[final_width, final_height] = general.scaleToRatio(
|
| 79 |
+
// new_width,
|
| 80 |
+
// g_old_slider_width,
|
| 81 |
+
// _,
|
| 82 |
+
// current_height,
|
| 83 |
+
// parseInt(evt.target.max * 64),
|
| 84 |
+
// parseInt(evt.target.min * 64)
|
| 85 |
+
// )
|
| 86 |
+
|
| 87 |
+
// evt.target.value = parseInt(final_width / 64)
|
| 88 |
+
// html_manip.autoFillInHeight(final_height)
|
| 89 |
+
// }
|
| 90 |
+
|
| 91 |
+
// g_old_slider_width = final_width // update the old value, so we can use it later
|
| 92 |
+
// document.getElementById('lWidth').textContent = parseInt(final_width)
|
| 93 |
+
// })
|
| 94 |
+
|
| 95 |
+
function heightSliderOnChangeEventHandler(evt) {
|
| 96 |
+
let new_height = evt.target.value * 64
|
| 97 |
+
|
| 98 |
+
let final_width
|
| 99 |
+
let final_height = new_height
|
| 100 |
+
const b_link = getLinkWidthHeightState()
|
| 101 |
+
if (b_link) {
|
| 102 |
+
const current_width = html_manip.getWidth()
|
| 103 |
+
;[final_height, final_width] = general.scaleToRatio(
|
| 104 |
+
new_height,
|
| 105 |
+
g_old_slider_height,
|
| 106 |
+
_,
|
| 107 |
+
current_width,
|
| 108 |
+
parseInt(evt.target.max * 64),
|
| 109 |
+
parseInt(evt.target.min * 64)
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
evt.target.value = parseInt(final_height / 64)
|
| 113 |
+
html_manip.autoFillInWidth(final_width)
|
| 114 |
+
}
|
| 115 |
+
g_old_slider_height = final_height // update the old value, so we can use it later
|
| 116 |
+
document.getElementById('lHeight').textContent = parseInt(final_height)
|
| 117 |
+
}
|
| 118 |
+
document.getElementById('slHeight').addEventListener('change', (evt) => {
|
| 119 |
+
heightSliderOnChangeEventHandler(evt)
|
| 120 |
+
})
|
| 121 |
+
|
| 122 |
+
function getWidth() {
|
| 123 |
+
slider_width = document.getElementById('slWidth').value
|
| 124 |
+
const width = slider_width * 64
|
| 125 |
+
return width
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
function getHrWidth() {
|
| 129 |
+
slider_width = document.getElementById('hrWidth').value
|
| 130 |
+
const width = slider_width * 64
|
| 131 |
+
return width
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
function getHrHeight() {
|
| 135 |
+
slider_width = document.getElementById('hrHeight').value
|
| 136 |
+
const width = slider_width * 64
|
| 137 |
+
return width
|
| 138 |
+
}
|
| 139 |
+
function autoFillInWidth(width_value) {
|
| 140 |
+
const width_slider = document.getElementById('slHeight')
|
| 141 |
+
|
| 142 |
+
// g_old_slider_width = width_slider.value * 64 //store the old value
|
| 143 |
+
g_old_slider_width = width_value
|
| 144 |
+
|
| 145 |
+
document.getElementById('slWidth').value = `${width_value / 64}`
|
| 146 |
+
//update the label
|
| 147 |
+
document.getElementById('lWidth').innerHTML = `${parseInt(width_value)}`
|
| 148 |
+
updateResDifferenceLabel()
|
| 149 |
+
}
|
| 150 |
+
////// End Width//////////
|
| 151 |
+
|
| 152 |
+
////// Start Height//////////
|
| 153 |
+
|
| 154 |
+
function getHeight() {
|
| 155 |
+
slider_value = document.getElementById('slHeight').value
|
| 156 |
+
const height = slider_value * 64
|
| 157 |
+
return height
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
function autoFillInHeight(height_value) {
|
| 161 |
+
const height_slider = document.getElementById('slHeight')
|
| 162 |
+
// g_old_slider_height = height_slider.value * 64
|
| 163 |
+
g_old_slider_height = height_value //store the current value as old value. counterintuitive!. only use old value when the user directly manipulate the slider
|
| 164 |
+
|
| 165 |
+
height_slider.value = `${height_value / 64}`
|
| 166 |
+
//update the label
|
| 167 |
+
document.getElementById('lHeight').innerHTML = `${parseInt(height_value)}`
|
| 168 |
+
updateResDifferenceLabel()
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
function autoFillInHRHeight(height_value) {
|
| 172 |
+
document.getElementById('hrHeight').value = `${height_value / 64}`
|
| 173 |
+
//update the label
|
| 174 |
+
document.getElementById('hHeight').innerHTML = `${height_value}`
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
function autoFillInHRWidth(height_value) {
|
| 178 |
+
document.getElementById('hrWidth').value = `${height_value / 64}`
|
| 179 |
+
//update the label
|
| 180 |
+
document.getElementById('hWidth').innerHTML = `${height_value}`
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
////// End Height//////////
|
| 184 |
+
|
| 185 |
+
////// Start Denoising Strength//////////
|
| 186 |
+
document
|
| 187 |
+
.querySelector('#slDenoisingStrength')
|
| 188 |
+
.addEventListener('input', (evt) => {
|
| 189 |
+
const label_value = evt.target.value / 100
|
| 190 |
+
// console.log("label_value: ", label_value)
|
| 191 |
+
document.getElementById(
|
| 192 |
+
'lDenoisingStrength'
|
| 193 |
+
).innerHTML = `${label_value}`
|
| 194 |
+
})
|
| 195 |
+
|
| 196 |
+
//get the value that is relevant to stable diffusion
|
| 197 |
+
function getDenoisingStrength() {
|
| 198 |
+
const slider_value = document.getElementById('slDenoisingStrength').value
|
| 199 |
+
const denoising_strength_value = slider_value / 100.0
|
| 200 |
+
return denoising_strength_value
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
// display the value the user need to see in all elements related to denoising strength attribute
|
| 204 |
+
function autoFillInDenoisingStrength(denoising_strength_value) {
|
| 205 |
+
//sd denoising strength value range from [0,1] slider range from [0, 100]
|
| 206 |
+
//update the slider
|
| 207 |
+
document.getElementById('slDenoisingStrength').value = `${
|
| 208 |
+
denoising_strength_value * 100
|
| 209 |
+
}`
|
| 210 |
+
//update the label
|
| 211 |
+
document.getElementById(
|
| 212 |
+
'lDenoisingStrength'
|
| 213 |
+
).innerHTML = `${denoising_strength_value}`
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
////// End Denoising Strength//////////
|
| 217 |
+
|
| 218 |
+
////// Start Hi Res Fix//////////
|
| 219 |
+
|
| 220 |
+
document.getElementById('chInpaintFullRes').addEventListener('click', (ev) => {
|
| 221 |
+
const inpaint_padding_slider = document.getElementById('slInpaintPadding')
|
| 222 |
+
|
| 223 |
+
if (ev.target.checked) {
|
| 224 |
+
inpaint_padding_slider.style.display = 'block'
|
| 225 |
+
} else {
|
| 226 |
+
inpaint_padding_slider.style.display = 'none'
|
| 227 |
+
}
|
| 228 |
+
})
|
| 229 |
+
document.getElementById('chHiResFixs').addEventListener('click', (ev) => {
|
| 230 |
+
const container = document.getElementById('hi-res-sliders-container')
|
| 231 |
+
|
| 232 |
+
if (ev.target.checked) {
|
| 233 |
+
container.style.display = 'flex'
|
| 234 |
+
} else {
|
| 235 |
+
container.style.display = 'none'
|
| 236 |
+
}
|
| 237 |
+
})
|
| 238 |
+
//get the value that is relevant to stable diffusion
|
| 239 |
+
function getHiResFixs() {
|
| 240 |
+
const isChecked = document.getElementById('chHiResFixs').checked
|
| 241 |
+
return isChecked
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
function setHiResFixs(isChecked) {
|
| 245 |
+
document.getElementById('chHiResFixs').checked = isChecked
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
function sliderAddEventListener(
|
| 249 |
+
slider_id,
|
| 250 |
+
label_id,
|
| 251 |
+
multiplier,
|
| 252 |
+
fractionDigits = 2
|
| 253 |
+
) {
|
| 254 |
+
document.getElementById(slider_id).addEventListener('input', (evt) => {
|
| 255 |
+
const sd_value = evt.target.value * multiplier // convert slider value to SD ready value
|
| 256 |
+
document.getElementById(label_id).textContent =
|
| 257 |
+
Number(sd_value).toFixed(fractionDigits)
|
| 258 |
+
})
|
| 259 |
+
}
|
| 260 |
+
function sliderAddEventListener_new(
|
| 261 |
+
slider_id,
|
| 262 |
+
label_id,
|
| 263 |
+
slider_start,
|
| 264 |
+
slider_end,
|
| 265 |
+
sd_start,
|
| 266 |
+
sd_end
|
| 267 |
+
) {
|
| 268 |
+
document.getElementById(slider_id).addEventListener('input', (evt) => {
|
| 269 |
+
const sd_value = general.mapRange(
|
| 270 |
+
evt.target.value,
|
| 271 |
+
slider_start,
|
| 272 |
+
slider_end,
|
| 273 |
+
sd_start,
|
| 274 |
+
sd_end
|
| 275 |
+
) // convert slider value to SD ready value
|
| 276 |
+
|
| 277 |
+
document.getElementById(label_id).textContent =
|
| 278 |
+
Number(sd_value).toFixed(2)
|
| 279 |
+
})
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
//get the stable diffusion ready value from the slider with "slider_id"
|
| 283 |
+
//REFACTOR: delete, getSliderSdValue_Old is deprecated, instead use getSliderSdValue
|
| 284 |
+
function getSliderSdValue_Old(slider_id, multiplier) {
|
| 285 |
+
// console.warn(
|
| 286 |
+
// 'getSliderSdValue_Old is deprecated, instead use getSliderSdValue'
|
| 287 |
+
// )
|
| 288 |
+
const slider_value = document.getElementById(slider_id).value
|
| 289 |
+
const sd_value = slider_value * multiplier
|
| 290 |
+
return sd_value
|
| 291 |
+
}
|
| 292 |
+
//REFACTOR: delete, autoFillInSliderUi is deprecated, instead use setSliderSdValue
|
| 293 |
+
function autoFillInSliderUi(sd_value, slider_id, label_id, multiplier) {
|
| 294 |
+
// console.warn(
|
| 295 |
+
// 'autoFillInSliderUi is deprecated, instead use setSliderSdValue'
|
| 296 |
+
// )
|
| 297 |
+
//update the slider
|
| 298 |
+
document.getElementById(slider_id).value = `${sd_value * multiplier}`
|
| 299 |
+
//update the label
|
| 300 |
+
document.getElementById(label_id).innerHTML = `${sd_value}`
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
function getSliderSdValue(
|
| 304 |
+
slider_id,
|
| 305 |
+
slider_start,
|
| 306 |
+
slider_end,
|
| 307 |
+
sd_start,
|
| 308 |
+
sd_end
|
| 309 |
+
) {
|
| 310 |
+
const slider_value = document.getElementById(slider_id).value
|
| 311 |
+
// const sd_value = general.mapRange(slider_value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 312 |
+
const sd_value = general.mapRange(
|
| 313 |
+
slider_value,
|
| 314 |
+
slider_start,
|
| 315 |
+
slider_end,
|
| 316 |
+
sd_start,
|
| 317 |
+
sd_end
|
| 318 |
+
) // convert slider value to SD ready value
|
| 319 |
+
|
| 320 |
+
return sd_value
|
| 321 |
+
}
|
| 322 |
+
function setSliderSdValue(
|
| 323 |
+
slider_id,
|
| 324 |
+
label_id,
|
| 325 |
+
sd_value,
|
| 326 |
+
slider_start,
|
| 327 |
+
slider_end,
|
| 328 |
+
sd_start,
|
| 329 |
+
sd_end
|
| 330 |
+
) {
|
| 331 |
+
const slider_value = general.mapRange(
|
| 332 |
+
sd_value,
|
| 333 |
+
sd_start,
|
| 334 |
+
sd_end,
|
| 335 |
+
slider_start,
|
| 336 |
+
slider_end
|
| 337 |
+
) // convert slider value to SD ready value
|
| 338 |
+
document.getElementById(slider_id).value = slider_value.toString()
|
| 339 |
+
document.getElementById(label_id).innerHTML = sd_value.toString()
|
| 340 |
+
}
|
| 341 |
+
function getSliderSdValueByElement(
|
| 342 |
+
slider_element,
|
| 343 |
+
slider_start,
|
| 344 |
+
slider_end,
|
| 345 |
+
sd_start,
|
| 346 |
+
sd_end
|
| 347 |
+
) {
|
| 348 |
+
const slider_value = slider_element.value
|
| 349 |
+
// const sd_value = general.mapRange(slider_value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 350 |
+
const sd_value = general.mapRange(
|
| 351 |
+
slider_value,
|
| 352 |
+
slider_start,
|
| 353 |
+
slider_end,
|
| 354 |
+
sd_start,
|
| 355 |
+
sd_end
|
| 356 |
+
) // convert slider value to SD ready value
|
| 357 |
+
|
| 358 |
+
return sd_value
|
| 359 |
+
}
|
| 360 |
+
function setSliderSdValueByElements(
|
| 361 |
+
slider_element,
|
| 362 |
+
label_element,
|
| 363 |
+
sd_value,
|
| 364 |
+
slider_start,
|
| 365 |
+
slider_end,
|
| 366 |
+
sd_start,
|
| 367 |
+
sd_end
|
| 368 |
+
) {
|
| 369 |
+
const slider_value = general.mapRange(
|
| 370 |
+
sd_value,
|
| 371 |
+
sd_start,
|
| 372 |
+
sd_end,
|
| 373 |
+
slider_start,
|
| 374 |
+
slider_end
|
| 375 |
+
) // convert slider value to SD ready value
|
| 376 |
+
slider_element.value = slider_value.toString()
|
| 377 |
+
label_element.innerHTML = sd_value.toString()
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
//hrWidth is from [1 to 32] * 64 => [64 to 2048]
|
| 381 |
+
sliderAddEventListener('hrWidth', 'hWidth', 64)
|
| 382 |
+
sliderAddEventListener('hrHeight', 'hHeight', 64)
|
| 383 |
+
|
| 384 |
+
//convert hrDenoisingStrength from [1, 100] * 0.01 => [0.01 to 1]
|
| 385 |
+
sliderAddEventListener('hrDenoisingStrength', 'hDenoisingStrength', 0.01)
|
| 386 |
+
|
| 387 |
+
function autoFillInHiResFixs(firstphase_width, firstphase_height) {
|
| 388 |
+
//update the firstphase width slider and label
|
| 389 |
+
autoFillInSliderUi(firstphase_width, 'hrWidth', 'hWidth', 1.0 / 64)
|
| 390 |
+
//update the firstphase height slider and label
|
| 391 |
+
autoFillInSliderUi(firstphase_height, 'hrHeight', 'hHeight', 1.0 / 64)
|
| 392 |
+
}
|
| 393 |
+
////// End Hi Res Fix//////////
|
| 394 |
+
|
| 395 |
+
////// Start Inpaint Mask Weight//////////
|
| 396 |
+
function autoFillInInpaintMaskWeight(sd_value) {
|
| 397 |
+
//update the inpaint mask weight
|
| 398 |
+
autoFillInSliderUi(
|
| 399 |
+
sd_value,
|
| 400 |
+
'slInpaintingMaskWeight',
|
| 401 |
+
'lInpaintingMaskWeight',
|
| 402 |
+
100
|
| 403 |
+
)
|
| 404 |
+
}
|
| 405 |
+
////// End Inpaint Mask Weight//////////
|
| 406 |
+
|
| 407 |
+
////// Start Samplers//////////
|
| 408 |
+
function unCheckAllSamplers() {
|
| 409 |
+
document
|
| 410 |
+
.getElementsByClassName('rbSampler')
|
| 411 |
+
|
| 412 |
+
.forEach((e) => e.removeAttribute('checked'))
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
function getSelectedRadioButtonElement(rbClass) {
|
| 416 |
+
try {
|
| 417 |
+
const rb_element = [...document.getElementsByClassName(rbClass)].filter(
|
| 418 |
+
(e) => e.checked == true
|
| 419 |
+
)[0]
|
| 420 |
+
return rb_element
|
| 421 |
+
} catch (e) {
|
| 422 |
+
console.warn(e)
|
| 423 |
+
}
|
| 424 |
+
}
|
| 425 |
+
function getSamplerElementByName(sampler_name) {
|
| 426 |
+
try {
|
| 427 |
+
//assume the sampler_name is valid
|
| 428 |
+
//return the first
|
| 429 |
+
//convert htmlCollection into an array, then user filter to get the radio button with the value equals to sampler_name
|
| 430 |
+
const sampler_element = [
|
| 431 |
+
...document.getElementsByClassName('rbSampler'),
|
| 432 |
+
].filter((e) => e.value == sampler_name)[0]
|
| 433 |
+
return sampler_element
|
| 434 |
+
} catch (e) {
|
| 435 |
+
console.warn(`Sampler '${sampler_name}' not found ${e}`)
|
| 436 |
+
}
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
function getCheckedSamplerName() {
|
| 440 |
+
//we assume that the samplers exist and loaded in html
|
| 441 |
+
//return the name of the first checked sampler
|
| 442 |
+
try {
|
| 443 |
+
return [...document.getElementsByClassName('rbSampler')].filter(
|
| 444 |
+
(elm) => elm.checked == true
|
| 445 |
+
)[0].value
|
| 446 |
+
} catch (e) {
|
| 447 |
+
console.warn(e)
|
| 448 |
+
}
|
| 449 |
+
}
|
| 450 |
+
function getMode() {
|
| 451 |
+
return [...document.getElementsByClassName('rbMode')].filter(
|
| 452 |
+
(e) => e.checked == true
|
| 453 |
+
)[0].value
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
function getBackendType() {
|
| 457 |
+
return [...document.getElementsByClassName('rbBackendType')].filter(
|
| 458 |
+
(e) => e.checked == true
|
| 459 |
+
)[0].value
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
function getHordeApiKey() {
|
| 463 |
+
let key = document.getElementById('tiHordeApiKey').value
|
| 464 |
+
const valid_key = key ? key : '0000000000'
|
| 465 |
+
return valid_key
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
function setHordeApiKey(key) {
|
| 469 |
+
document.getElementById('tiHordeApiKey').value = key
|
| 470 |
+
}
|
| 471 |
+
function checkSampler(sampler_name) {
|
| 472 |
+
sampler_element = getSamplerElementByName(sampler_name)
|
| 473 |
+
sampler_element.checked = true
|
| 474 |
+
}
|
| 475 |
+
function autoFillInSampler(sampler_name) {
|
| 476 |
+
// unCheckAllSamplers()
|
| 477 |
+
checkSampler(sampler_name)
|
| 478 |
+
}
|
| 479 |
+
////// End Samplers//////////
|
| 480 |
+
|
| 481 |
+
////// Start Models//////////
|
| 482 |
+
|
| 483 |
+
function getModelElementByHash(model_hash) {
|
| 484 |
+
try {
|
| 485 |
+
//assume the model_hash is valid
|
| 486 |
+
//return the first model menu item element with model_hash
|
| 487 |
+
const model_element = [
|
| 488 |
+
...document.getElementsByClassName('mModelMenuItem'),
|
| 489 |
+
].filter((e) => e.dataset.model_hash == model_hash)[0]
|
| 490 |
+
return model_element
|
| 491 |
+
} catch (e) {
|
| 492 |
+
console.warn(`Model '${model_hash}' not found ${e}`)
|
| 493 |
+
}
|
| 494 |
+
}
|
| 495 |
+
function getModelHashByTitle(model_title) {
|
| 496 |
+
//return find the model hash by it's title
|
| 497 |
+
try {
|
| 498 |
+
return [...document.getElementsByClassName('mModelMenuItem')].filter(
|
| 499 |
+
(e) => e.dataset.model_title == model_title
|
| 500 |
+
)[0].dataset.model_hash
|
| 501 |
+
} catch (e) {
|
| 502 |
+
console.warn(e)
|
| 503 |
+
}
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
function getSelectedModelHash() {
|
| 507 |
+
//return the hash of the first selected model menu item
|
| 508 |
+
try {
|
| 509 |
+
return [...document.getElementsByClassName('mModelMenuItem')].filter(
|
| 510 |
+
(e) => e.selected == true
|
| 511 |
+
)[0].dataset.model_hash
|
| 512 |
+
} catch (e) {
|
| 513 |
+
console.warn(e)
|
| 514 |
+
}
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
function selectModelUi(model_hash) {
|
| 518 |
+
model_element = getModelElementByHash(model_hash)
|
| 519 |
+
model_element.selected = true
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
function autoFillInModel(model_hash) {
|
| 523 |
+
try {
|
| 524 |
+
// unCheckAllSamplers()
|
| 525 |
+
model_element = getModelElementByHash(model_hash)
|
| 526 |
+
selectModelUi(model_hash)
|
| 527 |
+
// model_element.
|
| 528 |
+
const model_title = model_element.dataset.model_title
|
| 529 |
+
return model_title
|
| 530 |
+
} catch (e) {
|
| 531 |
+
console.warn(e)
|
| 532 |
+
}
|
| 533 |
+
}
|
| 534 |
+
////// End Models//////////
|
| 535 |
+
|
| 536 |
+
////// Start Init Image && Init Image Mask//////////
|
| 537 |
+
|
| 538 |
+
function getInitImageElement() {
|
| 539 |
+
const ini_image_element = document.getElementById('init_image')
|
| 540 |
+
return ini_image_element
|
| 541 |
+
}
|
| 542 |
+
function setInitImageSrc(image_src) {
|
| 543 |
+
const ini_image_element = getInitImageElement()
|
| 544 |
+
ini_image_element.src = image_src
|
| 545 |
+
}
|
| 546 |
+
function setControlImageSrc(image_src, element_index = 0) {
|
| 547 |
+
const control_net_image_element = document.querySelector(
|
| 548 |
+
`#controlnet_settings_${element_index} .control_net_image_`
|
| 549 |
+
)
|
| 550 |
+
// const control_net_image_element = document.getElementById(
|
| 551 |
+
// 'control_net_image' + '_' + element_index
|
| 552 |
+
// )
|
| 553 |
+
control_net_image_element.src = image_src
|
| 554 |
+
}
|
| 555 |
+
function setControlMaskSrc(image_src, element_index = 0) {
|
| 556 |
+
const control_net_image_element = document.querySelector(
|
| 557 |
+
`#controlnet_settings_${element_index} .control_net_mask_`
|
| 558 |
+
)
|
| 559 |
+
// const control_net_image_element = document.getElementById(
|
| 560 |
+
// 'control_net_mask' + '_' + element_index
|
| 561 |
+
// )
|
| 562 |
+
control_net_image_element.src = image_src
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
+
function setProgressImageSrc(image_src) {
|
| 566 |
+
// const progress_image_element = document.getElementById('progressImage')
|
| 567 |
+
|
| 568 |
+
const progress_image_element = document.getElementById(
|
| 569 |
+
'divProgressImageViewerContainer'
|
| 570 |
+
)
|
| 571 |
+
// progress_image_element.src = image_src
|
| 572 |
+
|
| 573 |
+
progress_image_element.style.backgroundSize = 'contain'
|
| 574 |
+
progress_image_element.style.height = '500px'
|
| 575 |
+
|
| 576 |
+
progress_image_element.style.backgroundImage = `url('${image_src}')`
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
function getInitImageMaskElement() {
|
| 580 |
+
const ini_image_mask_element = document.getElementById('init_image_mask')
|
| 581 |
+
return ini_image_mask_element
|
| 582 |
+
}
|
| 583 |
+
function setInitImageMaskSrc(image_src) {
|
| 584 |
+
const ini_image_mask_element = getInitImageMaskElement()
|
| 585 |
+
ini_image_mask_element.src = image_src
|
| 586 |
+
}
|
| 587 |
+
////// End Init Image && Init Image Mask//////////
|
| 588 |
+
|
| 589 |
+
////// Start Generate Buttons //////////
|
| 590 |
+
|
| 591 |
+
function getGenerateButtonsElements() {
|
| 592 |
+
generate_buttons = [...document.getElementsByClassName('btnGenerateClass')]
|
| 593 |
+
return generate_buttons
|
| 594 |
+
}
|
| 595 |
+
function setGenerateButtonsColor(addClassName, removeClassName) {
|
| 596 |
+
const buttons = getGenerateButtonsElements()
|
| 597 |
+
buttons.forEach((button) => {
|
| 598 |
+
button.classList.add(addClassName)
|
| 599 |
+
button.classList.remove(removeClassName)
|
| 600 |
+
})
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
////// End Generate Buttons //////////
|
| 604 |
+
|
| 605 |
+
////// Start Servers Status //////////
|
| 606 |
+
|
| 607 |
+
function setAutomaticStatus(newStatusClass, oldStatusClass) {
|
| 608 |
+
document.getElementById('automaticStatus').classList.add(newStatusClass)
|
| 609 |
+
document.getElementById('automaticStatus').classList.remove(oldStatusClass)
|
| 610 |
+
}
|
| 611 |
+
function setProxyServerStatus(newStatusClass, oldStatusClass) {
|
| 612 |
+
document.getElementById('proxyServerStatus').classList.add(newStatusClass)
|
| 613 |
+
document
|
| 614 |
+
.getElementById('proxyServerStatus')
|
| 615 |
+
.classList.remove(oldStatusClass)
|
| 616 |
+
}
|
| 617 |
+
////// End Servers Status //////////
|
| 618 |
+
|
| 619 |
+
////// Start Extras //////////
|
| 620 |
+
|
| 621 |
+
sliderAddEventListener('slUpscaleSize', 'lUpscaleSize', 0.1, 1)
|
| 622 |
+
|
| 623 |
+
function getUpscaleSize() {
|
| 624 |
+
slider_width = document.getElementById('slUpscaleSize').value
|
| 625 |
+
const size = slider_width / 10
|
| 626 |
+
return size
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
sliderAddEventListener('slUpscaler2Visibility', 'lUpscaler2Visibility', 0.1, 1)
|
| 630 |
+
|
| 631 |
+
function getUpscaler2Visibility() {
|
| 632 |
+
slider_width = document.getElementById('slUpscaler2Visibility').value
|
| 633 |
+
const size = slider_width / 10
|
| 634 |
+
return size
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
sliderAddEventListener('slGFPGANVisibility', 'lGFPGANVisibility', 0.1, 1)
|
| 638 |
+
|
| 639 |
+
function getGFPGANVisibility() {
|
| 640 |
+
slider_width = document.getElementById('slGFPGANVisibility').value
|
| 641 |
+
const size = slider_width / 10
|
| 642 |
+
return size
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
sliderAddEventListener(
|
| 646 |
+
'slCodeFormerVisibility',
|
| 647 |
+
'lCodeFormerVisibility',
|
| 648 |
+
0.1,
|
| 649 |
+
1
|
| 650 |
+
)
|
| 651 |
+
|
| 652 |
+
function getCodeFormerVisibility() {
|
| 653 |
+
slider_width = document.getElementById('slCodeFormerVisibility').value
|
| 654 |
+
const size = slider_width / 10
|
| 655 |
+
return size
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
sliderAddEventListener('slCodeFormerWeight', 'lCodeFormerWeight', 0.1, 1)
|
| 659 |
+
|
| 660 |
+
function getCodeFormerWeight() {
|
| 661 |
+
slider_width = document.getElementById('slCodeFormerWeight').value
|
| 662 |
+
const size = slider_width / 10
|
| 663 |
+
return size
|
| 664 |
+
}
|
| 665 |
+
|
| 666 |
+
////// End Extras //////////
|
| 667 |
+
|
| 668 |
+
////// Start Reset Settings Button //////////
|
| 669 |
+
|
| 670 |
+
const defaultSettings = {
|
| 671 |
+
model: null,
|
| 672 |
+
prompt_shortcut: null,
|
| 673 |
+
positive_prompt: '',
|
| 674 |
+
negative_prompt: '',
|
| 675 |
+
selection_mode: null,
|
| 676 |
+
batch_number: 1,
|
| 677 |
+
steps: 20,
|
| 678 |
+
width: 512,
|
| 679 |
+
height: 512,
|
| 680 |
+
firstphase_width: 512,
|
| 681 |
+
firstphase_height: 512,
|
| 682 |
+
cfg: 7,
|
| 683 |
+
denoising_strength: 0.7,
|
| 684 |
+
hi_res_denoising_strength: 0.7,
|
| 685 |
+
mask_blur: 8,
|
| 686 |
+
inpaint_at_full_res: false,
|
| 687 |
+
hi_res_fix: false,
|
| 688 |
+
inpaint_padding: 0,
|
| 689 |
+
seed: -1,
|
| 690 |
+
samplers: null,
|
| 691 |
+
mask_content: null,
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
const snapshot_btns = Array.from(
|
| 695 |
+
document.getElementsByClassName('snapshotButton')
|
| 696 |
+
)
|
| 697 |
+
snapshot_btns.forEach((element) =>
|
| 698 |
+
element.addEventListener('click', async () => {
|
| 699 |
+
try {
|
| 700 |
+
await psapi.snapshot_layerExe()
|
| 701 |
+
} catch (e) {
|
| 702 |
+
console.warn(e)
|
| 703 |
+
}
|
| 704 |
+
})
|
| 705 |
+
)
|
| 706 |
+
|
| 707 |
+
const reset_btns = Array.from(document.getElementsByClassName('resetButton'))
|
| 708 |
+
reset_btns.forEach((element) =>
|
| 709 |
+
element.addEventListener('click', async () => {
|
| 710 |
+
try {
|
| 711 |
+
autoFillDefaultSettings(defaultSettings)
|
| 712 |
+
} catch (e) {
|
| 713 |
+
console.warn(e)
|
| 714 |
+
}
|
| 715 |
+
})
|
| 716 |
+
)
|
| 717 |
+
|
| 718 |
+
function getBatchNumber() {
|
| 719 |
+
// return document.getElementById('tiNumberOfImages').value
|
| 720 |
+
return document.getElementById('tiNumberOfBatchSize').value
|
| 721 |
+
}
|
| 722 |
+
function autoFillInBatchNumber(batch_number) {
|
| 723 |
+
// document.getElementById('tiNumberOfImages').value = String(batch_number)
|
| 724 |
+
document.getElementById('tiNumberOfBatchSize').value = String(batch_number)
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
function getSteps() {
|
| 728 |
+
return document.getElementById('tiNumberOfSteps').value
|
| 729 |
+
}
|
| 730 |
+
function autoFillInSteps(steps) {
|
| 731 |
+
document.getElementById('tiNumberOfSteps').value = String(steps)
|
| 732 |
+
}
|
| 733 |
+
function autoFillDefaultSettings(default_settings) {
|
| 734 |
+
autoFillSettings(default_settings)
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
function setCFG(cfg_value) {
|
| 738 |
+
document.getElementById('slCfgScale').value = cfg_value
|
| 739 |
+
}
|
| 740 |
+
function getCFG() {
|
| 741 |
+
return document.getElementById('slCfgScale').value
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
function autoFillSettings(settings) {
|
| 745 |
+
try {
|
| 746 |
+
//reset all UI settings except model selection and sampler selection
|
| 747 |
+
autoFillInPrompt(settings['positive_prompt'])
|
| 748 |
+
autoFillInNegativePrompt(settings['negative_prompt'])
|
| 749 |
+
autoFillInBatchNumber(settings['batch_number'])
|
| 750 |
+
autoFillInSteps(settings['steps'])
|
| 751 |
+
autoFillInWidth(settings['width'])
|
| 752 |
+
autoFillInHeight(settings['height'])
|
| 753 |
+
autoFillInHiResFixs(
|
| 754 |
+
settings['firstphase_width'],
|
| 755 |
+
settings['firstphase_height']
|
| 756 |
+
)
|
| 757 |
+
document.getElementById('slCfgScale').value = settings['cfg']
|
| 758 |
+
autoFillInDenoisingStrength(settings['denoising_strength'])
|
| 759 |
+
autoFillInSliderUi(
|
| 760 |
+
settings['hi_res_denoising_strength'],
|
| 761 |
+
'hrDenoisingStrength',
|
| 762 |
+
'hDenoisingStrength',
|
| 763 |
+
100
|
| 764 |
+
)
|
| 765 |
+
document.getElementById('slMaskBlur').value = settings['mask_blur']
|
| 766 |
+
document.getElementById('chInpaintFullRes').checked =
|
| 767 |
+
settings['inpaint_at_full_res']
|
| 768 |
+
setHiResFixs(settings['hi_res_fix'])
|
| 769 |
+
document.getElementById('tiSeed').value = String(settings['seed'])
|
| 770 |
+
} catch (e) {
|
| 771 |
+
console.warn(e)
|
| 772 |
+
}
|
| 773 |
+
}
|
| 774 |
+
////// End Reset Settings Button //////////
|
| 775 |
+
|
| 776 |
+
function getMaskBlur() {
|
| 777 |
+
const isDisabled = document
|
| 778 |
+
.getElementById('slMaskBlur')
|
| 779 |
+
.hasAttribute('disabled')
|
| 780 |
+
let mask_blur = 0
|
| 781 |
+
if (isDisabled) {
|
| 782 |
+
mask_blur = 0
|
| 783 |
+
} else {
|
| 784 |
+
mask_blur = document.getElementById('slMaskBlur').value
|
| 785 |
+
}
|
| 786 |
+
return mask_blur
|
| 787 |
+
}
|
| 788 |
+
function setMaskBlur(mask_blur) {
|
| 789 |
+
document.getElementById('slMaskBlur').value = mask_blur
|
| 790 |
+
}
|
| 791 |
+
|
| 792 |
+
function getPromptShortcut() {
|
| 793 |
+
//read json string
|
| 794 |
+
//converted into json object
|
| 795 |
+
const prompt_shortcut_string =
|
| 796 |
+
document.getElementById('taPromptShortcut').value
|
| 797 |
+
const prompt_shortcut = JSON.parse(prompt_shortcut_string)
|
| 798 |
+
return prompt_shortcut
|
| 799 |
+
}
|
| 800 |
+
function setPromptShortcut(prompt_shortcut) {
|
| 801 |
+
//prompt_shortcut is json object
|
| 802 |
+
//convert it into pretty json string and save it in the prompt shortcut textarea
|
| 803 |
+
var JSONInPrettyFormat = JSON.stringify(prompt_shortcut, undefined, 7)
|
| 804 |
+
document.getElementById('taPromptShortcut').value = JSONInPrettyFormat
|
| 805 |
+
}
|
| 806 |
+
|
| 807 |
+
////start selection mode/////
|
| 808 |
+
function getSelectionMode() {
|
| 809 |
+
return [...document.getElementsByClassName('rbSelectionMode')].filter(
|
| 810 |
+
(e) => e.checked == true
|
| 811 |
+
)[0].value
|
| 812 |
+
}
|
| 813 |
+
function getMaskContent() {
|
| 814 |
+
return [...document.getElementsByClassName('rbMaskContent')].filter(
|
| 815 |
+
(e) => e.checked == true
|
| 816 |
+
)[0].value
|
| 817 |
+
}
|
| 818 |
+
function setMaskContent(value) {
|
| 819 |
+
try {
|
| 820 |
+
//assume the sampler_name is valid
|
| 821 |
+
//return the first
|
| 822 |
+
//convert htmlCollection into an array, then user filter to get the radio button with the value equals to sampler_name
|
| 823 |
+
const mask_content_element = [
|
| 824 |
+
...document.getElementsByClassName('rbMaskContent'),
|
| 825 |
+
].filter((e) => e.value == value)[0]
|
| 826 |
+
mask_content_element.checked = true
|
| 827 |
+
return mask_content_element
|
| 828 |
+
} catch (e) {
|
| 829 |
+
console.warn(e)
|
| 830 |
+
}
|
| 831 |
+
}
|
| 832 |
+
|
| 833 |
+
function addHistoryButtonsHtml(img_html) {
|
| 834 |
+
// Create new container element
|
| 835 |
+
const container = document.createElement('div')
|
| 836 |
+
|
| 837 |
+
container.className = 'viewer-image-container'
|
| 838 |
+
|
| 839 |
+
const elem = document.getElementById('svg_sp_btn')
|
| 840 |
+
// Create a copy of it
|
| 841 |
+
const clone = elem.cloneNode(true)
|
| 842 |
+
const button = clone
|
| 843 |
+
button.style.display = null
|
| 844 |
+
button.removeAttribute('id')
|
| 845 |
+
|
| 846 |
+
button.setAttribute('title', 'place the image on the canvas')
|
| 847 |
+
|
| 848 |
+
// Create button element
|
| 849 |
+
// const button = document.createElement('sp-button');
|
| 850 |
+
button.className = 'viewer-image-button'
|
| 851 |
+
// button.innerHTML = "Button";
|
| 852 |
+
|
| 853 |
+
button.addEventListener('click', async () => {
|
| 854 |
+
//set init image event listener, use when settion is active
|
| 855 |
+
let image_path = img_html.dataset.path
|
| 856 |
+
const image_path_escape = image_path.replace(/\o/g, '/o') //escape string "\o" in "\output"
|
| 857 |
+
|
| 858 |
+
// load the image from "data:image/png;base64," base64_str
|
| 859 |
+
const base64_image = img_html.src.replace('data:image/png;base64,', '')
|
| 860 |
+
await base64ToFile(base64_image)
|
| 861 |
+
})
|
| 862 |
+
|
| 863 |
+
// Append elements to container
|
| 864 |
+
container.appendChild(img_html)
|
| 865 |
+
container.appendChild(button)
|
| 866 |
+
|
| 867 |
+
return container
|
| 868 |
+
}
|
| 869 |
+
function getSeed() {
|
| 870 |
+
const seed = document.getElementById('tiSeed').value
|
| 871 |
+
return seed
|
| 872 |
+
}
|
| 873 |
+
function setSeed(new_seed) {
|
| 874 |
+
document.getElementById('tiSeed').value = new_seed
|
| 875 |
+
}
|
| 876 |
+
|
| 877 |
+
function getMaskExpansion() {
|
| 878 |
+
const mask_expansion = document.getElementById('slMaskExpansion').value
|
| 879 |
+
return mask_expansion
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
function setMaskExpansion(mask_expansion) {
|
| 883 |
+
document.getElementById('slMaskExpansion').value = mask_expansion
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
+
function updateProgressBarsHtml(new_value, progress_text = 'Progress...') {
|
| 887 |
+
document.querySelectorAll('.pProgressBars').forEach((bar_elm) => {
|
| 888 |
+
// id = el.getAttribute("id")
|
| 889 |
+
// console.log("progressbar id:", id)
|
| 890 |
+
try {
|
| 891 |
+
bar_elm.setAttribute('value', new_value)
|
| 892 |
+
document
|
| 893 |
+
.querySelectorAll('.lProgressLabel')
|
| 894 |
+
.forEach((lable_elm) => {
|
| 895 |
+
lable_elm.innerHTML = progress_text
|
| 896 |
+
// else el.innerHTML = 'No work in progress'
|
| 897 |
+
})
|
| 898 |
+
} catch (e) {
|
| 899 |
+
console.warn(e) //value is not valid
|
| 900 |
+
}
|
| 901 |
+
})
|
| 902 |
+
|
| 903 |
+
// document.querySelector('#pProgressBar').value
|
| 904 |
+
}
|
| 905 |
+
///end selection mode////
|
| 906 |
+
function getLinkWidthHeightState() {
|
| 907 |
+
const state_str = document.getElementById('linkWidthHeight').dataset.b_link // sometime it's true and other time it's "true"
|
| 908 |
+
const b_state = state_str.toString() === 'true' ? true : false
|
| 909 |
+
return b_state
|
| 910 |
+
}
|
| 911 |
+
function setLinkWidthHeightState(state) {
|
| 912 |
+
document.getElementById('linkWidthHeight').dataset.b_link = state
|
| 913 |
+
}
|
| 914 |
+
function isSquareThumbnail() {
|
| 915 |
+
return document.getElementById('chSquareThumbnail').checked
|
| 916 |
+
}
|
| 917 |
+
|
| 918 |
+
async function populateMenu(
|
| 919 |
+
html_menu_id,
|
| 920 |
+
menu_item_class,
|
| 921 |
+
items,
|
| 922 |
+
createMenuItemHtml,
|
| 923 |
+
b_keep_old_selection = false,
|
| 924 |
+
label = ''
|
| 925 |
+
) {
|
| 926 |
+
// function createMenuItemHtml(item, item_html_element) {
|
| 927 |
+
// // menu_item_element.innerHTML = item.title
|
| 928 |
+
// // menu_item_element.dataset.model_hash = model.hash
|
| 929 |
+
// // menu_item_element.dataset.model_title = model.title
|
| 930 |
+
// }
|
| 931 |
+
|
| 932 |
+
try {
|
| 933 |
+
const html_menu_element = document.getElementById(html_menu_id)
|
| 934 |
+
html_menu_element.innerHTML = '' // empty the menu
|
| 935 |
+
if (label) {
|
| 936 |
+
const label_item = document.createElement('sp-menu-item')
|
| 937 |
+
label_item.selected = true
|
| 938 |
+
label_item.disabled = true
|
| 939 |
+
label_item.innerText = label
|
| 940 |
+
html_menu_element.appendChild(label_item)
|
| 941 |
+
}
|
| 942 |
+
for (let item of items) {
|
| 943 |
+
const menu_item_element = document.createElement('sp-menu-item')
|
| 944 |
+
menu_item_element.className = menu_item_class
|
| 945 |
+
createMenuItemHtml(item, menu_item_element)
|
| 946 |
+
html_menu_element.appendChild(menu_item_element)
|
| 947 |
+
}
|
| 948 |
+
} catch (e) {
|
| 949 |
+
b_result = false
|
| 950 |
+
console.warn(e)
|
| 951 |
+
}
|
| 952 |
+
return b_result
|
| 953 |
+
}
|
| 954 |
+
async function populateMenuByElement(
|
| 955 |
+
html_menu_element,
|
| 956 |
+
menu_item_class,
|
| 957 |
+
items,
|
| 958 |
+
createMenuItemHtml,
|
| 959 |
+
b_keep_old_selection = false,
|
| 960 |
+
label = ''
|
| 961 |
+
) {
|
| 962 |
+
// function createMenuItemHtml(item, item_html_element) {
|
| 963 |
+
// // menu_item_element.innerHTML = item.title
|
| 964 |
+
// // menu_item_element.dataset.model_hash = model.hash
|
| 965 |
+
// // menu_item_element.dataset.model_title = model.title
|
| 966 |
+
// }
|
| 967 |
+
|
| 968 |
+
try {
|
| 969 |
+
html_menu_element.innerHTML = '' // empty the menu
|
| 970 |
+
if (label) {
|
| 971 |
+
const label_item = document.createElement('sp-menu-item')
|
| 972 |
+
label_item.selected = true
|
| 973 |
+
label_item.disabled = true
|
| 974 |
+
label_item.innerText = label
|
| 975 |
+
html_menu_element.appendChild(label_item)
|
| 976 |
+
}
|
| 977 |
+
for (let item of items) {
|
| 978 |
+
const menu_item_element = document.createElement('sp-menu-item')
|
| 979 |
+
menu_item_element.className = menu_item_class
|
| 980 |
+
createMenuItemHtml(item, menu_item_element)
|
| 981 |
+
html_menu_element.appendChild(menu_item_element)
|
| 982 |
+
}
|
| 983 |
+
} catch (e) {
|
| 984 |
+
b_result = false
|
| 985 |
+
console.warn(e)
|
| 986 |
+
}
|
| 987 |
+
return b_result
|
| 988 |
+
}
|
| 989 |
+
function getSelectedMenuItem(menu_id) {
|
| 990 |
+
try {
|
| 991 |
+
const menu_element = document.getElementById(menu_id)
|
| 992 |
+
return menu_element.selectedOptions[0]
|
| 993 |
+
} catch (e) {
|
| 994 |
+
console.warn(e)
|
| 995 |
+
}
|
| 996 |
+
}
|
| 997 |
+
function getSelectedMenuItemByElement(menu_element) {
|
| 998 |
+
try {
|
| 999 |
+
// const menu_element = document.getElementById(menu_id)
|
| 1000 |
+
return menu_element.selectedOptions[0]
|
| 1001 |
+
} catch (e) {
|
| 1002 |
+
console.warn(e)
|
| 1003 |
+
}
|
| 1004 |
+
}
|
| 1005 |
+
function selectMenuItem(menu_id, item) {
|
| 1006 |
+
try {
|
| 1007 |
+
const menu_element = document.getElementById(menu_id)
|
| 1008 |
+
const option = Array.from(menu_element.options).filter(
|
| 1009 |
+
(element) => element.value === item
|
| 1010 |
+
)[0]
|
| 1011 |
+
option.selected = true
|
| 1012 |
+
} catch (e) {
|
| 1013 |
+
unselectMenuItem(menu_id)
|
| 1014 |
+
console.warn(e)
|
| 1015 |
+
}
|
| 1016 |
+
}
|
| 1017 |
+
function selectMenuItemByElement(menu_element, item) {
|
| 1018 |
+
try {
|
| 1019 |
+
const option = Array.from(menu_element.options).filter(
|
| 1020 |
+
(element) => element.value === item
|
| 1021 |
+
)[0]
|
| 1022 |
+
// debugger
|
| 1023 |
+
option.selected = true
|
| 1024 |
+
// option.dispatchEvent(new Event('click'))
|
| 1025 |
+
// option.click()
|
| 1026 |
+
} catch (e) {
|
| 1027 |
+
unselectMenuItemByElement(menu_element)
|
| 1028 |
+
console.warn(e)
|
| 1029 |
+
}
|
| 1030 |
+
}
|
| 1031 |
+
function getSelectedMenuItemTextContent(menu_id) {
|
| 1032 |
+
try {
|
| 1033 |
+
const selected_item = getSelectedMenuItem(menu_id)
|
| 1034 |
+
if (selected_item.disabled === true) return '' // ignore the label item
|
| 1035 |
+
|
| 1036 |
+
const text_content = selected_item.textContent
|
| 1037 |
+
return text_content
|
| 1038 |
+
} catch (e) {
|
| 1039 |
+
console.warn(e)
|
| 1040 |
+
}
|
| 1041 |
+
}
|
| 1042 |
+
function getSelectedMenuItemTextContentByElement(menu_element) {
|
| 1043 |
+
try {
|
| 1044 |
+
const selected_item = getSelectedMenuItemByElement(menu_element)
|
| 1045 |
+
if (selected_item.disabled === true) return ''
|
| 1046 |
+
const text_content = selected_item.textContent
|
| 1047 |
+
return text_content
|
| 1048 |
+
} catch (e) {
|
| 1049 |
+
console.warn(e)
|
| 1050 |
+
}
|
| 1051 |
+
}
|
| 1052 |
+
function unselectMenuItem(menu_id) {
|
| 1053 |
+
try {
|
| 1054 |
+
document.getElementById(menu_id).selectedIndex = null
|
| 1055 |
+
} catch (e) {
|
| 1056 |
+
console.warn(e)
|
| 1057 |
+
}
|
| 1058 |
+
}
|
| 1059 |
+
function unselectMenuItemByElement(menu_element) {
|
| 1060 |
+
try {
|
| 1061 |
+
menu_element.selectedIndex = null
|
| 1062 |
+
} catch (e) {
|
| 1063 |
+
console.warn(e)
|
| 1064 |
+
}
|
| 1065 |
+
}
|
| 1066 |
+
|
| 1067 |
+
function getUseNsfw() {
|
| 1068 |
+
//this method is shared between horde native and horde script
|
| 1069 |
+
const b_nsfw = document.getElementById('chUseNSFW').checked
|
| 1070 |
+
return b_nsfw
|
| 1071 |
+
}
|
| 1072 |
+
function getUseSilentMode_Old() {
|
| 1073 |
+
const b_use_silent_mode = document.getElementById('chUseSilentMode').checked
|
| 1074 |
+
return b_use_silent_mode
|
| 1075 |
+
}
|
| 1076 |
+
function getUseSilentMode() {
|
| 1077 |
+
let b_use_silent_mode = true //fast machine
|
| 1078 |
+
const pc_speed = getSelectedRadioButtonElement('rbPCSpeed').value
|
| 1079 |
+
if (pc_speed === 'slow') {
|
| 1080 |
+
b_use_silent_mode = false // use noisy mode
|
| 1081 |
+
} else if (pc_speed === 'fast') {
|
| 1082 |
+
b_use_silent_mode = true // use silent mode
|
| 1083 |
+
}
|
| 1084 |
+
// const b_use_silent_mode = document.getElementById('chUseSilentMode').checked
|
| 1085 |
+
return b_use_silent_mode
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
module.exports = {
|
| 1089 |
+
getPrompt,
|
| 1090 |
+
autoFillInPrompt,
|
| 1091 |
+
getNegativePrompt,
|
| 1092 |
+
autoFillInNegativePrompt,
|
| 1093 |
+
getDenoisingStrength,
|
| 1094 |
+
autoFillInDenoisingStrength,
|
| 1095 |
+
getWidth,
|
| 1096 |
+
autoFillInWidth,
|
| 1097 |
+
getHeight,
|
| 1098 |
+
autoFillInHeight,
|
| 1099 |
+
getSliderSdValue,
|
| 1100 |
+
setSliderSdValue,
|
| 1101 |
+
autoFillInHiResFixs,
|
| 1102 |
+
getHiResFixs,
|
| 1103 |
+
setHiResFixs,
|
| 1104 |
+
autoFillInSliderUi,
|
| 1105 |
+
getCheckedSamplerName,
|
| 1106 |
+
autoFillInSampler,
|
| 1107 |
+
autoFillInModel,
|
| 1108 |
+
getMode,
|
| 1109 |
+
setInitImageSrc,
|
| 1110 |
+
setInitImageMaskSrc,
|
| 1111 |
+
setGenerateButtonsColor,
|
| 1112 |
+
setAutomaticStatus,
|
| 1113 |
+
setProxyServerStatus,
|
| 1114 |
+
defaultSettings,
|
| 1115 |
+
autoFillDefaultSettings,
|
| 1116 |
+
autoFillSettings,
|
| 1117 |
+
getMaskBlur,
|
| 1118 |
+
setMaskBlur,
|
| 1119 |
+
|
| 1120 |
+
autoFillInHRHeight,
|
| 1121 |
+
autoFillInHRWidth,
|
| 1122 |
+
getPromptShortcut,
|
| 1123 |
+
setPromptShortcut,
|
| 1124 |
+
getModelHashByTitle,
|
| 1125 |
+
getSelectionMode,
|
| 1126 |
+
autoFillInInpaintMaskWeight,
|
| 1127 |
+
autoFillInSteps,
|
| 1128 |
+
getSteps,
|
| 1129 |
+
getBatchNumber,
|
| 1130 |
+
autoFillInBatchNumber,
|
| 1131 |
+
getHrWidth,
|
| 1132 |
+
getHrHeight,
|
| 1133 |
+
setCFG,
|
| 1134 |
+
getCFG,
|
| 1135 |
+
getMaskContent,
|
| 1136 |
+
setMaskContent,
|
| 1137 |
+
addHistoryButtonsHtml,
|
| 1138 |
+
|
| 1139 |
+
getSeed,
|
| 1140 |
+
setSeed,
|
| 1141 |
+
getMaskExpansion,
|
| 1142 |
+
setMaskExpansion,
|
| 1143 |
+
getUpscaleSize,
|
| 1144 |
+
getUpscaler2Visibility,
|
| 1145 |
+
getCodeFormerVisibility,
|
| 1146 |
+
getGFPGANVisibility,
|
| 1147 |
+
getCodeFormerWeight,
|
| 1148 |
+
updateProgressBarsHtml,
|
| 1149 |
+
getBackendType,
|
| 1150 |
+
getHordeApiKey,
|
| 1151 |
+
setProgressImageSrc,
|
| 1152 |
+
getLinkWidthHeightState,
|
| 1153 |
+
setLinkWidthHeightState,
|
| 1154 |
+
isSquareThumbnail,
|
| 1155 |
+
setControlImageSrc,
|
| 1156 |
+
setControlMaskSrc,
|
| 1157 |
+
|
| 1158 |
+
setHordeApiKey,
|
| 1159 |
+
populateMenu,
|
| 1160 |
+
getSelectedMenuItem,
|
| 1161 |
+
getSelectedMenuItemTextContent,
|
| 1162 |
+
getUseNsfw,
|
| 1163 |
+
getUseSilentMode,
|
| 1164 |
+
unselectMenuItem,
|
| 1165 |
+
selectMenuItem,
|
| 1166 |
+
getSliderSdValue_Old,
|
| 1167 |
+
getSelectedRadioButtonElement,
|
| 1168 |
+
getInitImageMaskElement,
|
| 1169 |
+
sliderAddEventListener_new,
|
| 1170 |
+
getSliderSdValueByElement,
|
| 1171 |
+
setSliderSdValueByElements,
|
| 1172 |
+
populateMenuByElement,
|
| 1173 |
+
selectMenuItemByElement,
|
| 1174 |
+
unselectMenuItemByElement,
|
| 1175 |
+
getSelectedMenuItemByElement,
|
| 1176 |
+
getSelectedMenuItemTextContentByElement,
|
| 1177 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/io.js
ADDED
|
@@ -0,0 +1,836 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const psapi = require('../psapi')
|
| 2 |
+
// const sdapi = require('../sdapi_py_re')
|
| 3 |
+
const layer_util = require('../utility/layer')
|
| 4 |
+
const general = require('./general')
|
| 5 |
+
const Jimp = require('../jimp/browser/lib/jimp.min')
|
| 6 |
+
|
| 7 |
+
const { executeAsModal } = require('photoshop').core
|
| 8 |
+
const batchPlay = require('photoshop').action.batchPlay
|
| 9 |
+
const formats = require('uxp').storage.formats
|
| 10 |
+
const storage = require('uxp').storage
|
| 11 |
+
const fs = storage.localFileSystem
|
| 12 |
+
|
| 13 |
+
async function isBlackAndWhiteImage(base64EncodedImage) {
|
| 14 |
+
try {
|
| 15 |
+
// Load your base64 encoded image
|
| 16 |
+
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
|
| 17 |
+
console.log(
|
| 18 |
+
'isBlackAndWhiteImage(): image.bitmap.width, image.bitmap.height: ',
|
| 19 |
+
image.bitmap.width,
|
| 20 |
+
image.bitmap.height
|
| 21 |
+
)
|
| 22 |
+
// Check if your image only has one channel
|
| 23 |
+
return (
|
| 24 |
+
image.bitmap.width === image.bitmap.height &&
|
| 25 |
+
image.bitmap.width === 1
|
| 26 |
+
)
|
| 27 |
+
} catch (e) {
|
| 28 |
+
console.warn(e)
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
async function convertBlackAndWhiteImageToRGBChannels(base64EncodedImage) {
|
| 33 |
+
// Load your base64 encoded image
|
| 34 |
+
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
|
| 35 |
+
|
| 36 |
+
// Convert your black and white image to RGB channels
|
| 37 |
+
image.color([
|
| 38 |
+
{ apply: 'red', params: [255] },
|
| 39 |
+
{ apply: 'green', params: [255] },
|
| 40 |
+
{ apply: 'blue', params: [255] },
|
| 41 |
+
])
|
| 42 |
+
|
| 43 |
+
// Get your base64 encoded black and white image with RGB channels
|
| 44 |
+
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
|
| 45 |
+
Jimp.MIME_JPEG
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
return base64EncodedImageWithRGBChannels
|
| 49 |
+
}
|
| 50 |
+
async function convertBlackAndWhiteImageToRGBChannels2(base64EncodedImage) {
|
| 51 |
+
try {
|
| 52 |
+
// Load your base64 encoded image
|
| 53 |
+
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
|
| 54 |
+
|
| 55 |
+
// Convert your black and white image to RGB channels
|
| 56 |
+
image.color([{ apply: 'mix', params: ['#ffffff', 100] }])
|
| 57 |
+
|
| 58 |
+
// Get your base64 encoded black and white image with RGB channels
|
| 59 |
+
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
|
| 60 |
+
Jimp.MIME_JPEG
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
return base64EncodedImageWithRGBChannels
|
| 64 |
+
} catch (e) {
|
| 65 |
+
console.warn(e)
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
async function convertBlackAndWhiteImageToRGBChannels3(base64EncodedImage) {
|
| 69 |
+
try {
|
| 70 |
+
// Load your base64 encoded image
|
| 71 |
+
const image = await Jimp.read(Buffer.from(base64EncodedImage, 'base64'))
|
| 72 |
+
|
| 73 |
+
// Convert your black and white image to RGB channels
|
| 74 |
+
// image.color([{ apply: 'mix', params: ['#ffffff', 100] }])
|
| 75 |
+
|
| 76 |
+
// Get your base64 encoded black and white image with RGB channels
|
| 77 |
+
const base64EncodedImageWithRGBChannels = await image.getBase64Async(
|
| 78 |
+
Jimp.MIME_PNG
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
return base64EncodedImageWithRGBChannels
|
| 82 |
+
} catch (e) {
|
| 83 |
+
console.warn(e)
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
async function snapShotLayer() {
|
| 88 |
+
//snapshot layer with no mask
|
| 89 |
+
let command = [
|
| 90 |
+
// Select All Layers current layer
|
| 91 |
+
{
|
| 92 |
+
_obj: 'selectAllLayers',
|
| 93 |
+
_target: [
|
| 94 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
| 95 |
+
],
|
| 96 |
+
},
|
| 97 |
+
// Duplicate current layer
|
| 98 |
+
// {"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},
|
| 99 |
+
{
|
| 100 |
+
// ID: ids,
|
| 101 |
+
_obj: 'duplicate',
|
| 102 |
+
_target: [
|
| 103 |
+
{ _enum: 'ordinal', _ref: 'layer', _value: 'targetEnum' },
|
| 104 |
+
],
|
| 105 |
+
// version: 5
|
| 106 |
+
},
|
| 107 |
+
|
| 108 |
+
// Merge Layers
|
| 109 |
+
{ _obj: 'mergeLayersNew' },
|
| 110 |
+
// Make
|
| 111 |
+
{
|
| 112 |
+
_obj: 'make',
|
| 113 |
+
at: { _enum: 'channel', _ref: 'channel', _value: 'mask' },
|
| 114 |
+
new: { _class: 'channel' },
|
| 115 |
+
using: { _enum: 'userMaskEnabled', _value: 'revealSelection' },
|
| 116 |
+
},
|
| 117 |
+
// Set Selection
|
| 118 |
+
{
|
| 119 |
+
_obj: 'set',
|
| 120 |
+
_target: [{ _property: 'selection', _ref: 'channel' }],
|
| 121 |
+
to: { _enum: 'ordinal', _ref: 'channel', _value: 'targetEnum' },
|
| 122 |
+
},
|
| 123 |
+
//make a group
|
| 124 |
+
{
|
| 125 |
+
_obj: 'make',
|
| 126 |
+
_target: [
|
| 127 |
+
{
|
| 128 |
+
_ref: 'layerSection',
|
| 129 |
+
},
|
| 130 |
+
],
|
| 131 |
+
from: {
|
| 132 |
+
_ref: 'layer',
|
| 133 |
+
_enum: 'ordinal',
|
| 134 |
+
_value: 'targetEnum',
|
| 135 |
+
},
|
| 136 |
+
layerSectionStart: 512,
|
| 137 |
+
layerSectionEnd: 513,
|
| 138 |
+
name: 'Group 2',
|
| 139 |
+
_options: {
|
| 140 |
+
dialogOptions: 'dontDisplay',
|
| 141 |
+
},
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
_obj: 'mergeLayersNew',
|
| 145 |
+
_options: {
|
| 146 |
+
dialogOptions: 'dontDisplay',
|
| 147 |
+
},
|
| 148 |
+
},
|
| 149 |
+
]
|
| 150 |
+
|
| 151 |
+
const result = await batchPlay(command, {
|
| 152 |
+
synchronousExecution: true,
|
| 153 |
+
modalBehavior: 'execute',
|
| 154 |
+
})
|
| 155 |
+
|
| 156 |
+
return result
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
async function snapShotLayerExe() {
|
| 160 |
+
await executeAsModal(async () => {
|
| 161 |
+
//create a fill layer above the background layer, so that it's present in the snapshot
|
| 162 |
+
try {
|
| 163 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 164 |
+
|
| 165 |
+
// const backgroundLayer = await app.activeDocument.backgroundLayer
|
| 166 |
+
|
| 167 |
+
await psapi.createSolidLayer(255, 255, 255)
|
| 168 |
+
const solid_layer = await app.activeDocument.activeLayers[0]
|
| 169 |
+
// await psapi.unSelectMarqueeExe()//unselect the
|
| 170 |
+
|
| 171 |
+
// await solid_layer.moveAbove(backgroundLayer)
|
| 172 |
+
// await snapShotLayer() //create a layer with only the opaque pixels
|
| 173 |
+
// await psapi.reSelectMarqueeExe(selectionInfo)
|
| 174 |
+
// await solid_layer.delete()
|
| 175 |
+
} catch (e) {
|
| 176 |
+
console.warn(e)
|
| 177 |
+
}
|
| 178 |
+
})
|
| 179 |
+
await executeAsModal(async () => {
|
| 180 |
+
//create a fill layer above the background layer, so that it's present in the snapshot
|
| 181 |
+
try {
|
| 182 |
+
const solid_layer = await app.activeDocument.activeLayers[0]
|
| 183 |
+
const backgroundLayer = await app.activeDocument.backgroundLayer
|
| 184 |
+
await solid_layer.moveAbove(backgroundLayer)
|
| 185 |
+
await psapi.unselectActiveLayersExe()
|
| 186 |
+
await snapShotLayer() //create a layer with only the opaque pixels
|
| 187 |
+
// await psapi.reSelectMarqueeExe(selectionInfo)
|
| 188 |
+
// await psapi.unSelectMarqueeExe()//unselect the
|
| 189 |
+
await solid_layer.delete()
|
| 190 |
+
} catch (e) {
|
| 191 |
+
console.warn(e)
|
| 192 |
+
}
|
| 193 |
+
})
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
class IO {
|
| 197 |
+
// constructor() {}
|
| 198 |
+
static async exportWebp(layer, export_width, export_height) {
|
| 199 |
+
await executeAsModal(async () => {
|
| 200 |
+
//we assume we have a valid layer rectangular image/layer, no transparency
|
| 201 |
+
const doc_entry = await getCurrentDocFolder() //get the main document folder before we switch doc
|
| 202 |
+
const layer_info = await layer_util.Layer.getLayerInfo(layer)
|
| 203 |
+
//*) create a new document
|
| 204 |
+
const new_doc = await IOHelper.createDocumentExe(
|
| 205 |
+
export_width,
|
| 206 |
+
export_height
|
| 207 |
+
)
|
| 208 |
+
const new_layer = await layer_util.Layer.duplicateToDoc(
|
| 209 |
+
layer,
|
| 210 |
+
new_doc
|
| 211 |
+
)
|
| 212 |
+
//*) resize the layer to the same dimension as the document
|
| 213 |
+
|
| 214 |
+
await layer_util.Layer.scaleTo(
|
| 215 |
+
new_layer,
|
| 216 |
+
new_doc.width,
|
| 217 |
+
new_doc.height
|
| 218 |
+
) //
|
| 219 |
+
await layer_util.Layer.moveTo(new_layer, 0, 0) //move to the top left corner
|
| 220 |
+
//
|
| 221 |
+
await IOHelper.saveAsWebpExe(doc_entry) //save current document as .webp file, save it into doc_entry folder
|
| 222 |
+
await new_doc.closeWithoutSaving()
|
| 223 |
+
})
|
| 224 |
+
}
|
| 225 |
+
static async exportPng() {}
|
| 226 |
+
static async exportDoc() {}
|
| 227 |
+
static async exportLayer() {}
|
| 228 |
+
|
| 229 |
+
static async base64PngToPngFile(
|
| 230 |
+
base64_png,
|
| 231 |
+
folder,
|
| 232 |
+
image_name = 'temp_base64Png.png'
|
| 233 |
+
) {
|
| 234 |
+
const arrayBuffer = _base64ToArrayBuffer(base64_png)
|
| 235 |
+
|
| 236 |
+
// const folder = await storage.localFileSystem.getTemporaryFolder()
|
| 237 |
+
|
| 238 |
+
const file = await folder.createFile(image_name, { overwrite: true })
|
| 239 |
+
|
| 240 |
+
await file.write(arrayBuffer, { format: storage.formats.binary })
|
| 241 |
+
return file
|
| 242 |
+
}
|
| 243 |
+
static async openImageFileAsDocument(file_entry) {
|
| 244 |
+
const new_doc = await app.open(file_entry)
|
| 245 |
+
return new_doc
|
| 246 |
+
}
|
| 247 |
+
static async base64PngToBase64Webp(base64_png) {
|
| 248 |
+
let base64_webp
|
| 249 |
+
try {
|
| 250 |
+
await executeAsModal(async () => {
|
| 251 |
+
try {
|
| 252 |
+
const main_doc_entry = await getCurrentDocFolder()
|
| 253 |
+
//save the base64_png to .png file
|
| 254 |
+
const temp_folder = await fs.getTemporaryFolder()
|
| 255 |
+
const png_file = await this.base64PngToPngFile(
|
| 256 |
+
base64_png,
|
| 257 |
+
temp_folder
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
//load the .png file as a layer in new document
|
| 261 |
+
const new_doc = await this.openImageFileAsDocument(png_file)
|
| 262 |
+
//save document as .webp
|
| 263 |
+
const [_, webp_file] = await IOHelper.saveAsWebpExe(
|
| 264 |
+
main_doc_entry
|
| 265 |
+
) //save current document as .webp file, save it into doc_entry folder
|
| 266 |
+
await new_doc.closeWithoutSaving()
|
| 267 |
+
//load/read the .webp file as an arraybuffer
|
| 268 |
+
const ArrayBufferWebp = await webp_file.read({
|
| 269 |
+
format: formats.binary,
|
| 270 |
+
})
|
| 271 |
+
|
| 272 |
+
//convert the arraybuffer to base64Webp string
|
| 273 |
+
|
| 274 |
+
base64_webp = _arrayBufferToBase64(ArrayBufferWebp)
|
| 275 |
+
} catch (e) {
|
| 276 |
+
console.warn(e)
|
| 277 |
+
}
|
| 278 |
+
})
|
| 279 |
+
return base64_webp
|
| 280 |
+
} catch (e) {
|
| 281 |
+
console.warn(e)
|
| 282 |
+
}
|
| 283 |
+
}
|
| 284 |
+
static async base64WebpFromFile(file_entry) {
|
| 285 |
+
//file_entry most be .webp
|
| 286 |
+
let webp_base64
|
| 287 |
+
try {
|
| 288 |
+
await executeAsModal(async () => {
|
| 289 |
+
const arrayBuffer = await file_entry.read({
|
| 290 |
+
format: formats.binary,
|
| 291 |
+
})
|
| 292 |
+
console.log('webp arrayBuffer:', arrayBuffer)
|
| 293 |
+
|
| 294 |
+
const base64_image = _arrayBufferToBase64(arrayBuffer) //convert the buffer to base64
|
| 295 |
+
console.log('base64_image:', base64_image)
|
| 296 |
+
webp_base64 = base64_image
|
| 297 |
+
})
|
| 298 |
+
return [webp_base64, webp_arrayBuffer]
|
| 299 |
+
} catch (e) {
|
| 300 |
+
console.warn(e)
|
| 301 |
+
}
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
static async base64ToLayer(
|
| 305 |
+
base64_png,
|
| 306 |
+
image_name = 'base64_to_layer.png',
|
| 307 |
+
to_x = 0,
|
| 308 |
+
to_y = 0,
|
| 309 |
+
width = 512,
|
| 310 |
+
height = 512,
|
| 311 |
+
format = 'png'
|
| 312 |
+
) {
|
| 313 |
+
let layer
|
| 314 |
+
if (format === 'png') {
|
| 315 |
+
layer = await IOBase64ToLayer.base64PngToLayer(
|
| 316 |
+
base64_png,
|
| 317 |
+
image_name
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
psapi.setVisibleExe(layer, true)
|
| 321 |
+
await layer_util.Layer.scaleTo(layer, width, height) //
|
| 322 |
+
await layer_util.Layer.moveTo(layer, to_x, to_y) //move to the top left corner
|
| 323 |
+
psapi.setVisibleExe(layer, true)
|
| 324 |
+
}
|
| 325 |
+
return layer
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
static async getSelectionFromCanvasAsBase64Silent(
|
| 329 |
+
selectionInfo,
|
| 330 |
+
b_resize = false,
|
| 331 |
+
resize_width = 0,
|
| 332 |
+
resize_height = 0
|
| 333 |
+
) {
|
| 334 |
+
//it will save the document then crop it so that only the selection area are left.
|
| 335 |
+
//return arrayBuffer or base64Png?
|
| 336 |
+
try {
|
| 337 |
+
let file
|
| 338 |
+
const folder = await fs.getTemporaryFolder()
|
| 339 |
+
await executeAsModal(
|
| 340 |
+
async () => {
|
| 341 |
+
const canvas_image_name = 'canvas_image.png'
|
| 342 |
+
file = await folder.createFile(canvas_image_name, {
|
| 343 |
+
overwrite: true,
|
| 344 |
+
})
|
| 345 |
+
|
| 346 |
+
const currentDocument = app.activeDocument
|
| 347 |
+
await currentDocument.saveAs.png(file, null, true)
|
| 348 |
+
//save file end
|
| 349 |
+
|
| 350 |
+
//read the saved image.png
|
| 351 |
+
},
|
| 352 |
+
|
| 353 |
+
{ commandName: 'readPng' }
|
| 354 |
+
)
|
| 355 |
+
|
| 356 |
+
const arrayBuffer = await file.read({
|
| 357 |
+
format: formats.binary,
|
| 358 |
+
})
|
| 359 |
+
|
| 360 |
+
// const selectionInfo = g_generation_session.selectionInfo
|
| 361 |
+
// const selectionInfo = await psapi.getSelectionInfoExe()
|
| 362 |
+
const cropped_base64_url = await IOHelper.cropPng(
|
| 363 |
+
arrayBuffer,
|
| 364 |
+
selectionInfo,
|
| 365 |
+
true,
|
| 366 |
+
resize_width,
|
| 367 |
+
resize_height
|
| 368 |
+
)
|
| 369 |
+
const cropped_base64 = general.base64UrlToBase64(cropped_base64_url)
|
| 370 |
+
|
| 371 |
+
// html_manip.setInitImageSrc(cropped_base64_url)
|
| 372 |
+
return cropped_base64
|
| 373 |
+
} catch (e) {
|
| 374 |
+
console.warn(e)
|
| 375 |
+
}
|
| 376 |
+
}
|
| 377 |
+
static async getSelectionFromCanvasAsBase64NonSilent(
|
| 378 |
+
layer,
|
| 379 |
+
image_name,
|
| 380 |
+
width,
|
| 381 |
+
height
|
| 382 |
+
) {
|
| 383 |
+
try {
|
| 384 |
+
const image_buffer = await psapi.newExportPng(
|
| 385 |
+
layer,
|
| 386 |
+
image_name,
|
| 387 |
+
width,
|
| 388 |
+
height
|
| 389 |
+
)
|
| 390 |
+
|
| 391 |
+
const base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
|
| 392 |
+
//send the base64 to the server to save the file in the desired directory
|
| 393 |
+
// await sdapi.requestSavePng(base64_image, image_name)
|
| 394 |
+
// await saveFileInSubFolder(base64_image, document_name, image_name)
|
| 395 |
+
// debugger
|
| 396 |
+
const { requestSavePng } = require('../sdapi_py_re')
|
| 397 |
+
await requestSavePng(base64_image, image_name)
|
| 398 |
+
return base64_image
|
| 399 |
+
} catch (e) {
|
| 400 |
+
console.warn(e)
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
static async getSelectionFromCanvasAsBase64Interface(
|
| 404 |
+
width,
|
| 405 |
+
height,
|
| 406 |
+
layer,
|
| 407 |
+
selectionInfo,
|
| 408 |
+
resize = true,
|
| 409 |
+
use_silent_mode = true,
|
| 410 |
+
image_name = 'temp.png'
|
| 411 |
+
) {
|
| 412 |
+
let base64_image
|
| 413 |
+
if (use_silent_mode) {
|
| 414 |
+
base64_image = await this.getSelectionFromCanvasAsBase64Silent(
|
| 415 |
+
selectionInfo,
|
| 416 |
+
resize,
|
| 417 |
+
width,
|
| 418 |
+
height
|
| 419 |
+
)
|
| 420 |
+
} else {
|
| 421 |
+
base64_image = await this.getSelectionFromCanvasAsBase64NonSilent(
|
| 422 |
+
layer,
|
| 423 |
+
image_name,
|
| 424 |
+
width,
|
| 425 |
+
height
|
| 426 |
+
)
|
| 427 |
+
}
|
| 428 |
+
return base64_image
|
| 429 |
+
}
|
| 430 |
+
static async getSelectionFromCanvasAsBase64Interface_New(
|
| 431 |
+
width,
|
| 432 |
+
height,
|
| 433 |
+
selectionInfo,
|
| 434 |
+
resize = true,
|
| 435 |
+
image_name = 'temp.png'
|
| 436 |
+
) {
|
| 437 |
+
//use this version, it has less parameters
|
| 438 |
+
const use_silent_mode = html_manip.getUseSilentMode()
|
| 439 |
+
let layer = null
|
| 440 |
+
if (!use_silent_mode) {
|
| 441 |
+
await psapi.snapshot_layerExe()
|
| 442 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
| 443 |
+
layer = snapshotLayer
|
| 444 |
+
}
|
| 445 |
+
let base64_image
|
| 446 |
+
if (use_silent_mode) {
|
| 447 |
+
base64_image = await this.getSelectionFromCanvasAsBase64Silent(
|
| 448 |
+
selectionInfo,
|
| 449 |
+
resize,
|
| 450 |
+
width,
|
| 451 |
+
height
|
| 452 |
+
)
|
| 453 |
+
} else {
|
| 454 |
+
base64_image = await this.getSelectionFromCanvasAsBase64NonSilent(
|
| 455 |
+
layer,
|
| 456 |
+
image_name,
|
| 457 |
+
width,
|
| 458 |
+
height
|
| 459 |
+
)
|
| 460 |
+
}
|
| 461 |
+
await layer_util.deleteLayers([layer]) //delete the snapshot layer if it exists
|
| 462 |
+
return base64_image
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
static async urlToLayer(image_url, image_file_name = 'image_from_url.png') {
|
| 466 |
+
try {
|
| 467 |
+
await psapi.unselectActiveLayersExe()
|
| 468 |
+
const temp_entry = await fs.getTemporaryFolder()
|
| 469 |
+
await downloadItExe(image_url, temp_entry, image_file_name)
|
| 470 |
+
} catch (e) {
|
| 471 |
+
console.warn('urlToLayer()', image_url, image_file_name, e)
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
}
|
| 475 |
+
|
| 476 |
+
class IOHelper {
|
| 477 |
+
static async saveAsWebp(doc_entry) {
|
| 478 |
+
//doc_entry must be in dataFolder or tempFolder
|
| 479 |
+
//save document as webp
|
| 480 |
+
const document_id = app.activeDocument.id
|
| 481 |
+
|
| 482 |
+
// doc_entry = await getCurrentDocFolder()
|
| 483 |
+
const file_entry = await doc_entry.createFile('temp.webp', {
|
| 484 |
+
overwrite: true,
|
| 485 |
+
})
|
| 486 |
+
|
| 487 |
+
const token = await fs.createSessionToken(file_entry)
|
| 488 |
+
const result = await batchPlay(
|
| 489 |
+
[
|
| 490 |
+
{
|
| 491 |
+
_obj: 'save',
|
| 492 |
+
as: {
|
| 493 |
+
_obj: 'WebPFormat',
|
| 494 |
+
compression: {
|
| 495 |
+
_enum: 'WebPCompression',
|
| 496 |
+
_value: 'compressionLossless',
|
| 497 |
+
},
|
| 498 |
+
includeXMPData: false,
|
| 499 |
+
includeEXIFData: false,
|
| 500 |
+
includePsExtras: false,
|
| 501 |
+
},
|
| 502 |
+
in: {
|
| 503 |
+
_path: token,
|
| 504 |
+
_kind: 'local',
|
| 505 |
+
},
|
| 506 |
+
documentID: 59,
|
| 507 |
+
copy: true,
|
| 508 |
+
lowerCase: true,
|
| 509 |
+
saveStage: {
|
| 510 |
+
_enum: 'saveStageType',
|
| 511 |
+
_value: 'saveBegin',
|
| 512 |
+
},
|
| 513 |
+
_options: {
|
| 514 |
+
dialogOptions: 'dontDisplay',
|
| 515 |
+
},
|
| 516 |
+
},
|
| 517 |
+
],
|
| 518 |
+
{
|
| 519 |
+
synchronousExecution: true,
|
| 520 |
+
modalBehavior: 'execute',
|
| 521 |
+
}
|
| 522 |
+
)
|
| 523 |
+
|
| 524 |
+
return [result, file_entry]
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
static async saveAsWebpExe(doc_entry) {
|
| 528 |
+
let result
|
| 529 |
+
let file_entry
|
| 530 |
+
await executeAsModal(async () => {
|
| 531 |
+
;[result, file_entry] = await this.saveAsWebp(doc_entry)
|
| 532 |
+
})
|
| 533 |
+
return [result, file_entry]
|
| 534 |
+
}
|
| 535 |
+
static async createDocumentExe(width, height) {
|
| 536 |
+
let new_doc
|
| 537 |
+
try {
|
| 538 |
+
await executeAsModal(async () => {
|
| 539 |
+
new_doc = await app.documents.add({
|
| 540 |
+
width: width,
|
| 541 |
+
height: height,
|
| 542 |
+
resolution: await app.activeDocument.resolution,
|
| 543 |
+
mode: 'RGBColorMode',
|
| 544 |
+
fill: 'transparent',
|
| 545 |
+
})
|
| 546 |
+
})
|
| 547 |
+
} catch (e) {
|
| 548 |
+
console.warn(e)
|
| 549 |
+
}
|
| 550 |
+
return new_doc
|
| 551 |
+
}
|
| 552 |
+
static async cropPng(
|
| 553 |
+
arrayBuffer,
|
| 554 |
+
selectionInfo,
|
| 555 |
+
b_resize = false,
|
| 556 |
+
resize_width = 0,
|
| 557 |
+
resize_height = 0
|
| 558 |
+
) {
|
| 559 |
+
//crop png from array buffer
|
| 560 |
+
//have the option to resize the after cropping
|
| 561 |
+
|
| 562 |
+
const crop_x = selectionInfo.left
|
| 563 |
+
const crop_y = selectionInfo.top
|
| 564 |
+
const crop_w = selectionInfo.width
|
| 565 |
+
const crop_h = selectionInfo.height
|
| 566 |
+
const base64_url_result = await Jimp.read(arrayBuffer)
|
| 567 |
+
.then(async (img) => {
|
| 568 |
+
let cropped_img = await img.crop(crop_x, crop_y, crop_w, crop_h)
|
| 569 |
+
|
| 570 |
+
let resized_img
|
| 571 |
+
if (b_resize) {
|
| 572 |
+
resized_img = await cropped_img.resize(
|
| 573 |
+
resize_width,
|
| 574 |
+
resize_height
|
| 575 |
+
)
|
| 576 |
+
} else {
|
| 577 |
+
resized_img = cropped_img
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
const base64_url = await resized_img.getBase64Async(
|
| 581 |
+
Jimp.MIME_PNG
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
// console.log('jimp: base64_url: ', base64_url)
|
| 585 |
+
// document.getElementById("image").setAttribute("src", data);
|
| 586 |
+
|
| 587 |
+
return base64_url
|
| 588 |
+
})
|
| 589 |
+
.catch((error) => {
|
| 590 |
+
console.error(error)
|
| 591 |
+
})
|
| 592 |
+
return base64_url_result
|
| 593 |
+
}
|
| 594 |
+
}
|
| 595 |
+
|
| 596 |
+
class IOBase64ToLayer {
|
| 597 |
+
static {}
|
| 598 |
+
static async base64PngToLayer(base64_png, image_name) {
|
| 599 |
+
//unselect all layers so that the imported layer get place at the top of the document
|
| 600 |
+
await psapi.unselectActiveLayersExe()
|
| 601 |
+
|
| 602 |
+
const imported_layer = await base64ToFile(base64_png, image_name) //silent import into the document
|
| 603 |
+
|
| 604 |
+
return imported_layer
|
| 605 |
+
}
|
| 606 |
+
}
|
| 607 |
+
class IOFolder {
|
| 608 |
+
static {}
|
| 609 |
+
static async createSettingsFolder() {
|
| 610 |
+
//create a folder named "Settings" in the DataFolder
|
| 611 |
+
let settings_entry
|
| 612 |
+
await executeAsModal(async () => {
|
| 613 |
+
settings_entry = await this.createFolderSafe('Settings')
|
| 614 |
+
})
|
| 615 |
+
return settings_entry
|
| 616 |
+
}
|
| 617 |
+
static async findOrCreateFolderExe(folder_name) {
|
| 618 |
+
//create a folder named "Settings" in the DataFolder
|
| 619 |
+
let folder_entry
|
| 620 |
+
await executeAsModal(async () => {
|
| 621 |
+
folder_entry = await this.createFolderSafe(folder_name)
|
| 622 |
+
})
|
| 623 |
+
return folder_entry
|
| 624 |
+
}
|
| 625 |
+
|
| 626 |
+
static async doesFolderExist(folder_name) {
|
| 627 |
+
//check if folder exist. return true if it does. false if it doesn't.
|
| 628 |
+
const data_folder = await fs.getDataFolder()
|
| 629 |
+
let b_exist = false
|
| 630 |
+
let folder
|
| 631 |
+
try {
|
| 632 |
+
folder = await data_folder.getEntry(folder_name)
|
| 633 |
+
b_exist = true
|
| 634 |
+
} catch (e) {
|
| 635 |
+
// console.warn(e)
|
| 636 |
+
b_exist = false
|
| 637 |
+
}
|
| 638 |
+
return b_exist
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
static async createFolderSafe(folder_name) {
|
| 642 |
+
//will always return a folder. it will create the folder if it doesn't exist.
|
| 643 |
+
try {
|
| 644 |
+
// const uuid = await getUniqueDocumentId()
|
| 645 |
+
const data_folder = await fs.getDataFolder()
|
| 646 |
+
|
| 647 |
+
let folder_entry
|
| 648 |
+
try {
|
| 649 |
+
folder_entry = await data_folder.getEntry(folder_name)
|
| 650 |
+
} catch (e) {
|
| 651 |
+
console.warn(e)
|
| 652 |
+
//create document folder
|
| 653 |
+
folder_entry = await data_folder.createFolder(folder_name)
|
| 654 |
+
}
|
| 655 |
+
|
| 656 |
+
return folder_entry
|
| 657 |
+
} catch (e) {
|
| 658 |
+
console.warn(e)
|
| 659 |
+
}
|
| 660 |
+
}
|
| 661 |
+
|
| 662 |
+
static async getDocumentFolderNativePath() {
|
| 663 |
+
try {
|
| 664 |
+
const uuid = await getUniqueDocumentId()
|
| 665 |
+
|
| 666 |
+
let doc_folder = await this.getDocFolder(uuid)
|
| 667 |
+
const path = general.fixNativePath(doc_folder.nativePath)
|
| 668 |
+
return path
|
| 669 |
+
} catch (e) {
|
| 670 |
+
console.warn(e)
|
| 671 |
+
}
|
| 672 |
+
return ''
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
static async getDocFolder(doc_uuid) {
|
| 676 |
+
//will create folder if does not exist. always return a folder entry
|
| 677 |
+
const doc_entry = await getDocFolder(doc_uuid)
|
| 678 |
+
return doc_entry
|
| 679 |
+
}
|
| 680 |
+
static async getSettingsFolder() {
|
| 681 |
+
//will create folder if does not exist. always return a folder entry
|
| 682 |
+
const settings_entry = await this.createSettingsFolder()
|
| 683 |
+
return settings_entry
|
| 684 |
+
}
|
| 685 |
+
static async getPresetFolder() {
|
| 686 |
+
//will create folder if does not exist. always return a folder entry
|
| 687 |
+
const preset_entry = await this.findOrCreateFolderExe('Preset')
|
| 688 |
+
return preset_entry
|
| 689 |
+
}
|
| 690 |
+
static async getCustomPresetFolder(
|
| 691 |
+
custom_preset_folder_name = 'custom_preset'
|
| 692 |
+
) {
|
| 693 |
+
//will create folder if does not exist. always return a folder entry
|
| 694 |
+
const preset_entry = await this.findOrCreateFolderExe(
|
| 695 |
+
custom_preset_folder_name
|
| 696 |
+
)
|
| 697 |
+
return preset_entry
|
| 698 |
+
}
|
| 699 |
+
static async createFolderIfDoesNotExist(folder_name) {
|
| 700 |
+
try {
|
| 701 |
+
await executeAsModal(async () => {
|
| 702 |
+
try {
|
| 703 |
+
const folder = await fs.getDataFolder()
|
| 704 |
+
const sub_folder = await folder.createFolder(folder_name)
|
| 705 |
+
} catch (e) {
|
| 706 |
+
console.warn(e)
|
| 707 |
+
}
|
| 708 |
+
})
|
| 709 |
+
} catch (e) {
|
| 710 |
+
console.warn(e)
|
| 711 |
+
}
|
| 712 |
+
}
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
class IOLog {
|
| 716 |
+
static {}
|
| 717 |
+
static async saveLogToFile(json, file_name) {
|
| 718 |
+
try {
|
| 719 |
+
const plugin_folder = await fs.getDataFolder()
|
| 720 |
+
const file = await plugin_folder.createFile(file_name, {
|
| 721 |
+
type: storage.types.file,
|
| 722 |
+
overwrite: true,
|
| 723 |
+
})
|
| 724 |
+
|
| 725 |
+
const JSONInPrettyFormat = JSON.stringify(json, undefined, 4)
|
| 726 |
+
await file.write(JSONInPrettyFormat, {
|
| 727 |
+
format: storage.formats.utf8,
|
| 728 |
+
append: true,
|
| 729 |
+
})
|
| 730 |
+
} catch (e) {
|
| 731 |
+
console.warn(e)
|
| 732 |
+
}
|
| 733 |
+
}
|
| 734 |
+
}
|
| 735 |
+
class IOJson {
|
| 736 |
+
static {}
|
| 737 |
+
static async saveJsonToFile(json, folder_entry, file_name) {
|
| 738 |
+
try {
|
| 739 |
+
const file = await folder_entry.createFile(file_name, {
|
| 740 |
+
type: storage.types.file,
|
| 741 |
+
overwrite: true,
|
| 742 |
+
})
|
| 743 |
+
|
| 744 |
+
const JSONInPrettyFormat = JSON.stringify(json, undefined, 4)
|
| 745 |
+
await file.write(JSONInPrettyFormat, {
|
| 746 |
+
format: storage.formats.utf8,
|
| 747 |
+
append: false,
|
| 748 |
+
})
|
| 749 |
+
} catch (e) {
|
| 750 |
+
console.warn(e)
|
| 751 |
+
}
|
| 752 |
+
}
|
| 753 |
+
|
| 754 |
+
static async saveJsonToFileExe(json, folder_entry, file_name) {
|
| 755 |
+
await executeAsModal(async () => {
|
| 756 |
+
await this.saveJsonToFile(json, folder_entry, file_name)
|
| 757 |
+
})
|
| 758 |
+
}
|
| 759 |
+
static async loadJsonFromFile(folder_entry, file_name) {
|
| 760 |
+
const json_file_name = file_name
|
| 761 |
+
|
| 762 |
+
try {
|
| 763 |
+
const json_entry = await folder_entry.getEntry(json_file_name)
|
| 764 |
+
if (json_entry) {
|
| 765 |
+
const json = JSON.parse(
|
| 766 |
+
await json_entry.read({
|
| 767 |
+
format: storage.formats.utf8,
|
| 768 |
+
})
|
| 769 |
+
)
|
| 770 |
+
return json
|
| 771 |
+
}
|
| 772 |
+
} catch (e) {
|
| 773 |
+
console.warn(e)
|
| 774 |
+
}
|
| 775 |
+
}
|
| 776 |
+
|
| 777 |
+
static async saveSettingsToFile(settings_json, settings_file_name) {
|
| 778 |
+
await executeAsModal(async () => {
|
| 779 |
+
// debugger
|
| 780 |
+
const folder_entry = await IOFolder.getSettingsFolder('Settings')
|
| 781 |
+
await this.saveJsonToFile(
|
| 782 |
+
settings_json,
|
| 783 |
+
folder_entry,
|
| 784 |
+
settings_file_name
|
| 785 |
+
)
|
| 786 |
+
})
|
| 787 |
+
}
|
| 788 |
+
static async loadSettingsFromFile(settings_file_name) {
|
| 789 |
+
const folder_entry = await IOFolder.getSettingsFolder('Settings')
|
| 790 |
+
const settings_json = await this.loadJsonFromFile(
|
| 791 |
+
folder_entry,
|
| 792 |
+
settings_file_name
|
| 793 |
+
)
|
| 794 |
+
return settings_json
|
| 795 |
+
}
|
| 796 |
+
static async saveHordeSettingsToFile(settings_json) {
|
| 797 |
+
const settings_file_name = 'horde_settings.json'
|
| 798 |
+
await this.saveSettingsToFile(settings_json, settings_file_name)
|
| 799 |
+
}
|
| 800 |
+
static async loadHordeSettingsFromFile() {
|
| 801 |
+
const settings_file_name = 'horde_settings.json'
|
| 802 |
+
const settings_json = await this.loadSettingsFromFile(
|
| 803 |
+
settings_file_name
|
| 804 |
+
)
|
| 805 |
+
return settings_json
|
| 806 |
+
}
|
| 807 |
+
|
| 808 |
+
static async getJsonEntries(doc_entry) {
|
| 809 |
+
let entries = await doc_entry.getEntries()
|
| 810 |
+
const json_entries = entries.filter(
|
| 811 |
+
(e) => e.isFile && e.name.toLowerCase().includes('.json') // must be a file and has the of the type .json
|
| 812 |
+
)
|
| 813 |
+
console.log('json_entries: ', json_entries)
|
| 814 |
+
// .forEach((e) => console.log(e.name))
|
| 815 |
+
return json_entries
|
| 816 |
+
}
|
| 817 |
+
static async deleteFile(doc_entry, file_name) {
|
| 818 |
+
try {
|
| 819 |
+
const file_entry = await doc_entry.getEntry(file_name)
|
| 820 |
+
file_entry.delete()
|
| 821 |
+
} catch (e) {}
|
| 822 |
+
}
|
| 823 |
+
}
|
| 824 |
+
|
| 825 |
+
module.exports = {
|
| 826 |
+
IO,
|
| 827 |
+
snapShotLayerExe,
|
| 828 |
+
IOHelper,
|
| 829 |
+
IOJson,
|
| 830 |
+
IOFolder,
|
| 831 |
+
IOLog,
|
| 832 |
+
convertBlackAndWhiteImageToRGBChannels,
|
| 833 |
+
convertBlackAndWhiteImageToRGBChannels2,
|
| 834 |
+
convertBlackAndWhiteImageToRGBChannels3,
|
| 835 |
+
isBlackAndWhiteImage,
|
| 836 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/layer.js
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { batchPlay } = require('photoshop').action
|
| 2 |
+
const { executeAsModal } = require('photoshop').core
|
| 3 |
+
const {
|
| 4 |
+
cleanLayers,
|
| 5 |
+
getLayerIndex,
|
| 6 |
+
selectLayers,
|
| 7 |
+
unSelectMarqueeCommand,
|
| 8 |
+
unSelectMarqueeExe,
|
| 9 |
+
getSelectionInfoExe,
|
| 10 |
+
reSelectMarqueeExe,
|
| 11 |
+
} = require('../psapi')
|
| 12 |
+
|
| 13 |
+
const psapi = require('../psapi')
|
| 14 |
+
|
| 15 |
+
async function createNewLayerExe(layerName, opacity = 100) {
|
| 16 |
+
await executeAsModal(async () => {
|
| 17 |
+
await createNewLayerCommand(layerName, opacity)
|
| 18 |
+
})
|
| 19 |
+
const new_layer = await app.activeDocument.activeLayers[0]
|
| 20 |
+
return new_layer
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
async function createNewLayerCommand(layerName, opacity = 100) {
|
| 24 |
+
return await app.activeDocument.createLayer({
|
| 25 |
+
name: layerName,
|
| 26 |
+
opacity: opacity,
|
| 27 |
+
mode: 'normal',
|
| 28 |
+
})
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
async function deleteLayers(layers) {
|
| 32 |
+
try {
|
| 33 |
+
await cleanLayers(layers)
|
| 34 |
+
} catch (e) {
|
| 35 |
+
console.warn(e)
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
async function getIndexCommand() {
|
| 40 |
+
const command = {
|
| 41 |
+
_obj: 'get',
|
| 42 |
+
_target: [
|
| 43 |
+
{
|
| 44 |
+
_property: 'itemIndex',
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
_ref: 'layer',
|
| 48 |
+
_enum: 'ordinal',
|
| 49 |
+
_value: 'targetEnum',
|
| 50 |
+
},
|
| 51 |
+
],
|
| 52 |
+
}
|
| 53 |
+
const result = await batchPlay([command], {
|
| 54 |
+
synchronousExecution: true,
|
| 55 |
+
modalBehavior: 'execute',
|
| 56 |
+
})
|
| 57 |
+
|
| 58 |
+
return result
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
async function getIndexExe() {
|
| 62 |
+
let index
|
| 63 |
+
await executeAsModal(async () => {
|
| 64 |
+
index = await getIndexCommand()
|
| 65 |
+
})
|
| 66 |
+
|
| 67 |
+
return index
|
| 68 |
+
}
|
| 69 |
+
const photoshop = require('photoshop')
|
| 70 |
+
|
| 71 |
+
const collapseFolderCommand = async (expand = false, recursive = false) => {
|
| 72 |
+
let result
|
| 73 |
+
try {
|
| 74 |
+
result = await batchPlay(
|
| 75 |
+
[
|
| 76 |
+
{
|
| 77 |
+
_obj: 'set',
|
| 78 |
+
_target: {
|
| 79 |
+
_ref: [
|
| 80 |
+
{ _property: 'layerSectionExpanded' },
|
| 81 |
+
{
|
| 82 |
+
_ref: 'layer',
|
| 83 |
+
_enum: 'ordinal',
|
| 84 |
+
_value: 'targetEnum',
|
| 85 |
+
},
|
| 86 |
+
],
|
| 87 |
+
},
|
| 88 |
+
to: expand,
|
| 89 |
+
recursive,
|
| 90 |
+
_options: { dialogOptions: 'dontDisplay' },
|
| 91 |
+
},
|
| 92 |
+
],
|
| 93 |
+
{ synchronousExecution: true }
|
| 94 |
+
)
|
| 95 |
+
} catch (e) {
|
| 96 |
+
console.error(e.message)
|
| 97 |
+
}
|
| 98 |
+
return result
|
| 99 |
+
}
|
| 100 |
+
async function collapseFolderExe(layers, expand = false, recursive = false) {
|
| 101 |
+
for (let layer of layers) {
|
| 102 |
+
try {
|
| 103 |
+
await executeAsModal(async () => {
|
| 104 |
+
const is_visible = await layer.visible // don't change the visiblity of the layer when collapsing
|
| 105 |
+
await selectLayers([layer])
|
| 106 |
+
await collapseFolderCommand(expand, recursive)
|
| 107 |
+
layer.visible = is_visible
|
| 108 |
+
})
|
| 109 |
+
} catch (e) {
|
| 110 |
+
console.warn(e)
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
class Layer {
|
| 116 |
+
static doesLayerExist(layer) {
|
| 117 |
+
let b_exist = false
|
| 118 |
+
try {
|
| 119 |
+
if (typeof layer !== 'undefined' && layer && layer.name) {
|
| 120 |
+
//it will throw an error if the layer has been deleted
|
| 121 |
+
b_exist = true
|
| 122 |
+
// return true
|
| 123 |
+
}
|
| 124 |
+
// b_exist = true
|
| 125 |
+
} catch (e) {
|
| 126 |
+
b_exist = false
|
| 127 |
+
// console.warn(e)
|
| 128 |
+
}
|
| 129 |
+
return b_exist
|
| 130 |
+
}
|
| 131 |
+
static async getLayerInfo(layer) {
|
| 132 |
+
const bounds = layer.bounds
|
| 133 |
+
const height = bounds.bottom - bounds.top
|
| 134 |
+
const width = bounds.right - bounds.left
|
| 135 |
+
const layer_info = {
|
| 136 |
+
height: height,
|
| 137 |
+
width: width,
|
| 138 |
+
left: bounds.left,
|
| 139 |
+
right: bounds.right,
|
| 140 |
+
top: bounds.top,
|
| 141 |
+
bottom: bounds.bottom,
|
| 142 |
+
}
|
| 143 |
+
console.log('layer_info:', layer_info)
|
| 144 |
+
return layer_info
|
| 145 |
+
}
|
| 146 |
+
static async scaleTo(layer, new_width, new_height) {
|
| 147 |
+
await executeAsModal(async () => {
|
| 148 |
+
try {
|
| 149 |
+
const selection_info = await psapi.getSelectionInfoExe()
|
| 150 |
+
await psapi.unSelectMarqueeExe()
|
| 151 |
+
|
| 152 |
+
console.log('scaleLayer got called')
|
| 153 |
+
// const activeLayer = getActiveLayer()
|
| 154 |
+
// const activeLayer = await app.activeDocument.activeLayers[0]
|
| 155 |
+
|
| 156 |
+
const layer_info = await this.getLayerInfo(layer)
|
| 157 |
+
const scale_x_ratio = (new_width / layer_info.width) * 100
|
| 158 |
+
const scale_y_ratio = (new_height / layer_info.height) * 100
|
| 159 |
+
console.log('scale_x_y_ratio:', scale_x_ratio, scale_y_ratio)
|
| 160 |
+
await layer.scale(scale_x_ratio, scale_y_ratio)
|
| 161 |
+
await psapi.reSelectMarqueeExe(selection_info)
|
| 162 |
+
} catch (e) {
|
| 163 |
+
console.warn(e)
|
| 164 |
+
}
|
| 165 |
+
})
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
static async moveTo(layer, to_x, to_y) {
|
| 169 |
+
try {
|
| 170 |
+
await executeAsModal(async () => {
|
| 171 |
+
try {
|
| 172 |
+
//translate doesn't work with selection active. so store the selection and then unselect. move the layer, then reselect the selection info
|
| 173 |
+
const selection_info = await psapi.getSelectionInfoExe()
|
| 174 |
+
await psapi.unSelectMarqueeExe()
|
| 175 |
+
|
| 176 |
+
const layer_info = await this.getLayerInfo(layer)
|
| 177 |
+
const top_dist = layer_info.top - to_y
|
| 178 |
+
const left_dist = layer_info.left - to_x
|
| 179 |
+
console.log('-left_dist, -top_dist', -left_dist, -top_dist)
|
| 180 |
+
await layer.translate(-left_dist, -top_dist)
|
| 181 |
+
|
| 182 |
+
await psapi.reSelectMarqueeExe(selection_info)
|
| 183 |
+
} catch (e) {
|
| 184 |
+
console.warn(e)
|
| 185 |
+
}
|
| 186 |
+
})
|
| 187 |
+
} catch (e) {
|
| 188 |
+
console.warn(e)
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
static resizeTo() {}
|
| 192 |
+
static fitSelection() {}
|
| 193 |
+
static async duplicateToDoc(layer, to_doc) {
|
| 194 |
+
const dupLayer = await layer.duplicate(to_doc)
|
| 195 |
+
// await selectLayers([dupLayer])
|
| 196 |
+
return dupLayer
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
static async duplicateLayerExe(layer) {
|
| 200 |
+
let layer_copy
|
| 201 |
+
try {
|
| 202 |
+
await executeAsModal(async () => {
|
| 203 |
+
layer_copy = await layer.duplicate()
|
| 204 |
+
})
|
| 205 |
+
} catch (e) {
|
| 206 |
+
console.warn('duplication error:', e)
|
| 207 |
+
}
|
| 208 |
+
return layer_copy
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
static {}
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
const hasBackgroundLayerDesc = () => ({
|
| 215 |
+
_obj: 'get',
|
| 216 |
+
_target: [
|
| 217 |
+
{ _property: 'hasBackgroundLayer' },
|
| 218 |
+
{
|
| 219 |
+
_ref: 'document',
|
| 220 |
+
_enum: 'ordinal',
|
| 221 |
+
_value: 'targetEnum',
|
| 222 |
+
},
|
| 223 |
+
],
|
| 224 |
+
})
|
| 225 |
+
async function hasBackgroundLayer() {
|
| 226 |
+
// check if a document has a background layer
|
| 227 |
+
try {
|
| 228 |
+
const result = await batchPlay([hasBackgroundLayerDesc()], {
|
| 229 |
+
synchronousExecution: true,
|
| 230 |
+
modalBehavior: 'execute',
|
| 231 |
+
})
|
| 232 |
+
const b_hasBackgroundLayer = result[0]?.hasBackgroundLayer
|
| 233 |
+
return b_hasBackgroundLayer
|
| 234 |
+
} catch (e) {
|
| 235 |
+
console.warn(e)
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
const makeBackgroundLayerDesc = () => ({
|
| 239 |
+
_obj: 'make',
|
| 240 |
+
_target: [
|
| 241 |
+
{
|
| 242 |
+
_ref: 'backgroundLayer',
|
| 243 |
+
},
|
| 244 |
+
],
|
| 245 |
+
using: {
|
| 246 |
+
_ref: 'layer',
|
| 247 |
+
_enum: 'ordinal',
|
| 248 |
+
_value: 'targetEnum',
|
| 249 |
+
},
|
| 250 |
+
_options: { failOnMissingProperty: false, failOnMissingElement: false },
|
| 251 |
+
// _options: {
|
| 252 |
+
// dialogOptions: 'dontDisplay',
|
| 253 |
+
// },
|
| 254 |
+
})
|
| 255 |
+
|
| 256 |
+
const createSolidLayerDesc = (r, g, b) => ({
|
| 257 |
+
_obj: 'make',
|
| 258 |
+
_target: [
|
| 259 |
+
{
|
| 260 |
+
_ref: 'contentLayer',
|
| 261 |
+
},
|
| 262 |
+
],
|
| 263 |
+
using: {
|
| 264 |
+
_obj: 'contentLayer',
|
| 265 |
+
type: {
|
| 266 |
+
_obj: 'solidColorLayer',
|
| 267 |
+
color: {
|
| 268 |
+
_obj: 'RGBColor',
|
| 269 |
+
red: r,
|
| 270 |
+
grain: g,
|
| 271 |
+
blue: b,
|
| 272 |
+
},
|
| 273 |
+
},
|
| 274 |
+
},
|
| 275 |
+
_options: {
|
| 276 |
+
dialogOptions: 'dontDisplay',
|
| 277 |
+
},
|
| 278 |
+
})
|
| 279 |
+
|
| 280 |
+
const toggleBackgroundLayerDesc = () => ({
|
| 281 |
+
_obj: 'show',
|
| 282 |
+
null: [
|
| 283 |
+
{
|
| 284 |
+
_ref: 'layer',
|
| 285 |
+
_property: 'background',
|
| 286 |
+
},
|
| 287 |
+
],
|
| 288 |
+
toggleOptionsPalette: true,
|
| 289 |
+
_options: {
|
| 290 |
+
dialogOptions: 'dontDisplay',
|
| 291 |
+
},
|
| 292 |
+
})
|
| 293 |
+
|
| 294 |
+
async function toggleBackgroundLayerExe() {
|
| 295 |
+
try {
|
| 296 |
+
await executeAsModal(async () => {
|
| 297 |
+
const result = await batchPlay([toggleBackgroundLayerDesc()], {
|
| 298 |
+
synchronousExecution: true,
|
| 299 |
+
modalBehavior: 'execute',
|
| 300 |
+
})
|
| 301 |
+
console.log('toggleBackgroundLayerExe result: ', result)
|
| 302 |
+
})
|
| 303 |
+
} catch (e) {
|
| 304 |
+
console.warn(e)
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
async function createBackgroundLayer(r = 255, g = 255, b = 255) {
|
| 309 |
+
try {
|
| 310 |
+
const has_background = await hasBackgroundLayer()
|
| 311 |
+
if (has_background) {
|
| 312 |
+
//no need to create a background layer
|
| 313 |
+
return null
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
//reselect the selection area if it exist
|
| 317 |
+
|
| 318 |
+
await executeAsModal(async () => {
|
| 319 |
+
//store the selection area and then unselected
|
| 320 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 321 |
+
await psapi.unSelectMarqueeExe()
|
| 322 |
+
const active_layers = app.activeDocument.activeLayers
|
| 323 |
+
|
| 324 |
+
// await createNewLayerCommand('background') //create layer
|
| 325 |
+
//make the layer into background
|
| 326 |
+
const result = await batchPlay(
|
| 327 |
+
[createSolidLayerDesc(r, g, b), makeBackgroundLayerDesc()],
|
| 328 |
+
{
|
| 329 |
+
synchronousExecution: true,
|
| 330 |
+
modalBehavior: 'execute',
|
| 331 |
+
}
|
| 332 |
+
)
|
| 333 |
+
|
| 334 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
| 335 |
+
await psapi.selectLayersExe(active_layers)
|
| 336 |
+
})
|
| 337 |
+
} catch (e) {
|
| 338 |
+
console.warn(e)
|
| 339 |
+
}
|
| 340 |
+
}
|
| 341 |
+
async function fixImageBackgroundLayer() {
|
| 342 |
+
//convert the background layer to a normal layer
|
| 343 |
+
//create a new layer
|
| 344 |
+
//convert the new layer to background
|
| 345 |
+
}
|
| 346 |
+
module.exports = {
|
| 347 |
+
createNewLayerExe,
|
| 348 |
+
deleteLayers,
|
| 349 |
+
getIndexExe,
|
| 350 |
+
collapseFolderExe,
|
| 351 |
+
Layer,
|
| 352 |
+
hasBackgroundLayer,
|
| 353 |
+
createBackgroundLayer,
|
| 354 |
+
createSolidLayerDesc,
|
| 355 |
+
makeBackgroundLayerDesc,
|
| 356 |
+
toggleBackgroundLayerExe,
|
| 357 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/notification.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const dialog_box = require('../dialog_box')
|
| 2 |
+
const psapi = require('../psapi')
|
| 3 |
+
const { createBackgroundLayer } = require('./layer')
|
| 4 |
+
class Notification {
|
| 5 |
+
static {}
|
| 6 |
+
static async webuiIsOffline() {
|
| 7 |
+
const r1 = await dialog_box.prompt(
|
| 8 |
+
'Automatic1111 is Offline',
|
| 9 |
+
"make sure Automatic1111 is running in the background, or select the 'native horde' option from the horde tab",
|
| 10 |
+
['Cancel', 'OK']
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
try {
|
| 14 |
+
if (r1 === 'Cancel') {
|
| 15 |
+
/* cancelled or No */
|
| 16 |
+
console.log('cancel')
|
| 17 |
+
} else if (r1 === 'OK') {
|
| 18 |
+
console.log('ok')
|
| 19 |
+
}
|
| 20 |
+
} catch (e) {
|
| 21 |
+
console.warn(e)
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
static async webuiAPIMissing() {
|
| 25 |
+
const r1 = await dialog_box.prompt(
|
| 26 |
+
"The Plugin can't communicate with Automatic1111",
|
| 27 |
+
'Automatic1111 is running, but you forgot to add --api flag to the webui command flags',
|
| 28 |
+
['Cancel', 'OK']
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
try {
|
| 32 |
+
if (r1 === 'Cancel') {
|
| 33 |
+
/* cancelled or No */
|
| 34 |
+
console.log('cancel')
|
| 35 |
+
} else if (r1 === 'OK') {
|
| 36 |
+
console.log('ok')
|
| 37 |
+
}
|
| 38 |
+
} catch (e) {
|
| 39 |
+
console.warn(e)
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
static async backgroundLayerIsMissing() {
|
| 43 |
+
const r1 = await dialog_box.prompt(
|
| 44 |
+
'You need a white background layer present in your document',
|
| 45 |
+
'',
|
| 46 |
+
['Cancel', 'Create']
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
try {
|
| 50 |
+
if (r1 === 'Cancel') {
|
| 51 |
+
/* cancelled or No */
|
| 52 |
+
console.log('cancel')
|
| 53 |
+
return false
|
| 54 |
+
} else if (r1 === 'Create') {
|
| 55 |
+
//store the selection area and then unselected
|
| 56 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 57 |
+
await psapi.unSelectMarqueeExe()
|
| 58 |
+
const active_layers = app.activeDocument.activeLayers
|
| 59 |
+
|
| 60 |
+
//create a background layer with no selection active
|
| 61 |
+
await createBackgroundLayer()
|
| 62 |
+
console.log('create background layer')
|
| 63 |
+
//reselect the selection area if it exist
|
| 64 |
+
|
| 65 |
+
await psapi.reSelectMarqueeExe(selectionInfo)
|
| 66 |
+
await psapi.selectLayersExe(active_layers)
|
| 67 |
+
return true
|
| 68 |
+
}
|
| 69 |
+
} catch (e) {
|
| 70 |
+
console.warn(e)
|
| 71 |
+
}
|
| 72 |
+
return false
|
| 73 |
+
}
|
| 74 |
+
static async inactiveSelectionArea(is_active_session) {
|
| 75 |
+
let buttons = ['Cancel', 'Rectangular Marquee']
|
| 76 |
+
if (is_active_session) {
|
| 77 |
+
buttons.push('Continue Session')
|
| 78 |
+
}
|
| 79 |
+
const r1 = await dialog_box.prompt(
|
| 80 |
+
'Please Select a Rectangular Area',
|
| 81 |
+
'You Forgot to select a Rectangular Area',
|
| 82 |
+
buttons
|
| 83 |
+
)
|
| 84 |
+
if (r1 === 'Cancel') {
|
| 85 |
+
/* cancelled or No */
|
| 86 |
+
console.log('cancel')
|
| 87 |
+
return false
|
| 88 |
+
} else if (r1 === 'Rectangular Marquee') {
|
| 89 |
+
console.log('Rectangular Marquee')
|
| 90 |
+
psapi.selectMarqueeRectangularToolExe()
|
| 91 |
+
return false // should this be false?! what does true and false means in this context?! Yes: it should be false since boolean value represent wither we have an active selection area or not
|
| 92 |
+
} else if (r1 === 'Continue Session') {
|
| 93 |
+
await activateSessionSelectionArea()
|
| 94 |
+
return true
|
| 95 |
+
}
|
| 96 |
+
return false
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
Notification,
|
| 102 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/online_data.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"new_version": "v1.2.4",
|
| 3 |
+
"update_message": "Your version is outdated.Please visit our Github page and download the one click installer / .ccx file.\nRun the .ccx file and it will automatically update the current version of your plug in. No data will be lost."
|
| 4 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/presets/controlnet_preset.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const MaintainPositionSettings = {
|
| 2 |
+
0: {
|
| 3 |
+
module: 'openpose',
|
| 4 |
+
model: 'control_sd15_openpose [fef5e48e]',
|
| 5 |
+
weight: 1,
|
| 6 |
+
resize_mode: null,
|
| 7 |
+
lowvram: null,
|
| 8 |
+
processor_res: null,
|
| 9 |
+
threshold_a: null,
|
| 10 |
+
threshold_b: null,
|
| 11 |
+
guidance_start: 0,
|
| 12 |
+
guidance_end: 0.3,
|
| 13 |
+
guessmode: null,
|
| 14 |
+
},
|
| 15 |
+
1: {
|
| 16 |
+
module: 'depth',
|
| 17 |
+
model: 'control_sd15_depth [fef5e48e]',
|
| 18 |
+
weight: 0.8,
|
| 19 |
+
resize_mode: null,
|
| 20 |
+
lowvram: null,
|
| 21 |
+
processor_res: null,
|
| 22 |
+
threshold_a: null,
|
| 23 |
+
threshold_b: null,
|
| 24 |
+
guidance_start: 0,
|
| 25 |
+
guidance_end: 0.6,
|
| 26 |
+
guessmode: null,
|
| 27 |
+
},
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
const Pose_Depth_Canny_HandFix = {
|
| 31 |
+
0: {
|
| 32 |
+
module: 'openpose',
|
| 33 |
+
model: 'control_sd15_openpose [fef5e48e]',
|
| 34 |
+
weight: 1,
|
| 35 |
+
resize_mode: null,
|
| 36 |
+
lowvram: null,
|
| 37 |
+
processor_res: null,
|
| 38 |
+
threshold_a: null,
|
| 39 |
+
threshold_b: null,
|
| 40 |
+
guidance_start: 0,
|
| 41 |
+
guidance_end: 1,
|
| 42 |
+
guessmode: null,
|
| 43 |
+
},
|
| 44 |
+
1: {
|
| 45 |
+
module: 'depth',
|
| 46 |
+
model: 'control_sd15_depth [fef5e48e]',
|
| 47 |
+
weight: 1.3,
|
| 48 |
+
resize_mode: null,
|
| 49 |
+
lowvram: null,
|
| 50 |
+
processor_res: null,
|
| 51 |
+
threshold_a: null,
|
| 52 |
+
threshold_b: null,
|
| 53 |
+
guidance_start: 0.3,
|
| 54 |
+
guidance_end: 1,
|
| 55 |
+
guessmode: null,
|
| 56 |
+
},
|
| 57 |
+
2: {
|
| 58 |
+
module: 'canny',
|
| 59 |
+
model: 'control_sd15_canny [fef5e48e]',
|
| 60 |
+
weight: 1.3,
|
| 61 |
+
resize_mode: null,
|
| 62 |
+
lowvram: null,
|
| 63 |
+
processor_res: null,
|
| 64 |
+
threshold_a: null,
|
| 65 |
+
threshold_b: null,
|
| 66 |
+
guidance_start: 0.3,
|
| 67 |
+
guidance_end: 1,
|
| 68 |
+
guessmode: null,
|
| 69 |
+
},
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
MaintainComposition_Character = {
|
| 73 |
+
0: {
|
| 74 |
+
module: 'openpose',
|
| 75 |
+
model: 'control_sd15_openpose [fef5e48e]',
|
| 76 |
+
weight: 1,
|
| 77 |
+
resize_mode: null,
|
| 78 |
+
lowvram: null,
|
| 79 |
+
processor_res: null,
|
| 80 |
+
threshold_a: null,
|
| 81 |
+
threshold_b: null,
|
| 82 |
+
guidance_start: 0,
|
| 83 |
+
guidance_end: 0.5,
|
| 84 |
+
guessmode: null,
|
| 85 |
+
},
|
| 86 |
+
1: {
|
| 87 |
+
module: 'canny',
|
| 88 |
+
model: 'control_sd15_canny [fef5e48e]',
|
| 89 |
+
weight: 1,
|
| 90 |
+
resize_mode: null,
|
| 91 |
+
lowvram: null,
|
| 92 |
+
processor_res: null,
|
| 93 |
+
threshold_a: null,
|
| 94 |
+
threshold_b: null,
|
| 95 |
+
guidance_start: 0,
|
| 96 |
+
guidance_end: 0.8,
|
| 97 |
+
guessmode: null,
|
| 98 |
+
},
|
| 99 |
+
2: {
|
| 100 |
+
weight: 1,
|
| 101 |
+
resize_mode: null,
|
| 102 |
+
lowvram: null,
|
| 103 |
+
processor_res: null,
|
| 104 |
+
threshold_a: null,
|
| 105 |
+
threshold_b: null,
|
| 106 |
+
guidance_start: 0,
|
| 107 |
+
guidance_end: 1,
|
| 108 |
+
guessmode: null,
|
| 109 |
+
},
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
const LogoCreation = {
|
| 113 |
+
0: {
|
| 114 |
+
module: 'canny',
|
| 115 |
+
model: 'control_sd15_canny [fef5e48e]',
|
| 116 |
+
weight: 1.3,
|
| 117 |
+
resize_mode: null,
|
| 118 |
+
lowvram: null,
|
| 119 |
+
processor_res: null,
|
| 120 |
+
threshold_a: null,
|
| 121 |
+
threshold_b: null,
|
| 122 |
+
guidance_start: 0,
|
| 123 |
+
guidance_end: 0.9,
|
| 124 |
+
guessmode: null,
|
| 125 |
+
},
|
| 126 |
+
1: {
|
| 127 |
+
module: 'scribble',
|
| 128 |
+
model: 'control_sd15_scribble [fef5e48e]',
|
| 129 |
+
weight: 1,
|
| 130 |
+
resize_mode: null,
|
| 131 |
+
lowvram: null,
|
| 132 |
+
processor_res: null,
|
| 133 |
+
threshold_a: null,
|
| 134 |
+
threshold_b: null,
|
| 135 |
+
guidance_start: 0,
|
| 136 |
+
guidance_end: 1,
|
| 137 |
+
guessmode: null,
|
| 138 |
+
},
|
| 139 |
+
2: {
|
| 140 |
+
weight: 1,
|
| 141 |
+
resize_mode: null,
|
| 142 |
+
lowvram: null,
|
| 143 |
+
processor_res: null,
|
| 144 |
+
threshold_a: null,
|
| 145 |
+
threshold_b: null,
|
| 146 |
+
guidance_start: 0,
|
| 147 |
+
guidance_end: 1,
|
| 148 |
+
guessmode: null,
|
| 149 |
+
},
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
const Backgrounds = {
|
| 153 |
+
0: {
|
| 154 |
+
module: 'mlsd',
|
| 155 |
+
model: 'control_sd15_mlsd [fef5e48e]',
|
| 156 |
+
weight: 1.3,
|
| 157 |
+
resize_mode: null,
|
| 158 |
+
lowvram: null,
|
| 159 |
+
processor_res: null,
|
| 160 |
+
threshold_a: null,
|
| 161 |
+
threshold_b: null,
|
| 162 |
+
guidance_start: 0,
|
| 163 |
+
guidance_end: 0.7,
|
| 164 |
+
guessmode: null,
|
| 165 |
+
},
|
| 166 |
+
1: {
|
| 167 |
+
weight: 1,
|
| 168 |
+
resize_mode: null,
|
| 169 |
+
lowvram: null,
|
| 170 |
+
processor_res: null,
|
| 171 |
+
threshold_a: null,
|
| 172 |
+
threshold_b: null,
|
| 173 |
+
guidance_start: 0,
|
| 174 |
+
guidance_end: 1,
|
| 175 |
+
guessmode: null,
|
| 176 |
+
},
|
| 177 |
+
2: {
|
| 178 |
+
weight: 1,
|
| 179 |
+
resize_mode: null,
|
| 180 |
+
lowvram: null,
|
| 181 |
+
processor_res: null,
|
| 182 |
+
threshold_a: null,
|
| 183 |
+
threshold_b: null,
|
| 184 |
+
guidance_start: 0,
|
| 185 |
+
guidance_end: 1,
|
| 186 |
+
guessmode: null,
|
| 187 |
+
},
|
| 188 |
+
}
|
| 189 |
+
const ControlNetNativePresets = {
|
| 190 |
+
'Maintain Position': MaintainPositionSettings,
|
| 191 |
+
'Hand Fix': Pose_Depth_Canny_HandFix,
|
| 192 |
+
'Maintain Composition (Character)': MaintainComposition_Character,
|
| 193 |
+
'Logo Creation': LogoCreation,
|
| 194 |
+
Backgrounds: Backgrounds,
|
| 195 |
+
}
|
| 196 |
+
module.exports = {
|
| 197 |
+
ControlNetNativePresets,
|
| 198 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/presets/preset.js
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const io = require('../io')
|
| 2 |
+
const html_manip = require('../html_manip')
|
| 3 |
+
const Enum = require('../../enum')
|
| 4 |
+
const event = require('../event')
|
| 5 |
+
|
| 6 |
+
// const control_net = require('../../utility/tab/control_net')
|
| 7 |
+
let settings = {
|
| 8 |
+
model: null,
|
| 9 |
+
prompt_shortcut: null,
|
| 10 |
+
positive_prompt: null,
|
| 11 |
+
negative_prompt: null,
|
| 12 |
+
selection_mode: null,
|
| 13 |
+
batch_number: null,
|
| 14 |
+
steps: null,
|
| 15 |
+
width: null,
|
| 16 |
+
height: null,
|
| 17 |
+
firstphase_width: null,
|
| 18 |
+
firstphase_height: null,
|
| 19 |
+
cfg: null,
|
| 20 |
+
denoising_strength: null,
|
| 21 |
+
hi_res_denoising_strength: null,
|
| 22 |
+
mask_blur: null,
|
| 23 |
+
inpaint_at_full_res: null,
|
| 24 |
+
hi_res_fix: null,
|
| 25 |
+
inpaint_padding: null,
|
| 26 |
+
seed: null,
|
| 27 |
+
samplers: null,
|
| 28 |
+
mask_content: null,
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
let LatentNoiseSettings = {
|
| 32 |
+
model: null,
|
| 33 |
+
prompt_shortcut: null,
|
| 34 |
+
positive_prompt: null,
|
| 35 |
+
negative_prompt: null,
|
| 36 |
+
generation_mode: null,
|
| 37 |
+
batch_number: null,
|
| 38 |
+
steps: null,
|
| 39 |
+
width: null,
|
| 40 |
+
height: null,
|
| 41 |
+
firstphase_width: null,
|
| 42 |
+
firstphase_height: null,
|
| 43 |
+
cfg: null,
|
| 44 |
+
denoising_strength: 0.92,
|
| 45 |
+
hi_res_denoising_strength: null,
|
| 46 |
+
mask_blur: null,
|
| 47 |
+
inpaint_at_full_res: null,
|
| 48 |
+
hi_res_fix: null,
|
| 49 |
+
inpaint_padding: null,
|
| 50 |
+
seed: null,
|
| 51 |
+
samplers: null,
|
| 52 |
+
mask_content: '2',
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
let FillSettings = {
|
| 56 |
+
model: null,
|
| 57 |
+
prompt_shortcut: null,
|
| 58 |
+
positive_prompt: null,
|
| 59 |
+
negative_prompt: null,
|
| 60 |
+
generation_mode: null,
|
| 61 |
+
batch_number: null,
|
| 62 |
+
steps: null,
|
| 63 |
+
width: null,
|
| 64 |
+
height: null,
|
| 65 |
+
firstphase_width: null,
|
| 66 |
+
firstphase_height: null,
|
| 67 |
+
cfg: null,
|
| 68 |
+
denoising_strength: 0.7,
|
| 69 |
+
hi_res_denoising_strength: null,
|
| 70 |
+
mask_blur: null,
|
| 71 |
+
inpaint_at_full_res: null,
|
| 72 |
+
hi_res_fix: null,
|
| 73 |
+
inpaint_padding: null,
|
| 74 |
+
seed: null,
|
| 75 |
+
samplers: null,
|
| 76 |
+
mask_content: '0',
|
| 77 |
+
}
|
| 78 |
+
let OriginalSettings = {
|
| 79 |
+
model: null,
|
| 80 |
+
prompt_shortcut: null,
|
| 81 |
+
positive_prompt: null,
|
| 82 |
+
negative_prompt: null,
|
| 83 |
+
generation_mode: null,
|
| 84 |
+
batch_number: null,
|
| 85 |
+
steps: null,
|
| 86 |
+
width: null,
|
| 87 |
+
height: null,
|
| 88 |
+
firstphase_width: null,
|
| 89 |
+
firstphase_height: null,
|
| 90 |
+
cfg: null,
|
| 91 |
+
denoising_strength: 0.7,
|
| 92 |
+
hi_res_denoising_strength: null,
|
| 93 |
+
mask_blur: null,
|
| 94 |
+
inpaint_at_full_res: null,
|
| 95 |
+
hi_res_fix: null,
|
| 96 |
+
inpaint_padding: null,
|
| 97 |
+
seed: null,
|
| 98 |
+
samplers: null,
|
| 99 |
+
mask_content: '1',
|
| 100 |
+
}
|
| 101 |
+
let HealBrushSettings = {
|
| 102 |
+
model: null,
|
| 103 |
+
prompt_shortcut: null,
|
| 104 |
+
positive_prompt: null,
|
| 105 |
+
negative_prompt: null,
|
| 106 |
+
generation_mode: null,
|
| 107 |
+
batch_number: null,
|
| 108 |
+
steps: '25',
|
| 109 |
+
width: null,
|
| 110 |
+
height: null,
|
| 111 |
+
firstphase_width: null,
|
| 112 |
+
firstphase_height: null,
|
| 113 |
+
cfg: '9',
|
| 114 |
+
denoising_strength: 0.92,
|
| 115 |
+
hi_res_denoising_strength: null,
|
| 116 |
+
mask_blur: 1,
|
| 117 |
+
inpaint_at_full_res: null,
|
| 118 |
+
hi_res_fix: null,
|
| 119 |
+
inpaint_padding: null,
|
| 120 |
+
seed: null,
|
| 121 |
+
samplers: null,
|
| 122 |
+
mask_content: '2',
|
| 123 |
+
mask_expansion: 2,
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
function nullAllSettings() {}
|
| 127 |
+
|
| 128 |
+
class Preset {
|
| 129 |
+
constructor() {}
|
| 130 |
+
|
| 131 |
+
loadPresetFromJson(preset_path) {}
|
| 132 |
+
savePresetToJson(preset_path, settings) {}
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
function getPresetSettingsHtml() {
|
| 136 |
+
const value_str = document.getElementById('taPresetSettings').value
|
| 137 |
+
const value_json = JSON.parse(value_str)
|
| 138 |
+
return value_json
|
| 139 |
+
}
|
| 140 |
+
function setPresetSettingsHtml(preset_settings) {
|
| 141 |
+
const JSONInPrettyFormat = JSON.stringify(preset_settings, undefined, 7)
|
| 142 |
+
preset_settings_element = document.getElementById('taPresetSettings')
|
| 143 |
+
preset_settings_element.value = JSONInPrettyFormat
|
| 144 |
+
|
| 145 |
+
const new_lines_count = general.countNewLines(JSONInPrettyFormat)
|
| 146 |
+
new_lines_count
|
| 147 |
+
preset_settings_element.style.height =
|
| 148 |
+
Math.min(new_lines_count * 12 + 100, 800).toString() + 'px'
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
function getPresetName() {
|
| 152 |
+
const preset_name = document.getElementById('tiPresetName').value
|
| 153 |
+
return preset_name
|
| 154 |
+
}
|
| 155 |
+
function setPresetName(preset_name) {
|
| 156 |
+
document.getElementById('tiPresetName').value = preset_name
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
function getPresetSettings(preset_type) {
|
| 160 |
+
let preset_settings
|
| 161 |
+
if (preset_type === Enum.PresetTypeEnum['SDPreset']) {
|
| 162 |
+
preset_settings = g_ui_settings_object.getSettings()
|
| 163 |
+
} else if (preset_type === Enum.PresetTypeEnum['ControlNetPreset']) {
|
| 164 |
+
const { ControlNetUnit } = require('../../utility/tab/control_net') // only import ControlNetUnit to avoid circular dependency
|
| 165 |
+
// preset_settings = control_net.ControlNetUnit.getUnits()
|
| 166 |
+
|
| 167 |
+
preset_settings = ControlNetUnit.getUnits()
|
| 168 |
+
}
|
| 169 |
+
return preset_settings
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
function getPresetType() {
|
| 173 |
+
const presetType = document.getElementById('rgPresetType').selected
|
| 174 |
+
|
| 175 |
+
return presetType
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
document.getElementById('btnNewPreset').addEventListener('click', () => {
|
| 179 |
+
// const g_ui_settings_object = getUISettingsObject()
|
| 180 |
+
// debugger
|
| 181 |
+
const preset_type = getPresetType()
|
| 182 |
+
const preset_settings = getPresetSettings(preset_type)
|
| 183 |
+
|
| 184 |
+
// const settings = g_ui_settings_object.getSettings()
|
| 185 |
+
|
| 186 |
+
setPresetSettingsHtml(preset_settings)
|
| 187 |
+
|
| 188 |
+
const preset_name = getPresetName()
|
| 189 |
+
setPresetNameLabel(preset_name)
|
| 190 |
+
})
|
| 191 |
+
|
| 192 |
+
function getPresetNameLabel() {
|
| 193 |
+
//use presetNameLabel as the final name for a preset
|
| 194 |
+
const preset_name = document.getElementById('lPresetName').textContent
|
| 195 |
+
return preset_name
|
| 196 |
+
}
|
| 197 |
+
function setPresetNameLabel(preset_name) {
|
| 198 |
+
document.getElementById('lPresetName').textContent = preset_name.trim()
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
async function populatePresetMenu() {
|
| 202 |
+
// presets = ['preset_1', 'preset_2', 'preset_3']
|
| 203 |
+
const preset_type = getPresetType()
|
| 204 |
+
const presets = await getAllCustomPresetsSettings(preset_type)
|
| 205 |
+
const presets_names = Object.keys(presets)
|
| 206 |
+
html_manip.populateMenu(
|
| 207 |
+
'mSettingTabPresetMenu',
|
| 208 |
+
'mPresetMenuItemClass',
|
| 209 |
+
presets_names,
|
| 210 |
+
(item, item_html_element) => {
|
| 211 |
+
item_html_element.innerHTML = item
|
| 212 |
+
}
|
| 213 |
+
)
|
| 214 |
+
}
|
| 215 |
+
async function deletePreset() {
|
| 216 |
+
try {
|
| 217 |
+
const preset_name = html_manip.getSelectedMenuItemTextContent(
|
| 218 |
+
'mSettingTabPresetMenu'
|
| 219 |
+
)
|
| 220 |
+
const preset_file_name = preset_name + '.json'
|
| 221 |
+
|
| 222 |
+
const preset_type = getPresetType()
|
| 223 |
+
const preset_folder_name = mapPresetTypeToPresetFolder(preset_type)
|
| 224 |
+
const custom_preset_entry = await io.IOFolder.getCustomPresetFolder(
|
| 225 |
+
preset_folder_name
|
| 226 |
+
)
|
| 227 |
+
|
| 228 |
+
await io.IOJson.deleteFile(custom_preset_entry, preset_file_name)
|
| 229 |
+
html_manip.unselectMenuItem('mSettingTabPresetMenu') // unselect the custom preset menu
|
| 230 |
+
setPresetSettingsHtml({}) //reset preset settings text area
|
| 231 |
+
setPresetName('')
|
| 232 |
+
setPresetNameLabel('')
|
| 233 |
+
await populatePresetMenu() // update the custom preset Menu
|
| 234 |
+
triggerUpdatePresetMenu(preset_type)
|
| 235 |
+
} catch (e) {
|
| 236 |
+
console.warn(e)
|
| 237 |
+
}
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
async function getCustomPresetEntries(preset_folder_name) {
|
| 241 |
+
const custom_preset_entry = await io.IOFolder.getCustomPresetFolder(
|
| 242 |
+
preset_folder_name
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
const custom_preset_entries = await io.IOJson.getJsonEntries(
|
| 246 |
+
custom_preset_entry
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
return custom_preset_entries
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
async function loadPresetSettingsFromFile(preset_file_name, preset_type) {
|
| 253 |
+
// const preset_type = getPresetType()
|
| 254 |
+
|
| 255 |
+
const preset_folder_name = mapPresetTypeToPresetFolder(preset_type)
|
| 256 |
+
const custom_preset_entry = await io.IOFolder.getCustomPresetFolder(
|
| 257 |
+
preset_folder_name
|
| 258 |
+
)
|
| 259 |
+
let preset_settings = {}
|
| 260 |
+
try {
|
| 261 |
+
preset_settings = await io.IOJson.loadJsonFromFile(
|
| 262 |
+
custom_preset_entry,
|
| 263 |
+
preset_file_name
|
| 264 |
+
)
|
| 265 |
+
} catch (e) {
|
| 266 |
+
console.warn(e)
|
| 267 |
+
}
|
| 268 |
+
return preset_settings
|
| 269 |
+
}
|
| 270 |
+
async function getAllCustomPresetsSettings(preset_type) {
|
| 271 |
+
const preset_folder_name = mapPresetTypeToPresetFolder(preset_type)
|
| 272 |
+
const custom_preset_entries = await getCustomPresetEntries(
|
| 273 |
+
preset_folder_name
|
| 274 |
+
)
|
| 275 |
+
let custom_presets = {}
|
| 276 |
+
for (const entry of custom_preset_entries) {
|
| 277 |
+
const preset_name = entry.name.split('.json')[0]
|
| 278 |
+
let preset_settings = await loadPresetSettingsFromFile(
|
| 279 |
+
entry.name,
|
| 280 |
+
preset_type
|
| 281 |
+
)
|
| 282 |
+
|
| 283 |
+
custom_presets[preset_name] = preset_settings
|
| 284 |
+
}
|
| 285 |
+
return custom_presets
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
function mapPresetTypeToPresetFolder(preset_type) {
|
| 289 |
+
let preset_folder
|
| 290 |
+
|
| 291 |
+
if (preset_type === Enum.PresetTypeEnum['SDPreset']) {
|
| 292 |
+
preset_folder = 'custom_preset'
|
| 293 |
+
} else if (preset_type === Enum.PresetTypeEnum['ControlNetPreset']) {
|
| 294 |
+
preset_folder = 'controlnet_preset'
|
| 295 |
+
}
|
| 296 |
+
return preset_folder
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
function triggerUpdatePresetMenu(preset_type) {
|
| 300 |
+
let menu_id
|
| 301 |
+
if (preset_type === Enum.PresetTypeEnum['SDPreset']) {
|
| 302 |
+
menu_id = '#mPresetMenu'
|
| 303 |
+
} else if (preset_type === Enum.PresetTypeEnum['ControlNetPreset']) {
|
| 304 |
+
menu_id = '#mControlNetPresetMenu'
|
| 305 |
+
}
|
| 306 |
+
event.triggerEvent(menu_id, event.updatePresetMenuEvent)
|
| 307 |
+
}
|
| 308 |
+
Array.from(document.getElementsByClassName('rbPresetType')).forEach((rb) => {
|
| 309 |
+
rb.addEventListener('click', async () => {
|
| 310 |
+
const preset_type = rb.value
|
| 311 |
+
await populatePresetMenu()
|
| 312 |
+
})
|
| 313 |
+
})
|
| 314 |
+
|
| 315 |
+
document.getElementById('btnSavePreset').addEventListener('click', async () => {
|
| 316 |
+
//save preset settings from textarea to json file
|
| 317 |
+
//reload the preset menu
|
| 318 |
+
const preset_type = getPresetType()
|
| 319 |
+
const custom_preset_folder_name = mapPresetTypeToPresetFolder(preset_type)
|
| 320 |
+
const custom_preset_entry = await io.IOFolder.getCustomPresetFolder(
|
| 321 |
+
custom_preset_folder_name
|
| 322 |
+
)
|
| 323 |
+
const preset_settings = getPresetSettingsHtml()
|
| 324 |
+
const preset_name = getPresetNameLabel()
|
| 325 |
+
|
| 326 |
+
//check if the file exist and prompt the user to override it or cancel
|
| 327 |
+
await io.IOJson.saveJsonToFileExe(
|
| 328 |
+
preset_settings,
|
| 329 |
+
custom_preset_entry,
|
| 330 |
+
preset_name + '.json'
|
| 331 |
+
)
|
| 332 |
+
await populatePresetMenu()
|
| 333 |
+
triggerUpdatePresetMenu(preset_type)
|
| 334 |
+
html_manip.selectMenuItem('mSettingTabPresetMenu', preset_name)
|
| 335 |
+
})
|
| 336 |
+
document
|
| 337 |
+
.getElementById('btnDeletePreset')
|
| 338 |
+
.addEventListener('click', async () => {
|
| 339 |
+
await deletePreset()
|
| 340 |
+
})
|
| 341 |
+
|
| 342 |
+
document.getElementById('tiPresetName').addEventListener('input', () => {
|
| 343 |
+
//save preset settings from textarea to json file
|
| 344 |
+
//reload the preset menu
|
| 345 |
+
const preset_name = getPresetName()
|
| 346 |
+
setPresetNameLabel(preset_name)
|
| 347 |
+
//check if the file exist and prompt the user to override it or cancel
|
| 348 |
+
})
|
| 349 |
+
document
|
| 350 |
+
.getElementById('mSettingTabPresetMenu')
|
| 351 |
+
.addEventListener('input', () => {
|
| 352 |
+
//Note: is this correct?! why use Input and change events together
|
| 353 |
+
//save preset settings from textarea to json file
|
| 354 |
+
//reload the preset menu
|
| 355 |
+
const preset_name = getPresetName()
|
| 356 |
+
setPresetNameLabel(preset_name)
|
| 357 |
+
//check if the file exist and prompt the user to override it or cancel
|
| 358 |
+
})
|
| 359 |
+
|
| 360 |
+
document
|
| 361 |
+
.getElementById('mSettingTabPresetMenu')
|
| 362 |
+
.addEventListener('change', async (evt) => {
|
| 363 |
+
try {
|
| 364 |
+
const preset_index = evt.target.selectedIndex
|
| 365 |
+
const preset_name = evt.target.options[preset_index].textContent
|
| 366 |
+
const preset_type = getPresetType()
|
| 367 |
+
setPresetName(preset_name)
|
| 368 |
+
setPresetNameLabel(preset_name)
|
| 369 |
+
|
| 370 |
+
const preset_settings = await loadPresetSettingsFromFile(
|
| 371 |
+
preset_name + '.json',
|
| 372 |
+
preset_type
|
| 373 |
+
)
|
| 374 |
+
setPresetSettingsHtml(preset_settings)
|
| 375 |
+
} catch (e) {}
|
| 376 |
+
})
|
| 377 |
+
|
| 378 |
+
document
|
| 379 |
+
.getElementById('mPresetMenu')
|
| 380 |
+
.addEventListener('updatePresetMenuEvent', async (event) => {
|
| 381 |
+
// console.log("I'm listening on a custom event")
|
| 382 |
+
const { populatePresetMenu } = require('../ui')
|
| 383 |
+
await populatePresetMenu()
|
| 384 |
+
})
|
| 385 |
+
|
| 386 |
+
async function initializePresetTab() {
|
| 387 |
+
try {
|
| 388 |
+
await populatePresetMenu()
|
| 389 |
+
|
| 390 |
+
const selected_rb =
|
| 391 |
+
html_manip.getSelectedRadioButtonElement('rbPresetType')
|
| 392 |
+
selected_rb.click() // to trigger the click event which will update the setting preset menu according to the preset type
|
| 393 |
+
} catch (e) {
|
| 394 |
+
console.error(e)
|
| 395 |
+
}
|
| 396 |
+
}
|
| 397 |
+
initializePresetTab()
|
| 398 |
+
module.exports = {
|
| 399 |
+
LatentNoiseSettings,
|
| 400 |
+
FillSettings,
|
| 401 |
+
OriginalSettings,
|
| 402 |
+
HealBrushSettings,
|
| 403 |
+
populatePresetMenu,
|
| 404 |
+
getCustomPresetEntries,
|
| 405 |
+
loadPresetSettingsFromFile,
|
| 406 |
+
getAllCustomPresetsSettings,
|
| 407 |
+
initializePresetTab,
|
| 408 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sampler.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
samplers = [
|
| 2 |
+
{
|
| 3 |
+
name: 'Euler a',
|
| 4 |
+
aliases: ['k_euler_a', 'k_euler_ancestral'],
|
| 5 |
+
options: {},
|
| 6 |
+
},
|
| 7 |
+
{
|
| 8 |
+
name: 'Euler',
|
| 9 |
+
aliases: ['k_euler'],
|
| 10 |
+
options: {},
|
| 11 |
+
},
|
| 12 |
+
{
|
| 13 |
+
name: 'LMS',
|
| 14 |
+
aliases: ['k_lms'],
|
| 15 |
+
options: {},
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
name: 'Heun',
|
| 19 |
+
aliases: ['k_heun'],
|
| 20 |
+
options: {},
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
name: 'DPM2',
|
| 24 |
+
aliases: ['k_dpm_2'],
|
| 25 |
+
options: {
|
| 26 |
+
discard_next_to_last_sigma: 'True',
|
| 27 |
+
},
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
name: 'DPM2 a',
|
| 31 |
+
aliases: ['k_dpm_2_a'],
|
| 32 |
+
options: {
|
| 33 |
+
discard_next_to_last_sigma: 'True',
|
| 34 |
+
},
|
| 35 |
+
},
|
| 36 |
+
{
|
| 37 |
+
name: 'DPM++ 2S a',
|
| 38 |
+
aliases: ['k_dpmpp_2s_a'],
|
| 39 |
+
options: {},
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
name: 'DPM++ 2M',
|
| 43 |
+
aliases: ['k_dpmpp_2m'],
|
| 44 |
+
options: {},
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
name: 'DPM++ SDE',
|
| 48 |
+
aliases: ['k_dpmpp_sde'],
|
| 49 |
+
options: {},
|
| 50 |
+
},
|
| 51 |
+
{
|
| 52 |
+
name: 'DPM fast',
|
| 53 |
+
aliases: ['k_dpm_fast'],
|
| 54 |
+
options: {},
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
name: 'DPM adaptive',
|
| 58 |
+
aliases: ['k_dpm_ad'],
|
| 59 |
+
options: {},
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
name: 'LMS Karras',
|
| 63 |
+
aliases: ['k_lms_ka'],
|
| 64 |
+
options: {
|
| 65 |
+
scheduler: 'karras',
|
| 66 |
+
},
|
| 67 |
+
},
|
| 68 |
+
{
|
| 69 |
+
name: 'DPM2 Karras',
|
| 70 |
+
aliases: ['k_dpm_2_ka'],
|
| 71 |
+
options: {
|
| 72 |
+
scheduler: 'karras',
|
| 73 |
+
discard_next_to_last_sigma: 'True',
|
| 74 |
+
},
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
name: 'DPM2 a Karras',
|
| 78 |
+
aliases: ['k_dpm_2_a_ka'],
|
| 79 |
+
options: {
|
| 80 |
+
scheduler: 'karras',
|
| 81 |
+
discard_next_to_last_sigma: 'True',
|
| 82 |
+
},
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
name: 'DPM++ 2S a Karras',
|
| 86 |
+
aliases: ['k_dpmpp_2s_a_ka'],
|
| 87 |
+
options: {
|
| 88 |
+
scheduler: 'karras',
|
| 89 |
+
},
|
| 90 |
+
},
|
| 91 |
+
{
|
| 92 |
+
name: 'DPM++ 2M Karras',
|
| 93 |
+
aliases: ['k_dpmpp_2m_ka'],
|
| 94 |
+
options: {
|
| 95 |
+
scheduler: 'karras',
|
| 96 |
+
},
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
name: 'DPM++ SDE Karras',
|
| 100 |
+
aliases: ['k_dpmpp_sde_ka'],
|
| 101 |
+
options: {
|
| 102 |
+
scheduler: 'karras',
|
| 103 |
+
},
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
name: 'DDIM',
|
| 107 |
+
aliases: [],
|
| 108 |
+
options: {},
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
name: 'PLMS',
|
| 112 |
+
aliases: [],
|
| 113 |
+
options: {},
|
| 114 |
+
},
|
| 115 |
+
]
|
| 116 |
+
|
| 117 |
+
module.exports = { samplers }
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sd_scripts/horde.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function requestModelsHorde() {
|
| 2 |
+
//get the models list from url
|
| 3 |
+
// https://stablehorde.net/api/v2/status/models
|
| 4 |
+
|
| 5 |
+
console.log('requestModelsHorde: ')
|
| 6 |
+
|
| 7 |
+
const full_url = 'https://stablehorde.net/api/v2/status/models'
|
| 8 |
+
let request = await fetch(full_url)
|
| 9 |
+
let json = await request.json()
|
| 10 |
+
console.log('hordes models json:')
|
| 11 |
+
console.dir(json)
|
| 12 |
+
|
| 13 |
+
return json
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
function addHordeModelMenuItem(model_title, model_name) {
|
| 17 |
+
// console.log(model_title,model_name)
|
| 18 |
+
const menu_item_element = document.createElement('sp-menu-item')
|
| 19 |
+
menu_item_element.className = 'mModelMenuItemHorde'
|
| 20 |
+
menu_item_element.innerHTML = model_title
|
| 21 |
+
|
| 22 |
+
menu_item_element.dataset.name = model_name
|
| 23 |
+
return menu_item_element
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
async function refreshModelsHorde() {
|
| 27 |
+
try {
|
| 28 |
+
let g_models_horde = await requestModelsHorde()
|
| 29 |
+
// const models_menu_element = document.getElementById('mModelsMenu')
|
| 30 |
+
// models_menu_element.value = ""
|
| 31 |
+
//(optional): sort the models
|
| 32 |
+
|
| 33 |
+
g_models_horde.sort(function (a, b) {
|
| 34 |
+
return b.count - a.count
|
| 35 |
+
})
|
| 36 |
+
// g_models_horde = g_models_horde.sort( compareModelCounts );
|
| 37 |
+
document.getElementById('mModelsMenuHorde').innerHTML = ''
|
| 38 |
+
let model_item_random = addHordeModelMenuItem('Random', 'Random')
|
| 39 |
+
// model_item_random.selected = true
|
| 40 |
+
document
|
| 41 |
+
.getElementById('mModelsMenuHorde')
|
| 42 |
+
.appendChild(model_item_random)
|
| 43 |
+
for (let model of g_models_horde) {
|
| 44 |
+
// console.log(model.name, model.count) //Log
|
| 45 |
+
const model_html_tile = `${model.name}: ${model.count}`
|
| 46 |
+
const model_item_element = addHordeModelMenuItem(
|
| 47 |
+
model_html_tile,
|
| 48 |
+
model.name
|
| 49 |
+
)
|
| 50 |
+
if (model.name === 'stable_diffusion') {
|
| 51 |
+
// TODO: refactor this code outside the for loop
|
| 52 |
+
// maybe call it in an init function
|
| 53 |
+
//selection the stable diffusion model by default
|
| 54 |
+
model_item_element.selected = true
|
| 55 |
+
}
|
| 56 |
+
document
|
| 57 |
+
.getElementById('mModelsMenuHorde')
|
| 58 |
+
.appendChild(model_item_element)
|
| 59 |
+
}
|
| 60 |
+
} catch (e) {
|
| 61 |
+
console.warn(e)
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
function getModelHorde() {
|
| 65 |
+
return [...document.getElementsByClassName('mModelMenuItemHorde')].filter(
|
| 66 |
+
(e) => e.selected == true
|
| 67 |
+
)[0].dataset.name
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
function getScriptArgs() {
|
| 71 |
+
const model = getModelHorde()
|
| 72 |
+
const b_nsfw = document.getElementById('chUseNSFW').checked
|
| 73 |
+
const b_shared_laion = document.getElementById('chUseSharedLaion').checked
|
| 74 |
+
|
| 75 |
+
let seed_variation = document.getElementById('slSeedVariation').value
|
| 76 |
+
seed_variation = parseInt(seed_variation)
|
| 77 |
+
const script_args_json = {
|
| 78 |
+
model: model,
|
| 79 |
+
nsfw: b_nsfw,
|
| 80 |
+
shared_laion: b_shared_laion,
|
| 81 |
+
seed_variation: seed_variation,
|
| 82 |
+
post_processing_1: 'None',
|
| 83 |
+
post_processing_2: 'None',
|
| 84 |
+
post_processing_3: 'None',
|
| 85 |
+
}
|
| 86 |
+
const script_args = Object.values(script_args_json)
|
| 87 |
+
return script_args
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
document
|
| 91 |
+
.getElementById('btnRefreshModelsHorde')
|
| 92 |
+
.addEventListener('click', async () => {
|
| 93 |
+
await refreshModelsHorde()
|
| 94 |
+
})
|
| 95 |
+
|
| 96 |
+
const script_name = 'Run on Stable Horde'
|
| 97 |
+
|
| 98 |
+
refreshModelsHorde() //refresh the model when importing the script
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
requestModelsHorde,
|
| 102 |
+
refreshModelsHorde,
|
| 103 |
+
getModelHorde,
|
| 104 |
+
|
| 105 |
+
getScriptArgs,
|
| 106 |
+
script_name,
|
| 107 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/config.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class SdConfig {
|
| 2 |
+
constructor() {
|
| 3 |
+
this.config //store sd options
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
async getConfig() {
|
| 7 |
+
try {
|
| 8 |
+
this.config = await sdapi.requestGetConfig()
|
| 9 |
+
return this.config
|
| 10 |
+
} catch (e) {
|
| 11 |
+
console.warn(e)
|
| 12 |
+
}
|
| 13 |
+
}
|
| 14 |
+
getUpscalerModels() {
|
| 15 |
+
try {
|
| 16 |
+
// const upscaler_comp = this.config.components.filter(comp =>comp.props.elem_id === "txt2img_hr_upscaler")[0]
|
| 17 |
+
let upscaler_comp
|
| 18 |
+
// console.log('this.config: ', this.config)
|
| 19 |
+
for (let comp of this.config.components) {
|
| 20 |
+
if (comp?.props?.elem_id) {
|
| 21 |
+
const elem_id = comp?.props?.elem_id
|
| 22 |
+
if (elem_id === 'txt2img_hr_upscaler') {
|
| 23 |
+
console.log('elem_id: ', elem_id)
|
| 24 |
+
upscaler_comp = comp
|
| 25 |
+
break
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
console.log('upscaler_comp: ', upscaler_comp)
|
| 30 |
+
const upscalers = upscaler_comp.props.choices
|
| 31 |
+
|
| 32 |
+
return upscalers
|
| 33 |
+
} catch (e) {
|
| 34 |
+
console.warn(e)
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
getControlNetMaxModelsNum() {
|
| 39 |
+
try {
|
| 40 |
+
let max_models_num = 0
|
| 41 |
+
for (let comp of this.config.components) {
|
| 42 |
+
if (comp?.props?.elem_id) {
|
| 43 |
+
const elem_id = comp?.props?.elem_id
|
| 44 |
+
if (elem_id === 'setting_control_net_max_models_num') {
|
| 45 |
+
console.log(
|
| 46 |
+
'setting_control_net_max_models_num: ',
|
| 47 |
+
comp?.props?.value
|
| 48 |
+
)
|
| 49 |
+
max_models_num = comp?.props?.value
|
| 50 |
+
break
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
console.log('max_models_num: ', max_models_num)
|
| 55 |
+
return max_models_num
|
| 56 |
+
} catch (e) {
|
| 57 |
+
console.warn(e)
|
| 58 |
+
return 1 // default max number is one
|
| 59 |
+
}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
getControlNetPreprocessors() {
|
| 63 |
+
try {
|
| 64 |
+
let max_models_num
|
| 65 |
+
let choices
|
| 66 |
+
for (let comp of this.config.components) {
|
| 67 |
+
const label = comp?.props?.label
|
| 68 |
+
if (label === 'Preprocessor') {
|
| 69 |
+
choices = comp?.props?.choices
|
| 70 |
+
break
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
console.log('Preprocessor list: ', choices)
|
| 74 |
+
return choices
|
| 75 |
+
} catch (e) {
|
| 76 |
+
console.warn(e)
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
module.exports = {
|
| 82 |
+
SdConfig,
|
| 83 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/horde_native.js
ADDED
|
@@ -0,0 +1,731 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const general = require('../general')
|
| 2 |
+
const psapi = require('../../psapi')
|
| 3 |
+
const html_manip = require('../html_manip')
|
| 4 |
+
const layer_util = require('../layer')
|
| 5 |
+
const dummy = require('../dummy')
|
| 6 |
+
const io = require('../io')
|
| 7 |
+
class HordeSettings {
|
| 8 |
+
static {}
|
| 9 |
+
static async saveSettings() {
|
| 10 |
+
try {
|
| 11 |
+
const settings = await getSettings()
|
| 12 |
+
|
| 13 |
+
let native_horde_settings = await mapPluginSettingsToHorde(settings)
|
| 14 |
+
const horde_api_key = html_manip.getHordeApiKey()
|
| 15 |
+
native_horde_settings['api_key'] = html_manip.getHordeApiKey()
|
| 16 |
+
await io.IOJson.saveHordeSettingsToFile(native_horde_settings)
|
| 17 |
+
} catch (e) {
|
| 18 |
+
console.warn(e)
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
static async loadSettings() {
|
| 22 |
+
try {
|
| 23 |
+
let native_horde_settings =
|
| 24 |
+
await io.IOJson.loadHordeSettingsFromFile()
|
| 25 |
+
html_manip.setHordeApiKey(native_horde_settings['api_key'])
|
| 26 |
+
} catch (e) {
|
| 27 |
+
console.warn(e)
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
class hordeGenerator {
|
| 32 |
+
//horde generation process:
|
| 33 |
+
//*) get the settings
|
| 34 |
+
//*) get send request
|
| 35 |
+
//*) wait for response
|
| 36 |
+
//*) load the image to the canvas
|
| 37 |
+
//*) move and scale image to the selection
|
| 38 |
+
//*) save the image to history/data folder
|
| 39 |
+
//*) load the image data into the plugin / viewer tab
|
| 40 |
+
//*)
|
| 41 |
+
|
| 42 |
+
//other options:
|
| 43 |
+
//*)interrupt the generation process
|
| 44 |
+
//*)cancel the generation process on error
|
| 45 |
+
|
| 46 |
+
constructor() {
|
| 47 |
+
this.horde_settings
|
| 48 |
+
this.plugin_settings
|
| 49 |
+
this.currentGenerationResult = null
|
| 50 |
+
this.requestStatus = null
|
| 51 |
+
this.isProcessHordeResultCalled = false
|
| 52 |
+
this.maxWaitTime = 0
|
| 53 |
+
this.waiting = 0
|
| 54 |
+
this.isCanceled = false
|
| 55 |
+
this.horde_id = null
|
| 56 |
+
this.last_horde_id = null
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
async getSettings() {
|
| 60 |
+
try {
|
| 61 |
+
const workers = await getWorkers()
|
| 62 |
+
|
| 63 |
+
const workers_ids = getWorkerID(workers)
|
| 64 |
+
const settings = await getSettings()
|
| 65 |
+
this.plugin_settings = settings
|
| 66 |
+
let payload = await mapPluginSettingsToHorde(settings)
|
| 67 |
+
// payload['workers'] = workers_ids
|
| 68 |
+
payload['workers'] = []
|
| 69 |
+
|
| 70 |
+
this.horde_settings = payload
|
| 71 |
+
return this.horde_settings
|
| 72 |
+
} catch (e) {
|
| 73 |
+
console.warn('getSettings: ', e)
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
/**
|
| 78 |
+
* @returns {json}{payload, dir_name, images_info, metadata}
|
| 79 |
+
*/
|
| 80 |
+
async generateRequest(settings) {
|
| 81 |
+
try {
|
| 82 |
+
this.horde_id = null //reset request_id
|
| 83 |
+
this.requestStatus = await requestHorde(settings)
|
| 84 |
+
if (this.requestStatus?.message) {
|
| 85 |
+
await app.showAlert(this.requestStatus?.message)
|
| 86 |
+
}
|
| 87 |
+
this.horde_id = this.requestStatus.id
|
| 88 |
+
console.log(
|
| 89 |
+
'generateRequest this.requestStatus: ',
|
| 90 |
+
this.requestStatus
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
const images_info = await this.startCheckingProgress()
|
| 94 |
+
const result = await this.toGenerationFormat(images_info)
|
| 95 |
+
console.warn('generateRequest() images_info: ', images_info)
|
| 96 |
+
console.warn('generateRequest() result: ', result)
|
| 97 |
+
|
| 98 |
+
html_manip.updateProgressBarsHtml(0) // reset progress bar
|
| 99 |
+
return result
|
| 100 |
+
} catch (e) {
|
| 101 |
+
this.horde_id = null
|
| 102 |
+
console.warn(e)
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
async generate() {
|
| 106 |
+
//*) get the settings
|
| 107 |
+
this.horde_settings = await this.getSettings()
|
| 108 |
+
//*) send generateRequest() and trigger the progress bar update
|
| 109 |
+
this.isCanceled = false
|
| 110 |
+
const result = await this.generateRequest(this.horde_settings)
|
| 111 |
+
|
| 112 |
+
return result
|
| 113 |
+
//*) store the generation result in the currentGenerationResult
|
| 114 |
+
|
| 115 |
+
//*) return the generation currentGenerationResult
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
isValidGeneration() {
|
| 119 |
+
if (this.currentGenerationResult) {
|
| 120 |
+
return true // if true if valid, false otherwise
|
| 121 |
+
} else {
|
| 122 |
+
return false
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
preGenerate() {}
|
| 126 |
+
// async layerToBase64WebpToFile
|
| 127 |
+
//convert layer to .webp file
|
| 128 |
+
//read the .webp file as buffer data base64 .webp
|
| 129 |
+
async layerToBase64Webp(layer, document_name, image_name) {
|
| 130 |
+
const width = html_manip.getWidth()
|
| 131 |
+
const height = html_manip.getHeight()
|
| 132 |
+
const image_buffer = await psapi.newExportPng(
|
| 133 |
+
layer,
|
| 134 |
+
image_name,
|
| 135 |
+
width,
|
| 136 |
+
height
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
const base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
|
| 140 |
+
//send the base64 to the server to save the file in the desired directory
|
| 141 |
+
// await sdapi.requestSavePng(base64_image, image_name)
|
| 142 |
+
await saveFileInSubFolder(base64_image, document_name, image_name)
|
| 143 |
+
return base64_image
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
async layerToBase64ToFile(layer, document_name, image_name) {
|
| 147 |
+
const width = html_manip.getWidth()
|
| 148 |
+
const height = html_manip.getHeight()
|
| 149 |
+
const image_buffer = await psapi.newExportPng(
|
| 150 |
+
layer,
|
| 151 |
+
image_name,
|
| 152 |
+
width,
|
| 153 |
+
height
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
const base64_image = _arrayBufferToBase64(image_buffer) //convert the buffer to base64
|
| 157 |
+
//send the base64 to the server to save the file in the desired directory
|
| 158 |
+
// await sdapi.requestSavePng(base64_image, image_name)
|
| 159 |
+
await saveFileInSubFolder(base64_image, document_name, image_name)
|
| 160 |
+
return base64_image
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
async toGenerationFormat(images_info) {
|
| 164 |
+
//convert the output of native horde generation to the values that generate() can use
|
| 165 |
+
try {
|
| 166 |
+
//images_info[0] = {path:path,base64:base64png}
|
| 167 |
+
// let last_images_paths = await silentImagesToLayersExe(images_info)
|
| 168 |
+
let last_images_paths = {}
|
| 169 |
+
for (const image_info of images_info) {
|
| 170 |
+
const path = image_info['path']
|
| 171 |
+
// const base64_image = image_info['base64']
|
| 172 |
+
const layer = image_info['layer']
|
| 173 |
+
const [document_name, image_name] = path.split('/')
|
| 174 |
+
|
| 175 |
+
// await saveFileInSubFolder(base64_image, document_name, image_name)
|
| 176 |
+
image_info['base64'] = await this.layerToBase64ToFile(
|
| 177 |
+
layer,
|
| 178 |
+
document_name,
|
| 179 |
+
image_name
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
// delete the layer made by the webp image.
|
| 183 |
+
await layer_util.deleteLayers([layer])
|
| 184 |
+
// await layer.delete()
|
| 185 |
+
|
| 186 |
+
// const json_file_name = `${image_name.split('.')[0]}.json`
|
| 187 |
+
this.plugin_settings['auto_metadata'] =
|
| 188 |
+
image_info?.auto_metadata
|
| 189 |
+
|
| 190 |
+
// g_generation_session.base64OutputImages[path] =
|
| 191 |
+
// image_info['base64']
|
| 192 |
+
// await saveJsonFileInSubFolder(
|
| 193 |
+
// this.plugin_settings,
|
| 194 |
+
// document_name,
|
| 195 |
+
// json_file_name
|
| 196 |
+
// ) //save the settings
|
| 197 |
+
// last_images_paths[path] = image_info['layer']
|
| 198 |
+
// images_info.push({
|
| 199 |
+
// base64: i,
|
| 200 |
+
// path: image_path,
|
| 201 |
+
// auto_metadata: auto_metadata_json,
|
| 202 |
+
// })
|
| 203 |
+
// // console.log("metadata_json: ", metadata_json)
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
// if (g_generation_session.isFirstGeneration) {
|
| 207 |
+
// //store them in the generation session for viewer manager to use
|
| 208 |
+
// g_generation_session.image_paths_to_layers = last_images_paths
|
| 209 |
+
// } else {
|
| 210 |
+
// g_generation_session.image_paths_to_layers = {
|
| 211 |
+
// ...g_generation_session.image_paths_to_layers,
|
| 212 |
+
// ...last_images_paths,
|
| 213 |
+
// }
|
| 214 |
+
// // g_number_generation_per_session++
|
| 215 |
+
|
| 216 |
+
// }
|
| 217 |
+
const dir_name = 'temp_dir_name'
|
| 218 |
+
return {
|
| 219 |
+
// payload: payload,
|
| 220 |
+
dir_name: dir_name,
|
| 221 |
+
images_info: images_info,
|
| 222 |
+
metadata: this.plugin_settings,
|
| 223 |
+
}
|
| 224 |
+
} catch (e) {
|
| 225 |
+
console.warn(e)
|
| 226 |
+
}
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
async toSession(images_info) {
|
| 230 |
+
try {
|
| 231 |
+
//images_info[0] = {path:path,base64:base64png}
|
| 232 |
+
// let last_images_paths = await silentImagesToLayersExe(images_info)
|
| 233 |
+
let last_images_paths = {}
|
| 234 |
+
for (const image_info of images_info) {
|
| 235 |
+
const path = image_info['path']
|
| 236 |
+
// const base64_image = image_info['base64']
|
| 237 |
+
const layer = image_info['layer']
|
| 238 |
+
const [document_name, image_name] = path.split('/')
|
| 239 |
+
|
| 240 |
+
// await saveFileInSubFolder(base64_image, document_name, image_name)
|
| 241 |
+
image_info['base64'] = await this.layerToBase64ToFile(
|
| 242 |
+
layer,
|
| 243 |
+
document_name,
|
| 244 |
+
image_name
|
| 245 |
+
)
|
| 246 |
+
const json_file_name = `${image_name.split('.')[0]}.json`
|
| 247 |
+
this.plugin_settings['auto_metadata'] =
|
| 248 |
+
image_info?.auto_metadata
|
| 249 |
+
|
| 250 |
+
g_generation_session.base64OutputImages[path] =
|
| 251 |
+
image_info['base64']
|
| 252 |
+
await saveJsonFileInSubFolder(
|
| 253 |
+
this.plugin_settings,
|
| 254 |
+
document_name,
|
| 255 |
+
json_file_name
|
| 256 |
+
) //save the settings
|
| 257 |
+
last_images_paths[path] = image_info['layer']
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
if (g_generation_session.isFirstGeneration) {
|
| 261 |
+
//store them in the generation session for viewer manager to use
|
| 262 |
+
g_generation_session.image_paths_to_layers = last_images_paths
|
| 263 |
+
} else {
|
| 264 |
+
g_generation_session.image_paths_to_layers = {
|
| 265 |
+
...g_generation_session.image_paths_to_layers,
|
| 266 |
+
...last_images_paths,
|
| 267 |
+
}
|
| 268 |
+
// g_number_generation_per_session++
|
| 269 |
+
}
|
| 270 |
+
} catch (e) {
|
| 271 |
+
console.warn(e)
|
| 272 |
+
}
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
async interruptRequest(horde_id) {
|
| 276 |
+
try {
|
| 277 |
+
console.log('interruptRquest():')
|
| 278 |
+
|
| 279 |
+
const full_url = `https://stablehorde.net/api/v2/generate/status/${horde_id}`
|
| 280 |
+
|
| 281 |
+
console.log(full_url)
|
| 282 |
+
|
| 283 |
+
let response = await fetch(full_url, {
|
| 284 |
+
method: 'DELETE',
|
| 285 |
+
headers: {
|
| 286 |
+
Accept: 'application/json',
|
| 287 |
+
'Content-Type': 'application/json',
|
| 288 |
+
// 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
| 289 |
+
'Client-Agent': 'unknown:0:unknown',
|
| 290 |
+
},
|
| 291 |
+
})
|
| 292 |
+
|
| 293 |
+
let result = await response.json()
|
| 294 |
+
console.log('interruptReqquest result:', result)
|
| 295 |
+
|
| 296 |
+
return result
|
| 297 |
+
} catch (e) {
|
| 298 |
+
console.warn(e)
|
| 299 |
+
return
|
| 300 |
+
}
|
| 301 |
+
}
|
| 302 |
+
async interrupt() {
|
| 303 |
+
try {
|
| 304 |
+
html_manip.updateProgressBarsHtml(0)
|
| 305 |
+
// g_generation_session.request_status = Enum.requestStatus['']
|
| 306 |
+
this.last_horde_id = this.horde_id
|
| 307 |
+
this.horde_id = null //horde_id could be used startCheckingprogress() so we need to nullify it as soon as possible. TODO: refactor this dependency.
|
| 308 |
+
this.isCanceled = true
|
| 309 |
+
// this.interval_id = clearTimeout(this.interval_id)
|
| 310 |
+
await this.interruptRequest(this.last_horde_id)
|
| 311 |
+
} catch (e) {
|
| 312 |
+
console.warn(e)
|
| 313 |
+
}
|
| 314 |
+
}
|
| 315 |
+
async postGeneration() {
|
| 316 |
+
toggleTwoButtonsByClass(false, 'btnGenerateClass', 'btnInterruptClass')
|
| 317 |
+
}
|
| 318 |
+
async processHordeResult() {
|
| 319 |
+
//*) get the result from the horde server
|
| 320 |
+
//*) save them locally to output directory
|
| 321 |
+
//*) import them into the canvas
|
| 322 |
+
//*) resize and move the layers to fit the selection
|
| 323 |
+
//*) return the results to be stored and processed by the g_generation_session
|
| 324 |
+
try {
|
| 325 |
+
if (this.isProcessHordeResultCalled) {
|
| 326 |
+
return
|
| 327 |
+
}
|
| 328 |
+
this.isProcessHordeResultCalled = true
|
| 329 |
+
console.log('horde request is done')
|
| 330 |
+
// g_b_request_result = true
|
| 331 |
+
const temp_id = this.horde_id //this.horde_id will reset
|
| 332 |
+
// cancelRequestClientSide()
|
| 333 |
+
g_horde_generation_result = await requestHordeStatus(temp_id)
|
| 334 |
+
|
| 335 |
+
const generations = g_horde_generation_result.generations
|
| 336 |
+
const writeable_entry = await getCurrentDocFolder()
|
| 337 |
+
const images_info = [] //{path:image_path,base64:}
|
| 338 |
+
for (const image_horde_container of generations) {
|
| 339 |
+
try {
|
| 340 |
+
const url = image_horde_container.img
|
| 341 |
+
const image_file_name = general.newOutputImageName('webp')
|
| 342 |
+
|
| 343 |
+
const image_layer = await downloadItExe(
|
| 344 |
+
url,
|
| 345 |
+
writeable_entry,
|
| 346 |
+
image_file_name
|
| 347 |
+
) //download the image from url, it works even with .webp format
|
| 348 |
+
const image_png_file_name =
|
| 349 |
+
general.convertImageNameToPng(image_file_name)
|
| 350 |
+
|
| 351 |
+
const uuid = await getUniqueDocumentId()
|
| 352 |
+
const image_path = `${uuid}/${image_png_file_name}` //this is the png path
|
| 353 |
+
images_info.push({
|
| 354 |
+
path: image_path,
|
| 355 |
+
base64: dummy.getDummyBase64(), //TODO:change this to the base64_png
|
| 356 |
+
layer: image_layer,
|
| 357 |
+
})
|
| 358 |
+
await psapi.layerToSelection(
|
| 359 |
+
g_generation_session.selectionInfo
|
| 360 |
+
) //TODO: create a safe layerToSelection function
|
| 361 |
+
} catch (e) {
|
| 362 |
+
console.warn(e)
|
| 363 |
+
}
|
| 364 |
+
}
|
| 365 |
+
this.isProcessHordeResultCalled = false //reset for next generation
|
| 366 |
+
return images_info
|
| 367 |
+
} catch (e) {
|
| 368 |
+
console.warn(e)
|
| 369 |
+
}
|
| 370 |
+
}
|
| 371 |
+
updateHordeProgressBar(check_horde_status) {
|
| 372 |
+
//update the progress bar proceduer
|
| 373 |
+
console.log('this.maxWaitTime: ', this.maxWaitTime)
|
| 374 |
+
console.log(
|
| 375 |
+
"check_horde_status['wait_time']: ",
|
| 376 |
+
check_horde_status['wait_time']
|
| 377 |
+
)
|
| 378 |
+
console.log(
|
| 379 |
+
"check_horde_status['waiting']: ",
|
| 380 |
+
check_horde_status['waiting']
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
this.maxWaitTime = Math.max(
|
| 384 |
+
check_horde_status['wait_time'],
|
| 385 |
+
this.maxWaitTime
|
| 386 |
+
) // return the max time value, so we could use to calculate the complection percentage
|
| 387 |
+
const delta_time = this.maxWaitTime - check_horde_status['wait_time']
|
| 388 |
+
|
| 389 |
+
if (isNaN(this.maxWaitTime) || parseInt(this.maxWaitTime) === 0) {
|
| 390 |
+
this.maxWaitTime = 0 // reset to zero
|
| 391 |
+
} else {
|
| 392 |
+
console.log('delta_time:', delta_time)
|
| 393 |
+
console.log('this.maxWaitTime:', this.maxWaitTime)
|
| 394 |
+
|
| 395 |
+
const completion_percentage = (delta_time / this.maxWaitTime) * 100
|
| 396 |
+
console.log('completion_percentage:', completion_percentage)
|
| 397 |
+
|
| 398 |
+
html_manip.updateProgressBarsHtml(completion_percentage)
|
| 399 |
+
}
|
| 400 |
+
}
|
| 401 |
+
async startCheckingProgress() {
|
| 402 |
+
console.log('startCheckingProgress is called')
|
| 403 |
+
return await new Promise((resolve, reject) => {
|
| 404 |
+
if (this.horde_id && !this.isCanceled) {
|
| 405 |
+
this.interval_id = setTimeout(async () => {
|
| 406 |
+
try {
|
| 407 |
+
console.warn(
|
| 408 |
+
'startCheckingProgress(): horde_id and isCanceled',
|
| 409 |
+
this.horde_id,
|
| 410 |
+
this.isCanceled
|
| 411 |
+
)
|
| 412 |
+
//check the request status
|
| 413 |
+
const check_json = await requestHordeCheck(
|
| 414 |
+
this.horde_id
|
| 415 |
+
)
|
| 416 |
+
|
| 417 |
+
this.updateHordeProgressBar(check_json)
|
| 418 |
+
|
| 419 |
+
if (check_json['done']) {
|
| 420 |
+
// this.interval_id = clearTimeout(this.interval_id)
|
| 421 |
+
|
| 422 |
+
const images_info = await this.processHordeResult()
|
| 423 |
+
if (this.horde_id) {
|
| 424 |
+
this.last_horde_id = this.horde_id
|
| 425 |
+
this.horde_id = null
|
| 426 |
+
}
|
| 427 |
+
return resolve(images_info)
|
| 428 |
+
} else {
|
| 429 |
+
//the request is not done and the user hasn't canceled it
|
| 430 |
+
console.warn(
|
| 431 |
+
'startCheckingProgress(): reqursive startCheckingProgress call',
|
| 432 |
+
this.horde_id,
|
| 433 |
+
this.isCanceled
|
| 434 |
+
)
|
| 435 |
+
const horde_result =
|
| 436 |
+
await this.startCheckingProgress() // start another check
|
| 437 |
+
return resolve(horde_result) // return the result of the new check
|
| 438 |
+
}
|
| 439 |
+
} catch (e) {
|
| 440 |
+
console.warn(e)
|
| 441 |
+
const result = await this.startCheckingProgress()
|
| 442 |
+
return resolve(result)
|
| 443 |
+
}
|
| 444 |
+
}, 3000)
|
| 445 |
+
} else {
|
| 446 |
+
console.warn(
|
| 447 |
+
'startCheckingProgress: else block',
|
| 448 |
+
this.horde_id,
|
| 449 |
+
this.isCanceled
|
| 450 |
+
)
|
| 451 |
+
return resolve()
|
| 452 |
+
}
|
| 453 |
+
})
|
| 454 |
+
}
|
| 455 |
+
}
|
| 456 |
+
const webui_to_horde_samplers = {
|
| 457 |
+
'Euler a': 'k_euler_a',
|
| 458 |
+
Euler: 'k_euler',
|
| 459 |
+
LMS: 'k_lms',
|
| 460 |
+
Heun: 'k_heun',
|
| 461 |
+
DPM2: 'k_dpm_2',
|
| 462 |
+
'DPM2 a': 'k_dpm_2_a',
|
| 463 |
+
'DPM++ 2S a': 'k_dpmpp_2s_a',
|
| 464 |
+
'DPM++ 2M': 'k_dpmpp_2m',
|
| 465 |
+
'DPM++ SDE': 'k_dpmpp_sde',
|
| 466 |
+
'DPM fast': 'k_dpm_fast',
|
| 467 |
+
'DPM adaptive': 'k_dpm_adaptive',
|
| 468 |
+
'LMS Karras': 'k_lms',
|
| 469 |
+
'DPM2 Karras': 'k_dpm_2',
|
| 470 |
+
'DPM2 a Karras': 'k_dpm_2_a',
|
| 471 |
+
'DPM++ 2S a Karras': 'k_dpmpp_2s_a',
|
| 472 |
+
'DPM++ 2M Karras': 'k_dpmpp_2m',
|
| 473 |
+
'DPM++ SDE Karras': 'k_dpmpp_sde',
|
| 474 |
+
DDIM: 'ddim',
|
| 475 |
+
PLMS: 'plms',
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
//get workers
|
| 479 |
+
//select a worker
|
| 480 |
+
//send a request => requestHorde(horde_settings)
|
| 481 |
+
//check for progress => requestHordeCheck(request_id)
|
| 482 |
+
//when progress is full, request the result => requestHordeStatus(request_id)
|
| 483 |
+
|
| 484 |
+
async function mapPluginSettingsToHorde(plugin_settings) {
|
| 485 |
+
const { getModelHorde } = require('../sd_scripts/horde')
|
| 486 |
+
const ps = plugin_settings // for shortness
|
| 487 |
+
const sampler = webui_to_horde_samplers[ps['sampler_index']]
|
| 488 |
+
const model = getModelHorde()
|
| 489 |
+
let horde_prompt
|
| 490 |
+
if (ps['negative_prompt'].length > 0) {
|
| 491 |
+
horde_prompt = `${ps['prompt']} ### ${ps['negative_prompt']}`
|
| 492 |
+
} else {
|
| 493 |
+
horde_prompt = ps['prompt'] //no negative prompt
|
| 494 |
+
}
|
| 495 |
+
const extra_payload = {}
|
| 496 |
+
if (ps['mode'] === 'img2img') {
|
| 497 |
+
// payload['source_image'] = ps['init_images']
|
| 498 |
+
// let current_doc_entry =await getCurrentDocFolder()
|
| 499 |
+
// let webp_file = await current_doc_entry.getEntry('temp.webp')
|
| 500 |
+
// let base64_webp = await io.IO.base64WebpFromFile(webp_file)
|
| 501 |
+
// payload['source_image'] = io.IO.base64WebpFromFile()
|
| 502 |
+
// console.log('base64_webp:', base64_webp)
|
| 503 |
+
|
| 504 |
+
// const dummy_str = getDummyWebpBase64()
|
| 505 |
+
// if (base64_webp === dummy_str) {
|
| 506 |
+
// console.warn('the same base64')
|
| 507 |
+
// } else {
|
| 508 |
+
// console.warn('different base64')
|
| 509 |
+
// }
|
| 510 |
+
// payload['source_image'] = dummy_str
|
| 511 |
+
|
| 512 |
+
// payload['source_image'] = base64.b64encode(buffer.getvalue()).decode() //does it need to be webp?
|
| 513 |
+
|
| 514 |
+
const init_image_base64_webp = await io.IO.base64PngToBase64Webp(
|
| 515 |
+
ps['init_images'][0]
|
| 516 |
+
)
|
| 517 |
+
extra_payload['source_image'] = init_image_base64_webp
|
| 518 |
+
extra_payload['source_processing'] = 'img2img'
|
| 519 |
+
} else if (ps['mode'] === 'inpaint' || ps['mode'] === 'outpaint') {
|
| 520 |
+
const init_image_base64_webp = await io.IO.base64PngToBase64Webp(
|
| 521 |
+
ps['init_images'][0]
|
| 522 |
+
)
|
| 523 |
+
const mask_base64_webp = await io.IO.base64PngToBase64Webp(ps['mask'])
|
| 524 |
+
extra_payload['source_processing'] = 'inpainting'
|
| 525 |
+
extra_payload['source_image'] = init_image_base64_webp
|
| 526 |
+
extra_payload['source_mask'] = mask_base64_webp
|
| 527 |
+
// payload["source_mask"] = base64.b64encode(buffer.getvalue()).decode()//does it need to be webp?
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
let seed = ps['seed']
|
| 531 |
+
if (parseInt(ps['seed']) === -1) {
|
| 532 |
+
const random_seed = Math.floor(Math.random() * 100000000000 + 1) // Date.now() doesn't have enough resolution to avoid duplicate
|
| 533 |
+
seed = random_seed.toString()
|
| 534 |
+
}
|
| 535 |
+
const width = general.nearestMultiple(ps['width'], 64)
|
| 536 |
+
const height = general.nearestMultiple(ps['height'], 64)
|
| 537 |
+
const nsfw = html_manip.getUseNsfw()
|
| 538 |
+
let horde_payload = {
|
| 539 |
+
prompt: horde_prompt,
|
| 540 |
+
params: {
|
| 541 |
+
sampler_name: sampler,
|
| 542 |
+
toggles: [1, 4],
|
| 543 |
+
cfg_scale: ps['cfg_scale'],
|
| 544 |
+
denoising_strength: ps['denoising_strength'],
|
| 545 |
+
seed: seed,
|
| 546 |
+
height: height,
|
| 547 |
+
width: width,
|
| 548 |
+
seed_variation: 1,
|
| 549 |
+
post_processing: ['GFPGAN'],
|
| 550 |
+
karras: false,
|
| 551 |
+
tiling: false,
|
| 552 |
+
steps: parseInt(ps['steps']),
|
| 553 |
+
n: 1,
|
| 554 |
+
},
|
| 555 |
+
nsfw: nsfw,
|
| 556 |
+
trusted_workers: true,
|
| 557 |
+
censor_nsfw: false,
|
| 558 |
+
// workers: ['4c79ab19-8e6c-4054-83b3-773b7ce71ece'],
|
| 559 |
+
// workers: workers_ids,
|
| 560 |
+
// models: ['stable_diffusion'],
|
| 561 |
+
models: [model],
|
| 562 |
+
// source_image: 'string',
|
| 563 |
+
// source_processing: 'img2img',
|
| 564 |
+
// source_mask: 'string',
|
| 565 |
+
...extra_payload,
|
| 566 |
+
r2: true,
|
| 567 |
+
shared: false,
|
| 568 |
+
}
|
| 569 |
+
return horde_payload
|
| 570 |
+
}
|
| 571 |
+
|
| 572 |
+
function getWorkerID(workers_json) {
|
| 573 |
+
let workers_ids = []
|
| 574 |
+
for (worker of workers_json) {
|
| 575 |
+
workers_ids.push(worker?.id)
|
| 576 |
+
}
|
| 577 |
+
console.log('workers_ids:', workers_ids)
|
| 578 |
+
|
| 579 |
+
return workers_ids
|
| 580 |
+
}
|
| 581 |
+
async function getWorkers() {
|
| 582 |
+
const full_url = 'https://stablehorde.net/api/v2/workers'
|
| 583 |
+
// const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
| 584 |
+
console.log(full_url)
|
| 585 |
+
|
| 586 |
+
let request = await fetch(full_url, {
|
| 587 |
+
method: 'GET',
|
| 588 |
+
headers: {
|
| 589 |
+
Accept: 'application/json',
|
| 590 |
+
},
|
| 591 |
+
})
|
| 592 |
+
|
| 593 |
+
let workers = await request.json()
|
| 594 |
+
// const workers_ids = getWorkerID(workers)
|
| 595 |
+
console.log('requestHorde workers:', workers)
|
| 596 |
+
return workers
|
| 597 |
+
}
|
| 598 |
+
async function requestHorde(payload) {
|
| 599 |
+
// const workers = await getWorkers()
|
| 600 |
+
|
| 601 |
+
// const workers_ids = getWorkerID(workers)
|
| 602 |
+
// const settings = await getSettings()
|
| 603 |
+
// payload = mapPluginSettingsToHorde(settings)
|
| 604 |
+
// payload['workers'] = workers_ids
|
| 605 |
+
// payload = {
|
| 606 |
+
// prompt: 'string',
|
| 607 |
+
// params: {
|
| 608 |
+
// sampler_name: 'k_lms',
|
| 609 |
+
// toggles: [1, 4],
|
| 610 |
+
// cfg_scale: 5,
|
| 611 |
+
// denoising_strength: 0.75,
|
| 612 |
+
// // seed: 'string',
|
| 613 |
+
// height: 512,
|
| 614 |
+
// width: 512,
|
| 615 |
+
// seed_variation: 1,
|
| 616 |
+
// post_processing: ['GFPGAN'],
|
| 617 |
+
// karras: false,
|
| 618 |
+
// tiling: false,
|
| 619 |
+
// steps: 5,
|
| 620 |
+
// n: 1,
|
| 621 |
+
// },
|
| 622 |
+
// nsfw: false,
|
| 623 |
+
// trusted_workers: true,
|
| 624 |
+
// censor_nsfw: false,
|
| 625 |
+
// // workers: ['4c79ab19-8e6c-4054-83b3-773b7ce71ece'],
|
| 626 |
+
// workers: workers_ids,
|
| 627 |
+
// models: ['stable_diffusion'],
|
| 628 |
+
// // source_image: 'string',
|
| 629 |
+
// // source_processing: 'img2img',
|
| 630 |
+
// // source_mask: 'string',
|
| 631 |
+
// r2: true,
|
| 632 |
+
// shared: false,
|
| 633 |
+
// }
|
| 634 |
+
try {
|
| 635 |
+
console.log('requestHorde():')
|
| 636 |
+
|
| 637 |
+
const full_url = 'https://stablehorde.net/api/v2/generate/async'
|
| 638 |
+
// const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
| 639 |
+
console.log(full_url)
|
| 640 |
+
|
| 641 |
+
const horde_api_key = html_manip.getHordeApiKey()
|
| 642 |
+
let request = await fetch(full_url, {
|
| 643 |
+
method: 'POST',
|
| 644 |
+
headers: {
|
| 645 |
+
Accept: 'application/json',
|
| 646 |
+
'Content-Type': 'application/json',
|
| 647 |
+
apikey: horde_api_key,
|
| 648 |
+
|
| 649 |
+
'Client-Agent': 'unknown:0:unknown',
|
| 650 |
+
},
|
| 651 |
+
body: JSON.stringify(payload),
|
| 652 |
+
})
|
| 653 |
+
|
| 654 |
+
let json = await request.json()
|
| 655 |
+
console.log('requestHorde json:', json)
|
| 656 |
+
|
| 657 |
+
return json
|
| 658 |
+
} catch (e) {
|
| 659 |
+
console.warn(e)
|
| 660 |
+
return {}
|
| 661 |
+
}
|
| 662 |
+
}
|
| 663 |
+
async function requestHordeCheck(id) {
|
| 664 |
+
try {
|
| 665 |
+
console.log('requestHordeCheck():')
|
| 666 |
+
const base_url = 'https://stablehorde.net/api/v2/generate/check'
|
| 667 |
+
|
| 668 |
+
const full_url = `${base_url}/${id}`
|
| 669 |
+
// const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
| 670 |
+
console.log(full_url)
|
| 671 |
+
const payload = {}
|
| 672 |
+
let request = await fetch(full_url, {
|
| 673 |
+
method: 'GET',
|
| 674 |
+
headers: {
|
| 675 |
+
Accept: 'application/json',
|
| 676 |
+
'Content-Type': 'application/json',
|
| 677 |
+
// 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
| 678 |
+
'Client-Agent': 'unknown:0:unknown',
|
| 679 |
+
},
|
| 680 |
+
})
|
| 681 |
+
|
| 682 |
+
let json = await request.json()
|
| 683 |
+
console.log('requestHordeCheck json:', json)
|
| 684 |
+
|
| 685 |
+
return json
|
| 686 |
+
} catch (e) {
|
| 687 |
+
console.warn(e)
|
| 688 |
+
return {}
|
| 689 |
+
}
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
async function requestHordeStatus(id) {
|
| 693 |
+
try {
|
| 694 |
+
console.log('requestHordeStatus():')
|
| 695 |
+
const base_url = 'https://stablehorde.net/api/v2/generate/status'
|
| 696 |
+
|
| 697 |
+
const full_url = `${base_url}/${id}`
|
| 698 |
+
// const full_url = 'https://stablehorde.net/api/v2/generate/sync'
|
| 699 |
+
console.log(full_url)
|
| 700 |
+
const payload = {}
|
| 701 |
+
let request = await fetch(full_url, {
|
| 702 |
+
method: 'GET',
|
| 703 |
+
headers: {
|
| 704 |
+
Accept: 'application/json',
|
| 705 |
+
'Content-Type': 'application/json',
|
| 706 |
+
// 'Client-Agent': '4c79ab19-8e6c-4054-83b3-773b7ce71ece',
|
| 707 |
+
'Client-Agent': 'unknown:0:unknown',
|
| 708 |
+
},
|
| 709 |
+
})
|
| 710 |
+
|
| 711 |
+
let json = await request.json()
|
| 712 |
+
console.log('requestHordeStatus json:', json)
|
| 713 |
+
|
| 714 |
+
return json
|
| 715 |
+
} catch (e) {
|
| 716 |
+
console.warn(e)
|
| 717 |
+
}
|
| 718 |
+
}
|
| 719 |
+
|
| 720 |
+
let g_horde_generation_result
|
| 721 |
+
let g_b_request_result = false
|
| 722 |
+
function cancelRequestClientSide() {
|
| 723 |
+
this.interval_id = clearTimeout(this.interval_id)
|
| 724 |
+
// g_id = null
|
| 725 |
+
g_b_request_result = false
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
module.exports = {
|
| 729 |
+
hordeGenerator,
|
| 730 |
+
HordeSettings,
|
| 731 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/metadata_to_json.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// import serverHelper
|
| 2 |
+
// # 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'
|
| 3 |
+
// def convertMetadataToJson(metadata_str):
|
| 4 |
+
// print(metadata_str)
|
| 5 |
+
// last_new_line_index = metadata_str.rindex('\n')
|
| 6 |
+
// prompt = metadata_str[:last_new_line_index]
|
| 7 |
+
// other_settings = metadata_str[last_new_line_index+1:]
|
| 8 |
+
|
| 9 |
+
// print("prompt:", prompt)
|
| 10 |
+
// print("other_settings:", other_settings)
|
| 11 |
+
// sub_settings = other_settings.split(",")
|
| 12 |
+
// print("sub_settings: ",sub_settings)
|
| 13 |
+
|
| 14 |
+
// settings_dict = {}
|
| 15 |
+
// settings_dict['prompt'] = prompt
|
| 16 |
+
|
| 17 |
+
// for setting in sub_settings:
|
| 18 |
+
// [key,value]= setting.split(":")
|
| 19 |
+
// key = key.lstrip(' ')
|
| 20 |
+
// value = value.lstrip(' ')
|
| 21 |
+
// settings_dict[key] = value
|
| 22 |
+
// import json
|
| 23 |
+
// settings_json = json.dumps(settings_dict)
|
| 24 |
+
// print("settings_dict: ",settings_dict)
|
| 25 |
+
// print("settings_json ",settings_json)
|
| 26 |
+
// return settings_json
|
| 27 |
+
|
| 28 |
+
// // function getMetadataFromPng(image_path){
|
| 29 |
+
|
| 30 |
+
// // // image_path = "./output/5c42fd2a-6708-45e2-b282-2e9f3894368e/output- 1672476035.4888158.png"
|
| 31 |
+
// // // 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"
|
| 32 |
+
// // im = Image.open(image_path)
|
| 33 |
+
// // # im.load() # Needed only for .png EXIF data (see citation above)
|
| 34 |
+
// // # print(im.info['parameters'])
|
| 35 |
+
// // metadata_string = im.info['parameters']
|
| 36 |
+
// // metadata_json_string = convertMetadataToJson(metadata_string)
|
| 37 |
+
// // metadata_dict = json.loads(metadata_json_string)
|
| 38 |
+
// // print("metadata_dict: ", metadata_dict)
|
| 39 |
+
// // # print(im.info['meta_to_read'])
|
| 40 |
+
// // return metadata_dict
|
| 41 |
+
|
| 42 |
+
// }
|
| 43 |
+
// def createMetadataJsonFileIfNotExist(image_path):
|
| 44 |
+
|
| 45 |
+
// # image_name = os.path.splitext(image_path)
|
| 46 |
+
// image_name = Path(image_path).stem
|
| 47 |
+
// # parent_dir_path = Path(image_path)
|
| 48 |
+
// # parent_dir_path = image_path.split(image_name)[0]
|
| 49 |
+
// # os.path.join()
|
| 50 |
+
// head = os.path.split(image_path)[0]
|
| 51 |
+
// json_file_tail = f'{image_name}.json'
|
| 52 |
+
// json_full_path = os.path.join(head,json_file_tail)
|
| 53 |
+
// print("image_name: ",image_name)
|
| 54 |
+
// print("json_full_path: ",json_full_path)
|
| 55 |
+
// isExist = os.path.exists(json_full_path)
|
| 56 |
+
// if(isExist):
|
| 57 |
+
// #read metadata from json
|
| 58 |
+
// metadata_dict = serverHelper.readJson(json_full_path)
|
| 59 |
+
|
| 60 |
+
// else:
|
| 61 |
+
// #read metadata from image
|
| 62 |
+
// #save the metadata to a json file
|
| 63 |
+
// metadata_dict = getMetadataFromPng(image_path)
|
| 64 |
+
// serverHelper.writeJson(json_full_path,metadata_dict)
|
| 65 |
+
// return metadata_dict
|
| 66 |
+
|
| 67 |
+
// if __name__ == "__main__":
|
| 68 |
+
// 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"
|
| 69 |
+
// # getMetadataFromPng(image_path)
|
| 70 |
+
// createMetadataJsonFileIfNotExist(image_path)
|
| 71 |
+
|
| 72 |
+
// module.exports = {
|
| 73 |
+
// convertMetadataToJson,
|
| 74 |
+
// getMetadataFromPng,
|
| 75 |
+
// createMetadataJsonFileIfNotExist,
|
| 76 |
+
// }
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/options.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class SdOptions {
|
| 2 |
+
constructor() {
|
| 3 |
+
// this.status = false // true if we have a valid copy of sd options, false otherwise
|
| 4 |
+
this.options //store sd options
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
async getOptions() {
|
| 8 |
+
try {
|
| 9 |
+
// if (this.status) {
|
| 10 |
+
// return this.options
|
| 11 |
+
// } else {
|
| 12 |
+
// this.options = await sdapi.requestGetOptions()
|
| 13 |
+
// if (this.options) {
|
| 14 |
+
// this.status = true
|
| 15 |
+
// }
|
| 16 |
+
// }
|
| 17 |
+
this.options = await sdapi.requestGetOptions()
|
| 18 |
+
return this.options
|
| 19 |
+
} catch (e) {
|
| 20 |
+
console.warn(e)
|
| 21 |
+
}
|
| 22 |
+
}
|
| 23 |
+
getCurrentModel() {
|
| 24 |
+
const current_model = this.options?.sd_model_checkpoint
|
| 25 |
+
return current_model
|
| 26 |
+
}
|
| 27 |
+
getInpaintingMaskWeight() {
|
| 28 |
+
const inpainting_mask_weight = this.options?.inpainting_mask_weight
|
| 29 |
+
return inpainting_mask_weight
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
// const sd_options = new SdOptions()
|
| 33 |
+
// sd_options.option?.sd_model_checkpoint
|
| 34 |
+
|
| 35 |
+
module.exports = {
|
| 36 |
+
SdOptions,
|
| 37 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/prompt_shortcut.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
function find_words_inside_braces(string) {
|
| 2 |
+
const re = /\{(.*?)\}/g
|
| 3 |
+
let keywords = string.match(re)
|
| 4 |
+
// console.log('keywords: ', keywords)
|
| 5 |
+
if (!keywords) {
|
| 6 |
+
//avoid null keywords
|
| 7 |
+
keywords = []
|
| 8 |
+
}
|
| 9 |
+
return keywords
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
function replaceShortcut(text, prompt_shortcut_json) {
|
| 13 |
+
const original_keywords = find_words_inside_braces(text)
|
| 14 |
+
const strip_keywords = original_keywords.map((s) => {
|
| 15 |
+
let content = s.slice(1, -1) //remove '{' and '}'
|
| 16 |
+
content = content.trim() //remove any space in the beginning and end of content
|
| 17 |
+
return content
|
| 18 |
+
})
|
| 19 |
+
|
| 20 |
+
// original_substrings = list(map(lambda s: '{'+s+'}',raw_keywords))
|
| 21 |
+
|
| 22 |
+
// print("strip_keywords: ", strip_keywords)
|
| 23 |
+
// print("original_substrings: ",original_substrings)
|
| 24 |
+
// # print ("text:",text)
|
| 25 |
+
|
| 26 |
+
let i = 0
|
| 27 |
+
for (const word of strip_keywords) {
|
| 28 |
+
// # word = word.strip()
|
| 29 |
+
// print("word: ",word)
|
| 30 |
+
if (word.length > 0 && prompt_shortcut_json.hasOwnProperty(word)) {
|
| 31 |
+
const prompt = prompt_shortcut_json[word]
|
| 32 |
+
console.log('prompt: ', prompt)
|
| 33 |
+
text = text.replace(original_keywords[i], prompt)
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
console.log('final text: ', text)
|
| 37 |
+
return text
|
| 38 |
+
}
|
| 39 |
+
module.exports = {
|
| 40 |
+
find_words_inside_braces,
|
| 41 |
+
replaceShortcut,
|
| 42 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/sdapi/python_replacement.js
ADDED
|
@@ -0,0 +1,594 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//how to get environment variable in javascript
|
| 2 |
+
const settings_tab = require('../tab/settings')
|
| 3 |
+
const { getPromptShortcut } = require('../html_manip')
|
| 4 |
+
const general = require('../general')
|
| 5 |
+
// function newOutputImageName(format = 'png') {
|
| 6 |
+
// const random_id = Math.floor(Math.random() * 100000000000 + 1) // Date.now() doesn't have enough resolution to avoid duplicate
|
| 7 |
+
// const image_name = `output- ${Date.now()}-${random_id}.${format}`
|
| 8 |
+
// console.log('generated image name:', image_name)
|
| 9 |
+
// return image_name
|
| 10 |
+
// }
|
| 11 |
+
|
| 12 |
+
function convertMetadataToJson(metadata_str) {
|
| 13 |
+
try {
|
| 14 |
+
console.log('metadata_str:', metadata_str)
|
| 15 |
+
const last_new_line_index = metadata_str.lastIndexOf('\n')
|
| 16 |
+
|
| 17 |
+
const prompt = metadata_str.slice(0, last_new_line_index)
|
| 18 |
+
const other_settings = metadata_str.slice(last_new_line_index + 1, -1)
|
| 19 |
+
|
| 20 |
+
console.log('prompt:', prompt)
|
| 21 |
+
console.log('other_settings:', other_settings)
|
| 22 |
+
const sub_settings = other_settings.split(',')
|
| 23 |
+
console.log('sub_settings: ', sub_settings)
|
| 24 |
+
|
| 25 |
+
const settings_json = {}
|
| 26 |
+
settings_json['prompt'] = prompt
|
| 27 |
+
|
| 28 |
+
for (const setting of sub_settings) {
|
| 29 |
+
let [key, value] = setting.split(':').map((s) => s.trimLeft())
|
| 30 |
+
// key = key.lstrip(' ')
|
| 31 |
+
// value = value.lstrip(' ')
|
| 32 |
+
settings_json[key] = value
|
| 33 |
+
// import json
|
| 34 |
+
// settings_json = json.dumps(settings_dict)
|
| 35 |
+
// print("settings_dict: ",settings_dict)
|
| 36 |
+
// print("settings_json ",settings_json)
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
return settings_json
|
| 40 |
+
} catch (e) {
|
| 41 |
+
console.warn(e)
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
async function getAuto1111Metadata(base64_image) {
|
| 46 |
+
try {
|
| 47 |
+
console.log('getAuto1111Metadata: ')
|
| 48 |
+
|
| 49 |
+
const full_url = `${g_sd_url}/sdapi/v1/png-info`
|
| 50 |
+
|
| 51 |
+
const payload = {
|
| 52 |
+
image: 'data:image/png;base64,' + base64_image,
|
| 53 |
+
}
|
| 54 |
+
let request = await fetch(full_url, {
|
| 55 |
+
method: 'POST',
|
| 56 |
+
headers: {
|
| 57 |
+
Accept: 'application/json',
|
| 58 |
+
'Content-Type': 'application/json',
|
| 59 |
+
},
|
| 60 |
+
body: JSON.stringify(payload),
|
| 61 |
+
})
|
| 62 |
+
|
| 63 |
+
let json = await request.json()
|
| 64 |
+
console.log("json['info']:", json['info'])
|
| 65 |
+
|
| 66 |
+
console.log('getAuto1111Metadata json:', json)
|
| 67 |
+
|
| 68 |
+
return json['info']
|
| 69 |
+
} catch (e) {
|
| 70 |
+
console.warn(e)
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
async function convertToStandardResponse(settings, images, uuid) {
|
| 74 |
+
try {
|
| 75 |
+
//standardized the response between modes and backends
|
| 76 |
+
const uniqueDocumentId = uuid // maybe use the generation_session uuid
|
| 77 |
+
|
| 78 |
+
const image_paths = []
|
| 79 |
+
|
| 80 |
+
const metadata = []
|
| 81 |
+
const images_info = []
|
| 82 |
+
|
| 83 |
+
for (i of images) {
|
| 84 |
+
let auto_metadata_json = {}
|
| 85 |
+
try {
|
| 86 |
+
const auto_metadata_str = await getAuto1111Metadata(i)
|
| 87 |
+
auto_metadata_json = convertMetadataToJson(auto_metadata_str)
|
| 88 |
+
console.warn(
|
| 89 |
+
'auto_metadata_json.Seed:',
|
| 90 |
+
auto_metadata_json?.Seed
|
| 91 |
+
)
|
| 92 |
+
} catch (e) {
|
| 93 |
+
console.warn(e)
|
| 94 |
+
auto_metadata_json = {} // set the metadata to empty if there an error while getting the metadata
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
const image_name = general.newOutputImageName()
|
| 98 |
+
const image_path = `${uniqueDocumentId}/${image_name}`
|
| 99 |
+
|
| 100 |
+
images_info.push({
|
| 101 |
+
base64: i,
|
| 102 |
+
path: image_path,
|
| 103 |
+
auto_metadata: auto_metadata_json,
|
| 104 |
+
})
|
| 105 |
+
// console.log("metadata_json: ", metadata_json)
|
| 106 |
+
}
|
| 107 |
+
const dir_name = 'temp_dir_name'
|
| 108 |
+
return {
|
| 109 |
+
payload: settings,
|
| 110 |
+
dir_name: dir_name,
|
| 111 |
+
images_info: images_info,
|
| 112 |
+
metadata: metadata,
|
| 113 |
+
}
|
| 114 |
+
} catch (e) {
|
| 115 |
+
console.warn(e)
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
function replacePromptsWithShortcuts(
|
| 119 |
+
prompt,
|
| 120 |
+
negative_prompt,
|
| 121 |
+
prompt_shortcut_dic
|
| 122 |
+
) {
|
| 123 |
+
// const prompt_shortcut_dict = prompt_shortcut.load()
|
| 124 |
+
// prompt_shortcut_dict.update(payload["prompt_shortcut_ui_dict"])
|
| 125 |
+
new_prompt = prompt_shortcut.replaceShortcut(prompt, prompt_shortcut_dic)
|
| 126 |
+
// # edit negative prompt, replaceShortcut(negative_prompt)
|
| 127 |
+
new_negative_prompt = prompt_shortcut.replaceShortcut(
|
| 128 |
+
negative_prompt,
|
| 129 |
+
prompt_shortcut_dic
|
| 130 |
+
)
|
| 131 |
+
return [new_prompt, new_negative_prompt]
|
| 132 |
+
}
|
| 133 |
+
async function txt2ImgRequest(payload) {
|
| 134 |
+
console.log('payload:', payload)
|
| 135 |
+
|
| 136 |
+
if (payload['use_prompt_shortcut']) {
|
| 137 |
+
const [new_prompt, new_negative_prompt] = replacePromptsWithShortcuts(
|
| 138 |
+
payload['prompt'],
|
| 139 |
+
payload['negative_prompt'],
|
| 140 |
+
payload['prompt_shortcut_ui_dict']
|
| 141 |
+
)
|
| 142 |
+
payload['prompt'] = new_prompt
|
| 143 |
+
payload['negative_prompt'] = new_negative_prompt
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
const endpoint = 'sdapi/v1/txt2img'
|
| 147 |
+
try {
|
| 148 |
+
console.log('txt2ImgRequest(): about to send a fetch request')
|
| 149 |
+
|
| 150 |
+
const full_url = `${g_sd_url}/${endpoint}`
|
| 151 |
+
console.log(full_url)
|
| 152 |
+
|
| 153 |
+
let request = await fetch(full_url, {
|
| 154 |
+
method: 'POST',
|
| 155 |
+
headers: {
|
| 156 |
+
Accept: 'application/json',
|
| 157 |
+
'Content-Type': 'application/json',
|
| 158 |
+
},
|
| 159 |
+
body: JSON.stringify(payload),
|
| 160 |
+
// "body": payload
|
| 161 |
+
})
|
| 162 |
+
|
| 163 |
+
let r = await request.json()
|
| 164 |
+
console.log('txt2ImgRequest json:', r)
|
| 165 |
+
|
| 166 |
+
const uniqueDocumentId = payload['uniqueDocumentId']
|
| 167 |
+
// dir_fullpath,dirName = serverHelper.getUniqueDocumentDirPathName(uniqueDocumentId)
|
| 168 |
+
// serverHelper.createFolder(dir_fullpath)
|
| 169 |
+
const image_paths = []
|
| 170 |
+
|
| 171 |
+
const metadata = []
|
| 172 |
+
const images_info = []
|
| 173 |
+
|
| 174 |
+
for (i of r['images']) {
|
| 175 |
+
let auto_metadata_json = {}
|
| 176 |
+
try {
|
| 177 |
+
const auto_metadata_str = await getAuto1111Metadata(i)
|
| 178 |
+
auto_metadata_json = convertMetadataToJson(auto_metadata_str)
|
| 179 |
+
console.warn(
|
| 180 |
+
'auto_metadata_json.Seed:',
|
| 181 |
+
auto_metadata_json?.Seed
|
| 182 |
+
)
|
| 183 |
+
} catch (e) {
|
| 184 |
+
console.warn(e)
|
| 185 |
+
auto_metadata_json = {} // set the metadata to empty if there an error while getting the metadata
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
// response2 = await client.post(url=f'{sd_url}/sdapi/v1/png-info', json=png_payload)
|
| 189 |
+
// pnginfo = PngImagePlugin.PngInfo()
|
| 190 |
+
// pnginfo.add_text("parameters", response2.json().get("info"))
|
| 191 |
+
|
| 192 |
+
const image_name = general.newOutputImageName()
|
| 193 |
+
const image_path = `${uniqueDocumentId}/${image_name}`
|
| 194 |
+
|
| 195 |
+
// image_path = f'output/{dirName}/{image_name}'
|
| 196 |
+
// image_paths.append(image_path)
|
| 197 |
+
// image.save(f'./{image_path}', pnginfo=pnginfo)
|
| 198 |
+
|
| 199 |
+
// metadata_info = response2.json().get("info")
|
| 200 |
+
// metadata_json = metadata_to_json.convertMetadataToJson(metadata_info)
|
| 201 |
+
// metadata.append(metadata_json)
|
| 202 |
+
|
| 203 |
+
images_info.push({
|
| 204 |
+
base64: i,
|
| 205 |
+
path: image_path,
|
| 206 |
+
auto_metadata: auto_metadata_json,
|
| 207 |
+
})
|
| 208 |
+
// console.log("metadata_json: ", metadata_json)
|
| 209 |
+
}
|
| 210 |
+
const dir_name = 'temp_dir_name'
|
| 211 |
+
return {
|
| 212 |
+
payload: payload,
|
| 213 |
+
dir_name: dir_name,
|
| 214 |
+
images_info: images_info,
|
| 215 |
+
metadata: metadata,
|
| 216 |
+
}
|
| 217 |
+
} catch (e) {
|
| 218 |
+
console.warn(e)
|
| 219 |
+
return {}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
// const request_path = '/sdapi/v1/txt2img'
|
| 223 |
+
}
|
| 224 |
+
function getExtensionUrl() {
|
| 225 |
+
const extension_type = settings_tab.getExtensionType()
|
| 226 |
+
let extension_url
|
| 227 |
+
if (extension_type === 'auto1111_extension') {
|
| 228 |
+
extension_url = `${g_sd_url}/sdapi/auto-photoshop-sd`
|
| 229 |
+
} else if (extension_type === 'proxy_server') {
|
| 230 |
+
extension_url = 'http://127.0.0.1:8000'
|
| 231 |
+
} else {
|
| 232 |
+
//none
|
| 233 |
+
extension_url = ''
|
| 234 |
+
}
|
| 235 |
+
return extension_url
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
async function openUrlRequest(url) {
|
| 239 |
+
try {
|
| 240 |
+
const payload = {
|
| 241 |
+
url: url,
|
| 242 |
+
}
|
| 243 |
+
// const full_url = 'http://127.0.0.1:8000/mask/expansion/'
|
| 244 |
+
const extension_url = getExtensionUrl()
|
| 245 |
+
const full_url = `${extension_url}/open/url/`
|
| 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 |
+
// "body": payload
|
| 254 |
+
})
|
| 255 |
+
|
| 256 |
+
let r = await request.json()
|
| 257 |
+
|
| 258 |
+
console.log('openUrlRequest json:', r)
|
| 259 |
+
return r['url']
|
| 260 |
+
} catch (e) {
|
| 261 |
+
console.warn(e)
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
async function maskExpansionRequest(original_mask, mask_expansion_value) {
|
| 265 |
+
// const endpoint = 'sdapi/v1/img2img'
|
| 266 |
+
// const full_url = `${g_sd_url}/${endpoint}`
|
| 267 |
+
|
| 268 |
+
try {
|
| 269 |
+
const payload = {
|
| 270 |
+
mask: original_mask,
|
| 271 |
+
mask_expansion: mask_expansion_value,
|
| 272 |
+
}
|
| 273 |
+
// const full_url = 'http://127.0.0.1:8000/mask/expansion/'
|
| 274 |
+
const extension_url = getExtensionUrl()
|
| 275 |
+
const full_url = `${extension_url}/mask/expansion/`
|
| 276 |
+
let request = await fetch(full_url, {
|
| 277 |
+
method: 'POST',
|
| 278 |
+
headers: {
|
| 279 |
+
Accept: 'application/json',
|
| 280 |
+
'Content-Type': 'application/json',
|
| 281 |
+
},
|
| 282 |
+
body: JSON.stringify(payload),
|
| 283 |
+
// "body": payload
|
| 284 |
+
})
|
| 285 |
+
|
| 286 |
+
let r = await request.json()
|
| 287 |
+
|
| 288 |
+
console.log('maskExpansionRequest json:', r)
|
| 289 |
+
return r['mask']
|
| 290 |
+
} catch (e) {
|
| 291 |
+
console.warn(e)
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
async function img2ImgRequest(sd_url, payload) {
|
| 295 |
+
console.log('payload:', payload)
|
| 296 |
+
|
| 297 |
+
if (payload['use_prompt_shortcut']) {
|
| 298 |
+
const [new_prompt, new_negative_prompt] = replacePromptsWithShortcuts(
|
| 299 |
+
payload['prompt'],
|
| 300 |
+
payload['negative_prompt'],
|
| 301 |
+
payload['prompt_shortcut_ui_dict']
|
| 302 |
+
)
|
| 303 |
+
payload['prompt'] = new_prompt
|
| 304 |
+
payload['negative_prompt'] = new_negative_prompt
|
| 305 |
+
}
|
| 306 |
+
// init_img_dir = "./init_images"
|
| 307 |
+
// init_img_name = payload['init_image_name']
|
| 308 |
+
// init_img = Image.open(f"{init_img_dir}/{init_img_name}")
|
| 309 |
+
// init_img_str = img_2_b64(init_img)
|
| 310 |
+
// payload['init_images'] = [init_img_str]
|
| 311 |
+
|
| 312 |
+
// init_img_mask_name = payload.get('init_image_mask_name',"")
|
| 313 |
+
|
| 314 |
+
// #only if image exist then try to open it
|
| 315 |
+
|
| 316 |
+
// if(len(init_img_mask_name) > 0):
|
| 317 |
+
// init_img_mask = Image.open(f"{init_img_dir}/{init_img_mask_name}")
|
| 318 |
+
|
| 319 |
+
// if (payload['use_sharp_mask'] === false && payload['mask']) {
|
| 320 |
+
// //only if mask is available and sharp_mask is off
|
| 321 |
+
// // use blurry and expanded mask
|
| 322 |
+
// const iterations = payload['mask_expansion']
|
| 323 |
+
// const mask = await maskExpansionRequest(payload['mask'], iterations)
|
| 324 |
+
// if (mask) {
|
| 325 |
+
// payload['mask'] = mask
|
| 326 |
+
// }
|
| 327 |
+
// }
|
| 328 |
+
|
| 329 |
+
// print(type(init_img_str))
|
| 330 |
+
// #request the images to be generated
|
| 331 |
+
|
| 332 |
+
const endpoint = 'sdapi/v1/img2img'
|
| 333 |
+
|
| 334 |
+
const full_url = `${sd_url}/${endpoint}`
|
| 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 |
+
// "body": payload
|
| 343 |
+
})
|
| 344 |
+
|
| 345 |
+
let r = await request.json()
|
| 346 |
+
|
| 347 |
+
console.log('img2ImgRequest json:', r)
|
| 348 |
+
|
| 349 |
+
const uniqueDocumentId = payload['uniqueDocumentId']
|
| 350 |
+
// dir_fullpath,dirName = serverHelper.getUniqueDocumentDirPathName(uniqueDocumentId)
|
| 351 |
+
// serverHelper.createFolder(dir_fullpath)
|
| 352 |
+
const image_paths = []
|
| 353 |
+
const metadata = []
|
| 354 |
+
const images_info = []
|
| 355 |
+
|
| 356 |
+
for (i of r['images']) {
|
| 357 |
+
// image = Image.open(io.BytesIO(base64.b64decode(i.split(",",1)[0])))
|
| 358 |
+
let auto_metadata_json = {}
|
| 359 |
+
try {
|
| 360 |
+
const auto_metadata_str = await getAuto1111Metadata(i)
|
| 361 |
+
auto_metadata_json = convertMetadataToJson(auto_metadata_str)
|
| 362 |
+
} catch (e) {
|
| 363 |
+
console.warn(e)
|
| 364 |
+
auto_metadata_json = {} // set the metadata to empty if there an error while getting the metadata
|
| 365 |
+
}
|
| 366 |
+
// response2 = await client.post(url=f'{sd_url}/sdapi/v1/png-info', json=png_payload, timeout=None)
|
| 367 |
+
// pnginfo = PngImagePlugin.PngInfo()
|
| 368 |
+
// pnginfo.add_text("parameters", response2.json().get("info"))
|
| 369 |
+
// image_name = f'output- {time.time()}.png'
|
| 370 |
+
// image_path = f'output/{dirName}/{image_name}'
|
| 371 |
+
// image_paths.append(image_path)
|
| 372 |
+
// image.save(f'./{image_path}', pnginfo=pnginfo)
|
| 373 |
+
|
| 374 |
+
// metadata_info = response2.json().get("info")
|
| 375 |
+
// metadata_json = metadata_to_json.convertMetadataToJson(metadata_info)
|
| 376 |
+
// metadata.append(metadata_json)
|
| 377 |
+
const image_name = general.newOutputImageName()
|
| 378 |
+
const image_path = `${uniqueDocumentId}/${image_name}`
|
| 379 |
+
|
| 380 |
+
images_info.push({
|
| 381 |
+
base64: i,
|
| 382 |
+
path: image_path,
|
| 383 |
+
auto_metadata: auto_metadata_json,
|
| 384 |
+
})
|
| 385 |
+
// print("metadata_json: ", metadata_json)
|
| 386 |
+
}
|
| 387 |
+
const dir_name = 'temp_dir_name'
|
| 388 |
+
// return [dirName, images_info, metadata]
|
| 389 |
+
return {
|
| 390 |
+
payload: payload,
|
| 391 |
+
dir_name: dir_name,
|
| 392 |
+
images_info: images_info,
|
| 393 |
+
metadata: metadata,
|
| 394 |
+
}
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
async function getOutputImagesEntries(doc_entry) {
|
| 398 |
+
let entries = await doc_entry.getEntries()
|
| 399 |
+
const output_images_entries = entries.filter(
|
| 400 |
+
(e) => e.isFile && e.name.toLowerCase().includes('.png') // must be a file and has the of the type .png
|
| 401 |
+
)
|
| 402 |
+
console.log('output_images_entries: ', output_images_entries)
|
| 403 |
+
// .forEach((e) => console.log(e.name))
|
| 404 |
+
return output_images_entries
|
| 405 |
+
}
|
| 406 |
+
|
| 407 |
+
async function getMetaDataForOutputEntry(doc_entry, output_entry) {
|
| 408 |
+
const json_file_name = `${output_entry.name.split('.')[0]}.json`
|
| 409 |
+
|
| 410 |
+
try {
|
| 411 |
+
const json_entry = await doc_entry.getEntry(json_file_name)
|
| 412 |
+
if (json_entry) {
|
| 413 |
+
// await json_entry.read()
|
| 414 |
+
|
| 415 |
+
const json = JSON.parse(
|
| 416 |
+
await json_entry.read({
|
| 417 |
+
format: storage.formats.utf8,
|
| 418 |
+
})
|
| 419 |
+
)
|
| 420 |
+
return json
|
| 421 |
+
}
|
| 422 |
+
} catch (e) {
|
| 423 |
+
console.warn(e)
|
| 424 |
+
}
|
| 425 |
+
return {}
|
| 426 |
+
}
|
| 427 |
+
async function loadHistory(payload) {
|
| 428 |
+
// {'image_paths','metadata_setting'}
|
| 429 |
+
const history = {}
|
| 430 |
+
|
| 431 |
+
// const uniqueDocumentId = payload['uniqueDocumentId']
|
| 432 |
+
// const uniqueDocumentId = await getUniqueDocumentId()
|
| 433 |
+
|
| 434 |
+
const uuid = await getUniqueDocumentId()
|
| 435 |
+
const doc_entry = await getDocFolder(uuid)
|
| 436 |
+
const output_images_entries = await getOutputImagesEntries(doc_entry)
|
| 437 |
+
history['image_paths'] = []
|
| 438 |
+
history['metadata_jsons'] = []
|
| 439 |
+
history['base64_images'] = []
|
| 440 |
+
for (const output_entry of output_images_entries) {
|
| 441 |
+
history['image_paths'].push(output_entry.name)
|
| 442 |
+
const metadata_json = await getMetaDataForOutputEntry(
|
| 443 |
+
doc_entry,
|
| 444 |
+
output_entry
|
| 445 |
+
)
|
| 446 |
+
history['metadata_jsons'].push(metadata_json)
|
| 447 |
+
|
| 448 |
+
const arrayBuffer = await output_entry.read({ format: formats.binary })
|
| 449 |
+
const base64_image = _arrayBufferToBase64(arrayBuffer) //convert the buffer to base64
|
| 450 |
+
|
| 451 |
+
// const base64 =
|
| 452 |
+
history['base64_images'].push(base64_image)
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
// image_paths = glob.glob(f'./output/{uniqueDocumentId}/*.png')
|
| 456 |
+
// settings_paths = glob.glob(f'./output/{uniqueDocumentId}/*.json')#note: why is we are not using settings_paths?
|
| 457 |
+
// print("loadHistory: image_paths:", image_paths)
|
| 458 |
+
|
| 459 |
+
// history['image_paths'] = image_paths
|
| 460 |
+
// history['metadata_jsons'] = []
|
| 461 |
+
// history['base64_images'] = []
|
| 462 |
+
// for image_path in image_paths:
|
| 463 |
+
// print("image_path: ", image_path)
|
| 464 |
+
// metadata_dict = metadata_to_json.createMetadataJsonFileIfNotExist(image_path)
|
| 465 |
+
// history['metadata_jsons'].append(metadata_dict)
|
| 466 |
+
|
| 467 |
+
// img = Image.open(image_path)
|
| 468 |
+
// base64_image = img_2_b64(img)
|
| 469 |
+
// history['base64_images'].append(base64_image)
|
| 470 |
+
|
| 471 |
+
// except:
|
| 472 |
+
|
| 473 |
+
// print(f'{request}')
|
| 474 |
+
|
| 475 |
+
// #reverse the order so that newer generated images path will be shown first
|
| 476 |
+
|
| 477 |
+
// history['image_paths'].reverse()
|
| 478 |
+
// history['metadata_jsons'].reverse()
|
| 479 |
+
// history['base64_images'].reverse()
|
| 480 |
+
return {
|
| 481 |
+
image_paths: history['image_paths'],
|
| 482 |
+
metadata_jsons: history['metadata_jsons'],
|
| 483 |
+
base64_images: history['base64_images'],
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
async function savePromptShortcut(json, file_name) {
|
| 488 |
+
console.warn(
|
| 489 |
+
"savePromptShortcut() is deprecated, use it's IO class instead "
|
| 490 |
+
)
|
| 491 |
+
try {
|
| 492 |
+
const json_file_name = file_name
|
| 493 |
+
|
| 494 |
+
const folder = await storage.localFileSystem.getDataFolder()
|
| 495 |
+
|
| 496 |
+
const file = await folder.createFile(json_file_name, {
|
| 497 |
+
type: storage.types.file,
|
| 498 |
+
overwrite: true,
|
| 499 |
+
})
|
| 500 |
+
|
| 501 |
+
const JSONInPrettyFormat = JSON.stringify(json, undefined, 4)
|
| 502 |
+
await file.write(JSONInPrettyFormat, {
|
| 503 |
+
format: storage.formats.utf8,
|
| 504 |
+
append: false,
|
| 505 |
+
})
|
| 506 |
+
} catch (e) {
|
| 507 |
+
console.warn(e)
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
async function loadPromptShortcut(file_name) {
|
| 512 |
+
const json_file_name = file_name
|
| 513 |
+
|
| 514 |
+
const folder = await storage.localFileSystem.getDataFolder()
|
| 515 |
+
|
| 516 |
+
try {
|
| 517 |
+
const json_entry = await folder.getEntry(json_file_name)
|
| 518 |
+
if (json_entry) {
|
| 519 |
+
// await json_entry.read()
|
| 520 |
+
|
| 521 |
+
const json = JSON.parse(
|
| 522 |
+
await json_entry.read({
|
| 523 |
+
format: storage.formats.utf8,
|
| 524 |
+
})
|
| 525 |
+
)
|
| 526 |
+
return json
|
| 527 |
+
}
|
| 528 |
+
} catch (e) {
|
| 529 |
+
console.warn(e)
|
| 530 |
+
}
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
async function extraSingleImageRequest(sd_url, payload) {
|
| 534 |
+
console.log('extraSingleImageRequest payload:', payload)
|
| 535 |
+
|
| 536 |
+
const endpoint = 'sdapi/v1/extra-single-image'
|
| 537 |
+
|
| 538 |
+
const full_url = `${sd_url}/${endpoint}`
|
| 539 |
+
let request = await fetch(full_url, {
|
| 540 |
+
method: 'POST',
|
| 541 |
+
headers: {
|
| 542 |
+
Accept: 'application/json',
|
| 543 |
+
'Content-Type': 'application/json',
|
| 544 |
+
},
|
| 545 |
+
body: JSON.stringify(payload),
|
| 546 |
+
// "body": payload
|
| 547 |
+
})
|
| 548 |
+
|
| 549 |
+
let r = await request.json()
|
| 550 |
+
|
| 551 |
+
const images_info = []
|
| 552 |
+
|
| 553 |
+
const image = r['image']
|
| 554 |
+
|
| 555 |
+
let auto_metadata_json = {}
|
| 556 |
+
|
| 557 |
+
const uniqueDocumentId = payload['uniqueDocumentId']
|
| 558 |
+
const image_name = general.newOutputImageName()
|
| 559 |
+
const image_path = `${uniqueDocumentId}/${image_name}`
|
| 560 |
+
|
| 561 |
+
images_info.push({
|
| 562 |
+
base64: image,
|
| 563 |
+
path: image_path,
|
| 564 |
+
auto_metadata: auto_metadata_json,
|
| 565 |
+
})
|
| 566 |
+
|
| 567 |
+
console.log('extraSingleImageRequest response json:', r)
|
| 568 |
+
|
| 569 |
+
const dir_name = 'temp_dir_name'
|
| 570 |
+
const metadata = []
|
| 571 |
+
|
| 572 |
+
return {
|
| 573 |
+
payload: payload,
|
| 574 |
+
dir_name: dir_name,
|
| 575 |
+
images_info: images_info,
|
| 576 |
+
metadata: metadata,
|
| 577 |
+
}
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
module.exports = {
|
| 581 |
+
txt2ImgRequest,
|
| 582 |
+
img2ImgRequest,
|
| 583 |
+
loadHistory,
|
| 584 |
+
maskExpansionRequest,
|
| 585 |
+
getExtensionUrl,
|
| 586 |
+
savePromptShortcut,
|
| 587 |
+
loadPromptShortcut,
|
| 588 |
+
|
| 589 |
+
convertMetadataToJson,
|
| 590 |
+
openUrlRequest,
|
| 591 |
+
replacePromptsWithShortcuts,
|
| 592 |
+
extraSingleImageRequest,
|
| 593 |
+
convertToStandardResponse,
|
| 594 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/session.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { cleanLayers } = require('../psapi')
|
| 2 |
+
const psapi = require('../psapi')
|
| 3 |
+
const io = require('./io')
|
| 4 |
+
const Enum = require('../enum')
|
| 5 |
+
const { ViewerManager } = require('../viewer')
|
| 6 |
+
const { base64ToBase64Url } = require('./general')
|
| 7 |
+
const html_manip = require('./html_manip')
|
| 8 |
+
const layer_util = require('./layer')
|
| 9 |
+
const SessionState = {
|
| 10 |
+
Active: 'active',
|
| 11 |
+
Inactive: 'inactive',
|
| 12 |
+
}
|
| 13 |
+
const GarbageCollectionState = {
|
| 14 |
+
Accept: 'accept', // accept all generated images
|
| 15 |
+
Discard: 'discard', //discard all generated images
|
| 16 |
+
DiscardSelected: 'discard_selected',
|
| 17 |
+
AcceptSelected: 'accept_selected', //accept_selected only chosen images
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
class GenerationSession {
|
| 21 |
+
constructor() {
|
| 22 |
+
//this should be unique session id and it also should act as the total number of sessions been created in the project
|
| 23 |
+
this.id = 0
|
| 24 |
+
this.state = SessionState['Inactive']
|
| 25 |
+
this.mode = 'txt2img'
|
| 26 |
+
this.selectionInfo = null
|
| 27 |
+
this.isFirstGeneration = true // only before the first generation is requested should this be true
|
| 28 |
+
this.outputGroup
|
| 29 |
+
this.prevOutputGroup
|
| 30 |
+
this.isLoadingActive = false
|
| 31 |
+
this.base64OutputImages = {} //image_id/path => base64_image
|
| 32 |
+
this.base64initImages = {} //init_image_path => base64
|
| 33 |
+
this.base64maskImage = []
|
| 34 |
+
this.base64maskExpansionImage
|
| 35 |
+
this.activeBase64InitImage
|
| 36 |
+
this.activeBase64MaskImage
|
| 37 |
+
this.image_paths_to_layers = {}
|
| 38 |
+
this.progress_layer
|
| 39 |
+
this.last_settings //the last settings been used for generation
|
| 40 |
+
this.controlNetImage = [] // base64 images (one for each control net)
|
| 41 |
+
this.controlNetMask = [] // base64 images (one for each control net)
|
| 42 |
+
this.request_status = Enum.RequestStateEnum['Finished'] //finish or ideal state
|
| 43 |
+
this.is_control_net = false
|
| 44 |
+
this.control_net_selection_info
|
| 45 |
+
this.control_net_preview_selection_info
|
| 46 |
+
}
|
| 47 |
+
isActive() {
|
| 48 |
+
return this.state === SessionState['Active']
|
| 49 |
+
}
|
| 50 |
+
isInactive() {
|
| 51 |
+
return this.state === SessionState['Inactive']
|
| 52 |
+
}
|
| 53 |
+
activate() {
|
| 54 |
+
this.state = SessionState['Active']
|
| 55 |
+
}
|
| 56 |
+
deactivate() {
|
| 57 |
+
this.state = SessionState['Inactive']
|
| 58 |
+
}
|
| 59 |
+
name() {
|
| 60 |
+
return `session - ${this.id}`
|
| 61 |
+
}
|
| 62 |
+
async startSession() {
|
| 63 |
+
this.id += 1 //increment the session id for each session we start
|
| 64 |
+
this.activate()
|
| 65 |
+
this.isFirstGeneration = true // only before the first generation is requested should this be true
|
| 66 |
+
|
| 67 |
+
console.log('current session id: ', this.id)
|
| 68 |
+
try {
|
| 69 |
+
const session_name = this.name()
|
| 70 |
+
const activeLayers = await app.activeDocument.activeLayers
|
| 71 |
+
await psapi.unselectActiveLayersExe() // unselect all layer so the create group is place at the top of the document
|
| 72 |
+
this.prevOutputGroup = this.outputGroup
|
| 73 |
+
const outputGroup = await psapi.createEmptyGroup(session_name)
|
| 74 |
+
await executeAsModal(async () => {
|
| 75 |
+
outputGroup.allLocked = true //lock the session folder so that it can't move
|
| 76 |
+
})
|
| 77 |
+
this.outputGroup = outputGroup
|
| 78 |
+
await psapi.selectLayersExe(activeLayers)
|
| 79 |
+
} catch (e) {
|
| 80 |
+
console.warn(e)
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
async endSession(garbage_collection_state) {
|
| 85 |
+
try {
|
| 86 |
+
if (!this.isActive()) {
|
| 87 |
+
//return if the session is not active
|
| 88 |
+
return null
|
| 89 |
+
}
|
| 90 |
+
this.state = SessionState['Inactive'] // end the session by deactivate it
|
| 91 |
+
|
| 92 |
+
this.deactivate()
|
| 93 |
+
|
| 94 |
+
if (garbage_collection_state === GarbageCollectionState['Accept']) {
|
| 95 |
+
await acceptAll()
|
| 96 |
+
} else if (
|
| 97 |
+
garbage_collection_state === GarbageCollectionState['Discard']
|
| 98 |
+
) {
|
| 99 |
+
//this should be discardAll()
|
| 100 |
+
|
| 101 |
+
await discardAll()
|
| 102 |
+
} else if (
|
| 103 |
+
garbage_collection_state ===
|
| 104 |
+
GarbageCollectionState['DiscardSelected']
|
| 105 |
+
) {
|
| 106 |
+
//this should be discardAllExcept(selectedLayers)
|
| 107 |
+
await discardSelected() //this will discard what is not been highlighted
|
| 108 |
+
} else if (
|
| 109 |
+
garbage_collection_state ===
|
| 110 |
+
GarbageCollectionState['AcceptSelected']
|
| 111 |
+
) {
|
| 112 |
+
//this should be discardAllExcept(selectedLayers)
|
| 113 |
+
await discard() //this will discard what is not been highlighted
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
//delete the old selection area
|
| 117 |
+
// g_generation_session.selectionInfo = {}
|
| 118 |
+
|
| 119 |
+
this.isFirstGeneration = true // only before the first generation is requested should this be true
|
| 120 |
+
// const is_visible = await this.outputGroup.visible
|
| 121 |
+
g_viewer_manager.last_selected_viewer_obj = null // TODO: move this in viewerManager endSession()
|
| 122 |
+
g_viewer_manager.onSessionEnd()
|
| 123 |
+
await layer_util.collapseFolderExe([this.outputGroup], false) // close the folder group
|
| 124 |
+
await executeAsModal(async () => {
|
| 125 |
+
this.outputGroup.allLocked = false //unlock the session folder on session end
|
| 126 |
+
})
|
| 127 |
+
// this.outputGroup.visible = is_visible
|
| 128 |
+
|
| 129 |
+
if (
|
| 130 |
+
this.mode === generationMode['Inpaint'] &&
|
| 131 |
+
g_sd_mode === generationMode['Inpaint']
|
| 132 |
+
) {
|
| 133 |
+
//create "Mask -- Paint White to Mask -- temporary" layer if current session was inpiant and the selected session is inpaint
|
| 134 |
+
// the current inpaint session ended on inpaint
|
| 135 |
+
g_b_mask_layer_exist = false
|
| 136 |
+
await layer_util.deleteLayers([g_inpaint_mask_layer])
|
| 137 |
+
await createTempInpaintMaskLayer()
|
| 138 |
+
}
|
| 139 |
+
//delete controlNet image, Note: don't delete control net, let the user disable controlNet if doesn't want to use it
|
| 140 |
+
// this.controlNetImage = null
|
| 141 |
+
// html_manip.setControlImageSrc('https://source.unsplash.com/random')
|
| 142 |
+
} catch (e) {
|
| 143 |
+
console.warn(e)
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
// initializeInitImage(group, snapshot, solid_background, path) {
|
| 147 |
+
// this.initGroup = group
|
| 148 |
+
// this.init_solid_background = solid_background
|
| 149 |
+
// this.InitSnapshot = snapshot
|
| 150 |
+
// }
|
| 151 |
+
deleteInitImageLayers() {}
|
| 152 |
+
async closePreviousOutputGroup() {
|
| 153 |
+
try {
|
| 154 |
+
//close the previous output folder
|
| 155 |
+
|
| 156 |
+
if (this.prevOutputGroup) {
|
| 157 |
+
// const is_visible = await this.prevOutputGroup.visible
|
| 158 |
+
await layer_util.collapseFolderExe(
|
| 159 |
+
[this.prevOutputGroup],
|
| 160 |
+
false
|
| 161 |
+
) // close the folder group
|
| 162 |
+
// and reselect the current output folder for clarity
|
| 163 |
+
await psapi.selectLayersExe([this.outputGroup])
|
| 164 |
+
// this.prevOutputGroup.visible = is_visible
|
| 165 |
+
}
|
| 166 |
+
} catch (e) {
|
| 167 |
+
console.warn(e)
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
isSameMode(selected_mode) {
|
| 171 |
+
if (this.mode === selected_mode) {
|
| 172 |
+
return true
|
| 173 |
+
}
|
| 174 |
+
return false
|
| 175 |
+
}
|
| 176 |
+
loadLastSession() {
|
| 177 |
+
//load the last session from the server
|
| 178 |
+
}
|
| 179 |
+
saveCurrentSession() {
|
| 180 |
+
//all session info will be saved in a json file in the project folder
|
| 181 |
+
}
|
| 182 |
+
async moveToTopOfOutputGroup(layer) {
|
| 183 |
+
const output_group_id = await this.outputGroup.id
|
| 184 |
+
let group_index = await psapi.getLayerIndex(output_group_id)
|
| 185 |
+
const indexOffset = 1 //1 for background, 0 if no background exist
|
| 186 |
+
await executeAsModal(async () => {
|
| 187 |
+
await psapi.selectLayersExe([layer]) //the move command is selection selection sensitive
|
| 188 |
+
await psapi.moveToGroupCommand(group_index - indexOffset, layer.id)
|
| 189 |
+
})
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
async deleteProgressLayer() {
|
| 193 |
+
try {
|
| 194 |
+
await layer_util.deleteLayers([this.progress_layer]) // delete the old progress layer
|
| 195 |
+
} catch (e) {
|
| 196 |
+
console.warn(e)
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
deleteProgressImageHtml() {
|
| 200 |
+
try {
|
| 201 |
+
// await layer_util.deleteLayers([this.progress_layer]) // delete the old progress layer
|
| 202 |
+
// document.getElementById('progressImage').style.width = '0px'
|
| 203 |
+
// document.getElementById('progressImage').style.height = '0px'
|
| 204 |
+
|
| 205 |
+
document.getElementById(
|
| 206 |
+
'divProgressImageViewerContainer'
|
| 207 |
+
).style.height = '0px'
|
| 208 |
+
} catch (e) {
|
| 209 |
+
console.warn(e)
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
async deleteProgressImage() {
|
| 213 |
+
this.deleteProgressImageHtml()
|
| 214 |
+
await this.deleteProgressLayer()
|
| 215 |
+
}
|
| 216 |
+
async setControlNetImageHelper() {
|
| 217 |
+
const width = html_manip.getWidth()
|
| 218 |
+
const height = html_manip.getHeight()
|
| 219 |
+
|
| 220 |
+
//get the selection from the canvas as base64 png, make sure to resize to the width and height slider
|
| 221 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 222 |
+
this.control_net_selection_info = selectionInfo
|
| 223 |
+
this.control_net_preview_selection_info = selectionInfo
|
| 224 |
+
// const base64_image = await io.IO.getSelectionFromCanvasAsBase64Silent(
|
| 225 |
+
// selectionInfo,
|
| 226 |
+
// true,
|
| 227 |
+
// width,
|
| 228 |
+
// height
|
| 229 |
+
// )
|
| 230 |
+
|
| 231 |
+
const use_silent_mode = html_manip.getUseSilentMode()
|
| 232 |
+
let layer = null
|
| 233 |
+
if (!use_silent_mode) {
|
| 234 |
+
await psapi.snapshot_layerExe()
|
| 235 |
+
const snapshotLayer = await app.activeDocument.activeLayers[0]
|
| 236 |
+
layer = snapshotLayer
|
| 237 |
+
}
|
| 238 |
+
const base64_image =
|
| 239 |
+
await io.IO.getSelectionFromCanvasAsBase64Interface(
|
| 240 |
+
width,
|
| 241 |
+
height,
|
| 242 |
+
layer,
|
| 243 |
+
selectionInfo,
|
| 244 |
+
true,
|
| 245 |
+
use_silent_mode
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
await layer_util.deleteLayers([layer]) //delete the snapshot layer if it exists
|
| 249 |
+
return base64_image
|
| 250 |
+
}
|
| 251 |
+
async setControlNetImage(control_net_index = 0, base64_image) {
|
| 252 |
+
//check if the selection area is active
|
| 253 |
+
//convert layer to base64
|
| 254 |
+
//the width and height of the exported image
|
| 255 |
+
// const base64_image = this.setControlNetImageHelper()
|
| 256 |
+
this.controlNetImage[control_net_index] = base64_image
|
| 257 |
+
html_manip.setControlImageSrc(
|
| 258 |
+
base64ToBase64Url(base64_image),
|
| 259 |
+
control_net_index
|
| 260 |
+
)
|
| 261 |
+
// console.log('base64_img:', base64_image)
|
| 262 |
+
// await io.IO.base64ToLayer(base64_image)
|
| 263 |
+
}
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
module.exports = {
|
| 267 |
+
GenerationSession,
|
| 268 |
+
GarbageCollectionState,
|
| 269 |
+
SessionState,
|
| 270 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/control_net.js
ADDED
|
@@ -0,0 +1,1144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const api = require('../api')
|
| 2 |
+
const html_manip = require('../html_manip')
|
| 3 |
+
const selection = require('../../selection')
|
| 4 |
+
const note = require('../notification')
|
| 5 |
+
const controlnet_preset = require('../presets/controlnet_preset')
|
| 6 |
+
const preset = require('../presets/preset')
|
| 7 |
+
const Enum = require('../../enum')
|
| 8 |
+
const event = require('../event')
|
| 9 |
+
|
| 10 |
+
// const g_controlnet_max_supported_models = 3
|
| 11 |
+
let g_controlnet_presets
|
| 12 |
+
let g_module_detail
|
| 13 |
+
|
| 14 |
+
class ControlNetUnit {
|
| 15 |
+
static {}
|
| 16 |
+
|
| 17 |
+
static resetUnit(index) {
|
| 18 |
+
const controlnet_unit_default = {
|
| 19 |
+
module: null,
|
| 20 |
+
model: null,
|
| 21 |
+
weight: 1.0,
|
| 22 |
+
resize_mode: null,
|
| 23 |
+
lowvram: null,
|
| 24 |
+
processor_res: null,
|
| 25 |
+
threshold_a: null,
|
| 26 |
+
threshold_b: null,
|
| 27 |
+
|
| 28 |
+
guidance_start: 0,
|
| 29 |
+
guidance_end: 1,
|
| 30 |
+
guessmode: null,
|
| 31 |
+
}
|
| 32 |
+
this.setUnit(index, controlnet_unit_default)
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
static resetUnits() {
|
| 36 |
+
for (let i = 0; i < g_controlnet_max_models; ++i) {
|
| 37 |
+
this.resetUnit(i)
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
static getUnit(index) {
|
| 41 |
+
const controlnet_unit = {
|
| 42 |
+
module: this.getModule(index),
|
| 43 |
+
model: this.getModel(index),
|
| 44 |
+
weight: this.getWeight(index),
|
| 45 |
+
resize_mode: null,
|
| 46 |
+
lowvram: null,
|
| 47 |
+
processor_res: null,
|
| 48 |
+
threshold_a: null,
|
| 49 |
+
threshold_b: null,
|
| 50 |
+
|
| 51 |
+
guidance_start: this.getGuidanceStrengthStart(index),
|
| 52 |
+
guidance_end: this.getGuidanceStrengthEnd(index),
|
| 53 |
+
guessmode: null,
|
| 54 |
+
}
|
| 55 |
+
return controlnet_unit
|
| 56 |
+
}
|
| 57 |
+
static setUnit(index, unit_settings) {
|
| 58 |
+
const controlnet_unit_setters = {
|
| 59 |
+
module: this.setModule,
|
| 60 |
+
model: this.setModel,
|
| 61 |
+
weight: this.setWeight,
|
| 62 |
+
resize_mode: null,
|
| 63 |
+
lowvram: null,
|
| 64 |
+
processor_res: null,
|
| 65 |
+
threshold_a: null,
|
| 66 |
+
threshold_b: null,
|
| 67 |
+
|
| 68 |
+
guidance_start: this.setGuidanceStrengthStart,
|
| 69 |
+
guidance_end: this.setGuidanceStrengthEnd,
|
| 70 |
+
guessmode: null,
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
for (const [name, value] of Object.entries(unit_settings)) {
|
| 74 |
+
try {
|
| 75 |
+
if (
|
| 76 |
+
controlnet_unit_setters.hasOwnProperty(name)
|
| 77 |
+
//&& value.toString() // check if it has a value, null return error; undefine return error; 0 pass
|
| 78 |
+
) {
|
| 79 |
+
// if (value) {
|
| 80 |
+
const setter = controlnet_unit_setters[name]
|
| 81 |
+
|
| 82 |
+
setter(index, value)
|
| 83 |
+
// }
|
| 84 |
+
}
|
| 85 |
+
} catch (e) {
|
| 86 |
+
console.warn(e)
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
static getUnits() {
|
| 91 |
+
const controlnet_units = {}
|
| 92 |
+
|
| 93 |
+
for (let i = 0; i < g_controlnet_max_models; ++i) {
|
| 94 |
+
controlnet_units[i] = this.getUnit(i)
|
| 95 |
+
}
|
| 96 |
+
return controlnet_units
|
| 97 |
+
}
|
| 98 |
+
static setUnits(controlnet_units) {
|
| 99 |
+
for (const [index, unit] of Object.entries(controlnet_units)) {
|
| 100 |
+
try {
|
| 101 |
+
this.setUnit(index, unit)
|
| 102 |
+
} catch (e) {
|
| 103 |
+
console.warn(e)
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
static doesUnitExist(index) {
|
| 108 |
+
//TODO: check if controlnet unit exist
|
| 109 |
+
if (index >= 0) {
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
static getModule(index) {
|
| 114 |
+
const module = getSelectedModule(index)
|
| 115 |
+
return module
|
| 116 |
+
}
|
| 117 |
+
static setModule(index, module_item) {
|
| 118 |
+
try {
|
| 119 |
+
const module_menu_element = controlnetElement(
|
| 120 |
+
index,
|
| 121 |
+
'.mModulesMenuControlNet_'
|
| 122 |
+
)
|
| 123 |
+
|
| 124 |
+
html_manip.selectMenuItemByElement(module_menu_element, module_item)
|
| 125 |
+
// module_menu_element.dispatchEvent(new Event('click'))
|
| 126 |
+
// module_menu_element.click()
|
| 127 |
+
changeModule(module_item, index)
|
| 128 |
+
} catch (e) {
|
| 129 |
+
html_manip.unselectMenuItemByElement(module_menu_element)
|
| 130 |
+
console.warn(e)
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
static getModel(index) {
|
| 134 |
+
const model = getSelectedModel(index)
|
| 135 |
+
return model
|
| 136 |
+
}
|
| 137 |
+
static setModel(index, model_item) {
|
| 138 |
+
try {
|
| 139 |
+
const model_menu_element = controlnetElement(
|
| 140 |
+
index,
|
| 141 |
+
'.mModelsMenuControlNet_'
|
| 142 |
+
)
|
| 143 |
+
html_manip.selectMenuItemByElement(model_menu_element, model_item)
|
| 144 |
+
} catch (e) {
|
| 145 |
+
html_manip.unselectMenuItemByElement(model_menu_element)
|
| 146 |
+
console.warn(e)
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
static getWeight(index = 0) {
|
| 150 |
+
const weight = getWeight(index)
|
| 151 |
+
return weight
|
| 152 |
+
}
|
| 153 |
+
static setWeight(index, weight) {
|
| 154 |
+
setWeight(index, weight)
|
| 155 |
+
}
|
| 156 |
+
static getGuidanceStrengthStart(index) {
|
| 157 |
+
const guidance_strength = getControlNetGuidanceStrengthStart(index)
|
| 158 |
+
return guidance_strength
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
static setGuidanceStrengthStart(index, sd_value) {
|
| 162 |
+
setControlNetGuidanceStrengthStart(index, sd_value)
|
| 163 |
+
}
|
| 164 |
+
static getGuidanceStrengthEnd(index) {
|
| 165 |
+
const guidance_strength = getControlNetGuidanceStrengthEnd(index)
|
| 166 |
+
return guidance_strength
|
| 167 |
+
}
|
| 168 |
+
static setGuidanceStrengthEnd(index, sd_value) {
|
| 169 |
+
setControlNetGuidanceStrengthEnd(index, sd_value)
|
| 170 |
+
}
|
| 171 |
+
static getProcessorRes(index) {
|
| 172 |
+
const slider = controlnetElement(index, '.slControlNetProcessorRes_')
|
| 173 |
+
|
| 174 |
+
return slider.value
|
| 175 |
+
}
|
| 176 |
+
static setProcessorRes(index, sd_value) {
|
| 177 |
+
const slider = controlnetElement(index, '.slControlNetProcessorRes_')
|
| 178 |
+
slider.value = sd_value
|
| 179 |
+
}
|
| 180 |
+
static getThreshold(index, a_or_b) {
|
| 181 |
+
let slider
|
| 182 |
+
if (a_or_b === 'a') {
|
| 183 |
+
slider = controlnetElement(index, '.slControlNetThreshold_A_')
|
| 184 |
+
} else if (a_or_b === 'b') {
|
| 185 |
+
slider = controlnetElement(index, '.slControlNetThreshold_B_')
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
const sd_value = general.mapRange(
|
| 189 |
+
slider.value,
|
| 190 |
+
slider.min,
|
| 191 |
+
slider.max,
|
| 192 |
+
slider.dataset['sd_min'],
|
| 193 |
+
slider.dataset['sd_max']
|
| 194 |
+
)
|
| 195 |
+
return sd_value
|
| 196 |
+
}
|
| 197 |
+
static setThreshold(index, a_or_b, sd_value) {
|
| 198 |
+
let slider
|
| 199 |
+
let label
|
| 200 |
+
if (a_or_b === 'a') {
|
| 201 |
+
slider = controlnetElement(index, '.slControlNetThreshold_A_')
|
| 202 |
+
label = controlnetElement(index, '.lControlNetThreshold_A_')
|
| 203 |
+
} else if (a_or_b === 'b') {
|
| 204 |
+
slider = controlnetElement(index, '.slControlNetThreshold_B_')
|
| 205 |
+
label = controlnetElement(index, '.lControlNetThreshold_B_')
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
const slider_value = general.mapRange(
|
| 209 |
+
sd_value,
|
| 210 |
+
slider.dataset['sd_min'],
|
| 211 |
+
slider.dataset['sd_max'],
|
| 212 |
+
slider.min,
|
| 213 |
+
slider.max
|
| 214 |
+
)
|
| 215 |
+
slider.value = String(slider_value)
|
| 216 |
+
label.innerText = String(sd_value)
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
static getControlNetUnitJson(index = 0) {}
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
async function checkIfControlNetInstalled() {}
|
| 223 |
+
|
| 224 |
+
async function requestControlNetDetectMap(
|
| 225 |
+
controlnet_init_image,
|
| 226 |
+
_module,
|
| 227 |
+
processor_res,
|
| 228 |
+
threshold_a,
|
| 229 |
+
threshold_b
|
| 230 |
+
) {
|
| 231 |
+
try {
|
| 232 |
+
const payload = {
|
| 233 |
+
controlnet_module: _module,
|
| 234 |
+
controlnet_input_images: [controlnet_init_image],
|
| 235 |
+
controlnet_processor_res: processor_res,
|
| 236 |
+
controlnet_threshold_a: threshold_a,
|
| 237 |
+
controlnet_threshold_b: threshold_b,
|
| 238 |
+
}
|
| 239 |
+
const full_url = `${g_sd_url}/controlnet/detect`
|
| 240 |
+
|
| 241 |
+
// debugger
|
| 242 |
+
|
| 243 |
+
const response_data = await api.requestPost(full_url, payload)
|
| 244 |
+
|
| 245 |
+
// update the mask preview with the new detectMap
|
| 246 |
+
if (response_data['images'].length === 0) {
|
| 247 |
+
app.showAlert(response_data['info'])
|
| 248 |
+
}
|
| 249 |
+
return response_data['images'][0]
|
| 250 |
+
} catch (e) {
|
| 251 |
+
console.warn('requestControlNetDetectMap(): ', _module, e)
|
| 252 |
+
}
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
async function requestControlNetModelList() {
|
| 256 |
+
const control_net_json = await api.requestGet(
|
| 257 |
+
`${g_sd_url}/controlnet/model_list`
|
| 258 |
+
)
|
| 259 |
+
|
| 260 |
+
const model_list = control_net_json?.model_list
|
| 261 |
+
|
| 262 |
+
// const model_list = [
|
| 263 |
+
// 'none',
|
| 264 |
+
// 'control_sd15_depth [fef5e48e]',
|
| 265 |
+
// 'control_sd15_openpose [fef5e48e]',
|
| 266 |
+
// 'control_sd15_scribble [fef5e48e]',
|
| 267 |
+
// ]
|
| 268 |
+
return model_list
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
async function requestControlNetModuleList() {
|
| 272 |
+
// const control_net_json = await api.requestGet(
|
| 273 |
+
// `${g_sd_url}/controlnet/model_list`
|
| 274 |
+
// )
|
| 275 |
+
// const module_list = [
|
| 276 |
+
// // 'none',
|
| 277 |
+
// 'canny',
|
| 278 |
+
// 'depth',
|
| 279 |
+
// 'depth_leres',
|
| 280 |
+
// 'hed',
|
| 281 |
+
// 'mlsd',
|
| 282 |
+
// 'normal_map',
|
| 283 |
+
// 'openpose',
|
| 284 |
+
// // "openpose_hand",
|
| 285 |
+
// 'pidinet',
|
| 286 |
+
// 'scribble',
|
| 287 |
+
// 'fake_scribble',
|
| 288 |
+
// 'segmentation',
|
| 289 |
+
// ]
|
| 290 |
+
|
| 291 |
+
// const module_list = g_sd_config_obj.getControlNetPreprocessors()
|
| 292 |
+
|
| 293 |
+
const result = await api.requestGet(
|
| 294 |
+
`${g_sd_url}/controlnet/module_list?alias_names=1`
|
| 295 |
+
)
|
| 296 |
+
|
| 297 |
+
return result?.module_list
|
| 298 |
+
}
|
| 299 |
+
async function populateModelMenu() {
|
| 300 |
+
try {
|
| 301 |
+
const models = await requestControlNetModelList()
|
| 302 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
| 303 |
+
const menu_element = controlnetElement(
|
| 304 |
+
index,
|
| 305 |
+
'.mModelsMenuControlNet_'
|
| 306 |
+
)
|
| 307 |
+
html_manip.populateMenuByElement(
|
| 308 |
+
menu_element,
|
| 309 |
+
'mModelsMenuItemControlNet_',
|
| 310 |
+
models,
|
| 311 |
+
(item, item_html_element) => {
|
| 312 |
+
item_html_element.innerHTML = item
|
| 313 |
+
item_html_element.dataset['index'] = index
|
| 314 |
+
},
|
| 315 |
+
false,
|
| 316 |
+
'Select Model'
|
| 317 |
+
)
|
| 318 |
+
}
|
| 319 |
+
} catch (e) {
|
| 320 |
+
console.warn(e)
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
function changeModule(_module, index) {
|
| 325 |
+
// const index = index
|
| 326 |
+
|
| 327 |
+
const preprocessor_res_element = controlnetElement(
|
| 328 |
+
index,
|
| 329 |
+
'.slControlNetProcessorRes_'
|
| 330 |
+
)
|
| 331 |
+
|
| 332 |
+
const threshold_a_element = controlnetElement(
|
| 333 |
+
index,
|
| 334 |
+
'.slControlNetThreshold_A_'
|
| 335 |
+
)
|
| 336 |
+
const threshold_b_element = controlnetElement(
|
| 337 |
+
index,
|
| 338 |
+
'.slControlNetThreshold_B_'
|
| 339 |
+
)
|
| 340 |
+
|
| 341 |
+
const detail = g_module_detail[_module]
|
| 342 |
+
|
| 343 |
+
function remapArray(arr) {
|
| 344 |
+
let obj = {
|
| 345 |
+
preprocessor_res: arr[0] || null,
|
| 346 |
+
threshold_a: arr[1] || null,
|
| 347 |
+
threshold_b: arr[2] || null,
|
| 348 |
+
}
|
| 349 |
+
return obj
|
| 350 |
+
}
|
| 351 |
+
const params = remapArray(detail['sliders'])
|
| 352 |
+
const model_free = detail.model_free
|
| 353 |
+
|
| 354 |
+
// threshold_a_element.min = prams.
|
| 355 |
+
// threshold_a_element.max =
|
| 356 |
+
// debugger
|
| 357 |
+
if (model_free)
|
| 358 |
+
controlnetElement(
|
| 359 |
+
index,
|
| 360 |
+
'.mModelsMenuControlNet_'
|
| 361 |
+
).parentElement.style.display = 'none'
|
| 362 |
+
|
| 363 |
+
else
|
| 364 |
+
controlnetElement(
|
| 365 |
+
index,
|
| 366 |
+
'.mModelsMenuControlNet_'
|
| 367 |
+
).parentElement.style.display = 'block'
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
if (params?.preprocessor_res) {
|
| 371 |
+
const preprocessor_res_label_element = controlnetElement(
|
| 372 |
+
index,
|
| 373 |
+
'.labelControlNetProcessorRes_'
|
| 374 |
+
)
|
| 375 |
+
preprocessor_res_element.style.display = 'block'
|
| 376 |
+
preprocessor_res_label_element.innerText = params.preprocessor_res.name
|
| 377 |
+
} else {
|
| 378 |
+
preprocessor_res_element.style.display = 'none'
|
| 379 |
+
}
|
| 380 |
+
if (params?.threshold_a) {
|
| 381 |
+
const threshold_a_label_element = controlnetElement(
|
| 382 |
+
index,
|
| 383 |
+
'.labelControlNetThreshold_A_'
|
| 384 |
+
)
|
| 385 |
+
|
| 386 |
+
threshold_a_element.dataset['sd_min'] = params.threshold_a.min
|
| 387 |
+
threshold_a_element.dataset['sd_max'] = params.threshold_a.max
|
| 388 |
+
ControlNetUnit.setThreshold(index, 'a', params.threshold_a.value)
|
| 389 |
+
threshold_a_element.style.display = 'block'
|
| 390 |
+
threshold_a_label_element.innerText = params.threshold_a.name + ":"
|
| 391 |
+
} else {
|
| 392 |
+
ControlNetUnit.setThreshold(index, 'a', 32)
|
| 393 |
+
threshold_a_element.style.display = 'none'
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
if (params?.threshold_b) {
|
| 397 |
+
const threshold_b_label_element = controlnetElement(
|
| 398 |
+
index,
|
| 399 |
+
'.labelControlNetThreshold_B_'
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
threshold_b_element.dataset['sd_min'] = params.threshold_b.min
|
| 403 |
+
threshold_b_element.dataset['sd_max'] = params.threshold_b.max
|
| 404 |
+
ControlNetUnit.setThreshold(index, 'b', params.threshold_b.value)
|
| 405 |
+
threshold_b_element.style.display = 'block'
|
| 406 |
+
threshold_b_label_element.innerText = params.threshold_b.name + ":"
|
| 407 |
+
} else {
|
| 408 |
+
ControlNetUnit.setThreshold(index, 'b', 32)
|
| 409 |
+
threshold_b_element.style.display = 'none'
|
| 410 |
+
}
|
| 411 |
+
}
|
| 412 |
+
async function populatePreprocessorMenu() {
|
| 413 |
+
try {
|
| 414 |
+
// debugger
|
| 415 |
+
const modules = await requestControlNetModuleList()
|
| 416 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
| 417 |
+
const menu_element = controlnetElement(
|
| 418 |
+
index,
|
| 419 |
+
'.mModulesMenuControlNet_'
|
| 420 |
+
)
|
| 421 |
+
|
| 422 |
+
menu_element.dataset['index'] = String(index)
|
| 423 |
+
html_manip.populateMenuByElement(
|
| 424 |
+
menu_element,
|
| 425 |
+
'mModuleMenuItemControlNet_',
|
| 426 |
+
modules,
|
| 427 |
+
(item, item_html_element) => {
|
| 428 |
+
item_html_element.innerHTML = item
|
| 429 |
+
item_html_element.dataset['index'] = index
|
| 430 |
+
},
|
| 431 |
+
false,
|
| 432 |
+
'Select Module'
|
| 433 |
+
)
|
| 434 |
+
|
| 435 |
+
menu_element.addEventListener('click', (event) => {
|
| 436 |
+
changeModule(
|
| 437 |
+
event.target.innerText,
|
| 438 |
+
event.target.dataset['index']
|
| 439 |
+
)
|
| 440 |
+
})
|
| 441 |
+
}
|
| 442 |
+
} catch (e) {
|
| 443 |
+
console.warn(e)
|
| 444 |
+
}
|
| 445 |
+
}
|
| 446 |
+
function controlnetElement(index, class_) {
|
| 447 |
+
const element = document.querySelector(
|
| 448 |
+
`#controlnet_settings_${index} ${class_}`
|
| 449 |
+
)
|
| 450 |
+
return element
|
| 451 |
+
}
|
| 452 |
+
function getControlNetGuidanceStrengthStart(index) {
|
| 453 |
+
const slider_element = document.querySelector(
|
| 454 |
+
`#controlnet_settings_${index} .slControlNetGuidanceStrengthStart_`
|
| 455 |
+
)
|
| 456 |
+
const sd_value = html_manip.getSliderSdValueByElement(
|
| 457 |
+
slider_element,
|
| 458 |
+
0,
|
| 459 |
+
100,
|
| 460 |
+
0,
|
| 461 |
+
1
|
| 462 |
+
)
|
| 463 |
+
return sd_value
|
| 464 |
+
}
|
| 465 |
+
function setControlNetGuidanceStrengthStart(index, sd_value) {
|
| 466 |
+
const slider_element = controlnetElement(
|
| 467 |
+
index,
|
| 468 |
+
'.slControlNetGuidanceStrengthStart_'
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
const label_element = controlnetElement(
|
| 472 |
+
index,
|
| 473 |
+
'.lControlNetGuidanceStrengthStart_'
|
| 474 |
+
)
|
| 475 |
+
html_manip.setSliderSdValueByElements(
|
| 476 |
+
slider_element,
|
| 477 |
+
label_element,
|
| 478 |
+
sd_value,
|
| 479 |
+
0,
|
| 480 |
+
100,
|
| 481 |
+
0,
|
| 482 |
+
1
|
| 483 |
+
)
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
+
function getControlNetGuidanceStrengthEnd(index) {
|
| 487 |
+
const slider_element = controlnetElement(
|
| 488 |
+
index,
|
| 489 |
+
'.slControlNetGuidanceStrengthEnd_'
|
| 490 |
+
)
|
| 491 |
+
const sd_value = html_manip.getSliderSdValueByElement(
|
| 492 |
+
slider_element,
|
| 493 |
+
0,
|
| 494 |
+
100,
|
| 495 |
+
0,
|
| 496 |
+
1
|
| 497 |
+
)
|
| 498 |
+
return sd_value
|
| 499 |
+
}
|
| 500 |
+
function setControlNetGuidanceStrengthEnd(index, sd_value) {
|
| 501 |
+
const slider_element = controlnetElement(
|
| 502 |
+
index,
|
| 503 |
+
'.slControlNetGuidanceStrengthEnd_'
|
| 504 |
+
)
|
| 505 |
+
|
| 506 |
+
const label_element = controlnetElement(
|
| 507 |
+
index,
|
| 508 |
+
'.lControlNetGuidanceStrengthEnd_'
|
| 509 |
+
)
|
| 510 |
+
html_manip.setSliderSdValueByElements(
|
| 511 |
+
slider_element,
|
| 512 |
+
label_element,
|
| 513 |
+
sd_value,
|
| 514 |
+
0,
|
| 515 |
+
100,
|
| 516 |
+
0,
|
| 517 |
+
1
|
| 518 |
+
)
|
| 519 |
+
}
|
| 520 |
+
|
| 521 |
+
// controlnet settings getters
|
| 522 |
+
function getControlNetWeightGuidanceStrengthStart(index = 0) {
|
| 523 |
+
const slider_element = controlnetElement(
|
| 524 |
+
index,
|
| 525 |
+
'.slControlNetGuidanceStrengthStart_'
|
| 526 |
+
)
|
| 527 |
+
const slider_value = slider_element.value
|
| 528 |
+
const sd_value = general.mapRange(slider_value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 529 |
+
return sd_value
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
function getControlNetWeightGuidanceStrengthEnd(index = 0) {
|
| 533 |
+
const slider_value = controlnetElement(
|
| 534 |
+
index,
|
| 535 |
+
'.slControlNetGuidanceStrengthEnd_'
|
| 536 |
+
).value
|
| 537 |
+
|
| 538 |
+
const sd_value = general.mapRange(slider_value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 539 |
+
return sd_value
|
| 540 |
+
}
|
| 541 |
+
|
| 542 |
+
function getWeight(index = 0) {
|
| 543 |
+
const slider_value = document.querySelector(
|
| 544 |
+
`#controlnet_settings_${index} .slControlNetWeight_`
|
| 545 |
+
).value
|
| 546 |
+
|
| 547 |
+
const sd_value = general.mapRange(slider_value, 0, 100, 0, 2) // convert slider value to SD ready value
|
| 548 |
+
return sd_value
|
| 549 |
+
}
|
| 550 |
+
function setWeight(index = 0, sd_weight) {
|
| 551 |
+
const slider_element = document.querySelector(
|
| 552 |
+
`#controlnet_settings_${index} .slControlNetWeight_`
|
| 553 |
+
)
|
| 554 |
+
const label_element = document.querySelector(
|
| 555 |
+
`#controlnet_settings_${index} .lControlNetWeight_`
|
| 556 |
+
)
|
| 557 |
+
|
| 558 |
+
html_manip.setSliderSdValueByElements(
|
| 559 |
+
slider_element,
|
| 560 |
+
label_element,
|
| 561 |
+
sd_weight,
|
| 562 |
+
0,
|
| 563 |
+
100,
|
| 564 |
+
0,
|
| 565 |
+
2
|
| 566 |
+
)
|
| 567 |
+
}
|
| 568 |
+
function getUseLowVram(index = 0) {
|
| 569 |
+
const b_result = document.querySelector(
|
| 570 |
+
`#controlnet_settings_${index} .chlowVram_`
|
| 571 |
+
).checked
|
| 572 |
+
return b_result
|
| 573 |
+
}
|
| 574 |
+
function getEnableControlNet(index = 0) {
|
| 575 |
+
const is_enable = document.querySelector(
|
| 576 |
+
`#controlnet_settings_${index} .chEnableControlNet_`
|
| 577 |
+
).checked
|
| 578 |
+
return is_enable
|
| 579 |
+
}
|
| 580 |
+
function setEnable(index) {
|
| 581 |
+
document.querySelector(
|
| 582 |
+
`#controlnet_settings_${index} .chEnableControlNet_`
|
| 583 |
+
).checked = b_live_update
|
| 584 |
+
}
|
| 585 |
+
function getSelectedModule(index = 0) {
|
| 586 |
+
const menu_element = controlnetElement(index, '.mModulesMenuControlNet_')
|
| 587 |
+
// debugger
|
| 588 |
+
const module_name =
|
| 589 |
+
html_manip.getSelectedMenuItemTextContentByElement(menu_element)
|
| 590 |
+
|
| 591 |
+
return module_name
|
| 592 |
+
}
|
| 593 |
+
function getSelectedModel(index = 0) {
|
| 594 |
+
const menu_element = controlnetElement(index, '.mModelsMenuControlNet_')
|
| 595 |
+
const model_name =
|
| 596 |
+
html_manip.getSelectedMenuItemTextContentByElement(menu_element)
|
| 597 |
+
return model_name
|
| 598 |
+
}
|
| 599 |
+
function getUseGuessMode(index = 0) {
|
| 600 |
+
const is_guess_mode = document.querySelector(
|
| 601 |
+
`#controlnet_settings_${index} .chGuessMode_`
|
| 602 |
+
).checked
|
| 603 |
+
|
| 604 |
+
return is_guess_mode
|
| 605 |
+
}
|
| 606 |
+
function isControlNetModeEnable() {
|
| 607 |
+
let is_tab_enabled = !document.getElementById('chDisableControlNetTab')
|
| 608 |
+
.checked
|
| 609 |
+
|
| 610 |
+
let numOfEnabled = 0
|
| 611 |
+
if (g_controlnet_max_models <= 0) {
|
| 612 |
+
return false
|
| 613 |
+
}
|
| 614 |
+
|
| 615 |
+
if (is_tab_enabled) {
|
| 616 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
| 617 |
+
if (getEnableControlNet(index)) {
|
| 618 |
+
numOfEnabled += 1
|
| 619 |
+
}
|
| 620 |
+
}
|
| 621 |
+
}
|
| 622 |
+
let is_mode_enabled = is_tab_enabled // could be true
|
| 623 |
+
if (is_tab_enabled === false || numOfEnabled === 0) {
|
| 624 |
+
is_mode_enabled = false
|
| 625 |
+
}
|
| 626 |
+
return is_mode_enabled
|
| 627 |
+
}
|
| 628 |
+
// function getControlNetMaxModelsNumber() {
|
| 629 |
+
// return g_controlnet_max_supported_models
|
| 630 |
+
// }
|
| 631 |
+
|
| 632 |
+
function preprocessorData(
|
| 633 |
+
processor_res = 512,
|
| 634 |
+
threshold_a = 64,
|
| 635 |
+
threshold_b = 64,
|
| 636 |
+
a_min = 64,
|
| 637 |
+
a_max = 1024,
|
| 638 |
+
b_min = 64,
|
| 639 |
+
b_max = 1024,
|
| 640 |
+
processor_res_label = 'Annotator resolution',
|
| 641 |
+
threshold_a_label = 'threshold a',
|
| 642 |
+
threshold_b_label = 'threshold b'
|
| 643 |
+
) {
|
| 644 |
+
return {
|
| 645 |
+
processor_res,
|
| 646 |
+
threshold_a,
|
| 647 |
+
threshold_b,
|
| 648 |
+
a_min,
|
| 649 |
+
a_max,
|
| 650 |
+
b_min,
|
| 651 |
+
b_max,
|
| 652 |
+
processor_res_label,
|
| 653 |
+
threshold_a_label,
|
| 654 |
+
threshold_b_label,
|
| 655 |
+
}
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
function mapPluginSettingsToControlNet(plugin_settings) {
|
| 659 |
+
const ps = plugin_settings // for shortness
|
| 660 |
+
let controlnet_units = []
|
| 661 |
+
|
| 662 |
+
// debugger
|
| 663 |
+
let active_index = 0
|
| 664 |
+
for (let index = 0; index < g_controlnet_max_models; index++) {
|
| 665 |
+
const preprocessor_name = getSelectedModule(index)
|
| 666 |
+
|
| 667 |
+
controlnet_units[active_index] = {
|
| 668 |
+
enabled: getEnableControlNet(index),
|
| 669 |
+
input_image: g_generation_session.controlNetImage[index],
|
| 670 |
+
mask: '',
|
| 671 |
+
module: getSelectedModule(index),
|
| 672 |
+
model: getSelectedModel(index),
|
| 673 |
+
weight: getWeight(index),
|
| 674 |
+
resize_mode: 'Scale to Fit (Inner Fit)',
|
| 675 |
+
lowvram: getUseLowVram(index),
|
| 676 |
+
processor_res: ControlNetUnit.getProcessorRes(index),
|
| 677 |
+
threshold_a: ControlNetUnit.getThreshold(index, 'a'),
|
| 678 |
+
threshold_b: ControlNetUnit.getThreshold(index, 'b'),
|
| 679 |
+
// guidance: ,
|
| 680 |
+
guidance_start: getControlNetWeightGuidanceStrengthStart(index),
|
| 681 |
+
guidance_end: getControlNetWeightGuidanceStrengthEnd(index),
|
| 682 |
+
guessmode: false,
|
| 683 |
+
}
|
| 684 |
+
active_index++
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
if (
|
| 688 |
+
plugin_settings['mode'] === Enum.generationModeEnum['Img2Img'] ||
|
| 689 |
+
plugin_settings['mode'] === Enum.generationModeEnum['Inpaint'] ||
|
| 690 |
+
plugin_settings['mode'] === Enum.generationModeEnum['Outpaint']
|
| 691 |
+
) {
|
| 692 |
+
const b_use_guess_mode = getUseGuessMode()
|
| 693 |
+
controlnet_units[0]['guessmode'] = b_use_guess_mode
|
| 694 |
+
}
|
| 695 |
+
|
| 696 |
+
const controlnet_payload = {
|
| 697 |
+
...ps,
|
| 698 |
+
controlnet_units, //keep for backward compatibility for now
|
| 699 |
+
subseed: -1,
|
| 700 |
+
override_settings: {},
|
| 701 |
+
override_settings_restore_afterwards: true,
|
| 702 |
+
alwayson_scripts: {
|
| 703 |
+
controlnet: {
|
| 704 |
+
args: controlnet_units,
|
| 705 |
+
},
|
| 706 |
+
},
|
| 707 |
+
}
|
| 708 |
+
|
| 709 |
+
return controlnet_payload
|
| 710 |
+
}
|
| 711 |
+
function refreshControlNetTab() {}
|
| 712 |
+
|
| 713 |
+
async function populateControlNetPresetMenu() {
|
| 714 |
+
// const default_preset_name = 'Select CtrlNet Preset'
|
| 715 |
+
// const default_preset_settings = {} // empty preset
|
| 716 |
+
|
| 717 |
+
const custom_presets = await preset.getAllCustomPresetsSettings(
|
| 718 |
+
Enum.PresetTypeEnum['ControlNetPreset']
|
| 719 |
+
)
|
| 720 |
+
g_controlnet_presets = {
|
| 721 |
+
'Select CtrlNet Preset': {},
|
| 722 |
+
...controlnet_preset.ControlNetNativePresets,
|
| 723 |
+
...custom_presets,
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
const presets_names = Object.keys(g_controlnet_presets)
|
| 727 |
+
|
| 728 |
+
html_manip.populateMenu(
|
| 729 |
+
'mControlNetPresetMenu',
|
| 730 |
+
'mControlNetPresetMenuItem',
|
| 731 |
+
presets_names,
|
| 732 |
+
(preset_name, item_html_element) => {
|
| 733 |
+
item_html_element.innerHTML = preset_name
|
| 734 |
+
}
|
| 735 |
+
)
|
| 736 |
+
html_manip.selectMenuItem('mControlNetPresetMenu', 'Select CtrlNet Preset')
|
| 737 |
+
}
|
| 738 |
+
|
| 739 |
+
document
|
| 740 |
+
.getElementById('mControlNetPresetMenu')
|
| 741 |
+
.addEventListener('change', async (evt) => {
|
| 742 |
+
try {
|
| 743 |
+
ControlNetUnit.resetUnits()
|
| 744 |
+
const preset_index = evt.target.selectedIndex
|
| 745 |
+
const preset_name = evt.target.options[preset_index].textContent
|
| 746 |
+
units_settings = g_controlnet_presets[preset_name]
|
| 747 |
+
|
| 748 |
+
ControlNetUnit.setUnits(units_settings)
|
| 749 |
+
} catch (e) {
|
| 750 |
+
console.warn(e)
|
| 751 |
+
}
|
| 752 |
+
})
|
| 753 |
+
|
| 754 |
+
document
|
| 755 |
+
.getElementById('bSetAllControlImage')
|
| 756 |
+
.addEventListener('click', async () => {
|
| 757 |
+
const selectionInfo = await selection.Selection.getSelectionInfoExe()
|
| 758 |
+
if (selectionInfo) {
|
| 759 |
+
const base64_image =
|
| 760 |
+
await g_generation_session.setControlNetImageHelper()
|
| 761 |
+
|
| 762 |
+
for (index = 0; index < g_controlnet_max_models; index++) {
|
| 763 |
+
await g_generation_session.setControlNetImage(
|
| 764 |
+
index,
|
| 765 |
+
base64_image
|
| 766 |
+
)
|
| 767 |
+
}
|
| 768 |
+
} else {
|
| 769 |
+
await note.Notification.inactiveSelectionArea()
|
| 770 |
+
}
|
| 771 |
+
})
|
| 772 |
+
|
| 773 |
+
function initControlNetUnitsEventListeners(controlnet_max_models) {
|
| 774 |
+
for (let index = 0; index < controlnet_max_models; index++) {
|
| 775 |
+
//event listeners
|
| 776 |
+
controlnetElement(
|
| 777 |
+
index,
|
| 778 |
+
'.slControlNetGuidanceStrengthStart_'
|
| 779 |
+
).addEventListener('input', (evt) => {
|
| 780 |
+
// debugger
|
| 781 |
+
const sd_value = general.mapRange(evt.target.value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 782 |
+
controlnetElement(
|
| 783 |
+
index,
|
| 784 |
+
'.lControlNetGuidanceStrengthStart_'
|
| 785 |
+
).textContent = Number(sd_value).toFixed(2)
|
| 786 |
+
})
|
| 787 |
+
|
| 788 |
+
controlnetElement(
|
| 789 |
+
index,
|
| 790 |
+
'.slControlNetGuidanceStrengthEnd_'
|
| 791 |
+
).addEventListener('input', (evt) => {
|
| 792 |
+
// debugger
|
| 793 |
+
const sd_value = general.mapRange(evt.target.value, 0, 100, 0, 1) // convert slider value to SD ready value
|
| 794 |
+
controlnetElement(
|
| 795 |
+
index,
|
| 796 |
+
'.lControlNetGuidanceStrengthEnd_'
|
| 797 |
+
).textContent = Number(sd_value).toFixed(2)
|
| 798 |
+
})
|
| 799 |
+
|
| 800 |
+
document
|
| 801 |
+
.querySelector(`#controlnet_settings_${index} .slControlNetWeight_`)
|
| 802 |
+
.addEventListener('input', (evt) => {
|
| 803 |
+
// debugger
|
| 804 |
+
const sd_value = general.mapRange(
|
| 805 |
+
evt.target.value,
|
| 806 |
+
0,
|
| 807 |
+
100,
|
| 808 |
+
0,
|
| 809 |
+
2
|
| 810 |
+
) // convert slider value to SD ready value
|
| 811 |
+
document.querySelector(
|
| 812 |
+
`#controlnet_settings_${index} .lControlNetWeight_`
|
| 813 |
+
).textContent = Number(sd_value).toFixed(2)
|
| 814 |
+
})
|
| 815 |
+
|
| 816 |
+
// controlnetElement(index, '.slControlNetProcessorRes_').addEventListener(
|
| 817 |
+
// 'input',
|
| 818 |
+
// (evt) => {
|
| 819 |
+
// // debugger
|
| 820 |
+
// const sd_value = general.mapRange(
|
| 821 |
+
// evt.target.value,
|
| 822 |
+
// 64,
|
| 823 |
+
// 2048,
|
| 824 |
+
// 64,
|
| 825 |
+
// 2048
|
| 826 |
+
// ) // convert slider value to SD ready value
|
| 827 |
+
// controlnetElement(index, '.lControlNetProcessorRes_').textContent =
|
| 828 |
+
// Number(sd_value).toFixed(2)
|
| 829 |
+
// }
|
| 830 |
+
// )
|
| 831 |
+
controlnetElement(index, '.slControlNetThreshold_A_').addEventListener(
|
| 832 |
+
'input',
|
| 833 |
+
(event) => {
|
| 834 |
+
const slider = event.target
|
| 835 |
+
const sd_value = Number(
|
| 836 |
+
general
|
| 837 |
+
.mapRange(
|
| 838 |
+
slider.value,
|
| 839 |
+
slider.min,
|
| 840 |
+
slider.max,
|
| 841 |
+
slider.dataset['sd_min'],
|
| 842 |
+
slider.dataset['sd_max']
|
| 843 |
+
)
|
| 844 |
+
.toFixed(2)
|
| 845 |
+
)
|
| 846 |
+
controlnetElement(index, '.lControlNetThreshold_A_').innerText =
|
| 847 |
+
String(sd_value)
|
| 848 |
+
// ControlNetUnit.setThreshold(index, 'a', sd_value)
|
| 849 |
+
// controlnetElement(index, '.lControlNetThreshold_A_').value =
|
| 850 |
+
// sd_value
|
| 851 |
+
}
|
| 852 |
+
)
|
| 853 |
+
controlnetElement(index, '.slControlNetThreshold_B_').addEventListener(
|
| 854 |
+
'input',
|
| 855 |
+
(event) => {
|
| 856 |
+
const slider = event.target
|
| 857 |
+
const sd_value = Number(
|
| 858 |
+
general
|
| 859 |
+
.mapRange(
|
| 860 |
+
slider.value,
|
| 861 |
+
slider.min,
|
| 862 |
+
slider.max,
|
| 863 |
+
slider.dataset['sd_min'],
|
| 864 |
+
slider.dataset['sd_max']
|
| 865 |
+
)
|
| 866 |
+
.toFixed(2)
|
| 867 |
+
)
|
| 868 |
+
controlnetElement(index, '.lControlNetThreshold_B_').innerText =
|
| 869 |
+
String(sd_value)
|
| 870 |
+
// ControlNetUnit.setThreshold(index, 'a', sd_value)
|
| 871 |
+
// controlnetElement(index, '.lControlNetThreshold_A_').value =
|
| 872 |
+
// sd_value
|
| 873 |
+
}
|
| 874 |
+
)
|
| 875 |
+
document
|
| 876 |
+
.querySelector(`#controlnet_settings_${index} .bSetControlImage_`)
|
| 877 |
+
.addEventListener('click', async () => {
|
| 878 |
+
const selectionInfo =
|
| 879 |
+
await selection.Selection.getSelectionInfoExe()
|
| 880 |
+
if (selectionInfo) {
|
| 881 |
+
// debugger
|
| 882 |
+
const base64_image =
|
| 883 |
+
await g_generation_session.setControlNetImageHelper()
|
| 884 |
+
await g_generation_session.setControlNetImage(
|
| 885 |
+
index,
|
| 886 |
+
base64_image
|
| 887 |
+
)
|
| 888 |
+
} else {
|
| 889 |
+
await note.Notification.inactiveSelectionArea()
|
| 890 |
+
}
|
| 891 |
+
})
|
| 892 |
+
|
| 893 |
+
document
|
| 894 |
+
.querySelector(`#controlnet_settings_${index} .bControlMask_`)
|
| 895 |
+
.addEventListener('click', async () => {
|
| 896 |
+
await previewAnnotator(index)
|
| 897 |
+
})
|
| 898 |
+
}
|
| 899 |
+
}
|
| 900 |
+
document
|
| 901 |
+
.getElementById('mControlNetPresetMenu')
|
| 902 |
+
.addEventListener('updatePresetMenuEvent', async (event) => {
|
| 903 |
+
// console.log("I'm listening on a custom event")
|
| 904 |
+
await populateControlNetPresetMenu()
|
| 905 |
+
})
|
| 906 |
+
|
| 907 |
+
async function previewAnnotator(index) {
|
| 908 |
+
try {
|
| 909 |
+
const controlnet_init_image =
|
| 910 |
+
g_generation_session.controlNetImage[index]
|
| 911 |
+
const _module = ControlNetUnit.getModule(index)
|
| 912 |
+
const processor_res = ControlNetUnit.getProcessorRes(index)
|
| 913 |
+
const threshold_a = ControlNetUnit.getThreshold(index, 'a')
|
| 914 |
+
const threshold_b = ControlNetUnit.getThreshold(index, 'b')
|
| 915 |
+
if (!controlnet_init_image) {
|
| 916 |
+
const error = 'ControlNet initial image is empty'
|
| 917 |
+
app.showAlert(error)
|
| 918 |
+
throw error
|
| 919 |
+
}
|
| 920 |
+
if (!_module || _module === 'none') {
|
| 921 |
+
const error = 'select a valid controlnet module (preprocessor)'
|
| 922 |
+
app.showAlert(error)
|
| 923 |
+
throw error
|
| 924 |
+
}
|
| 925 |
+
|
| 926 |
+
const detect_map = await requestControlNetDetectMap(
|
| 927 |
+
controlnet_init_image,
|
| 928 |
+
_module,
|
| 929 |
+
processor_res,
|
| 930 |
+
threshold_a,
|
| 931 |
+
threshold_b
|
| 932 |
+
)
|
| 933 |
+
|
| 934 |
+
const rgb_detect_map_url =
|
| 935 |
+
await io.convertBlackAndWhiteImageToRGBChannels3(detect_map)
|
| 936 |
+
const rgb_detect_map = general.base64UrlToBase64(rgb_detect_map_url)
|
| 937 |
+
g_generation_session.controlNetMask[index] = rgb_detect_map
|
| 938 |
+
|
| 939 |
+
html_manip.setControlMaskSrc(rgb_detect_map_url, index)
|
| 940 |
+
} catch (e) {
|
| 941 |
+
console.warn('PreviewAnnotator click(): index: ', index, e)
|
| 942 |
+
}
|
| 943 |
+
}
|
| 944 |
+
async function previewAnnotatorFromCanvas(index) {
|
| 945 |
+
try {
|
| 946 |
+
const _module = ControlNetUnit.getModule(index)
|
| 947 |
+
|
| 948 |
+
const width = html_manip.getWidth()
|
| 949 |
+
const height = html_manip.getHeight()
|
| 950 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 951 |
+
g_generation_session.control_net_preview_selection_info = selectionInfo
|
| 952 |
+
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
| 953 |
+
width,
|
| 954 |
+
height,
|
| 955 |
+
selectionInfo,
|
| 956 |
+
true
|
| 957 |
+
)
|
| 958 |
+
|
| 959 |
+
if (!_module || _module === 'none') {
|
| 960 |
+
const error = 'select a valid controlnet module (preprocessor)'
|
| 961 |
+
app.showAlert(error)
|
| 962 |
+
throw error
|
| 963 |
+
}
|
| 964 |
+
|
| 965 |
+
const processor_res = ControlNetUnit.getProcessorRes(index)
|
| 966 |
+
const threshold_a = ControlNetUnit.getThreshold(index, 'a')
|
| 967 |
+
const threshold_b = ControlNetUnit.getThreshold(index, 'b')
|
| 968 |
+
|
| 969 |
+
const detect_map = await requestControlNetDetectMap(
|
| 970 |
+
base64,
|
| 971 |
+
_module,
|
| 972 |
+
processor_res,
|
| 973 |
+
threshold_a,
|
| 974 |
+
threshold_b
|
| 975 |
+
)
|
| 976 |
+
|
| 977 |
+
const rgb_detect_map_url =
|
| 978 |
+
await io.convertBlackAndWhiteImageToRGBChannels3(detect_map)
|
| 979 |
+
g_generation_session.controlNetMask[index] = detect_map
|
| 980 |
+
html_manip.setControlMaskSrc(rgb_detect_map_url, index)
|
| 981 |
+
} catch (e) {
|
| 982 |
+
console.warn('PreviewAnnotator click(): index: ', index, e)
|
| 983 |
+
}
|
| 984 |
+
}
|
| 985 |
+
// document
|
| 986 |
+
// .getElementById('bPreviewAnnotator_0')
|
| 987 |
+
// .addEventListener('click', async (event) => {
|
| 988 |
+
// const index = parseInt(event.target.dataset['controlnet-index'])
|
| 989 |
+
// await previewAnnotator(index)
|
| 990 |
+
// })
|
| 991 |
+
|
| 992 |
+
function initPreviewElement(index) {
|
| 993 |
+
//make init mask image use the thumbnail class with buttons
|
| 994 |
+
// const mask_image_html = document.getElementById(
|
| 995 |
+
// 'control_net_preview_image_0'
|
| 996 |
+
// )
|
| 997 |
+
|
| 998 |
+
const mask_image_html = controlnetElement(index, '.control_net_mask_')
|
| 999 |
+
const mask_parent_element = mask_image_html.parentElement
|
| 1000 |
+
|
| 1001 |
+
this.thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 1002 |
+
mask_image_html,
|
| 1003 |
+
'viewer-image-container'
|
| 1004 |
+
)
|
| 1005 |
+
|
| 1006 |
+
mask_parent_element.appendChild(thumbnail_container)
|
| 1007 |
+
|
| 1008 |
+
async function toCanvas(index) {
|
| 1009 |
+
// debugger
|
| 1010 |
+
if (
|
| 1011 |
+
g_generation_session.control_net_preview_selection_info &&
|
| 1012 |
+
g_generation_session.controlNetMask[index]
|
| 1013 |
+
) {
|
| 1014 |
+
const selection_info =
|
| 1015 |
+
g_generation_session.control_net_preview_selection_info
|
| 1016 |
+
const layer = await io.IO.base64ToLayer(
|
| 1017 |
+
g_generation_session.controlNetMask[index],
|
| 1018 |
+
'ControlNet Mask.png',
|
| 1019 |
+
selection_info.left,
|
| 1020 |
+
selection_info.top,
|
| 1021 |
+
selection_info.width,
|
| 1022 |
+
selection_info.height
|
| 1023 |
+
)
|
| 1024 |
+
} else {
|
| 1025 |
+
// await note.Notification.inactiveSelectionArea()
|
| 1026 |
+
app.showAlert('Mask Image is not available')
|
| 1027 |
+
}
|
| 1028 |
+
}
|
| 1029 |
+
async function toControlNetInitImage(index) {
|
| 1030 |
+
const preview_result_base64 = g_generation_session.controlNetMask[index]
|
| 1031 |
+
g_generation_session.controlNetImage[index] = preview_result_base64
|
| 1032 |
+
g_generation_session.control_net_selection_info =
|
| 1033 |
+
g_generation_session.control_net_preview_selection_info
|
| 1034 |
+
|
| 1035 |
+
const rgb_detect_map_url =
|
| 1036 |
+
await io.convertBlackAndWhiteImageToRGBChannels3(
|
| 1037 |
+
preview_result_base64
|
| 1038 |
+
)
|
| 1039 |
+
|
| 1040 |
+
// g_generation_session.controlNetMask[index] = rgb_detect_map
|
| 1041 |
+
|
| 1042 |
+
html_manip.setControlImageSrc(rgb_detect_map_url, index)
|
| 1043 |
+
}
|
| 1044 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 1045 |
+
this.thumbnail_container,
|
| 1046 |
+
'svg_sp_btn',
|
| 1047 |
+
'use as ControlNet init image',
|
| 1048 |
+
|
| 1049 |
+
toControlNetInitImage,
|
| 1050 |
+
index
|
| 1051 |
+
)
|
| 1052 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 1053 |
+
this.thumbnail_container,
|
| 1054 |
+
'svg_sp_btn_canvas',
|
| 1055 |
+
'move to the canvas',
|
| 1056 |
+
|
| 1057 |
+
toCanvas,
|
| 1058 |
+
index
|
| 1059 |
+
)
|
| 1060 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 1061 |
+
this.thumbnail_container,
|
| 1062 |
+
'svg_sp_btn_preview',
|
| 1063 |
+
'preview selection from canvas',
|
| 1064 |
+
|
| 1065 |
+
previewAnnotatorFromCanvas,
|
| 1066 |
+
index
|
| 1067 |
+
)
|
| 1068 |
+
}
|
| 1069 |
+
|
| 1070 |
+
function initControlNetUnit(index) {
|
| 1071 |
+
document.querySelector(
|
| 1072 |
+
`#controlnet_settings_${index} .controlnet_unit_label_`
|
| 1073 |
+
).textContent = `Control Net Settings Slot ${index}`
|
| 1074 |
+
}
|
| 1075 |
+
async function initializeControlNetTab(controlnet_max_models) {
|
| 1076 |
+
try {
|
| 1077 |
+
if (controlnet_max_models <= 0) {
|
| 1078 |
+
document.getElementById('controlnetMissingError').style.display =
|
| 1079 |
+
'block'
|
| 1080 |
+
|
| 1081 |
+
return
|
| 1082 |
+
}
|
| 1083 |
+
document.getElementById('controlnetMissingError').style.display = 'none'
|
| 1084 |
+
// if (controlnet_max_models > g_controlnet_max_models)
|
| 1085 |
+
// controlnet_max_models = g_controlnet_max_models
|
| 1086 |
+
|
| 1087 |
+
await populateControlNetPresetMenu()
|
| 1088 |
+
const parent_container = document.getElementById(
|
| 1089 |
+
'controlnet_parent_container'
|
| 1090 |
+
)
|
| 1091 |
+
parent_container.innerHTML = ''
|
| 1092 |
+
const controlnet_unit_template = document.getElementById(
|
| 1093 |
+
'controlnet_settings_template'
|
| 1094 |
+
)
|
| 1095 |
+
|
| 1096 |
+
for (let index = 0; index < controlnet_max_models; index++) {
|
| 1097 |
+
const controlnet_unit = controlnet_unit_template.cloneNode(true)
|
| 1098 |
+
controlnet_unit.id = 'controlnet_settings_' + index
|
| 1099 |
+
controlnet_unit.dataset['index'] = String(index)
|
| 1100 |
+
parent_container.appendChild(controlnet_unit)
|
| 1101 |
+
}
|
| 1102 |
+
|
| 1103 |
+
const full_url = `${g_sd_url}/controlnet/module_list?alias_names=1`
|
| 1104 |
+
let result_json = await api.requestGet(full_url)
|
| 1105 |
+
g_module_detail = result_json['module_detail']
|
| 1106 |
+
|
| 1107 |
+
initControlNetUnitsEventListeners(controlnet_max_models) // add event listener to all units after cloning
|
| 1108 |
+
|
| 1109 |
+
for (let index = 0; index < controlnet_max_models; index++) {
|
| 1110 |
+
await populateModelMenu(index)
|
| 1111 |
+
await populatePreprocessorMenu(index)
|
| 1112 |
+
document.getElementById(
|
| 1113 |
+
'controlnet_settings_' + index
|
| 1114 |
+
).style.display = 'block'
|
| 1115 |
+
initPreviewElement(index)
|
| 1116 |
+
|
| 1117 |
+
initControlNetUnit(index)
|
| 1118 |
+
}
|
| 1119 |
+
} catch (e) {
|
| 1120 |
+
console.warn(e)
|
| 1121 |
+
}
|
| 1122 |
+
}
|
| 1123 |
+
|
| 1124 |
+
module.exports = {
|
| 1125 |
+
requestControlNetModelList,
|
| 1126 |
+
populateModelMenu,
|
| 1127 |
+
initializeControlNetTab,
|
| 1128 |
+
getWeight,
|
| 1129 |
+
mapPluginSettingsToControlNet,
|
| 1130 |
+
getEnableControlNet,
|
| 1131 |
+
getSelectedModule,
|
| 1132 |
+
getSelectedModel,
|
| 1133 |
+
// getControlNetMaxModelsNumber,
|
| 1134 |
+
getControlNetGuidanceStrengthStart,
|
| 1135 |
+
setControlNetGuidanceStrengthStart,
|
| 1136 |
+
getControlNetGuidanceStrengthEnd,
|
| 1137 |
+
setControlNetGuidanceStrengthEnd,
|
| 1138 |
+
ControlNetUnit,
|
| 1139 |
+
populateControlNetPresetMenu,
|
| 1140 |
+
isControlNetModeEnable,
|
| 1141 |
+
getModuleDetail() {
|
| 1142 |
+
return g_module_detail
|
| 1143 |
+
}
|
| 1144 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/history_tab.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const settings_tab = require('./settings')
|
| 2 |
+
const sdapi = require('../../sdapi_py_re')
|
| 3 |
+
const thumbnail = require('../../thumbnail')
|
| 4 |
+
|
| 5 |
+
//REFACTORED: moved to history_tab.js
|
| 6 |
+
function getHistoryMetadata(img) {
|
| 7 |
+
//auto fill the ui with metadata
|
| 8 |
+
const metadata_json = JSON.parse(img.dataset.metadata_json_string)
|
| 9 |
+
console.log('metadata_json: ', metadata_json)
|
| 10 |
+
// document.querySelector('#tiSeed').value = metadata_json.Seed
|
| 11 |
+
|
| 12 |
+
//extract auto_metadata into the preset metadata
|
| 13 |
+
function convertAutoMetadataToPresset(metadata_json) {
|
| 14 |
+
metadata_json['seed'] = metadata_json?.auto_metadata?.Seed
|
| 15 |
+
}
|
| 16 |
+
convertAutoMetadataToPresset(metadata_json)
|
| 17 |
+
|
| 18 |
+
const b_use_original_prompt = settings_tab.getUseOriginalPrompt()
|
| 19 |
+
if (b_use_original_prompt) {
|
| 20 |
+
metadata_json['prompt'] = metadata_json?.original_prompt
|
| 21 |
+
? metadata_json['original_prompt']
|
| 22 |
+
: metadata_json['prompt']
|
| 23 |
+
|
| 24 |
+
metadata_json['negative_prompt'] =
|
| 25 |
+
metadata_json?.original_negative_prompt
|
| 26 |
+
? metadata_json['original_negative_prompt']
|
| 27 |
+
: metadata_json['negative_prompt']
|
| 28 |
+
}
|
| 29 |
+
document.querySelector('#historySeedLabel').textContent =
|
| 30 |
+
metadata_json?.seed
|
| 31 |
+
|
| 32 |
+
g_ui_settings_object.autoFillInSettings(metadata_json)
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
document
|
| 36 |
+
.getElementById('btnLoadHistory')
|
| 37 |
+
.addEventListener('click', async function () {
|
| 38 |
+
try {
|
| 39 |
+
const output_dir_relative = './server/python_server/'
|
| 40 |
+
const container = document.getElementById(
|
| 41 |
+
'divHistoryImagesContainer'
|
| 42 |
+
)
|
| 43 |
+
const uniqueDocumentId = await getUniqueDocumentId()
|
| 44 |
+
const [image_paths, metadata_jsons, base64_images] =
|
| 45 |
+
await sdapi.loadHistory(uniqueDocumentId)
|
| 46 |
+
|
| 47 |
+
while (container.firstChild) {
|
| 48 |
+
container.removeChild(container.firstChild)
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
const length = image_paths.length
|
| 52 |
+
// let i = length -1
|
| 53 |
+
|
| 54 |
+
// for (image_path of image_paths) {
|
| 55 |
+
for (let i = length - 1; i >= 0; --i) {
|
| 56 |
+
const img = document.createElement('img')
|
| 57 |
+
// img.src = `${output_dir_relative}/${image_path}`
|
| 58 |
+
const image_src = `data:image/png;base64, ${base64_images[i]}`
|
| 59 |
+
img.src = image_src
|
| 60 |
+
|
| 61 |
+
img.dataset.path = `${output_dir_relative}/${image_paths[i]}`
|
| 62 |
+
img.className = 'history-image'
|
| 63 |
+
img.dataset.metadata_json_string = JSON.stringify(
|
| 64 |
+
metadata_jsons[i]
|
| 65 |
+
)
|
| 66 |
+
console.log(`metadata_jsons[${i}]: `, metadata_jsons[i])
|
| 67 |
+
|
| 68 |
+
const img_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 69 |
+
img,
|
| 70 |
+
'viewer-image-container'
|
| 71 |
+
)
|
| 72 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 73 |
+
img_container,
|
| 74 |
+
'svg_sp_btn',
|
| 75 |
+
'copy metadata to settings',
|
| 76 |
+
history_tab.getHistoryMetadata,
|
| 77 |
+
img
|
| 78 |
+
)
|
| 79 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 80 |
+
img_container,
|
| 81 |
+
'svg_sp_btn_datadownload',
|
| 82 |
+
'place the image on the canvas',
|
| 83 |
+
moveHistoryImageToLayer,
|
| 84 |
+
img
|
| 85 |
+
)
|
| 86 |
+
container.appendChild(img_container)
|
| 87 |
+
// i++
|
| 88 |
+
}
|
| 89 |
+
} catch (e) {
|
| 90 |
+
console.warn(`loadHistory warning: ${e}`)
|
| 91 |
+
}
|
| 92 |
+
})
|
| 93 |
+
document
|
| 94 |
+
.getElementById('btnClearHistoryCache')
|
| 95 |
+
.addEventListener('click', () => {
|
| 96 |
+
const container = document.getElementById('divHistoryImagesContainer')
|
| 97 |
+
container.innerHTML = ''
|
| 98 |
+
})
|
| 99 |
+
module.exports = {
|
| 100 |
+
getHistoryMetadata,
|
| 101 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/image_search_tab.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const sdapi = require('../../sdapi_py_re')
|
| 2 |
+
|
| 3 |
+
const storage = require('uxp').storage
|
| 4 |
+
const fs = storage.localFileSystem
|
| 5 |
+
|
| 6 |
+
//REFACTOR: move to events.js
|
| 7 |
+
document
|
| 8 |
+
.getElementById('btnImageSearch')
|
| 9 |
+
.addEventListener('click', async function () {
|
| 10 |
+
try {
|
| 11 |
+
// const output_dir_relative = "./server/python_server/"
|
| 12 |
+
const container = document.getElementById(
|
| 13 |
+
'divImageSearchImagesContainer'
|
| 14 |
+
)
|
| 15 |
+
// const uniqueDocumentId = await getUniqueDocumentId()
|
| 16 |
+
// const [image_paths, metadata_jsons] = await sdapi.loadHistory(uniqueDocumentId)
|
| 17 |
+
const keywords = document.getElementById('imageSearchField').value
|
| 18 |
+
const image_search_objs = await sdapi.imageSearch(keywords)
|
| 19 |
+
while (container.firstChild) {
|
| 20 |
+
container.removeChild(container.firstChild)
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
// let i = 0
|
| 24 |
+
const temp_entry = await fs.getTemporaryFolder()
|
| 25 |
+
for (let image_search_obj of image_search_objs) {
|
| 26 |
+
const img = document.createElement('img')
|
| 27 |
+
// img.src = image_search_obj['image']
|
| 28 |
+
|
| 29 |
+
img.src = image_search_obj['thumbnail']
|
| 30 |
+
|
| 31 |
+
img.className = 'image-search'
|
| 32 |
+
// img.dataset.metadata_json_string = JSON.stringify(metadata_jsons[i])
|
| 33 |
+
container.appendChild(img)
|
| 34 |
+
img.addEventListener('click', async (e) => {
|
| 35 |
+
console.log(`the image url: ${img.src}`)
|
| 36 |
+
const link = img.src
|
| 37 |
+
const image_file_name = 'search_image_temp.png'
|
| 38 |
+
await io.IO.urlToLayer(link, image_file_name)
|
| 39 |
+
// await downloadItExe(link, temp_entry, image_file_name)
|
| 40 |
+
|
| 41 |
+
// const metadata_json = JSON.parse(e.target.dataset.metadata_json_string)
|
| 42 |
+
// console.log("metadata_json: ",metadata_json)
|
| 43 |
+
// document.querySelector('#tiSeed').value = metadata_json.Seed
|
| 44 |
+
// document.querySelector('#historySeedLabel').textContent = metadata_json.Seed
|
| 45 |
+
})
|
| 46 |
+
// i++
|
| 47 |
+
}
|
| 48 |
+
} catch (e) {
|
| 49 |
+
console.warn(`imageSearch warning: ${e}`)
|
| 50 |
+
}
|
| 51 |
+
})
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/lexica_tab.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const thumbnail = require('../../thumbnail')
|
| 2 |
+
const api = require('../api')
|
| 3 |
+
const io = require('../io')
|
| 4 |
+
const html_manip = require('../html_manip')
|
| 5 |
+
|
| 6 |
+
class Lexica {
|
| 7 |
+
constructor(items = []) {
|
| 8 |
+
//items is json object return from lexica request
|
| 9 |
+
this.items = items
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
delete() {
|
| 13 |
+
this.items = []
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
async function requestHostedUrl(base64) {
|
| 18 |
+
try {
|
| 19 |
+
const payload = {
|
| 20 |
+
key: '6d207e02198a847aa98d0a2a901485a5',
|
| 21 |
+
source: base64,
|
| 22 |
+
}
|
| 23 |
+
const url = 'https://freeimage.host/api/1/upload'
|
| 24 |
+
|
| 25 |
+
const result_json = await api.requestFormDataPost(url, payload)
|
| 26 |
+
|
| 27 |
+
const image_url = result_json.image.url
|
| 28 |
+
return image_url
|
| 29 |
+
} catch (e) {
|
| 30 |
+
console.warn(e)
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
async function requestLexica(search_query) {
|
| 35 |
+
const lexica_url = `https://lexica.art/api/v1/search?q=${search_query}`
|
| 36 |
+
const url_encoded = encodeURI(lexica_url)
|
| 37 |
+
result = await api.requestGet(url_encoded)
|
| 38 |
+
console.log('result:', result)
|
| 39 |
+
return result
|
| 40 |
+
}
|
| 41 |
+
function displayAllLexicaImages(lexica_items) {
|
| 42 |
+
const lexicaMasterImageContainer = document.getElementById(
|
| 43 |
+
'divLexicaImagesContainer'
|
| 44 |
+
)
|
| 45 |
+
lexicaMasterImageContainer.innerHTML = ''
|
| 46 |
+
for (item of lexica_items) {
|
| 47 |
+
displayLexicaImage(item)
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
function displayLexicaImage(lexica_item) {
|
| 51 |
+
// let lexica_item = {
|
| 52 |
+
// id: '0482ee68-0368-4eca-8846-5930db866b33',
|
| 53 |
+
// gallery: 'https://lexica.art?q=0482ee68-0368-4eca-8846-5930db866b33',
|
| 54 |
+
// src: 'https://lexica-serve-encoded-images.sharif.workers.dev/md/0482ee68-0368-4eca-8846-5930db866b33',
|
| 55 |
+
// srcSmall:
|
| 56 |
+
// 'https://lexica-serve-encoded-images.sharif.workers.dev/sm/0482ee68-0368-4eca-8846-5930db866b33',
|
| 57 |
+
// prompt: 'cute chubby blue fruits icons for mobile game ui ',
|
| 58 |
+
// width: 512,
|
| 59 |
+
// height: 512,
|
| 60 |
+
// seed: '1413536227',
|
| 61 |
+
// grid: false,
|
| 62 |
+
// model: 'stable-diffusion',
|
| 63 |
+
// guidance: 7,
|
| 64 |
+
// promptid: 'd9868972-dad8-477d-8e5a-4a0ae1e9b72b',
|
| 65 |
+
// nsfw: false,
|
| 66 |
+
// }
|
| 67 |
+
|
| 68 |
+
const lexicaMasterImageContainer = document.getElementById(
|
| 69 |
+
'divLexicaImagesContainer'
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
img_html = document.createElement('img')
|
| 73 |
+
img_html.classList.add('viewer-image')
|
| 74 |
+
img_html.src = lexica_item.srcSmall
|
| 75 |
+
img_html.style.width = '100px'
|
| 76 |
+
const thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 77 |
+
img_html,
|
| 78 |
+
'viewer-image-container'
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
async function loadOnCanvas(lexica_item) {
|
| 82 |
+
// lexica_item.
|
| 83 |
+
try {
|
| 84 |
+
const link = lexica_item.src
|
| 85 |
+
const image_file_name = 'lexica_image.png'
|
| 86 |
+
await io.IO.urlToLayer(link, image_file_name)
|
| 87 |
+
} catch (e) {
|
| 88 |
+
console.warn('loadOnCanvas(): ', lexica_item, e)
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
async function loadSettingsToUI(lexica_item) {
|
| 92 |
+
try {
|
| 93 |
+
const settings = {
|
| 94 |
+
prompt: lexica_item.prompt,
|
| 95 |
+
width: lexica_item.width,
|
| 96 |
+
height: lexica_item.height,
|
| 97 |
+
seed: lexica_item.seed,
|
| 98 |
+
cfg_scale: lexica_item.guidance,
|
| 99 |
+
}
|
| 100 |
+
g_ui_settings_object.autoFillInSettings(settings)
|
| 101 |
+
} catch (e) {
|
| 102 |
+
console.warn(e)
|
| 103 |
+
}
|
| 104 |
+
}
|
| 105 |
+
async function searchForSimilarImage(lexica_item) {
|
| 106 |
+
try {
|
| 107 |
+
document.getElementById('LexicaSearchField').value = lexica_item.src
|
| 108 |
+
const result_json = await requestLexica(lexica_item.src)
|
| 109 |
+
|
| 110 |
+
const lexica_items = result_json.images
|
| 111 |
+
|
| 112 |
+
displayAllLexicaImages(lexica_items)
|
| 113 |
+
} catch (e) {
|
| 114 |
+
console.warn(e)
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 118 |
+
thumbnail_container,
|
| 119 |
+
'svg_sp_btn_canvas',
|
| 120 |
+
'Load on Canvas',
|
| 121 |
+
loadOnCanvas,
|
| 122 |
+
lexica_item
|
| 123 |
+
)
|
| 124 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 125 |
+
thumbnail_container,
|
| 126 |
+
'svg_sp_btn',
|
| 127 |
+
'load settings',
|
| 128 |
+
loadSettingsToUI,
|
| 129 |
+
lexica_item
|
| 130 |
+
)
|
| 131 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 132 |
+
thumbnail_container,
|
| 133 |
+
'svg_sp_btn_search',
|
| 134 |
+
'Search for Similar Image',
|
| 135 |
+
searchForSimilarImage,
|
| 136 |
+
lexica_item
|
| 137 |
+
)
|
| 138 |
+
thumbnail_container.addEventListener('click', () => {
|
| 139 |
+
setLexicaPromptValue(lexica_item.prompt)
|
| 140 |
+
// taLexicaPrompt.style.position = 'fixed'
|
| 141 |
+
const originalPosition = taLexicaPrompt.offsetTop
|
| 142 |
+
const currentPosition = document.querySelector('body > div').scrollTop
|
| 143 |
+
|
| 144 |
+
const isScrolledPast = currentPosition > originalPosition
|
| 145 |
+
|
| 146 |
+
if (isScrolledPast) {
|
| 147 |
+
taLexicaPrompt.style.position = 'fixed'
|
| 148 |
+
} else {
|
| 149 |
+
taLexicaPrompt.style.position = 'static'
|
| 150 |
+
}
|
| 151 |
+
})
|
| 152 |
+
|
| 153 |
+
lexicaMasterImageContainer.appendChild(thumbnail_container)
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
const taLexicaPrompt = document.querySelector('#lexicaPrompt')
|
| 157 |
+
function setLexicaPromptValue(input) {
|
| 158 |
+
taLexicaPrompt.value = input
|
| 159 |
+
}
|
| 160 |
+
function getLexicaPromptValue() {
|
| 161 |
+
return taLexicaPrompt.value
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
document
|
| 165 |
+
.getElementById('btnSearchLexica')
|
| 166 |
+
.addEventListener('click', async () => {
|
| 167 |
+
const search_query = document.getElementById('LexicaSearchField').value
|
| 168 |
+
const result_json = await requestLexica(search_query)
|
| 169 |
+
|
| 170 |
+
const lexica_items = result_json.images
|
| 171 |
+
const lexica_obj = getLexicaObject()
|
| 172 |
+
lexica_obj.items = lexica_items
|
| 173 |
+
displayAllLexicaImages(lexica_items)
|
| 174 |
+
})
|
| 175 |
+
|
| 176 |
+
document
|
| 177 |
+
.getElementById('btnReverseSearchLexica')
|
| 178 |
+
.addEventListener('click', async () => {
|
| 179 |
+
//*) check if selection is valid
|
| 180 |
+
//*) get base64 from selection
|
| 181 |
+
//*) request global url from base64
|
| 182 |
+
//*) request Lexica search
|
| 183 |
+
|
| 184 |
+
try {
|
| 185 |
+
const width = html_manip.getWidth()
|
| 186 |
+
const height = html_manip.getHeight()
|
| 187 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 188 |
+
|
| 189 |
+
const base64 =
|
| 190 |
+
await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
| 191 |
+
width,
|
| 192 |
+
height,
|
| 193 |
+
selectionInfo,
|
| 194 |
+
true
|
| 195 |
+
)
|
| 196 |
+
const hosted_url = await requestHostedUrl(base64)
|
| 197 |
+
|
| 198 |
+
const result_json = await requestLexica(hosted_url)
|
| 199 |
+
|
| 200 |
+
const lexica_items = result_json.images
|
| 201 |
+
|
| 202 |
+
displayAllLexicaImages(lexica_items)
|
| 203 |
+
} catch (e) {
|
| 204 |
+
console.warn(e)
|
| 205 |
+
}
|
| 206 |
+
})
|
| 207 |
+
|
| 208 |
+
const windowEventListener = document
|
| 209 |
+
.querySelector('body > div')
|
| 210 |
+
.addEventListener('scroll', () => {
|
| 211 |
+
const originalPosition = taLexicaPrompt.offsetTop
|
| 212 |
+
const currentPosition = document.querySelector('body > div').scrollTop
|
| 213 |
+
taLexicaPrompt.style.position = 'static'
|
| 214 |
+
// const isScrolledPast = currentPosition > originalPosition
|
| 215 |
+
|
| 216 |
+
// if (isScrolledPast) {
|
| 217 |
+
// taLexicaPrompt.style.position = 'fixed'
|
| 218 |
+
// } else {
|
| 219 |
+
// taLexicaPrompt.style.position = 'static'
|
| 220 |
+
// }
|
| 221 |
+
})
|
| 222 |
+
|
| 223 |
+
const g_lexica_obj = new Lexica()
|
| 224 |
+
|
| 225 |
+
function getLexicaObject() {
|
| 226 |
+
return g_lexica_obj
|
| 227 |
+
}
|
| 228 |
+
function setLexicaObject(lexica_obj) {
|
| 229 |
+
g_lexica_obj = lexica_obj
|
| 230 |
+
}
|
| 231 |
+
module.exports = {
|
| 232 |
+
requestLexica,
|
| 233 |
+
displayLexicaImage,
|
| 234 |
+
displayAllLexicaImages,
|
| 235 |
+
requestHostedUrl,
|
| 236 |
+
Lexica,
|
| 237 |
+
getLexicaObject,
|
| 238 |
+
setLexicaObject,
|
| 239 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/sd.js
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const general = require('../general')
|
| 2 |
+
const thumbnail = require('../../thumbnail')
|
| 3 |
+
const html_manip = require('../html_manip')
|
| 4 |
+
const api = require('../api')
|
| 5 |
+
const psapi = require('../../psapi')
|
| 6 |
+
const sdapi = require('../../sdapi_py_re')
|
| 7 |
+
const Enum = require('../../enum')
|
| 8 |
+
//REFACTOR: move to notification.js
|
| 9 |
+
async function promptForUpdate(header_message, long_message) {
|
| 10 |
+
const shell = require('uxp').shell
|
| 11 |
+
|
| 12 |
+
;(async () => {
|
| 13 |
+
const buttons = ['Cancel', 'OK']
|
| 14 |
+
const r1 = await dialog_box.prompt(
|
| 15 |
+
header_message,
|
| 16 |
+
long_message,
|
| 17 |
+
buttons
|
| 18 |
+
// 'Please Update you Plugin. it will take about 10 seconds to update',
|
| 19 |
+
// 'update from discord, update from github'[
|
| 20 |
+
// ['Cancel', 'Discord', 'Github']
|
| 21 |
+
// ('Cancel', 'OK')
|
| 22 |
+
// ]
|
| 23 |
+
)
|
| 24 |
+
try {
|
| 25 |
+
let url
|
| 26 |
+
if (r1 === 'Cancel') {
|
| 27 |
+
/* cancelled or No */
|
| 28 |
+
console.log('cancel')
|
| 29 |
+
} else if (r1 === 'Github') {
|
| 30 |
+
url =
|
| 31 |
+
'https://github.com/AbdullahAlfaraj/Auto-Photoshop-StableDiffusion-Plugin'
|
| 32 |
+
// await py_re.openUrlRequest(url)
|
| 33 |
+
} else if (r1 === 'Discord') {
|
| 34 |
+
console.log('Discord')
|
| 35 |
+
// url = 'https://discord.gg/3mVEtrddXJ'
|
| 36 |
+
// url = 'https://discord.gg/YkUJXYWK3c'
|
| 37 |
+
// await py_re.openUrlRequest(url)
|
| 38 |
+
} else if (r1 === 'Ok') {
|
| 39 |
+
}
|
| 40 |
+
// console.log('url: ', url)
|
| 41 |
+
} catch (e) {
|
| 42 |
+
console.warn(e, url)
|
| 43 |
+
}
|
| 44 |
+
})()
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
async function updateClickEventHandler(current_version) {
|
| 48 |
+
try {
|
| 49 |
+
const online_data = await general.requestOnlineData()
|
| 50 |
+
const b_need_update = general.compareVersions(
|
| 51 |
+
current_version,
|
| 52 |
+
online_data.new_version
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
let header_message = "You're Plugin is up to date."
|
| 56 |
+
let long_message = ''
|
| 57 |
+
if (b_need_update) {
|
| 58 |
+
header_message = `New Version is Available (${online_data.new_version})`
|
| 59 |
+
long_message = online_data.update_message
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
await promptForUpdate(header_message, long_message)
|
| 63 |
+
} catch (e) {
|
| 64 |
+
console.warn(e)
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
function viewMaskExpansion() {
|
| 69 |
+
if (g_generation_session.base64maskExpansionImage) {
|
| 70 |
+
const mask_src = general.base64ToBase64Url(
|
| 71 |
+
g_generation_session.base64maskExpansionImage
|
| 72 |
+
)
|
| 73 |
+
html_manip.setInitImageMaskSrc(mask_src)
|
| 74 |
+
} else {
|
| 75 |
+
console.log(
|
| 76 |
+
'the mask has not been expanded, g_generation_session.base64maskExpansionImage is empty'
|
| 77 |
+
)
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
function viewDrawnMask() {
|
| 81 |
+
//this is the generated mask or user drawn mask, but it's not the mask after expansion
|
| 82 |
+
if (g_generation_session.activeBase64MaskImage) {
|
| 83 |
+
const mask_src = general.base64ToBase64Url(
|
| 84 |
+
g_generation_session.activeBase64MaskImage
|
| 85 |
+
)
|
| 86 |
+
html_manip.setInitImageMaskSrc(mask_src)
|
| 87 |
+
} else {
|
| 88 |
+
console.log('no mask is available')
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
async function clipInterrogate() {
|
| 93 |
+
try {
|
| 94 |
+
const width = html_manip.getWidth()
|
| 95 |
+
const height = html_manip.getHeight()
|
| 96 |
+
const selectionInfo = await psapi.getSelectionInfoExe()
|
| 97 |
+
|
| 98 |
+
const base64 = await io.IO.getSelectionFromCanvasAsBase64Interface_New(
|
| 99 |
+
width,
|
| 100 |
+
height,
|
| 101 |
+
selectionInfo,
|
| 102 |
+
true
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
const url = `${g_sd_url}/sdapi/v1/interrogate`
|
| 106 |
+
|
| 107 |
+
const payload = {
|
| 108 |
+
image: base64,
|
| 109 |
+
model: 'clip',
|
| 110 |
+
}
|
| 111 |
+
const result_json = await api.requestPost(url, payload)
|
| 112 |
+
console.log(result_json)
|
| 113 |
+
return result_json
|
| 114 |
+
} catch (e) {
|
| 115 |
+
console.warn(e)
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
function getHrScaleSliderSDValue() {
|
| 120 |
+
sd_value = html_manip.getSliderSdValue('hrScaleSlider', 1, 100, 1, 4)
|
| 121 |
+
return sd_value
|
| 122 |
+
}
|
| 123 |
+
function setHrScaleSliderSDValue(sd_value) {
|
| 124 |
+
const slider_id = 'hrScaleSlider'
|
| 125 |
+
const label_id = 'hrScaleLabel'
|
| 126 |
+
html_manip.setSliderSdValue(slider_id, label_id, sd_value, 1, 100, 1, 4)
|
| 127 |
+
}
|
| 128 |
+
function getImageCfgScaleSDValue() {
|
| 129 |
+
sd_value = html_manip.getSliderSdValue('slImageCfgScale', 0, 30, 0, 3)
|
| 130 |
+
return sd_value
|
| 131 |
+
}
|
| 132 |
+
function setImageCfgScaleSDValue(sd_value) {
|
| 133 |
+
const slider_id = 'slImageCfgScale'
|
| 134 |
+
const label_id = 'lImageCfgScale'
|
| 135 |
+
// debugger
|
| 136 |
+
html_manip.setSliderSdValue(slider_id, label_id, sd_value, 0, 30, 0, 3)
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
function updateHrScaleFromToLabel() {
|
| 140 |
+
//get width and height
|
| 141 |
+
//get hr scale by
|
| 142 |
+
//find the hr scale and height
|
| 143 |
+
|
| 144 |
+
const hr_scale = getHrScaleSliderSDValue()
|
| 145 |
+
const [width, height] = [html_manip.getWidth(), html_manip.getHeight()]
|
| 146 |
+
const [hr_width, hr_height] = [
|
| 147 |
+
parseInt(width * hr_scale),
|
| 148 |
+
parseInt(height * hr_scale),
|
| 149 |
+
]
|
| 150 |
+
document.getElementById(
|
| 151 |
+
'lHrScaleFromTo'
|
| 152 |
+
).textContent = `${width}x${height} -> ${hr_width}x${hr_height}`
|
| 153 |
+
}
|
| 154 |
+
function getLoraModelPrompt(lora_model_name) {
|
| 155 |
+
return `<lora:${lora_model_name}:1>`
|
| 156 |
+
}
|
| 157 |
+
async function populateLoraModelMenu() {
|
| 158 |
+
try {
|
| 159 |
+
const lora_models_json = await sdapi.requestLoraModels()
|
| 160 |
+
const lora_models_names = Object.keys(lora_models_json)
|
| 161 |
+
|
| 162 |
+
document.getElementById('mLoraModelMenu').innerHTML = ''
|
| 163 |
+
|
| 164 |
+
html_manip.populateMenu(
|
| 165 |
+
'mLoraModelMenu',
|
| 166 |
+
'mLoraModelItemClass',
|
| 167 |
+
lora_models_names,
|
| 168 |
+
(item, item_html_element) => {
|
| 169 |
+
item_html_element.innerHTML = item
|
| 170 |
+
item_html_element.onclick = () => {
|
| 171 |
+
const lora_prompt = getLoraModelPrompt(item)
|
| 172 |
+
const prompt = html_manip.getPrompt()
|
| 173 |
+
html_manip.autoFillInPrompt(`${prompt} ${lora_prompt}`)
|
| 174 |
+
}
|
| 175 |
+
},
|
| 176 |
+
false,
|
| 177 |
+
'Select Lora'
|
| 178 |
+
)
|
| 179 |
+
} catch (e) {
|
| 180 |
+
console.warn('populateLoraModelMenu error: ', e)
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
function displayImageCfgScaleSlider(mode) {
|
| 185 |
+
const b_slider_enabled = document.getElementById(
|
| 186 |
+
'chUseImageCfgScaleSlider'
|
| 187 |
+
).checked
|
| 188 |
+
if (b_slider_enabled) {
|
| 189 |
+
if (mode === Enum.generationModeEnum['Txt2Img']) {
|
| 190 |
+
document.getElementById('slImageCfgScale').style.display = 'none'
|
| 191 |
+
} else if (mode === Enum.generationModeEnum['Img2Img']) {
|
| 192 |
+
document.getElementById('slImageCfgScale').style.display = 'block'
|
| 193 |
+
} else if (mode === Enum.generationModeEnum['Inpaint']) {
|
| 194 |
+
document.getElementById('slImageCfgScale').style.display = 'block'
|
| 195 |
+
} else if (mode === Enum.generationModeEnum['Outpaint']) {
|
| 196 |
+
document.getElementById('slImageCfgScale').style.display = 'none'
|
| 197 |
+
} else {
|
| 198 |
+
document.getElementById('slImageCfgScale').style.display = 'none'
|
| 199 |
+
}
|
| 200 |
+
} else {
|
| 201 |
+
document.getElementById('slImageCfgScale').style.display = 'none'
|
| 202 |
+
}
|
| 203 |
+
}
|
| 204 |
+
function initInitMaskElement() {
|
| 205 |
+
//make init mask image use the thumbnail class with buttons
|
| 206 |
+
const mask_image_html = html_manip.getInitImageMaskElement()
|
| 207 |
+
const mask_parent_element = mask_image_html.parentElement
|
| 208 |
+
|
| 209 |
+
this.thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 210 |
+
mask_image_html,
|
| 211 |
+
'viewer-image-container'
|
| 212 |
+
)
|
| 213 |
+
mask_parent_element.appendChild(thumbnail_container)
|
| 214 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 215 |
+
this.thumbnail_container,
|
| 216 |
+
'svg_sp_btn',
|
| 217 |
+
'view original mask',
|
| 218 |
+
|
| 219 |
+
viewDrawnMask,
|
| 220 |
+
null
|
| 221 |
+
)
|
| 222 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 223 |
+
this.thumbnail_container,
|
| 224 |
+
'svg_sp_btn_expand',
|
| 225 |
+
'view modified mask',
|
| 226 |
+
|
| 227 |
+
viewMaskExpansion,
|
| 228 |
+
null
|
| 229 |
+
)
|
| 230 |
+
populateLoraModelMenu() // no need for await
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
async function refreshSDTab() {
|
| 234 |
+
populateLoraModelMenu()
|
| 235 |
+
}
|
| 236 |
+
document.getElementById('hrScaleSlider').addEventListener('input', (evt) => {
|
| 237 |
+
const sd_value = getHrScaleSliderSDValue()
|
| 238 |
+
setHrScaleSliderSDValue(sd_value.toFixed(2))
|
| 239 |
+
updateHrScaleFromToLabel()
|
| 240 |
+
})
|
| 241 |
+
document.getElementById('btnUpdate').addEventListener('click', async () => {
|
| 242 |
+
await updateClickEventHandler(g_version)
|
| 243 |
+
})
|
| 244 |
+
|
| 245 |
+
document
|
| 246 |
+
.getElementById('slMaskExpansion')
|
| 247 |
+
.addEventListener('change', async (evt) => {
|
| 248 |
+
document.getElementById('slMaskExpansion')
|
| 249 |
+
const original_mask = g_generation_session.activeBase64MaskImage
|
| 250 |
+
if (original_mask) {
|
| 251 |
+
//only if mask is available
|
| 252 |
+
// use blurry and expanded mask
|
| 253 |
+
const iterations = evt.target.value
|
| 254 |
+
const modified_mask = await py_re.maskExpansionRequest(
|
| 255 |
+
original_mask,
|
| 256 |
+
iterations
|
| 257 |
+
)
|
| 258 |
+
if (modified_mask) {
|
| 259 |
+
g_generation_session.base64maskExpansionImage = modified_mask
|
| 260 |
+
viewMaskExpansion()
|
| 261 |
+
}
|
| 262 |
+
}
|
| 263 |
+
})
|
| 264 |
+
|
| 265 |
+
document
|
| 266 |
+
.getElementById('btnInterrogate')
|
| 267 |
+
.addEventListener('click', async () => {
|
| 268 |
+
// start sudo timer after 1 seconds delay
|
| 269 |
+
setTimeout(() => {
|
| 270 |
+
g_generation_session.sudo_timer_id =
|
| 271 |
+
general.sudoTimer('Interrogate')
|
| 272 |
+
}, 1000)
|
| 273 |
+
const interrogate_result = await clipInterrogate()
|
| 274 |
+
|
| 275 |
+
if (interrogate_result.caption) {
|
| 276 |
+
html_manip.autoFillInPrompt(interrogate_result.caption)
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
// after the clipInterrogate finish stop the timer
|
| 280 |
+
|
| 281 |
+
html_manip.updateProgressBarsHtml(0, 'No work in progress')
|
| 282 |
+
g_generation_session.sudo_timer_id = clearInterval(
|
| 283 |
+
g_generation_session.sudo_timer_id
|
| 284 |
+
)
|
| 285 |
+
})
|
| 286 |
+
|
| 287 |
+
function ctrlBackspaceDelete(text) {
|
| 288 |
+
try {
|
| 289 |
+
let index = text.indexOf(String.fromCharCode(127))
|
| 290 |
+
let new_text = text
|
| 291 |
+
if (index >= 0) {
|
| 292 |
+
// Ctrl + Enter pressed
|
| 293 |
+
console.log('Ctrl + Enter pressed')
|
| 294 |
+
|
| 295 |
+
function ctrlBackspaceDeleteLogic(string, index) {
|
| 296 |
+
// if (index < 1) {
|
| 297 |
+
// return string
|
| 298 |
+
// }
|
| 299 |
+
// let i = index - 1
|
| 300 |
+
// while (
|
| 301 |
+
// i > 0 &&
|
| 302 |
+
// /\s/.test(string[i - 1]) === /\s/.test(string[i])
|
| 303 |
+
// ) {
|
| 304 |
+
// i--
|
| 305 |
+
// }
|
| 306 |
+
// return string.slice(0, i) + string.slice(index)
|
| 307 |
+
|
| 308 |
+
if (index < 1) {
|
| 309 |
+
return string
|
| 310 |
+
}
|
| 311 |
+
let i = index - 1
|
| 312 |
+
if (/\s/.test(string[i])) {
|
| 313 |
+
while (i > 0 && /\s/.test(string[i - 1])) {
|
| 314 |
+
i--
|
| 315 |
+
}
|
| 316 |
+
} else {
|
| 317 |
+
while (
|
| 318 |
+
i > 0 &&
|
| 319 |
+
/\s/.test(string[i - 1]) === /\s/.test(string[i])
|
| 320 |
+
) {
|
| 321 |
+
i--
|
| 322 |
+
}
|
| 323 |
+
}
|
| 324 |
+
return string.slice(0, i) + string.slice(index)
|
| 325 |
+
}
|
| 326 |
+
new_text = ctrlBackspaceDeleteLogic(text, index + 1) //+ 1 to also delete the backspace delete char
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
return new_text
|
| 330 |
+
} catch (error) {
|
| 331 |
+
console.warn(error)
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
// document.getElementById('taPrompt').addEventListener('input', (event) => {
|
| 336 |
+
// // debugger
|
| 337 |
+
// const value = event.target.value
|
| 338 |
+
// console.log('value: ', value)
|
| 339 |
+
// let index = value.indexOf(String.fromCharCode(127))
|
| 340 |
+
// console.log('index:', index)
|
| 341 |
+
// const new_text = ctrlBackspaceDelete(value)
|
| 342 |
+
// event.target.value = new_text
|
| 343 |
+
// console.log('new_text: ', new_text)
|
| 344 |
+
// })
|
| 345 |
+
function initSDTab() {
|
| 346 |
+
initInitMaskElement()
|
| 347 |
+
html_manip.sliderAddEventListener_new(
|
| 348 |
+
'slImageCfgScale',
|
| 349 |
+
'lImageCfgScale',
|
| 350 |
+
0,
|
| 351 |
+
30,
|
| 352 |
+
0,
|
| 353 |
+
3
|
| 354 |
+
)
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
initSDTab()
|
| 358 |
+
module.exports = {
|
| 359 |
+
updateClickEventHandler,
|
| 360 |
+
viewMaskExpansion,
|
| 361 |
+
viewDrawnMask,
|
| 362 |
+
clipInterrogate,
|
| 363 |
+
getHrScaleSliderSDValue,
|
| 364 |
+
getLoraModelPrompt,
|
| 365 |
+
populateLoraModelMenu,
|
| 366 |
+
getImageCfgScaleSDValue,
|
| 367 |
+
setImageCfgScaleSDValue,
|
| 368 |
+
refreshSDTab,
|
| 369 |
+
displayImageCfgScaleSlider,
|
| 370 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/settings.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const io = require('../io')
|
| 2 |
+
|
| 3 |
+
function getUseSharpMask() {
|
| 4 |
+
const isChecked = document.getElementById('chUseSharpMask').checked
|
| 5 |
+
return isChecked
|
| 6 |
+
}
|
| 7 |
+
function setUseSharpMask() {
|
| 8 |
+
console.warn('setUseSharpMask is not setup')
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
function getUseLiveProgressImage() {
|
| 12 |
+
const b_live_update = document.getElementById('chLiveProgressImage').checked
|
| 13 |
+
return b_live_update
|
| 14 |
+
}
|
| 15 |
+
function setUseLiveProgressImage(b_live_update) {
|
| 16 |
+
document.getElementById('chLiveProgressImage').checked = b_live_update
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
function getExtensionType() {
|
| 20 |
+
return [...document.getElementsByClassName('rbExtensionType')].filter(
|
| 21 |
+
(e) => e.checked == true
|
| 22 |
+
)[0].value
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
document.getElementById('btnGetDocPath').addEventListener('click', async () => {
|
| 26 |
+
const docPath = await io.IOFolder.getDocumentFolderNativePath()
|
| 27 |
+
document.getElementById('tiDocPath').value = docPath
|
| 28 |
+
|
| 29 |
+
const uuid = await getUniqueDocumentId()
|
| 30 |
+
doc_entry = await io.IOFolder.getDocFolder(uuid)
|
| 31 |
+
await shell.openPath(doc_entry.nativePath)
|
| 32 |
+
})
|
| 33 |
+
|
| 34 |
+
document.getElementById('btnSdUrl').addEventListener('click', async () => {
|
| 35 |
+
//change the sdUrl in server in proxy server
|
| 36 |
+
// console.log('you clicked btnSdUrl')
|
| 37 |
+
let new_sd_url = document.getElementById('tiSdUrl').value
|
| 38 |
+
changeSdUrl(new_sd_url)
|
| 39 |
+
})
|
| 40 |
+
|
| 41 |
+
function getSdUrlHtml() {
|
| 42 |
+
let sd_url = document.getElementById('tiSdUrl').value
|
| 43 |
+
return sd_url
|
| 44 |
+
}
|
| 45 |
+
function setSdUrlHtml(sd_url) {
|
| 46 |
+
document.getElementById('tiSdUrl').value = sd_url
|
| 47 |
+
}
|
| 48 |
+
async function changeSdUrl(sd_url) {
|
| 49 |
+
sd_url = sd_url.trim()
|
| 50 |
+
console.log('sd_url.trim(): ', sd_url)
|
| 51 |
+
|
| 52 |
+
if (sd_url.length > 0) {
|
| 53 |
+
//check if the last character of the url has "/" or '\' and remove it
|
| 54 |
+
|
| 55 |
+
last_index = sd_url.length - 1
|
| 56 |
+
|
| 57 |
+
if (sd_url[last_index] === '/' || sd_url[last_index] === '\\') {
|
| 58 |
+
sd_url = sd_url.slice(0, -1)
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
//submit the change
|
| 62 |
+
await sdapi.changeSdUrl(sd_url)
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
async function saveSettings() {
|
| 67 |
+
const settings_tab_settings = {
|
| 68 |
+
use_sharp_mask: getUseSharpMask(),
|
| 69 |
+
extension_type: getExtensionType(),
|
| 70 |
+
sd_url: getSdUrlHtml(),
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
const folder = await io.IOFolder.getSettingsFolder()
|
| 74 |
+
await io.IOJson.saveJsonToFile(
|
| 75 |
+
settings_tab_settings,
|
| 76 |
+
folder,
|
| 77 |
+
'settings_tab.json'
|
| 78 |
+
)
|
| 79 |
+
}
|
| 80 |
+
async function loadSettings() {
|
| 81 |
+
try {
|
| 82 |
+
const folder = await io.IOFolder.getSettingsFolder()
|
| 83 |
+
let settings_tab_settings = await io.IOJson.loadJsonFromFile(
|
| 84 |
+
folder,
|
| 85 |
+
'settings_tab.json'
|
| 86 |
+
)
|
| 87 |
+
setSdUrlHtml(settings_tab_settings['sd_url'])
|
| 88 |
+
await changeSdUrl(settings_tab_settings['sd_url'])
|
| 89 |
+
} catch (e) {
|
| 90 |
+
console.warn(e)
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
document.getElementById('chUseSharpMask').addEventListener('change', (ev) => {
|
| 95 |
+
const isChecked = ev.target.checked
|
| 96 |
+
if (isChecked) {
|
| 97 |
+
document.getElementById('slMaskBlur').setAttribute('disabled')
|
| 98 |
+
} else {
|
| 99 |
+
document.getElementById('slMaskBlur').removeAttribute('disabled')
|
| 100 |
+
}
|
| 101 |
+
})
|
| 102 |
+
|
| 103 |
+
document.getElementById('chUseSmartObject').addEventListener('change', (ev) => {
|
| 104 |
+
const isChecked = ev.target.checked
|
| 105 |
+
if (isChecked) {
|
| 106 |
+
g_b_use_smart_object = true
|
| 107 |
+
} else {
|
| 108 |
+
g_b_use_smart_object = false
|
| 109 |
+
}
|
| 110 |
+
})
|
| 111 |
+
|
| 112 |
+
function getUseOriginalPrompt() {
|
| 113 |
+
const b_use_original_prompt = document.getElementById(
|
| 114 |
+
'chUseOriginalPrompt'
|
| 115 |
+
).checked
|
| 116 |
+
return b_use_original_prompt
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
document
|
| 120 |
+
.getElementById('btnSaveSettingsTabs')
|
| 121 |
+
.addEventListener('click', async () => {
|
| 122 |
+
await saveSettings()
|
| 123 |
+
})
|
| 124 |
+
|
| 125 |
+
module.exports = {
|
| 126 |
+
getUseSharpMask,
|
| 127 |
+
setUseSharpMask,
|
| 128 |
+
getExtensionType,
|
| 129 |
+
getSdUrlHtml,
|
| 130 |
+
setSdUrlHtml,
|
| 131 |
+
changeSdUrl,
|
| 132 |
+
loadSettings,
|
| 133 |
+
saveSettings,
|
| 134 |
+
getUseLiveProgressImage,
|
| 135 |
+
setUseLiveProgressImage,
|
| 136 |
+
getUseOriginalPrompt,
|
| 137 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tab/share_tab.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const chLiveProgressImageElements = document.getElementsByClassName(
|
| 2 |
+
'chLiveProgressImageClass'
|
| 3 |
+
)
|
| 4 |
+
|
| 5 |
+
const default_preview_value = document.getElementById(
|
| 6 |
+
'chLiveProgressImage'
|
| 7 |
+
).checked
|
| 8 |
+
|
| 9 |
+
chLiveProgressImageElements.forEach((element) => {
|
| 10 |
+
element.checked = default_preview_value
|
| 11 |
+
element.addEventListener('click', (event) => {
|
| 12 |
+
value = element.checked
|
| 13 |
+
chLiveProgressImageElements.forEach((element) => {
|
| 14 |
+
element.checked = value
|
| 15 |
+
})
|
| 16 |
+
})
|
| 17 |
+
})
|
Auto-Photoshop-StableDiffusion-Plugin/utility/tips.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//tips that will display when you hover over a html element
|
| 2 |
+
const tips_json = {
|
| 3 |
+
snapshot: '',
|
| 4 |
+
txt2img: 'use this mode to generate images from text only',
|
| 5 |
+
img2img: 'use this mode to generate variation of an image',
|
| 6 |
+
inpaint:
|
| 7 |
+
'use this mode to generate variation of a small area of an image, while keeping the rest of the image intact',
|
| 8 |
+
outpaint:
|
| 9 |
+
'use this mode to (1) fill any missing area of an image,(2) expand an image',
|
| 10 |
+
generate: 'create',
|
| 11 |
+
discardAll: 'Delete all generated images from the canvas',
|
| 12 |
+
acceptAll: 'Keep all generated images on the canvas',
|
| 13 |
+
acceptSelected: 'Keep only the highlighted images',
|
| 14 |
+
discardSelected: 'Delete only the highlighted images',
|
| 15 |
+
modelMenu: 'select a model',
|
| 16 |
+
refresh: 'Refresh the plugin, only fixes minor issues.',
|
| 17 |
+
prompt_shortcut: 'use {keyword} form the prompts library',
|
| 18 |
+
inpaint: 'use when you need to modify an already existing part of an image',
|
| 19 |
+
img2img: 'use this mode when you want to generate variation of an image',
|
| 20 |
+
txt2img: 'use this mode to generate images based on text only',
|
| 21 |
+
batchNumber:
|
| 22 |
+
'the number of images to generate at once.The larger the number more VRAM stable diffusion will use.',
|
| 23 |
+
steps: 'how long should stable diffusion take to generate an image',
|
| 24 |
+
selection_mode_ratio:
|
| 25 |
+
'will auto fill the width and height slider to the same ratio as the selection area',
|
| 26 |
+
selection_mode_precise:
|
| 27 |
+
'auto fill width and height slider to the size as the selection area',
|
| 28 |
+
selection_mode_ignore:
|
| 29 |
+
'you will have to fill the width and height slider manually',
|
| 30 |
+
cfg_scale: 'larger value will put more emphasis on the prompt',
|
| 31 |
+
preset_menu:
|
| 32 |
+
'auto fill the plugin with smart settings, to speed up your working process.',
|
| 33 |
+
width: 'the generated image width',
|
| 34 |
+
height: 'the generated image height',
|
| 35 |
+
mask_expansion:
|
| 36 |
+
"the larger the value the more the mask will expand, '0' means use precise masking, use in combination with the mask blur",
|
| 37 |
+
mask_content_fill: '',
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
module.exports = { tips_json }
|
Auto-Photoshop-StableDiffusion-Plugin/utility/ui.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const html_manip = require('./html_manip')
|
| 2 |
+
const presets = require('./presets/preset')
|
| 3 |
+
const layer_util = require('../utility/layer')
|
| 4 |
+
const psapi = require('../psapi')
|
| 5 |
+
const Enum = require('../enum')
|
| 6 |
+
const { executeAsModal } = require('photoshop').core
|
| 7 |
+
|
| 8 |
+
class UI {
|
| 9 |
+
constructor() {}
|
| 10 |
+
|
| 11 |
+
onStartSessionUI() {
|
| 12 |
+
// will toggle the buttons needed when a generation session start
|
| 13 |
+
|
| 14 |
+
const accept_class_btns = Array.from(
|
| 15 |
+
document.getElementsByClassName('acceptClass')
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
const discard_class_btns = Array.from(
|
| 19 |
+
document.getElementsByClassName('discardClass')
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
const discard_selected_class_btns = Array.from(
|
| 23 |
+
document.getElementsByClassName('discardSelectedClass')
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
const accept_selected_class_btns = Array.from(
|
| 27 |
+
document.getElementsByClassName('acceptSelectedClass')
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
//show the accept and discard buttons when a new session is active
|
| 31 |
+
accept_class_btns.forEach(
|
| 32 |
+
(element) => (element.style.display = 'inline-block')
|
| 33 |
+
)
|
| 34 |
+
discard_class_btns.forEach(
|
| 35 |
+
(element) => (element.style.display = 'inline-block')
|
| 36 |
+
)
|
| 37 |
+
discard_selected_class_btns.forEach(
|
| 38 |
+
(element) => (element.style.display = 'inline-block')
|
| 39 |
+
)
|
| 40 |
+
accept_selected_class_btns.forEach(
|
| 41 |
+
(element) => (element.style.display = 'inline-block')
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
this.generateMoreUI()
|
| 45 |
+
}
|
| 46 |
+
onActiveSessionUI() {}
|
| 47 |
+
generateModeUI(mode) {
|
| 48 |
+
const generate_btns = Array.from(
|
| 49 |
+
document.getElementsByClassName('btnGenerateClass')
|
| 50 |
+
)
|
| 51 |
+
generate_btns.forEach((element) => {
|
| 52 |
+
element.textContent = `Generate ${mode}`
|
| 53 |
+
})
|
| 54 |
+
html_manip.setGenerateButtonsColor('generate', 'generate-more')
|
| 55 |
+
}
|
| 56 |
+
generateMoreUI() {
|
| 57 |
+
const generate_btns = Array.from(
|
| 58 |
+
document.getElementsByClassName('btnGenerateClass')
|
| 59 |
+
)
|
| 60 |
+
const generation_mode = g_generation_session.mode
|
| 61 |
+
const generation_name = getCurrentGenerationModeByValue(generation_mode)
|
| 62 |
+
generate_btns.forEach((element) => {
|
| 63 |
+
element.textContent = `Generate More ${generation_name}`
|
| 64 |
+
})
|
| 65 |
+
html_manip.setGenerateButtonsColor('generate-more', 'generate')
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
onEndSessionUI() {
|
| 69 |
+
const accept_class_btns = Array.from(
|
| 70 |
+
document.getElementsByClassName('acceptClass')
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
const discard_class_btns = Array.from(
|
| 74 |
+
document.getElementsByClassName('discardClass')
|
| 75 |
+
)
|
| 76 |
+
const discard_selected_class_btns = Array.from(
|
| 77 |
+
document.getElementsByClassName('discardSelectedClass')
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
const accept_selected_class_btns = Array.from(
|
| 81 |
+
//Node: change customClass to acceptSelectedClass
|
| 82 |
+
document.getElementsByClassName('acceptSelectedClass')
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
accept_class_btns.forEach((element) => (element.style.display = 'none'))
|
| 86 |
+
discard_class_btns.forEach(
|
| 87 |
+
(element) => (element.style.display = 'none')
|
| 88 |
+
)
|
| 89 |
+
discard_selected_class_btns.forEach(
|
| 90 |
+
(element) => (element.style.display = 'none')
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
accept_selected_class_btns.forEach(
|
| 94 |
+
(element) => (element.style.display = 'none')
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
this.generateModeUI(g_sd_mode)
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
setGenerateBtnText(textContent) {
|
| 101 |
+
const generate_btns = Array.from(
|
| 102 |
+
document.getElementsByClassName('btnGenerateClass')
|
| 103 |
+
)
|
| 104 |
+
generate_btns.forEach((element) => {
|
| 105 |
+
element.textContent = textContent
|
| 106 |
+
})
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
// const defaultSettings = {
|
| 111 |
+
// model: null,
|
| 112 |
+
// prompt_shortcut: null,
|
| 113 |
+
// positive_prompt: "",
|
| 114 |
+
// negative_prompt: "",
|
| 115 |
+
// selection_mode: null,
|
| 116 |
+
// batch_number: 1,
|
| 117 |
+
// steps: 20,
|
| 118 |
+
// width: 512 ,
|
| 119 |
+
// height:512,
|
| 120 |
+
// firstphase_width:512,
|
| 121 |
+
// firstphase_height:512,
|
| 122 |
+
// cfg:7,
|
| 123 |
+
// denoising_strength:0.7,
|
| 124 |
+
// hi_res_denoising_strength:0.7,
|
| 125 |
+
// mask_blur: 8,
|
| 126 |
+
// inpaint_at_full_res: false,
|
| 127 |
+
// hi_res_fix:false,
|
| 128 |
+
// inpaint_padding:0,
|
| 129 |
+
// seed:-1,
|
| 130 |
+
// samplers: null,
|
| 131 |
+
// mask_content:null
|
| 132 |
+
// }
|
| 133 |
+
|
| 134 |
+
class UIElement {
|
| 135 |
+
constructor() {
|
| 136 |
+
this.name
|
| 137 |
+
this.html_elem
|
| 138 |
+
this.sd_value
|
| 139 |
+
}
|
| 140 |
+
setValue() {}
|
| 141 |
+
getValue() {}
|
| 142 |
+
}
|
| 143 |
+
function createUIElement(getter, setter) {
|
| 144 |
+
let ui_element_obj = new UIElement()
|
| 145 |
+
ui_element_obj.getValue = getter
|
| 146 |
+
ui_element_obj.setValue = setter
|
| 147 |
+
return ui_element_obj
|
| 148 |
+
}
|
| 149 |
+
class UISettings {
|
| 150 |
+
// get and set the settings of the ui. the stable diffusion settings not the human friendly settings
|
| 151 |
+
constructor() {
|
| 152 |
+
// this.width = new ui.UIElement()
|
| 153 |
+
// this.width.getValue = html_manip.getWidth
|
| 154 |
+
// this.width.setValue = html_manip.autoFillInWidth
|
| 155 |
+
this.width = createUIElement(
|
| 156 |
+
html_manip.getWidth,
|
| 157 |
+
html_manip.autoFillInWidth
|
| 158 |
+
)
|
| 159 |
+
this.height = createUIElement(
|
| 160 |
+
html_manip.getHeight,
|
| 161 |
+
html_manip.autoFillInHeight
|
| 162 |
+
)
|
| 163 |
+
this.steps = createUIElement(
|
| 164 |
+
html_manip.getSteps,
|
| 165 |
+
html_manip.autoFillInSteps
|
| 166 |
+
)
|
| 167 |
+
this.batch_number = createUIElement(
|
| 168 |
+
html_manip.getBatchNumber,
|
| 169 |
+
html_manip.autoFillInBatchNumber
|
| 170 |
+
)
|
| 171 |
+
this.firstphase_width = createUIElement(
|
| 172 |
+
html_manip.getHrWidth,
|
| 173 |
+
html_manip.autoFillInHRWidth
|
| 174 |
+
)
|
| 175 |
+
this.firstphase_height = createUIElement(
|
| 176 |
+
html_manip.getHrHeight,
|
| 177 |
+
html_manip.autoFillInHRHeight
|
| 178 |
+
)
|
| 179 |
+
this.cfg = createUIElement(html_manip.getCFG, html_manip.setCFG)
|
| 180 |
+
this.denoising_strength = createUIElement(
|
| 181 |
+
html_manip.getDenoisingStrength,
|
| 182 |
+
html_manip.autoFillInDenoisingStrength
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
this.mask_content = createUIElement(
|
| 186 |
+
html_manip.getMaskContent,
|
| 187 |
+
html_manip.setMaskContent
|
| 188 |
+
)
|
| 189 |
+
this.seed = createUIElement(html_manip.getSeed, html_manip.setSeed)
|
| 190 |
+
this.prompt = createUIElement(
|
| 191 |
+
html_manip.getPrompt,
|
| 192 |
+
html_manip.autoFillInPrompt
|
| 193 |
+
)
|
| 194 |
+
this.negative_prompt = createUIElement(
|
| 195 |
+
html_manip.getNegativePrompt,
|
| 196 |
+
html_manip.autoFillInNegativePrompt
|
| 197 |
+
)
|
| 198 |
+
this.mask_blur = createUIElement(
|
| 199 |
+
html_manip.getMaskBlur,
|
| 200 |
+
html_manip.setMaskBlur
|
| 201 |
+
)
|
| 202 |
+
this.mask_expansion = createUIElement(
|
| 203 |
+
html_manip.getMaskExpansion,
|
| 204 |
+
html_manip.setMaskExpansion
|
| 205 |
+
)
|
| 206 |
+
this.samplers = createUIElement(
|
| 207 |
+
html_manip.getCheckedSamplerName,
|
| 208 |
+
html_manip.autoFillInSampler
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
this.uiElements = {
|
| 212 |
+
// model: null,
|
| 213 |
+
// prompt_shortcut: null,
|
| 214 |
+
prompt: this.prompt,
|
| 215 |
+
negative_prompt: this.negative_prompt,
|
| 216 |
+
// selection_mode: null,
|
| 217 |
+
batch_size: this.batch_number,
|
| 218 |
+
steps: this.steps,
|
| 219 |
+
width: this.width,
|
| 220 |
+
height: this.height,
|
| 221 |
+
firstphase_width: this.firstphase_width,
|
| 222 |
+
firstphase_height: this.firstphase_height,
|
| 223 |
+
cfg_scale: this.cfg,
|
| 224 |
+
denoising_strength: this.denoising_strength,
|
| 225 |
+
// hi_res_denoising_strength:0.7,
|
| 226 |
+
mask_blur: this.mask_blur,
|
| 227 |
+
mask_expansion: this.mask_expansion,
|
| 228 |
+
// inpaint_at_full_res: false,
|
| 229 |
+
// hi_res_fix:false,
|
| 230 |
+
// inpaint_padding:0,
|
| 231 |
+
seed: this.seed,
|
| 232 |
+
sampler_index: this.samplers,
|
| 233 |
+
mask_content: this.mask_content,
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
autoFillInSettings(settings) {
|
| 238 |
+
for (const [name, value] of Object.entries(settings)) {
|
| 239 |
+
if (this.uiElements.hasOwnProperty(name) && value) {
|
| 240 |
+
//get the values for debugging
|
| 241 |
+
const old_value = this.uiElements[name].getValue()
|
| 242 |
+
console.log(
|
| 243 |
+
'(name,old_value) => newValue:',
|
| 244 |
+
name,
|
| 245 |
+
old_value,
|
| 246 |
+
value
|
| 247 |
+
)
|
| 248 |
+
//set the value
|
| 249 |
+
this.uiElements[name].setValue(value)
|
| 250 |
+
}
|
| 251 |
+
}
|
| 252 |
+
}
|
| 253 |
+
getSettings() {
|
| 254 |
+
let settings = {}
|
| 255 |
+
for (const [name, ui_element] of Object.entries(this.uiElements)) {
|
| 256 |
+
if (ui_element) {
|
| 257 |
+
const value = ui_element.getValue()
|
| 258 |
+
settings[name] = value
|
| 259 |
+
}
|
| 260 |
+
}
|
| 261 |
+
return settings
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
saveAsJson(json_file_name, settings) {
|
| 265 |
+
for (const [name, value] of Object.entries(settings)) {
|
| 266 |
+
if (this.uiElements.hasOwnProperty(name) && value) {
|
| 267 |
+
//get the values for debugging
|
| 268 |
+
const old_value = this.uiElements[name].getValue()
|
| 269 |
+
console.log(
|
| 270 |
+
'(name,old_value) => newValue:',
|
| 271 |
+
name,
|
| 272 |
+
old_value,
|
| 273 |
+
value
|
| 274 |
+
)
|
| 275 |
+
|
| 276 |
+
//set the value
|
| 277 |
+
}
|
| 278 |
+
}
|
| 279 |
+
}
|
| 280 |
+
}
|
| 281 |
+
// const ui_settings = new UISettings()
|
| 282 |
+
|
| 283 |
+
function loadPreset(ui_settings, preset) {
|
| 284 |
+
console.log('preset:', preset)
|
| 285 |
+
ui_settings.autoFillInSettings(preset)
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
function loadLatentNoiseSettings(ui_settings) {
|
| 289 |
+
loadPreset(ui_settings, presets.LatentNoiseSettings)
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
function loadFillSettings(ui_settings) {
|
| 293 |
+
loadPreset(ui_settings, presets.FillSettings)
|
| 294 |
+
}
|
| 295 |
+
function loadOriginalSettings(ui_settings) {
|
| 296 |
+
loadPreset(ui_settings, presets.OriginalSettings)
|
| 297 |
+
}
|
| 298 |
+
async function loadHealBrushSettings(ui_settings) {
|
| 299 |
+
document.getElementById('rbModeInpaint').click()
|
| 300 |
+
|
| 301 |
+
loadPreset(ui_settings, presets.HealBrushSettings)
|
| 302 |
+
}
|
| 303 |
+
function loadCustomPreset(ui_settings_obj, custom_preset_settings) {
|
| 304 |
+
loadPreset(ui_settings_obj, custom_preset_settings)
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
function loadCustomPresetsSettings() {}
|
| 308 |
+
async function mapCustomPresetsToLoaders(ui_settings_obj) {
|
| 309 |
+
const name_to_settings_obj = await presets.getAllCustomPresetsSettings(
|
| 310 |
+
Enum.PresetTypeEnum['SDPreset']
|
| 311 |
+
)
|
| 312 |
+
const preset_name_to_loader_obj = {}
|
| 313 |
+
for (const [preset_name, preset_settings] of Object.entries(
|
| 314 |
+
name_to_settings_obj
|
| 315 |
+
)) {
|
| 316 |
+
preset_name_to_loader_obj[preset_name] = () => {
|
| 317 |
+
loadCustomPreset(ui_settings_obj, preset_settings)
|
| 318 |
+
}
|
| 319 |
+
}
|
| 320 |
+
return preset_name_to_loader_obj
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
const g_nativePresets = {
|
| 324 |
+
fill: loadFillSettings,
|
| 325 |
+
original: loadOriginalSettings,
|
| 326 |
+
'latent noise': loadLatentNoiseSettings,
|
| 327 |
+
'Heal Brush': loadHealBrushSettings,
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
async function getLoadedPresets(ui_settings_obj) {
|
| 331 |
+
let customPresets
|
| 332 |
+
|
| 333 |
+
customPresets = await mapCustomPresetsToLoaders(ui_settings_obj)
|
| 334 |
+
console.log('customPresets: ', customPresets)
|
| 335 |
+
let loadedPresets = {
|
| 336 |
+
...g_nativePresets,
|
| 337 |
+
...customPresets,
|
| 338 |
+
}
|
| 339 |
+
return loadedPresets
|
| 340 |
+
}
|
| 341 |
+
let g_ui_settings_object = new UISettings()
|
| 342 |
+
function getUISettingsObject() {
|
| 343 |
+
return g_ui_settings_object
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
//REFACTOR: move to ui.js
|
| 347 |
+
function addPresetMenuItem(preset_title) {
|
| 348 |
+
// console.log(model_title,model_name)
|
| 349 |
+
const menu_item_element = document.createElement('sp-menu-item')
|
| 350 |
+
menu_item_element.className = 'mPresetMenuItem'
|
| 351 |
+
menu_item_element.innerHTML = preset_title
|
| 352 |
+
|
| 353 |
+
// menu_item_element.addEventListener('select',()=>{
|
| 354 |
+
// preset_func(g_ui_settings)
|
| 355 |
+
// })
|
| 356 |
+
return menu_item_element
|
| 357 |
+
}
|
| 358 |
+
//REFACTOR: move to ui.js
|
| 359 |
+
async function populatePresetMenu() {
|
| 360 |
+
document.getElementById('mPresetMenu').innerHTML = ''
|
| 361 |
+
const divider_elem = document.createElement('sp-menu-divider')
|
| 362 |
+
const preset_name = 'Select Smart Preset'
|
| 363 |
+
const preset_func = () => {}
|
| 364 |
+
const dummy_preset_item = addPresetMenuItem(preset_name, preset_func)
|
| 365 |
+
dummy_preset_item.setAttribute('selected', 'selected')
|
| 366 |
+
// dummy_preset_item.setAttribute('disabled')
|
| 367 |
+
document.getElementById('mPresetMenu').appendChild(dummy_preset_item)
|
| 368 |
+
document.getElementById('mPresetMenu').appendChild(divider_elem)
|
| 369 |
+
const presets = await getLoadedPresets(g_ui_settings_object)
|
| 370 |
+
for ([key, value] of Object.entries(presets)) {
|
| 371 |
+
const preset_menu_item = addPresetMenuItem(key, value)
|
| 372 |
+
document.getElementById('mPresetMenu').appendChild(preset_menu_item)
|
| 373 |
+
}
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
populatePresetMenu()
|
| 377 |
+
//REFACTOR: move to preset_tab.js
|
| 378 |
+
document
|
| 379 |
+
.getElementById('mPresetMenu')
|
| 380 |
+
.addEventListener('change', async (evt) => {
|
| 381 |
+
const preset_index = evt.target.selectedIndex
|
| 382 |
+
const preset_name = evt.target.options[preset_index].textContent
|
| 383 |
+
const presets = await getLoadedPresets(g_ui_settings_object)
|
| 384 |
+
if (presets.hasOwnProperty(preset_name)) {
|
| 385 |
+
const loader = presets[preset_name]
|
| 386 |
+
if (loader.constructor.name === 'AsyncFunction') {
|
| 387 |
+
await loader(g_ui_settings_object)
|
| 388 |
+
} else {
|
| 389 |
+
loader(g_ui_settings_object)
|
| 390 |
+
}
|
| 391 |
+
}
|
| 392 |
+
})
|
| 393 |
+
|
| 394 |
+
module.exports = {
|
| 395 |
+
UI,
|
| 396 |
+
UIElement,
|
| 397 |
+
UISettings,
|
| 398 |
+
loadLatentNoiseSettings,
|
| 399 |
+
loadFillSettings,
|
| 400 |
+
loadHealBrushSettings,
|
| 401 |
+
getLoadedPresets,
|
| 402 |
+
getUISettingsObject,
|
| 403 |
+
populatePresetMenu,
|
| 404 |
+
}
|
Auto-Photoshop-StableDiffusion-Plugin/viewer.js
ADDED
|
@@ -0,0 +1,861 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// output image class: one image to one layer
|
| 2 |
+
// * path:
|
| 3 |
+
// * image layer
|
| 4 |
+
// * viewer()
|
| 5 |
+
// * select()
|
| 6 |
+
|
| 7 |
+
// * init image class: has three layers
|
| 8 |
+
// * path :
|
| 9 |
+
// * init image group layer
|
| 10 |
+
// * init image layer
|
| 11 |
+
// * background layer
|
| 12 |
+
|
| 13 |
+
// * mask class:
|
| 14 |
+
// * path
|
| 15 |
+
// * mask group
|
| 16 |
+
// * white mask
|
| 17 |
+
// * balck layer
|
| 18 |
+
// * select()
|
| 19 |
+
// * viewe()
|
| 20 |
+
const general = require('./utility/general')
|
| 21 |
+
const Enum = require('./enum')
|
| 22 |
+
const psapi = require('./psapi')
|
| 23 |
+
const layer_util = require('./utility/layer')
|
| 24 |
+
const thumbnail = require('./thumbnail')
|
| 25 |
+
const ViewerObjState = {
|
| 26 |
+
Delete: 'delete',
|
| 27 |
+
Unlink: 'unlink',
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
class ViewerImage {
|
| 31 |
+
constructor() {
|
| 32 |
+
this.img_html = null //
|
| 33 |
+
this.thumbnail_container = null
|
| 34 |
+
this.is_highlighted = false
|
| 35 |
+
this.can_highlight = true
|
| 36 |
+
this.is_active = false // active is a temporary highlight , the yellow/orang highlight
|
| 37 |
+
this.state = ViewerObjState['Unlink']
|
| 38 |
+
|
| 39 |
+
// true will delete the layers from the layer stacks when the session ends,
|
| 40 |
+
// false mean use this.state to determine whither you delete the layer or not
|
| 41 |
+
this.autoDelete = false
|
| 42 |
+
this.viewerManager = null // store link to the viewer manager of this document
|
| 43 |
+
this.viewerObjectType
|
| 44 |
+
this.objectId
|
| 45 |
+
}
|
| 46 |
+
info() {
|
| 47 |
+
console.log('state: ', this.state)
|
| 48 |
+
}
|
| 49 |
+
visible(visibleOn) {}
|
| 50 |
+
select() {}
|
| 51 |
+
isActive() {
|
| 52 |
+
return this.is_active
|
| 53 |
+
}
|
| 54 |
+
active(isActive) {
|
| 55 |
+
if (isActive) {
|
| 56 |
+
//unlink it if it's active
|
| 57 |
+
// this.state = ViewerObjState['Unlink']
|
| 58 |
+
|
| 59 |
+
this.img_html.classList.add('viewerImgActive')
|
| 60 |
+
} else {
|
| 61 |
+
if (this.getHighlight() === false) {
|
| 62 |
+
// if it's not active and it's not highlighted
|
| 63 |
+
// this.state = ViewerObjState['Delete']
|
| 64 |
+
} else {
|
| 65 |
+
// this.state = ViewerObjState['Unlink'] //it's not active but it's highlighted then keep it
|
| 66 |
+
}
|
| 67 |
+
this.img_html.classList.remove('viewerImgActive')
|
| 68 |
+
}
|
| 69 |
+
this.is_active = isActive
|
| 70 |
+
}
|
| 71 |
+
setAutoDelete(auto_delete) {
|
| 72 |
+
this.autoDelete = auto_delete
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
isSameLayer(layer_id) {}
|
| 76 |
+
setHighlight(is_highlighted) {
|
| 77 |
+
if (this.can_highlight) {
|
| 78 |
+
this.is_highlighted = is_highlighted
|
| 79 |
+
if (this.is_highlighted) {
|
| 80 |
+
// this.state = ViewerObjState['Unlink']
|
| 81 |
+
this.img_html.classList.add('viewerImgSelected')
|
| 82 |
+
} else {
|
| 83 |
+
this.img_html.classList.remove('viewerImgSelected')
|
| 84 |
+
// this.state = ViewerObjState["Delete"]
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
getHighlight() {
|
| 89 |
+
return this.is_highlighted
|
| 90 |
+
}
|
| 91 |
+
toggleHighlight() {
|
| 92 |
+
const toggle_value = !this.getHighlight()
|
| 93 |
+
this.setHighlight(toggle_value)
|
| 94 |
+
// this.is_highlighted = !this.is_highlighted
|
| 95 |
+
// this.img_html.classList.toggle("viewerImgSelected")
|
| 96 |
+
}
|
| 97 |
+
setImgHtml() {}
|
| 98 |
+
|
| 99 |
+
async delete() {
|
| 100 |
+
try {
|
| 101 |
+
if (this.img_html) {
|
| 102 |
+
this.img_html.remove() //delete the img html element
|
| 103 |
+
}
|
| 104 |
+
if (this.thumbnail_container) {
|
| 105 |
+
this.thumbnail_container.remove()
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
//1) it's output layer // can_highlight && this.getHighlight()
|
| 109 |
+
//2) it init or mask relate layers // this.autoDelete
|
| 110 |
+
//3) it output layer that been used as init layer // !can_highlight && !this.autoDelete
|
| 111 |
+
|
| 112 |
+
// do 1) and 2) here . test for 3) in InitImage
|
| 113 |
+
|
| 114 |
+
//1)
|
| 115 |
+
if (this.can_highlight && (this.getHighlight() || this.is_active)) {
|
| 116 |
+
//keep if can be highlighted and either is highlighted or active
|
| 117 |
+
this.state = ViewerObjState['Unlink']
|
| 118 |
+
} else {
|
| 119 |
+
//
|
| 120 |
+
this.state = ViewerObjState['Delete']
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
if (this.autoDelete) {
|
| 124 |
+
//remove if it's first automated layer
|
| 125 |
+
this.state = ViewerObjState['Delete']
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
// else {
|
| 129 |
+
// //discard only if it's
|
| 130 |
+
// if (this.autoDelete){
|
| 131 |
+
// this.state = ViewerObjState['Delete']
|
| 132 |
+
// }
|
| 133 |
+
// }
|
| 134 |
+
} catch (e) {
|
| 135 |
+
console.warn(e)
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
unlink() {
|
| 140 |
+
//keep the layer but unlink it from the ui
|
| 141 |
+
try {
|
| 142 |
+
this.img_html.remove() //delete the img html element
|
| 143 |
+
} catch (e) {
|
| 144 |
+
console.warn(e)
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
createThumbnailNew(img, _) {
|
| 149 |
+
this.img_html = img
|
| 150 |
+
this.thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 151 |
+
img,
|
| 152 |
+
'viewer-image-container'
|
| 153 |
+
)
|
| 154 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 155 |
+
this.thumbnail_container,
|
| 156 |
+
'svg_sp_btn',
|
| 157 |
+
'Use this as an initial image',
|
| 158 |
+
|
| 159 |
+
this.useOutputImageAsInitImage,
|
| 160 |
+
img
|
| 161 |
+
)
|
| 162 |
+
}
|
| 163 |
+
useOutputImageAsInitImage = async () => {
|
| 164 |
+
//set init image event listener, use when settion is active
|
| 165 |
+
// const layer = await app.activeDocument.activeLayers[0]
|
| 166 |
+
try {
|
| 167 |
+
// console.log('this.img_html:', this.img_html)
|
| 168 |
+
// await executeAsModal(() => {
|
| 169 |
+
// this.visible(true)
|
| 170 |
+
// })
|
| 171 |
+
// await this.select(true) //select() does take arguments
|
| 172 |
+
// this.active(true)
|
| 173 |
+
await executeAsModal(async () => {
|
| 174 |
+
await this.click(Enum.clickTypeEnum['Click'])
|
| 175 |
+
})
|
| 176 |
+
|
| 177 |
+
const layer = layer_util.Layer.doesLayerExist(this.layer)
|
| 178 |
+
? this.layer
|
| 179 |
+
: await app.activeDocument.activeLayers[0]
|
| 180 |
+
|
| 181 |
+
// const layer = this.layer
|
| 182 |
+
const image_info = await psapi.silentSetInitImage(
|
| 183 |
+
layer,
|
| 184 |
+
random_session_id
|
| 185 |
+
)
|
| 186 |
+
const image_name = image_info['name']
|
| 187 |
+
const path = `./server/python_server/init_images/${image_name}`
|
| 188 |
+
g_viewer_manager.addInitImageLayers(layer, path, false)
|
| 189 |
+
await g_viewer_manager.loadInitImageViewerObject(path)
|
| 190 |
+
} catch (e) {
|
| 191 |
+
console.warn(e)
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
createThumbnail(img, b_button_visible = true) {
|
| 195 |
+
this.img_html = img
|
| 196 |
+
// Create new container element
|
| 197 |
+
this.thumbnail_container = document.createElement('div')
|
| 198 |
+
|
| 199 |
+
this.thumbnail_container.className = 'viewer-image-container'
|
| 200 |
+
|
| 201 |
+
const elem = document.getElementById('svg_sp_btn')
|
| 202 |
+
|
| 203 |
+
// Create a copy of it
|
| 204 |
+
const clone = elem.cloneNode(true)
|
| 205 |
+
const button = clone
|
| 206 |
+
button.style.display = null
|
| 207 |
+
button.setAttribute(
|
| 208 |
+
'title',
|
| 209 |
+
'use this image to generate more variance like it'
|
| 210 |
+
)
|
| 211 |
+
|
| 212 |
+
// Create button element
|
| 213 |
+
// const button = document.createElement('sp-button');
|
| 214 |
+
button.className = 'viewer-image-button'
|
| 215 |
+
// button.innerHTML = "Button";
|
| 216 |
+
if (!b_button_visible) {
|
| 217 |
+
button.style.display = 'none'
|
| 218 |
+
}
|
| 219 |
+
button.addEventListener('click', async () => {
|
| 220 |
+
await useOutputImageAsInitImage()
|
| 221 |
+
})
|
| 222 |
+
|
| 223 |
+
// Append elements to container
|
| 224 |
+
this.thumbnail_container.appendChild(this.img_html)
|
| 225 |
+
this.thumbnail_container.appendChild(button)
|
| 226 |
+
|
| 227 |
+
// this.img_html = container
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
class OutputImage extends ViewerImage {
|
| 232 |
+
constructor(layer, path, viewer_manager) {
|
| 233 |
+
super()
|
| 234 |
+
this.layer = layer
|
| 235 |
+
this.path = path
|
| 236 |
+
this.img_html = null
|
| 237 |
+
this.viewerManager = viewer_manager
|
| 238 |
+
this.viewerObjectType = Enum.ViewerObjectTypeEnum['OutputImage']
|
| 239 |
+
this.objectId = path // the path is unique, so we will use it as an id
|
| 240 |
+
}
|
| 241 |
+
async click(click_type) {
|
| 242 |
+
console.log('click_type: ', click_type)
|
| 243 |
+
// if (this.isActive() && click_type === Enum.clickTypeEnum['Click']) {
|
| 244 |
+
// //convert consecutive clicks to AltClick
|
| 245 |
+
// click_type = Enum.clickTypeEnum['SecondClick']
|
| 246 |
+
// console.log('converted click_type: ', click_type)
|
| 247 |
+
// }
|
| 248 |
+
|
| 249 |
+
if (click_type === Enum.clickTypeEnum['Click']) {
|
| 250 |
+
//select layer
|
| 251 |
+
//turn the layer visible
|
| 252 |
+
//set the layer to active
|
| 253 |
+
this.visible(true)
|
| 254 |
+
await this.select(true) //select() does take arguments
|
| 255 |
+
this.active(true)
|
| 256 |
+
} else if (click_type === Enum.clickTypeEnum['ShiftClick']) {
|
| 257 |
+
this.visible(true)
|
| 258 |
+
await this.select(true) //select() does take arguments
|
| 259 |
+
this.setHighlight(true)
|
| 260 |
+
this.active(true)
|
| 261 |
+
// if (this.viewerManager.last_selected_viewer_obj) {
|
| 262 |
+
// //if the last selected layer is valid then converted last selected layer into highlight layer
|
| 263 |
+
// this.viewerManager.last_selected_viewer_obj.setHighlight(true)
|
| 264 |
+
// }
|
| 265 |
+
} else if (click_type === Enum.clickTypeEnum['AltClick']) {
|
| 266 |
+
// this.viewerManager.last_selected_viewer_obj = null
|
| 267 |
+
this.setHighlight(false)
|
| 268 |
+
this.visible(false)
|
| 269 |
+
this.active(false)
|
| 270 |
+
|
| 271 |
+
await psapi.unselectActiveLayersExe() //Note:can we move to ViewerManager.click()
|
| 272 |
+
} else if (click_type === Enum.clickTypeEnum['SecondClick']) {
|
| 273 |
+
//select layer
|
| 274 |
+
//turn the layer visible
|
| 275 |
+
//set the layer to active
|
| 276 |
+
this.visible(false)
|
| 277 |
+
await this.select(false) //select() does take arguments
|
| 278 |
+
this.active(false)
|
| 279 |
+
}
|
| 280 |
+
this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 281 |
+
}
|
| 282 |
+
visible(visibleOn) {
|
| 283 |
+
//turn the visibility for the layer
|
| 284 |
+
try {
|
| 285 |
+
super.visible(visibleOn)
|
| 286 |
+
if (layer_util.Layer.doesLayerExist(this.layer)) {
|
| 287 |
+
this.layer.visible = visibleOn
|
| 288 |
+
}
|
| 289 |
+
} catch (e) {
|
| 290 |
+
console.warn(e)
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
async select() {
|
| 294 |
+
//select the layer
|
| 295 |
+
super.select()
|
| 296 |
+
if (layer_util.Layer.doesLayerExist(this.layer)) {
|
| 297 |
+
await psapi.selectLayersExe([this.layer])
|
| 298 |
+
// console.log(`${this.layer.id} got selected`);
|
| 299 |
+
}
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
isSameLayer(layer_id) {
|
| 303 |
+
super.isSameLayer(layer_id)
|
| 304 |
+
const is_same = this.layer.id == layer_id
|
| 305 |
+
return is_same
|
| 306 |
+
}
|
| 307 |
+
isSameObject(object) {
|
| 308 |
+
if (
|
| 309 |
+
layer_util.Layer.doesLayerExist(this.layer) &&
|
| 310 |
+
layer_util.Layer.doesLayerExist(object.layer)
|
| 311 |
+
) {
|
| 312 |
+
return this.layer.id === object.layer.id
|
| 313 |
+
}
|
| 314 |
+
return false
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
setImgHtml(img_html) {
|
| 318 |
+
super.setImgHtml()
|
| 319 |
+
this.img_html = img_html
|
| 320 |
+
}
|
| 321 |
+
async delete() {
|
| 322 |
+
try {
|
| 323 |
+
await super.delete()
|
| 324 |
+
// this.img_html.remove()//delete the img html element
|
| 325 |
+
if (this.state === ViewerObjState['Delete']) {
|
| 326 |
+
await psapi.cleanLayers([this.layer])
|
| 327 |
+
}
|
| 328 |
+
} catch (e) {
|
| 329 |
+
console.warn(e)
|
| 330 |
+
}
|
| 331 |
+
}
|
| 332 |
+
info() {
|
| 333 |
+
super.info()
|
| 334 |
+
}
|
| 335 |
+
// unlink(){
|
| 336 |
+
// //keep the layer but unlink it from the ui
|
| 337 |
+
// try{
|
| 338 |
+
|
| 339 |
+
// super.unlink()
|
| 340 |
+
// this.img_html.remove()//delete the img html element
|
| 341 |
+
|
| 342 |
+
// }catch(e){
|
| 343 |
+
// console.warn(e)
|
| 344 |
+
// }
|
| 345 |
+
// }
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
class InitImage extends ViewerImage {
|
| 349 |
+
constructor(init_group, init_snapshot, solid_layer, path, viewer_manager) {
|
| 350 |
+
super()
|
| 351 |
+
this.init_group = init_group
|
| 352 |
+
this.init_snapshot = init_snapshot
|
| 353 |
+
this.solid_layer = solid_layer
|
| 354 |
+
|
| 355 |
+
this.path = path
|
| 356 |
+
this.can_highlight = false
|
| 357 |
+
this.viewerManager = viewer_manager
|
| 358 |
+
this.viewerObjectType = Enum.ViewerObjectTypeEnum['InitImage']
|
| 359 |
+
this.objectId = path // the path is unique, so we will use it as an id
|
| 360 |
+
// if (this.autoDelete === false){
|
| 361 |
+
// this.state = ViewerObjState['Unlink']
|
| 362 |
+
// }
|
| 363 |
+
}
|
| 364 |
+
async click(click_type) {
|
| 365 |
+
if (click_type === Enum.clickTypeEnum['Click']) {
|
| 366 |
+
//select layer
|
| 367 |
+
//turn the layer visible
|
| 368 |
+
//set the layer to active
|
| 369 |
+
this.visible(true)
|
| 370 |
+
await this.select(true) //select() does take arguments
|
| 371 |
+
this.active(true)
|
| 372 |
+
click_type = Enum.clickTypeEnum['Click'] // convert all click to Click
|
| 373 |
+
this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 374 |
+
} else if (click_type === Enum.clickTypeEnum['ShiftClick']) {
|
| 375 |
+
this.visible(true)
|
| 376 |
+
await this.select(true) //select() does take arguments
|
| 377 |
+
this.active(true)
|
| 378 |
+
// if (this.viewerManager.last_selected_viewer_obj) {
|
| 379 |
+
// //if the last selected layer is valid then converted last selected layer into highlight layer
|
| 380 |
+
// this.viewerManager.last_selected_viewer_obj.setHighlight(true)
|
| 381 |
+
// }
|
| 382 |
+
click_type = Enum.clickTypeEnum['Click'] // convert all click to Click
|
| 383 |
+
this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 384 |
+
}
|
| 385 |
+
// else if (click_type === Enum.clickTypeEnum['AltClick']) {
|
| 386 |
+
// // this.viewerManager.last_selected_viewer_obj = null
|
| 387 |
+
// this.setHighlight(false)
|
| 388 |
+
// this.visible(false)
|
| 389 |
+
// this.active(false)
|
| 390 |
+
|
| 391 |
+
// await psapi.unselectActiveLayersExe() //Note:can we move to ViewerManager.click()
|
| 392 |
+
// }
|
| 393 |
+
// this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 394 |
+
}
|
| 395 |
+
visible(visibleOn) {
|
| 396 |
+
try {
|
| 397 |
+
super.visible(visibleOn)
|
| 398 |
+
|
| 399 |
+
let visibleValues = []
|
| 400 |
+
if (visibleOn) {
|
| 401 |
+
visibleValues = [true, true, true]
|
| 402 |
+
} else {
|
| 403 |
+
visibleValues = [false, false, false]
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
if (layer_util.Layer.doesLayerExist(this.init_group)) {
|
| 407 |
+
this.init_group.visible = visibleValues[0]
|
| 408 |
+
}
|
| 409 |
+
if (layer_util.Layer.doesLayerExist(this.init_snapshot)) {
|
| 410 |
+
this.init_snapshot.visible = visibleValues[1]
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
if (layer_util.Layer.doesLayerExist(this.solid_layer)) {
|
| 414 |
+
this.solid_layer.visible = visibleValues[2]
|
| 415 |
+
}
|
| 416 |
+
|
| 417 |
+
if (!this.autoDelete) {
|
| 418 |
+
//means it's not the first init image
|
| 419 |
+
|
| 420 |
+
if (layer_util.Layer.doesLayerExist(this.solid_layer)) {
|
| 421 |
+
this.solid_layer.visible = false //turn it off sense the init group is above the output group, and the white solid will hide the init image reference located in the output group
|
| 422 |
+
}
|
| 423 |
+
}
|
| 424 |
+
} catch (e) {
|
| 425 |
+
console.warn(e)
|
| 426 |
+
}
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
async select() {
|
| 430 |
+
super.select()
|
| 431 |
+
|
| 432 |
+
const selectLayers = []
|
| 433 |
+
if (layer_util.Layer.doesLayerExist(this.init_group)) {
|
| 434 |
+
selectLayers.push(this.init_group)
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
await psapi.selectLayersExe(selectLayers)
|
| 438 |
+
// console.log(`${this.layer.id} got selected`);
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
isSameLayer(layer_id) {
|
| 442 |
+
super.isSameLayer(layer_id)
|
| 443 |
+
let is_same = false
|
| 444 |
+
if (layer_util.Layer.doesLayerExist(this.init_group)) {
|
| 445 |
+
is_same = this.init_group.id == layer_id
|
| 446 |
+
}
|
| 447 |
+
return is_same
|
| 448 |
+
}
|
| 449 |
+
setImgHtml(img_html) {
|
| 450 |
+
super.setImgHtml()
|
| 451 |
+
this.img_html = img_html
|
| 452 |
+
}
|
| 453 |
+
async delete() {
|
| 454 |
+
try {
|
| 455 |
+
await super.delete()
|
| 456 |
+
|
| 457 |
+
// this.img_html.remove()//delete the img html element
|
| 458 |
+
|
| 459 |
+
if (!this.autoDelete && !this.can_highlight) {
|
| 460 |
+
//don't delete since it's output layer that is been used as init image
|
| 461 |
+
this.state = ViewerObjState['Unlink']
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
if (this.state === ViewerObjState['Delete']) {
|
| 465 |
+
await psapi.cleanLayers([
|
| 466 |
+
this.init_group,
|
| 467 |
+
this.init_snapshot,
|
| 468 |
+
this.solid_layer,
|
| 469 |
+
])
|
| 470 |
+
}
|
| 471 |
+
} catch (e) {
|
| 472 |
+
console.warn(e)
|
| 473 |
+
}
|
| 474 |
+
}
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
class InitMaskImage extends ViewerImage {
|
| 478 |
+
constructor(mask_group, white_mark, solid_black, path, viewer_manager) {
|
| 479 |
+
super()
|
| 480 |
+
this.mask_group = mask_group
|
| 481 |
+
this.white_mark = white_mark
|
| 482 |
+
this.solid_black = solid_black
|
| 483 |
+
|
| 484 |
+
this.path = path
|
| 485 |
+
this.can_highlight = false
|
| 486 |
+
this.viewerManager = viewer_manager
|
| 487 |
+
this.viewerObjectType = Enum.ViewerObjectTypeEnum['MaskImage']
|
| 488 |
+
this.objectId = path // the path is unique, so we will use it as an id
|
| 489 |
+
}
|
| 490 |
+
async click(click_type) {
|
| 491 |
+
if (click_type === Enum.clickTypeEnum['Click']) {
|
| 492 |
+
//select layer
|
| 493 |
+
//turn the layer visible
|
| 494 |
+
//set the layer to active
|
| 495 |
+
this.visible(true)
|
| 496 |
+
await this.select(true) //select() does take arguments
|
| 497 |
+
this.active(true)
|
| 498 |
+
click_type = Enum.clickTypeEnum['Click'] // convert all click to Click
|
| 499 |
+
this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 500 |
+
} else if (click_type === Enum.clickTypeEnum['ShiftClick']) {
|
| 501 |
+
this.visible(true)
|
| 502 |
+
await this.select(true) //select() does take arguments
|
| 503 |
+
this.active(true)
|
| 504 |
+
// if (this.viewerManager.last_selected_viewer_obj) {
|
| 505 |
+
// //if the last selected layer is valid then converted last selected layer into highlight layer
|
| 506 |
+
// this.viewerManager.last_selected_viewer_obj.setHighlight(true)
|
| 507 |
+
// }
|
| 508 |
+
click_type = Enum.clickTypeEnum['Click'] // convert all click to Click
|
| 509 |
+
this.viewerManager.replaceLastSelection(click_type, this) //pass the click_type and this object
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
visible(visibleOn) {
|
| 513 |
+
try {
|
| 514 |
+
super.visible(visibleOn)
|
| 515 |
+
|
| 516 |
+
let visibleValues = []
|
| 517 |
+
if (visibleOn) {
|
| 518 |
+
visibleValues = [true, true, false]
|
| 519 |
+
} else {
|
| 520 |
+
visibleValues = [false, false, false]
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
if (layer_util.Layer.doesLayerExist(this.mask_group)) {
|
| 524 |
+
this.mask_group.visible = visibleValues[0]
|
| 525 |
+
}
|
| 526 |
+
if (layer_util.Layer.doesLayerExist(this.white_mark)) {
|
| 527 |
+
this.white_mark.visible = visibleValues[1]
|
| 528 |
+
}
|
| 529 |
+
if (layer_util.Layer.doesLayerExist(this.solid_black)) {
|
| 530 |
+
this.solid_black.visible = visibleValues[2]
|
| 531 |
+
}
|
| 532 |
+
} catch (e) {
|
| 533 |
+
console.warn(e)
|
| 534 |
+
}
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
async select() {
|
| 538 |
+
super.select()
|
| 539 |
+
|
| 540 |
+
const selectLayers = []
|
| 541 |
+
|
| 542 |
+
if (layer_util.Layer.doesLayerExist(this.white_mark)) {
|
| 543 |
+
selectLayers.push(this.white_mark)
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
await psapi.selectLayersExe(selectLayers)
|
| 547 |
+
// console.log(`${this.layer.id} got selected`);
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
isSameLayer(layer_id) {
|
| 551 |
+
super.isSameLayer(layer_id)
|
| 552 |
+
let is_same = false
|
| 553 |
+
if (layer_util.Layer.doesLayerExist(this.mask_group)) {
|
| 554 |
+
is_same = this.mask_group.id == layer_id
|
| 555 |
+
}
|
| 556 |
+
return is_same
|
| 557 |
+
}
|
| 558 |
+
setImgHtml(img_html) {
|
| 559 |
+
super.setImgHtml()
|
| 560 |
+
this.img_html = img_html
|
| 561 |
+
}
|
| 562 |
+
async delete() {
|
| 563 |
+
try {
|
| 564 |
+
await super.delete()
|
| 565 |
+
// this.img_html.remove()//delete the img html element
|
| 566 |
+
if (this.state === ViewerObjState['Delete']) {
|
| 567 |
+
await psapi.cleanLayers([
|
| 568 |
+
this.mask_group,
|
| 569 |
+
this.white_mark,
|
| 570 |
+
this.solid_black,
|
| 571 |
+
])
|
| 572 |
+
}
|
| 573 |
+
} catch (e) {
|
| 574 |
+
console.warn(e)
|
| 575 |
+
}
|
| 576 |
+
}
|
| 577 |
+
createThumbnailNew(img, _) {
|
| 578 |
+
this.img_html = img
|
| 579 |
+
this.thumbnail_container = thumbnail.Thumbnail.wrapImgInContainer(
|
| 580 |
+
img,
|
| 581 |
+
'viewer-image-container'
|
| 582 |
+
)
|
| 583 |
+
thumbnail.Thumbnail.addSPButtonToContainer(
|
| 584 |
+
this.thumbnail_container,
|
| 585 |
+
'svg_sp_btn',
|
| 586 |
+
'update the mask',
|
| 587 |
+
setMaskViewer,
|
| 588 |
+
img
|
| 589 |
+
)
|
| 590 |
+
}
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
class initImageLayers {
|
| 594 |
+
//store info about the init image related layers
|
| 595 |
+
constructor(group, snapshot, solid_background, autoDelete) {
|
| 596 |
+
this.group = group
|
| 597 |
+
this.snapshot = snapshot
|
| 598 |
+
this.solid_background = solid_background
|
| 599 |
+
this.autoDelete = autoDelete
|
| 600 |
+
}
|
| 601 |
+
}
|
| 602 |
+
class maskLayers {
|
| 603 |
+
//store info about the init image related layers
|
| 604 |
+
constructor(group, white_mark, solid_background, autoDelete) {
|
| 605 |
+
this.group = group
|
| 606 |
+
this.white_mark = white_mark
|
| 607 |
+
this.solid_background = solid_background
|
| 608 |
+
this.autoDelete = autoDelete
|
| 609 |
+
}
|
| 610 |
+
}
|
| 611 |
+
class ViewerManager {
|
| 612 |
+
//viewer manager will reset after the end of the session
|
| 613 |
+
//it will store
|
| 614 |
+
constructor() {
|
| 615 |
+
this.outputImages = []
|
| 616 |
+
this.initImages = []
|
| 617 |
+
this.initMaskImage
|
| 618 |
+
this.pathToViewerImage = {} // quick way to check if an link image path on disk to ViewerImage object.
|
| 619 |
+
this.initImageLayersJson = {} //{path: initImageLayers}
|
| 620 |
+
|
| 621 |
+
this.selectedOutputImages = {} //store the selected output images {path: outputImage}
|
| 622 |
+
|
| 623 |
+
this.mask_layer
|
| 624 |
+
this.maskLayersJson = {} //{path: MaskLayers}
|
| 625 |
+
|
| 626 |
+
//Note:move initGroup, to GenerationSession
|
| 627 |
+
this.initGroup
|
| 628 |
+
this.init_solid_background
|
| 629 |
+
this.maskGroup
|
| 630 |
+
this.mask_solid_background
|
| 631 |
+
|
| 632 |
+
//last_selected_obj
|
| 633 |
+
this.last_selected_viewer_obj
|
| 634 |
+
this.thumbnail_scaler = 1
|
| 635 |
+
this.isSquareThumbnail = false
|
| 636 |
+
this.init_image_container = document.getElementById(
|
| 637 |
+
'divInitImageViewerContainer'
|
| 638 |
+
)
|
| 639 |
+
}
|
| 640 |
+
|
| 641 |
+
replaceLastSelection(click_type, clicked_object) {
|
| 642 |
+
if (
|
| 643 |
+
this.last_selected_viewer_obj && // is valid last selected object
|
| 644 |
+
this.last_selected_viewer_obj.objectId !== clicked_object.objectId // not the same object
|
| 645 |
+
|
| 646 |
+
// clicked_object instanceof OutputImage &&
|
| 647 |
+
// !clicked_object.isSameObject(this.last_selected_viewer_obj)
|
| 648 |
+
) {
|
| 649 |
+
//if the current selection and the last selection are different
|
| 650 |
+
|
| 651 |
+
this.last_selected_viewer_obj.visible(false)
|
| 652 |
+
this.last_selected_viewer_obj.active(false)
|
| 653 |
+
}
|
| 654 |
+
if (click_type === Enum.clickTypeEnum['Click']) {
|
| 655 |
+
this.last_selected_viewer_obj = clicked_object
|
| 656 |
+
} else if (click_type === Enum.clickTypeEnum['ShiftClick']) {
|
| 657 |
+
if (this.last_selected_viewer_obj) {
|
| 658 |
+
//if the last selected layer is valid then converted last selected layer into highlight layer
|
| 659 |
+
this.last_selected_viewer_obj.setHighlight(true)
|
| 660 |
+
}
|
| 661 |
+
this.last_selected_viewer_obj = clicked_object
|
| 662 |
+
} else if (click_type === Enum.clickTypeEnum['AltClick']) {
|
| 663 |
+
this.last_selected_viewer_obj = null
|
| 664 |
+
} else if (click_type === Enum.clickTypeEnum['SecondClick']) {
|
| 665 |
+
this.last_selected_viewer_obj = null
|
| 666 |
+
}
|
| 667 |
+
}
|
| 668 |
+
initializeInitImage(group, snapshot, solid_background, path) {
|
| 669 |
+
console.warn('this method is deprecated, use the session.js method ')
|
| 670 |
+
this.initGroup = group
|
| 671 |
+
this.init_solid_background = solid_background
|
| 672 |
+
this.addInitImageLayers(snapshot, path, true)
|
| 673 |
+
}
|
| 674 |
+
initializeMask(group, white_mark, solid_background, path, base64) {
|
| 675 |
+
this.maskGroup = group
|
| 676 |
+
this.mask_solid_background = solid_background
|
| 677 |
+
this.addMaskLayers(white_mark, path, true, base64)
|
| 678 |
+
}
|
| 679 |
+
addMaskLayers(white_mark, path, auto_delete, base64) {
|
| 680 |
+
try {
|
| 681 |
+
if (!this.maskLayersJson.hasOwnProperty(path)) {
|
| 682 |
+
//it's a new mask, mostly for the first time storing the mask
|
| 683 |
+
|
| 684 |
+
const mask_layers = new maskLayers(
|
| 685 |
+
this.maskGroup,
|
| 686 |
+
white_mark,
|
| 687 |
+
this.mask_solid_background,
|
| 688 |
+
auto_delete
|
| 689 |
+
)
|
| 690 |
+
this.maskLayersJson[path] = mask_layers
|
| 691 |
+
} else {
|
| 692 |
+
//for updating the mask
|
| 693 |
+
|
| 694 |
+
//just update the html
|
| 695 |
+
const new_path = `${path}?t=${new Date().getTime()}`
|
| 696 |
+
console.log('new mask path: ', new_path)
|
| 697 |
+
// this.maskLayersJson[path].img_html.src = new_path
|
| 698 |
+
|
| 699 |
+
// this.pathToViewerImage[path].img_html.src = new_path
|
| 700 |
+
this.pathToViewerImage[path].img_html.src = base64ToSrc(base64)
|
| 701 |
+
}
|
| 702 |
+
} catch (e) {
|
| 703 |
+
console.warn(e)
|
| 704 |
+
}
|
| 705 |
+
}
|
| 706 |
+
updateMaskLayer() {}
|
| 707 |
+
addInitImageLayers(snapshot, path, auto_delete) {
|
| 708 |
+
try {
|
| 709 |
+
if (!this.initImageLayersJson.hasOwnProperty(path)) {
|
| 710 |
+
//if this is a new init image
|
| 711 |
+
//store it all of layers in a container object
|
| 712 |
+
const init_image_layers = new initImageLayers(
|
| 713 |
+
this.initGroup,
|
| 714 |
+
snapshot,
|
| 715 |
+
this.init_solid_background,
|
| 716 |
+
auto_delete
|
| 717 |
+
)
|
| 718 |
+
this.initImageLayersJson[path] = init_image_layers
|
| 719 |
+
}
|
| 720 |
+
} catch (e) {
|
| 721 |
+
console.warn(e)
|
| 722 |
+
}
|
| 723 |
+
}
|
| 724 |
+
|
| 725 |
+
hasViewerImage(path) {
|
| 726 |
+
if (this.pathToViewerImage.hasOwnProperty(path)) {
|
| 727 |
+
return true
|
| 728 |
+
}
|
| 729 |
+
return false
|
| 730 |
+
}
|
| 731 |
+
addOutputImage(layer, path) {
|
| 732 |
+
const outputImage = new OutputImage(layer, path, this)
|
| 733 |
+
|
| 734 |
+
this.outputImages.push(outputImage)
|
| 735 |
+
this.pathToViewerImage[path] = outputImage //
|
| 736 |
+
return outputImage
|
| 737 |
+
}
|
| 738 |
+
addInitImage(group, snapshot, solid_background, path, auto_delete) {
|
| 739 |
+
const initImage = new InitImage(
|
| 740 |
+
group,
|
| 741 |
+
snapshot,
|
| 742 |
+
solid_background,
|
| 743 |
+
path,
|
| 744 |
+
this
|
| 745 |
+
)
|
| 746 |
+
initImage.setAutoDelete(auto_delete)
|
| 747 |
+
this.initImages.push(initImage)
|
| 748 |
+
this.pathToViewerImage[path] = initImage
|
| 749 |
+
return initImage
|
| 750 |
+
}
|
| 751 |
+
addMask(group, white_mark, solid_background, path) {
|
| 752 |
+
const mask = new InitMaskImage(
|
| 753 |
+
group,
|
| 754 |
+
white_mark,
|
| 755 |
+
solid_background,
|
| 756 |
+
path,
|
| 757 |
+
this
|
| 758 |
+
)
|
| 759 |
+
|
| 760 |
+
this.initMaskImage = mask
|
| 761 |
+
this.pathToViewerImage[path] = mask
|
| 762 |
+
return mask
|
| 763 |
+
}
|
| 764 |
+
|
| 765 |
+
scaleThumbnails(
|
| 766 |
+
original_width,
|
| 767 |
+
original_height,
|
| 768 |
+
min_width,
|
| 769 |
+
min_height,
|
| 770 |
+
scaler
|
| 771 |
+
) {
|
| 772 |
+
//calculate the new width and height
|
| 773 |
+
|
| 774 |
+
const image_width = this.isSquareThumbnail
|
| 775 |
+
? 100
|
| 776 |
+
: g_generation_session.last_settings.width
|
| 777 |
+
const image_height = this.isSquareThumbnail
|
| 778 |
+
? 100
|
| 779 |
+
: g_generation_session.last_settings.height
|
| 780 |
+
|
| 781 |
+
const [new_width, new_height] = general.scaleToClosestKeepRatio(
|
| 782 |
+
image_width,
|
| 783 |
+
image_height,
|
| 784 |
+
100,
|
| 785 |
+
100
|
| 786 |
+
)
|
| 787 |
+
const [scaled_width, scaled_height] = [
|
| 788 |
+
new_width * scaler,
|
| 789 |
+
new_height * scaler,
|
| 790 |
+
]
|
| 791 |
+
|
| 792 |
+
for (let outputImage of this.outputImages) {
|
| 793 |
+
//get the image and it's container
|
| 794 |
+
const img = outputImage.img_html
|
| 795 |
+
const img_container = img.parentElement
|
| 796 |
+
|
| 797 |
+
img_container.style.width = scaled_width
|
| 798 |
+
img_container.style.height = scaled_height
|
| 799 |
+
img.style.width = scaled_width
|
| 800 |
+
img.style.height = scaled_height
|
| 801 |
+
//scale them to the new dimensions
|
| 802 |
+
}
|
| 803 |
+
}
|
| 804 |
+
onSessionEnd() {
|
| 805 |
+
this.outputImages = []
|
| 806 |
+
this.initImages = []
|
| 807 |
+
this.initMaskImage = null
|
| 808 |
+
|
| 809 |
+
this.pathToViewerImage = {} // quick way to check if an link image path on disk to ViewerImage object.
|
| 810 |
+
this.initImageLayersJson = {} //{path: initImageLayers}
|
| 811 |
+
|
| 812 |
+
this.selectedOutputImages = {} //store the selected output images {path: outputImage}
|
| 813 |
+
|
| 814 |
+
this.mask_layer = null
|
| 815 |
+
this.maskLayersJson = {} //{path: MaskLayers}
|
| 816 |
+
|
| 817 |
+
//Note:move initGroup, to GenerationSession
|
| 818 |
+
this.initGroup = null
|
| 819 |
+
this.init_solid_background = null
|
| 820 |
+
this.maskGroup = null
|
| 821 |
+
this.mask_solid_background = null
|
| 822 |
+
|
| 823 |
+
//last_selected_obj
|
| 824 |
+
this.last_selected_viewer_obj = null
|
| 825 |
+
// this.thumbnail_scaler = 1
|
| 826 |
+
// this.isSquareThumbnail = false
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
async loadInitImageViewerObject(path) {
|
| 830 |
+
if (!g_viewer_manager.hasViewerImage(path)) {
|
| 831 |
+
const group = this.initImageLayersJson[path].group
|
| 832 |
+
const snapshot = this.initImageLayersJson[path].snapshot
|
| 833 |
+
const solid_background =
|
| 834 |
+
this.initImageLayersJson[path].solid_background
|
| 835 |
+
const auto_delete = this.initImageLayersJson[path].autoDelete
|
| 836 |
+
const base64_image = g_generation_session.base64initImages[path]
|
| 837 |
+
await loadInitImageViewerObject(
|
| 838 |
+
group,
|
| 839 |
+
snapshot,
|
| 840 |
+
solid_background,
|
| 841 |
+
path,
|
| 842 |
+
auto_delete,
|
| 843 |
+
base64_image
|
| 844 |
+
)
|
| 845 |
+
}
|
| 846 |
+
}
|
| 847 |
+
deleteAll() {}
|
| 848 |
+
keepAll() {}
|
| 849 |
+
keepSelected() {}
|
| 850 |
+
deleteSelected() {}
|
| 851 |
+
deleteInitImages() {}
|
| 852 |
+
deleteMask() {}
|
| 853 |
+
}
|
| 854 |
+
|
| 855 |
+
module.exports = {
|
| 856 |
+
OutputImage,
|
| 857 |
+
InitImage,
|
| 858 |
+
InitMaskImage,
|
| 859 |
+
ViewerObjState,
|
| 860 |
+
ViewerManager,
|
| 861 |
+
}
|
Stable-Diffusion-Webui-Civitai-Helper/.github/ISSUE_TEMPLATE/simple-issue-template.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
name: Simple Issue template
|
| 3 |
+
about: Describe this issue template's purpose here.
|
| 4 |
+
title: ''
|
| 5 |
+
labels: ''
|
| 6 |
+
assignees: ''
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## Have you read document?
|
| 11 |
+
|
| 12 |
+
## Have you checked console log window's msg?
|
| 13 |
+
|
| 14 |
+
## Describe Issue
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
## Screenshot for UI issue
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
## Console log's msg or screenshot for function issue
|
Stable-Diffusion-Webui-Civitai-Helper/.gitignore
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
scripts/__pycache__/
|
| 2 |
+
scripts/ch_lib/__pycache__/
|
| 3 |
+
setting.json
|
Stable-Diffusion-Webui-Civitai-Helper/README.cn.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## 关于Civitai Helper2: Model Info Helper
|
| 2 |
+
Civitai助手2将改名为**Model Info助手**。目前还在缓慢开发中。你可以查看它的UI演示视频,了解它会是什么样子:
|
| 3 |
+
[https://youtu.be/mPcKwQDDH8s](https://youtu.be/mPcKwQDDH8s)
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
# Civitai Helper
|
| 7 |
+
Stable Diffusion Webui 扩展Civitai助手,用于更轻松的管理和使用Civitai模型。
|
| 8 |
+
|
| 9 |
+
[Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension)
|
| 10 |
+
|
| 11 |
+
# 注意
|
| 12 |
+
**本插件现在非常稳定,很多人用得很好,如果碰到问题,先看[常见问题](#常见问题),并检查命令行窗口的详情。**
|
| 13 |
+
开issue前,请先看文档。找茬行为的用户将会被拉黑,参考:[找茬行为会被拉黑](https://github.com/butaixianran/Stable-Diffusion-Webui-Civitai-Helper/issues/96#issuecomment-1500310981)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# 功能
|
| 17 |
+
[中文介绍视频(非官方)](https://youtu.be/x4tPWPmeAgM?t=373)
|
| 18 |
+
|
| 19 |
+
* 扫描所有模型,从Civitai下载模型信息和预览图
|
| 20 |
+
* 通过civitai模型页面url,连接本地模型和civitai模型信息
|
| 21 |
+
* 通过Civitai模型页面url,下载模型(含信息和预览图)到SD目录或子目录。
|
| 22 |
+
* 下载支持断点续传
|
| 23 |
+
* 批量检查本地模型,在civitai上的新版本
|
| 24 |
+
* 直接下载新版本模型到SD模型目录内(含信息和预览图)
|
| 25 |
+
* 修改了内置的"Extra Network"模型卡片,每个卡片增加了如下功能按钮:
|
| 26 |
+
- 🖼: 修改文字"replace preview"为这个图标
|
| 27 |
+
- 🌐: 在新标签页打开这个模型的Civitai页面
|
| 28 |
+
- 💡: 一键添加这个模型的触发词到关键词输入框
|
| 29 |
+
- 🏷: 一键使用这个模型预览图所使用的关键词
|
| 30 |
+
* 以上额外功能按钮支持thumbnail模式
|
| 31 |
+
* 增加一直显示按钮的选项,以供触屏用户使用
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# 安装
|
| 35 |
+
下载本项目为zip文件,解压到`你的SD webui目录/extensions`下即可。
|
| 36 |
+
|
| 37 |
+
不管是安装还是升级本插件,都要整个关闭SD Webui,重新启动它。只是Reload UI不起作用。
|
| 38 |
+
|
| 39 |
+
(如果用SD webui的插件界面安装,请先给git配置代理。它不是通过浏览器下载,是通过git下载。)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# 使用方法
|
| 43 |
+
|
| 44 |
+
## 更新你的SD webui
|
| 45 |
+
本扩展需要取到 Extra Network的卡片列表id。**这个是2023-02-06,才添加到SD webui里面的。**
|
| 46 |
+
|
| 47 |
+
所以,如果你用的版本比这个早,你就需要先更新你的SD Webui!
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
## 扫描模型
|
| 51 |
+
前往扩展页面"Civitai Helper",有个按钮叫:"Scan Model"
|
| 52 |
+
|
| 53 |
+

|
| 54 |
+
|
| 55 |
+
点击,就会扫描所有模型,生成SHA256码,用于从civitai获取模型信息和预览图。**扫描需要很久,耐心等待**。
|
| 56 |
+
|
| 57 |
+
每个模型,本扩展都会创建一个json文件,用来保存从civitai得到的模型信息。这个文件会保存在模型同目录下,名称为:"模型名字.civitai.info"。
|
| 58 |
+
|
| 59 |
+

|
| 60 |
+
|
| 61 |
+
如果模型信息文件已经存在,扫描时就会跳过这个模型。如果模型不是civitai的,就会创建个空信息文件,以避免以后重复扫描。
|
| 62 |
+
|
| 63 |
+
### 添加新模型
|
| 64 |
+
当你下载了新模型之后,只要再次点击扫描按钮即可。已经扫描过的文件不会重复扫描,会自动得到新模型的信息和预览图。无须重启SD webui。
|
| 65 |
+
|
| 66 |
+
## 模型卡片
|
| 67 |
+
**(先完成扫描,再使用卡片功能)**
|
| 68 |
+
打开SD webui's 内置的 "Extra Network" 页面,显示模型卡片
|
| 69 |
+
|
| 70 |
+

|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
移动鼠标到模型卡片底部,就会显示4个按钮:
|
| 74 |
+
- 🖼: 修改文字"replace preview"为这个图标
|
| 75 |
+
- 🌐: 在新标签页打开这个模型的Civitai页面
|
| 76 |
+
- 💡: 一键添加这个模型的触发词到关键词输入框
|
| 77 |
+
- 🏷: 一键使用这个模型预览图所使用的关键词
|
| 78 |
+
|
| 79 |
+

|
| 80 |
+
|
| 81 |
+
如果你没有看到这些额外的按钮,只要点击`Refresh Civitai Helper`,他们就会被重新添加到卡片上。
|
| 82 |
+
|
| 83 |
+

|
| 84 |
+
|
| 85 |
+
每次当Extra Network刷新,他都会删除掉额外的修改,我们的按钮就会消失。这时你就需要点击`Refresh Civitai Helper`把这些功能添加回去。
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
### 小图模式
|
| 89 |
+
以上功能按钮支持小图模式,但受制于SD Webui的CSS问题,目前,只能要么一直显示,要么一直不显示,不能鼠标滑过才显示。
|
| 90 |
+

|
| 91 |
+
|
| 92 |
+
## 下载
|
| 93 |
+
**(单任务,下载完一个再下另一个)**
|
| 94 |
+
通过Civitai模型页面Url下载模型,要3个步骤:
|
| 95 |
+
* 填入url,点击按钮获取模型信息
|
| 96 |
+
* 扩展会自动填入模型名称和类型,你需要选择下载的子目录和模型版本。
|
| 97 |
+
* 点击下载
|
| 98 |
+

|
| 99 |
+
|
| 100 |
+
下载过程会显示在命令行界面带个进度条。
|
| 101 |
+
支持断点续传,无畏大文件。
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
## 批量检查模型新版本
|
| 105 |
+
你可以按照模型类型,批量检查你的本地模型,在civitai上的新版本。你可以选择多个模型类型。
|
| 106 |
+

|
| 107 |
+
|
| 108 |
+
检查新版本的时候,每检查完一个模型,都会有一个1秒的延迟,所以速度有点慢。
|
| 109 |
+
|
| 110 |
+
这是为了保护Civitai避免因为本插件而短暂陷入类似DDos的局面。有些云服务商,有类似“免费用户每秒API请求不能超过1次”的保护机制。Civitai还没有这种设置。但我们还是得自觉保护它。因为如果它挂了,对大家都没有好处。
|
| 111 |
+
|
| 112 |
+
**检查完毕之后**,就会如下图,在UI上显示所有找到的新版本的信息。
|
| 113 |
+
|
| 114 |
+
每个模型新版本,都有3个链接。
|
| 115 |
+
* 第一个是这个模型的网页。
|
| 116 |
+
* 第二个是这个新版本的下载地址。
|
| 117 |
+
* 第三个是个按钮,在python端,直接下载新版本到模型目录内。
|
| 118 |
+
这种方式下载,下载详情显示在"Download Model"的区域和命令行窗口中。一次一个任务,不支持多任务。
|
| 119 |
+

|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
## 根据URL获取模型信息
|
| 124 |
+
如果无法在civitai上找到你的模型的SHA256,但你还是希望能把你的模型连接到一个civitai模型,你可以在本扩展页面,从列表中选择你的模型,并提供一个civitai模型页面的url。
|
| 125 |
+
|
| 126 |
+
点击按钮之后,扩展就会下载那个civitai模型的信息,作为你这个本地模型的信息使用。
|
| 127 |
+
|
| 128 |
+

|
| 129 |
+
|
| 130 |
+
## 代理
|
| 131 |
+
**如果你是刚更新新版本,你需要重启SD webui再来使用**
|
| 132 |
+
|
| 133 |
+
代理输入框在插件页面最下方。
|
| 134 |
+
|
| 135 |
+
**每次填入或清除代理后,都要保存,并用SDwebui设置页面的Reload UI按钮刷新UI**
|
| 136 |
+
|
| 137 |
+
然后所有发到civitai的请求就会用代理。
|
| 138 |
+
|
| 139 |
+
有些sock5代理, 需要使用socks5h开头的形式"socks5h://xxxxx"才能生效。
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
## 其他设置
|
| 144 |
+
**保存设置按钮, 会保存扫描模型区域,以及其他设置 这两个区域的选项**
|
| 145 |
+
|
| 146 |
+
* "一直显示按钮" 是为了方便触屏。
|
| 147 |
+
* "小图模式显示功能按钮" 会开关功能按钮在小图模式的显示
|
| 148 |
+

|
| 149 |
+
|
| 150 |
+
## 预览图
|
| 151 |
+
Extra Network支持两种预览图命名:`model_name.png` 和 `model_name.preview.png`。其中,`model_name.png`优先级较高。
|
| 152 |
+
|
| 153 |
+
当优先级较高的预览图不存在,他就会自动使用`model_name.preview.png`。
|
| 154 |
+
|
| 155 |
+
这样,你自己创建的预览图 和 网络下载的预览图,能够同时存在,并优先使用你自己创建的。
|
| 156 |
+
|
| 157 |
+
## 关键词
|
| 158 |
+
卡片上,添加关键词按钮,是添加从civitai预览图中得到的关键词,而不是你自己创建的图片的关键词。
|
| 159 |
+
|
| 160 |
+
civitai不是每个图片都有关键词,一个模型中,也不是所有预览图关键词都一样。所以这里是遍历所有civitai预览图信息,加载第一个有关键词的。
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
## SHA256
|
| 164 |
+
为了创建文件的SHA256,插件需要读取整个文件。对于大尺寸文件,就会很慢。
|
| 165 |
+
|
| 166 |
+
有两种情况,这个SHA256无法从civitai找到对应模型:
|
| 167 |
+
* 太老的模型,civitai没有存储SHA256.
|
| 168 |
+
* 模型作者,静静的换掉了模型文件,但没有修改描述和版本。所以,虽然网页上看不出来,但实际上civitai上的 和你本地的模型文件,已经不是同一个文件了。
|
| 169 |
+
|
| 170 |
+
这些情况下,你可以在插件上,通过提供模型页面的url,来获取模型信息文件。
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
## 新特性
|
| 175 |
+
从v1.5开始,v1.x不再接受任何新特性。所有新特性进入2.x。
|
| 176 |
+
|
| 177 |
+
2.x专注于自定义模型信息,并可能改名为"Model Info Helper"。因为不再是专注Civitai了。
|
| 178 |
+
|
| 179 |
+
从v1.5开始。v1.x进入维护阶段。
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
Enjoy!
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
## 常见问题
|
| 186 |
+
### 4个卡片按钮不显示
|
| 187 |
+
#### 汉化原因
|
| 188 |
+
下载新版,最新版已经处理汉化导致的问题。**双语汉化插件需要v1.6.1.1之后的版本才开始支持。**
|
| 189 |
+
|
| 190 |
+
#### 使用了云端汉化功能
|
| 191 |
+
如果是秋叶启动器,就关闭启动器“云端汉化”功能。如果是专门的云端汉化插件,就换用普通汉化插件。
|
| 192 |
+
|
| 193 |
+
#### 其他情况
|
| 194 |
+
首先,确保你点过了"Refresh Civitai Helper"刷新按钮。
|
| 195 |
+
|
| 196 |
+
然后,如果还有这个问题,那么唯一原因,是你没有使用最新版SD webui。
|
| 197 |
+
|
| 198 |
+
如果你修改过SD webui的文件, 你的更新操作可能会失败。你需要检查git命令行的输出信息,来确定你更新成功了。
|
| 199 |
+
|
| 200 |
+
git在很多时候,会拒绝升级,并告诉你有些冲突需要你手动先解决。如果你不看命令行输出,你就会以为你已经更新成功了,但其实并没有。
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
### Request model info from civitai
|
| 204 |
+
意思就是正在连接civitai,如果没有后面的信息,就是连不上,请挂代理。
|
| 205 |
+
|
| 206 |
+
|
| 207 |
+
### 扫描或获取模型信息失败
|
| 208 |
+
这个插件现在很稳定,所以,这个问题的原因,基本是是因为Civitai拒绝了你的连接请求。
|
| 209 |
+
|
| 210 |
+
Civitai不像那些大网站那么稳定。他网站会挂,会拒绝API连接,还会把API请求转到真人验证页面,来挡住。
|
| 211 |
+
|
| 212 |
+
Civitai还有连接池的设定。基本上,就是同时能允许的最大连接数。一旦达到这个数字,接下来的API连接请求,都会被拒绝。
|
| 213 |
+
|
| 214 |
+
所以,这种时候你只能等一下再试。
|
| 215 |
+
|
| 216 |
+
另外,对于国��用户,还有代理问题。现在国内都要用代理才能连上。
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
### 扫描之后得到了错误的预览图和模型信息
|
| 220 |
+
坏消息是,有些模型在civitai数据库中,保存的sha256完全是错的。查看下面的issue了解详情:
|
| 221 |
+
[https://github.com/civitai/civitai/issues/426](https://github.com/civitai/civitai/issues/426)
|
| 222 |
+
|
| 223 |
+
对于这种模型,那这个插件自然就无法获得正确的模型信息和预览图。
|
| 224 |
+
|
| 225 |
+
这种情况下,请删除扫描得到的模型信息和预览图,在插件界面提供正确的模型url来获取。
|
| 226 |
+
|
| 227 |
+
另外,civitai官方有个页面,专门用于回报带有错误sha256的模型:
|
| 228 |
+
[https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100](https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100)
|
| 229 |
+
|
| 230 |
+
请把这类模型反馈给civitai,好让他们进行修复。
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
### 使用colab时扫描失败
|
| 236 |
+
首先,在google中搜索你看到的错误信息。更有可能是,你碰到的是个colab的问题。
|
| 237 |
+
|
| 238 |
+
然后,如果colab连接了google drive,会有一次性访问文件数量的限制,而导致扫描失败。这是google drive的限制,请自行google搜索了解详情。
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
|
Stable-Diffusion-Webui-Civitai-Helper/README.jp.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### Language
|
| 2 |
+
[中文](README.cn.md)
|
| 3 |
+
[English](README.md)
|
| 4 |
+
[한국어(ChatGPT)](README.kr.md)
|
| 5 |
+
|
| 6 |
+
## About Civitai Helper2: Model Info Helper
|
| 7 |
+
Civitai Helper 2は、**ModelInfo Helper**に改名されます。現在開発中です。デモをご覧ください:
|
| 8 |
+
[YouTube](https://youtu.be/mPcKwQDDH8s)
|
| 9 |
+
|
| 10 |
+
# お知らせ
|
| 11 |
+
**この拡張機能は現在、非常に安定しています。もし問題があれば、コンソールログの詳細を確認し、[よくある質問](#よくある質問)を確認してください。**
|
| 12 |
+
|
| 13 |
+
# Civitai Helper
|
| 14 |
+
この拡張機能は、Civitaiのモデルをより簡単に扱えるようにするためのものです。
|
| 15 |
+
|
| 16 |
+
Civitai: [Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension)
|
| 17 |
+
|
| 18 |
+
# 機能
|
| 19 |
+
* 全てのモデルをスキャンし、Civitaiからモデル情報とプレビューをダウンロード
|
| 20 |
+
* CivitaiモデルページのURLを使って、ローカルモデルとCivitaiモデル情報を取得
|
| 21 |
+
* CivitaiモデルページのURLから、モデル(情報とプレビューを含む)をSDディレクトリまたはサブディレクトリにダウンロードする。
|
| 22 |
+
* ダウンロードは途中から再開可能
|
| 23 |
+
* ローカルのモデルとCivitai上の新しいバージョンを一括でチェック
|
| 24 |
+
* 新しいバージョンのモデルを直接モデルのディレクトリにダウンロード(情報とプレビュー画像を含む)
|
| 25 |
+
* 内蔵の**Extra Network**モデルカードを変更し、各カードに以下の機能ボタンを追加しました。
|
| 26 |
+
- 🖼: `replace preview`のテキストをこのアイコンに変更
|
| 27 |
+
- 🌐: このモデルのCivitaiページを新しいタブで開く
|
| 28 |
+
- 💡: このモデルのトリガーワードをキーワード入力欄に一括で追加する
|
| 29 |
+
- 🏷: このモデルのプレビュー画像で使用されているキーワードを一括で使用する
|
| 30 |
+
* 上記の追加機能ボタンは、サムネイルモードにも対応しています。
|
| 31 |
+
* タッチスクリーンデバイス向けに、常に表示されるボタンのオプションを追加しました。
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# インストール
|
| 35 |
+
SD webui's extensionタブから、`Install from url`のタブに移動。
|
| 36 |
+
このリポジトリのURLをコピーペーストし、インストールする。
|
| 37 |
+
|
| 38 |
+
または、このリポジトリをzipでダウンロードし、`./webui/extensions`へ展開してください。
|
| 39 |
+
|
| 40 |
+
この拡張機能をインストール、またはアップデートするたびに、SD Webui再起動する必要があります。
|
| 41 |
+
この拡張機能は、**UIを再読み込みする**だけでは動作しません。
|
| 42 |
+
|
| 43 |
+
# 使い方
|
| 44 |
+
|
| 45 |
+
## WebUIをアップデート
|
| 46 |
+
この拡張機能は`network cards id`を取得する必要があります。この機能は**2023-02-06**に追加されました。
|
| 47 |
+
**SD webuiがこれより前のバージョンである場合は、アップデートする必要があります!**
|
| 48 |
+
|
| 49 |
+
## モデルのスキャン
|
| 50 |
+
拡張機能タブから<kbd>Civitai Helper</kbd>へ。
|
| 51 |
+
<kbd>Scan model</kbd>というボタンがあります。
|
| 52 |
+
|
| 53 |
+

|
| 54 |
+
|
| 55 |
+
これをクリックすると、拡張機能がすべてのモデルをスキャンしてSHA256ハッシュを生成し、それを使ってCivitaiからモデル情報とプレビュー画像を取得します。
|
| 56 |
+
**スキャンには時間がかかります。 終了までお待ちください。**
|
| 57 |
+
|
| 58 |
+
各モデルに対して、Civitaiからすべてのモデル情報を保存するためのjsonファイルを作成します。このモデル情報ファイルは、modelsディレクトリ内の`Your_model_name.civitai.info`となります。
|
| 59 |
+
|
| 60 |
+

|
| 61 |
+
|
| 62 |
+
モデル情報ファイルがすでに存在する場合は、スキップされます。Civitaiでモデルが見つからない場合、空のモデル情報ファイルを作成するので、モデルが2回スキャンされることはありません。
|
| 63 |
+
|
| 64 |
+
### 新しいモデルを追加
|
| 65 |
+
新規のモデルがある場合、もう一度スキャンボタンをクリックするだけで、新しいモデルの情報とプレビューを取得できます。同じモデルを2回スキャンすることはありません。
|
| 66 |
+
|
| 67 |
+
## モデルカード
|
| 68 |
+
**(スキャン終了後に使用)**
|
| 69 |
+
SD webuiの`Extra Network`タブを開き、モデルカードを表示します。
|
| 70 |
+
|
| 71 |
+

|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
マウスをモデルカードの下部に移動すると、4つのボタンが表示されます。
|
| 75 |
+
- 🖼: プレビューを置き換えるためのテキストを`replace preview`からこのアイコンに変更します
|
| 76 |
+
- 🌐: このモデルのCivitaiページを新しいタブで開きます
|
| 77 |
+
- 💡: このモデルのトリガーワードをキーワード入力欄に一括追加します
|
| 78 |
+
- 🏷: このモデルのプレビュー画像に使用されているキーワードを一括で使用します
|
| 79 |
+
|
| 80 |
+

|
| 81 |
+
|
| 82 |
+
これらのボタンが表示���れない場合は、<kbd>Refresh Civitai Helper</kbd>をクリックすると、ボタンがカードに再追加されます。
|
| 83 |
+
|
| 84 |
+

|
| 85 |
+
|
| 86 |
+
`Extra Network`が更新されるたびに、余分な変更が削除され、ボタンが消えてしまいます。その場合は、「Refresh Civitai Helper」をクリックして、これらの機能を再度追加する必要があります。
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
### サムネイル
|
| 90 |
+
これらのボタンは、サムネイルをサポートしていますが、SD WebuiのCSSの問題により、現在は常に表示か非表示かのどちらかに制限されています。マウスをスライドして表示することはできません。
|
| 91 |
+

|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
## ダウンロード
|
| 95 |
+
**(タスクが一つ完了してから、次のタスクをダウンロードしてください)**
|
| 96 |
+
CivitaiモデルページのURLを使用してモデルをダウンロードするには、3つのステップが必要です。
|
| 97 |
+
1. URLを入力し、モデル情報を取得するためにボタンをクリック
|
| 98 |
+
2. 拡張機能が自動的にモデル名とタイプを入力します。ダウンロードするサブディレクトリとモデルバージョンを選択
|
| 99 |
+
3. ダウンロードをクリックします
|
| 100 |
+

|
| 101 |
+
|
| 102 |
+
ダウンロード状況は、CLIに進行状況バーを表示します。
|
| 103 |
+
断片的に再開することができ、大きなファイルをダウンロードする際にも心配する必要はありません。
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
## 新しいモデルのバージョンを確認する
|
| 107 |
+
モデルの種類に従って、ローカルのモデルを一括でCivitaiの新バージョンがないかをチェックすることができます。複数のモデルの種類を選択できます。
|
| 108 |
+

|
| 109 |
+
|
| 110 |
+
これを押すと、各モデルをチェックするたびに1秒の遅延が発生するため、速度がやや遅くなります。
|
| 111 |
+
|
| 112 |
+
これは、本拡張機能のユーザーの過失によるDDoSを回避し、Civitaiを保護するために行われます。
|
| 113 |
+
一部のクラウドサービスプロバイダーには、「無料ユーザーのAPIリクエストは1秒あたり1回を超えてはいけない」というような保護があります。Civitaiにはまだこのような設定がありませんが、我々はそれを自衛しなければなりません。
|
| 114 |
+
なぜなら、もしCivitaiがダウンした場合、誰にとっても良いことではないからです。
|
| 115 |
+
|
| 116 |
+
チェックが完了すると、すべての新しいバージョンがUIに表示されます。
|
| 117 |
+
|
| 118 |
+
各モデルの新しいバージョンには、3つのリンクがあります。
|
| 119 |
+
* 最初のものは、このモデルのWebページです。
|
| 120 |
+
* 2つ目は、この新しいバージョンのダウンロードアドレスです。
|
| 121 |
+
* 3つ目は、Python(拡張機能)側で新しいバージョンをモデルディレクトリに直接ダウンロードするボタンです。
|
| 122 |
+
この方法でダウンロードすると、ダウンロードの詳細が「Download Model」の領域とコマンドラインに表示されます。一度に1つのタスクしかサポートされていません。
|
| 123 |
+

|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
## URLからモデル情報を取得する
|
| 128 |
+
Civitai上で自分のモデルのSHA256が見つからない場合でも、自分のモデルをCivitaiモデルに接続したい場合は、この拡張機能のページから、モデルをリストから選択し、CivitaiモデルページのURLを提供することができます。
|
| 129 |
+
|
| 130 |
+
ボタンをクリックすると、拡張機能はCivitaiモデルの情報をダウンロードし、それをローカルモデルの情報として使用します。
|
| 131 |
+
|
| 132 |
+

|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
## その他の設定
|
| 137 |
+
**設定保存ボタンを押すと、<kbd>Scan Model</kbd>の設定とその他の設定の両方が保存されます。**
|
| 138 |
+
|
| 139 |
+
* <kbd>Always Display Button</kbd>は、タッチデバイスでの操作を容易にするためです。
|
| 140 |
+
* <kbd>Show Buttons on Thumb Mode</kbd>は、小さな画像モードでの機能ボタンの表示を切り替えます。
|
| 141 |
+

|
| 142 |
+
|
| 143 |
+
## プレビュー
|
| 144 |
+
Extra Networkは、2つのプレビュー画像の命名をサポートしています:`model_name.png`と`model_name.preview.png`。
|
| 145 |
+
デフォルトでは自動で`model_name.png`が優先的に使われます。
|
| 146 |
+
|
| 147 |
+
優先度が高いプレビュー画像が存在しない場合は、自動的に`model_name.preview.png`が使用されます。
|
| 148 |
+
|
| 149 |
+
これにより、自分で作成したプレビュー画像とネットからダウンロードしたプレビュー画像を同時に使用し、自分で作成したプレビュー画像を優先的に使用できます。
|
| 150 |
+
|
| 151 |
+
## プロンプト
|
| 152 |
+
カード上の<kbd>Use prompt from preview image</kbd>ボタンは、Civitaiプレビュー画像から取得したキーワードであり、自分で作成した画像のキーワードではありません。
|
| 153 |
+
|
| 154 |
+
Civitaiにはすべての画像にキーワードがあるわけではなく、1つのモデルに含まれるすべてのプレビュー画像のキーワードが同じであるわけでもありません。したがって、ここではすべてのCivitaiプレビュー画像情報を走査し、最初にキーワードがあるものを読み込みます。
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
## SHA256
|
| 158 |
+
ファイルのSHA256を作成するために、はファイル全体を読み取る必要があります。大きなファイルの場合、処理が遅くなります。
|
| 159 |
+
|
| 160 |
+
Civitaiで対応するモデルのSHA256が見つからない場合は、次の2つの場合が考えられます:
|
| 161 |
+
* 古すぎるモデルには、SHA256が保存されていません。
|
| 162 |
+
* モデルの作成者が静かにモデルファイルを変更しましたが、説明やバージョンを変更していないため、サイト上ではわかりませんが、実際にはCivitaiに保存されているモデルファイルとローカルのモデルファイルは異なるものとなっています。
|
| 163 |
+
|
| 164 |
+
これらの場合は、拡張機能にモデルページのURLを提供することで、モデルの情報ファイルを取得できます。
|
| 165 |
+
|
| 166 |
+
## Feature Request
|
| 167 |
+
v1.5以降のv1.xには新機能はありません。すべての新機能は2.xに移行されます。
|
| 168 |
+
2.xでは、カスタムモデル情報にフォーカスし、Civitaiだけではなく、`Model Info Helper`という名称に変更する可能性があります。
|
| 169 |
+
v1.5からv1.xはメンテナンスのフェーズに入ります。
|
| 170 |
+
|
| 171 |
+
お楽しみに!
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
## よくある質問
|
| 175 |
+
### 4つのカードボタンが表示されない
|
| 176 |
+
#### ローカライズの問題
|
| 177 |
+
新しいバージョンをダウンロードしてください。
|
| 178 |
+
最新バージョンでは、ローカライズによる問題が解決されています。
|
| 179 |
+
[バイリンガル拡張機能](https://github.com/journey-ad/sd-webui-bilingual-localization)は、v1.6.1.1以降のバージョンでサポートされるようになりました。
|
| 180 |
+
|
| 181 |
+
#### クラウドサービスベースの翻訳機能を使用した
|
| 182 |
+
クラウドサービスベースの翻訳機能を使用している場合は、通常のローカライズに変更してください。
|
| 183 |
+
|
| 184 |
+
#### その他の場合
|
| 185 |
+
まず、<kbd>Refresh Civitai Helper</kbd>をクリックして更新しましたか?
|
| 186 |
+
|
| 187 |
+
それでもこの問題が発生する場合は、おそらく最新バージョンのSD webuiを使用していないためです。
|
| 188 |
+
|
| 189 |
+
SD webuiのファイルを変更した場合、更新操作が失敗する可能性があります。更新が成功したかどうかを確認するには、gitコマンドラインの出力情報を確認する必要があります。
|
| 190 |
+
|
| 191 |
+
gitは、多くの場合、アップグレードを拒否し、手動で解決する必要があるいくつかの競合状態を示します。コマンドライン出力を見ない場合、更新が成功したと思うかもしれませんが、実際には成功していません。
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
### Request model info from civitai
|
| 195 |
+
これはcivitaiに接続しています。情報がない場合は接続できないため、プロキシを使用してください。
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
### スキャンまたはモデル情報の取得に失敗しました
|
| 199 |
+
この拡張機能は現在非常に安定しているため、この問題の原因は基本的にはCivitaiが接続要求を拒否したためです。
|
| 200 |
+
|
| 201 |
+
Civitaiは大きなウェブサイトとは異なり、安定していません。彼らのウェブサイトはダウンしたり、API接続を拒否したり、APIリクエストをCpatchaページに転送してブロックしたりすることがあります。
|
| 202 |
+
|
| 203 |
+
Civitaiには接続プールの上限もあります。基本的に、同時に許可される最大接続数です。この数字に達すると、以降のAPI接続要求はすべて拒否されます。
|
| 204 |
+
|
| 205 |
+
そのため、このような場合はしばらく待ってから再試行するしかありません。
|
| 206 |
+
|
| 207 |
+
### civitaiから誤ったモデル情報とプレビュー画像を取得する(Translated by ChatGPT)
|
| 208 |
+
悪いニュースですが、civitaiのデータベースには誤ったsha256で保存されたモデルがいくつかあります。詳細についてはこちらをご覧ください:
|
| 209 |
+
[https://github.com/civitai/civitai/issues/426](https://github.com/civitai/civitai/issues/426)
|
| 210 |
+
|
| 211 |
+
したがって、これらのモデルについては、この拡張機能では正しいモデル情報やプレビュー画像を取得できません。
|
| 212 |
+
|
| 213 |
+
この場合、モデル情報ファイルを削除し、この拡張機能のタブページでcivitaiのURLから正しいモデル情報を取得する必要があります。
|
| 214 |
+
|
| 215 |
+
また、誤ったsha256を持つこれらのモデルをcivitaiに報告することもできます。
|
| 216 |
+
[https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100](https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100)
|
| 217 |
+
|
| 218 |
+
civitaiにそのモデルを報告して修正してもらうようにしてください。
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
### colabを使用した際にスキャンに失敗する
|
| 222 |
+
まず、表示されたエラーメッセージをGoogleで検索してください。おそらくcolabの問題が発生している可能性があります。表示されたエラーメッセージを検索して、原因を特定してください。
|
| 223 |
+
|
| 224 |
+
Google Driveに接続する際には、ファイルへのアクセス数に制限があるため、スキャンが失敗することがよくあります。これはGoogle Drive側の制限です。詳細についてはインターネットで[検索](https://google.com)してください。
|
Stable-Diffusion-Webui-Civitai-Helper/README.kr.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Civitai Helper
|
| 2 |
+
Stable Diffusion Webui는 Civitai 모델을 더 쉽게 관리하고 사용하기 위한 Civitai Assistant 확장 기능입니다.
|
| 3 |
+
|
| 4 |
+
[Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension)
|
| 5 |
+
|
| 6 |
+
# 주의사항
|
| 7 |
+
**이 플러그인은 지금 매우 안정적이며 많은 사용자들이 잘 사용하고 있습니다. 문제가 발생하면, [자주 묻는 질문](#자주-묻는-질문)을 먼저 확인하고 명령 프롬프트 창의 세부 정보를 확인하세요.**
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
# 기능
|
| 13 |
+
* 모든 모델을 스캔하여 Civitai에서 모델 정보 및 미리보기 이미지 다운로드
|
| 14 |
+
* Civitai 모델 페이지 URL을 통해 로컬 모델 및 Civitai 모델 정보 연결
|
| 15 |
+
* Civitai 모델 페이지 URL을 통해 모델(정보 및 미리보기 이미지 포함) 다운로드하여 SD 디렉토리 또는 하위 디렉토리에 저장
|
| 16 |
+
* 이어받기 지원 다운로드
|
| 17 |
+
* 로컬 모델에서 Civitai에 새 버전이 있는지 일괄 확인
|
| 18 |
+
* 새 버전 모델을 SD 모델 디렉토리에 직접 다운로드(정보 및 미리보기 이미지 포함)
|
| 19 |
+
* "Extra Network" 모델 카드 내부를 수정하여 다음과 같은 기능 버튼을 추가:
|
| 20 |
+
- 🖼: "replace preview" 텍스트를 이 아이콘으로 변경
|
| 21 |
+
- 🌐: 해당 모델의 Civitai 페이지를 새 탭에서 열기
|
| 22 |
+
- 💡: 이 모델의 트리거 단어를 키워드 입력란에 일괄 추가
|
| 23 |
+
- 🏷: 이 모델 미리보기 이미지에 사용된 키워드 사용
|
| 24 |
+
* 위의 추가 기능 버튼은 썸네일 모드를 지원합니다.
|
| 25 |
+
* 터치 스크린 사용자를 위해 항상 표시되는 버튼 옵션 추가
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
# 설치
|
| 29 |
+
이 프로젝트를 zip 파일로 다운로드하고 SD webui 디렉토리/extensions에 압축 해제하면 됩니다.
|
| 30 |
+
|
| 31 |
+
이 플러그인을 설치하거나 업그레이드하려면 SD Webui를 완전히 종료하고 다시 시작해야 합니다. UI 다시로드는 작동하지 않습니다.
|
| 32 |
+
|
| 33 |
+
# 사용 방법
|
| 34 |
+
|
| 35 |
+
## SD Webui 업데이트
|
| 36 |
+
이 확장 기능은 Extra Network 카드 목록 ID를 가져와야 합니다. 이것은 2023-02-06에 SD Webui에 추가된 것입니다.
|
| 37 |
+
|
| 38 |
+
따라서, 만약 사용 중인 버전이 이보다 이전 버전이라면, 먼저 SD Webui를 업데이트해야 합니다!
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
## 모델 스캔
|
| 42 |
+
확장 페이지 "Civitai Helper"로 이동하고 "Scan Model"이라는 버튼을 클릭합니다.
|
| 43 |
+
|
| 44 |
+

|
| 45 |
+
|
| 46 |
+
클릭하면 모든 모델을 스캔하고 SHA256 코드를 생성하여 Civitai에서 모델 정보 및 미리보기 이미지를 가져옵니다. 스캔에는 시간이 걸리므로 인내심을 가지고 기다려주세요.
|
| 47 |
+
|
| 48 |
+
이 확장 기능은 각 모델마다 Civitai에서 얻은 모델 정보를 저장하는 JSON 파일을 생성합니다. 이 파일은 모델이 있는 디렉토리에 "모델 이름.civitai.info"라는 이름으로 저장됩니다.
|
| 49 |
+
|
| 50 |
+

|
| 51 |
+
|
| 52 |
+
모델 정보 파일이 이미 존재하는 경우 해당 모델은 스캔하지 않습니다. 모델이 Civitai가 아닌 경우 빈 정보 파일이 생성되어 나중에 중복 스캔을 피합니다.
|
| 53 |
+
|
| 54 |
+
### 새 모델 추가
|
| 55 |
+
새 모델을 다운로드한 후 스캔 버튼을 다시 클릭하면 됩니다. 이미 스캔된 파일은 다시 스캔하지 않으며 새 모델의 정보와 미리보기 이미지를 자동으로 얻을 수 있습니다. SD Webui를 다시 시작할 필요가 없습니다.
|
| 56 |
+
|
| 57 |
+
## 모델 카드
|
| 58 |
+
**(스캔을 완료한 후에 카드 기능을 사용하세요)**
|
| 59 |
+
SD Webui의 내장 "Extra Network" 페이지를 열어 모델 카드를 표시합니다.
|
| 60 |
+
|
| 61 |
+

|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
마우스를 모델 카드 아래쪽으로 이동하면 4개의 버튼이 표시됩니다:
|
| 65 |
+
- 🖼: "replace preview" 텍스트를이 아이콘으로 변경
|
| 66 |
+
- 🌐:이 모델의 Civitai 페이지를 새 탭에서 엽니다.
|
| 67 |
+
- 💡:이 모델의 트리거 단어를 키워드 입력 상자에 추가합니다.
|
| 68 |
+
- 🏷:이 모델 미리보기에 사용되는 키워드를 사용합니다.
|
| 69 |
+
|
| 70 |
+

|
| 71 |
+
|
| 72 |
+
이러한 추가 버튼이 표시되지 않으면 Refresh Civitai Helper를 클릭하여 다시 추가하십시오.
|
| 73 |
+
|
| 74 |
+

|
| 75 |
+
|
| 76 |
+
Extra Network가 새로 고침될 때마다이 추가 수정이 제거되므로 버튼이 사라지면 Refresh Civitai Helper를 클릭하여 기능을 다시 추가해야합니다.
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
### 작은 미리보기 모드
|
| 80 |
+
이러한 기능 버튼은 작은 미리보기 모드를 지원하지만 SD Webui의 CSS 문제로 인해 현재 항상 표시하거나 항상 표시하지 않아야합니다.
|
| 81 |
+

|
| 82 |
+
|
| 83 |
+
## 다운로드
|
| 84 |
+
**(한 번에 하나씩, 하나를 다운로드하고 다른 것을 다운로드하세요)**
|
| 85 |
+
Civitai 모델 페이지 URL을 통해 모델을 다운로드하려면 3 단계가 필요합니다:
|
| 86 |
+
* URL을 입력하고 모델 정보를 가져 오는 버튼을 클릭합니다.
|
| 87 |
+
* 확장 프로그램이 모델 이름과 유형을 자동으로 입력합니다. 다운로드 할 하위 디렉토리와 모델 버전을 선택해야합니다.
|
| 88 |
+
* 다운로드를 클릭하십시오.
|
| 89 |
+

|
| 90 |
+
|
| 91 |
+
다운로드 과정은 진행률 표시 줄이있는 명령 줄 인터페이스에서 표시됩니다.
|
| 92 |
+
일시 중지 및 다시 시작을 지원하며 대용량 파일도 문제없이 처리합니다.
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
## 일괄적으로 모델 새 버전 확인
|
| 96 |
+
Civitai에서 새 버전을 확인하기 위해 로컬 모델을 모델 유형 별로 일괄적으로 확인할 수 있습니다. 여러 모델 유형을 선택할 수 있습니다.
|
| 97 |
+

|
| 98 |
+
|
| 99 |
+
새 버전을 확인 할 때마다 모델이 모두 확인 될 때까지 1 초의 지연이 있으므로 속도가 다소 느립니다.
|
| 100 |
+
|
| 101 |
+
이것은 Civitai가 이 플러그인으로 인해 일시적으로 DDos와 유사한 상황에 빠지지 않도록 보호하기 위한 것입니다. 일부 클라우드 서비스 제공 업체는 "무료 사용자의 초당 API 요청 수는 1 회를 초과 할 수 없다"는 보호 메커니즘이 있습니다. Civitai는 이러한 설정이 없습니다. 그러나 우리는 여전히 그것을 보호해야합니다. 왜냐하면 그것이 다운되면 모두에게 좋지 않기 때문입니다.
|
| 102 |
+
|
| 103 |
+
확인이 완료되면 다음과 같이 UI에 모든 새 버전을 찾은 정보가 표시됩니다.
|
| 104 |
+
|
| 105 |
+
각 모델 새 버전에는 3 개의 링크가 있습니다.
|
| 106 |
+
* 첫 번째는 이 모델의 웹 페이지입니다.
|
| 107 |
+
* 두 번째는이 새 버전의 다운로드 주소입니다.
|
| 108 |
+
* 세 번째는 버튼입니다. Python 측에서 새 버전을 모델 디렉토리로 직접 다운로드합니다.
|
| 109 |
+
이 방식으로 다운로드하면 "모델 다운로드" 영역과 명령 줄 창에 다운로드 세부 정보가 표시됩니다. 한 번에 하나의 작업만 지원됩니다.
|
| 110 |
+

|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
## URL을 기반으로 모델 정보 가져오기
|
| 115 |
+
Civitai에서 모델의 SHA256을 찾을 수 없지만 여전히 Civitai 모델에 모델을 연결하고 싶다면 해당 확장 프로그램 페이지에서 모델을 선택하고 Civitai 모델 페이지의 URL을 제공할 수 있습니다.
|
| 116 |
+
|
| 117 |
+
버튼을 클릭하면 확장 프로그램이 해당 Civitai 모델의 정보를 다운로드하여 로컬 모델의 정보로 사용합니다.
|
| 118 |
+
|
| 119 |
+

|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
## 기타 설정
|
| 124 |
+
**설정 저장 버튼은 스캔 모델 영역 및 기타 설정 두 영역의 옵션을 저장합니다.**
|
| 125 |
+
|
| 126 |
+
* "항상 표시 버튼"은 터치 스크린에서 편리하게 사용하기 위한 것입니다.
|
| 127 |
+
* "작은 그림 모드에서 기능 버튼 표시"는 작은 그림 모드에서 기능 버튼을 표시할지 여부를 전환합니다.
|
| 128 |
+

|
| 129 |
+
|
| 130 |
+
## 미리보기 이미지
|
| 131 |
+
Extra Network는 model_name.png 및 model_name.preview.png 두 가지 미리보기 이미지 이름을 지원합니다. 여기서 model_name.png이 우선순위가 높습니다.
|
| 132 |
+
|
| 133 |
+
우선순위가 높은 미리보기 이미지가 없으면 자동으로 model_name.preview.png를 사용합니다.
|
| 134 |
+
|
| 135 |
+
이렇게 하면 직접 만든 미리보기 이미지와 인터넷에서 다운로드한 미리보기 이미지를 함께 사용할 수 있으며, 우선순위는 직접 만든 이미지가 높습니다.
|
| 136 |
+
|
| 137 |
+
## 키워드
|
| 138 |
+
카드에 키워드 추가 버튼은 civitai 미리보기 이미지에서 얻은 키워드를 추가하는 것이며, 사용자가 직접 만든 이미지의 키워드가 아닙니다.
|
| 139 |
+
|
| 140 |
+
모든 이미지에 키워드가 있는 것은 아니며, 모델에 따라 미리보기 이미지의 키워드가 모두 같지 않을 수 있습니다. 따라서 여기서는 civitai 모든 미리보기 이미지 정보를 탐색하여 첫 번째 키워드가 있는 이미지를 로드합니다.
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
## SHA256
|
| 144 |
+
파일의 SHA256을 생성하려면 플러그인에서 전체 파일을 읽어야 합니다. 대형 파일의 경우 시스템이 느려질 수 있습니다.
|
| 145 |
+
|
| 146 |
+
SHA256은 civitai에서 해당 모델을 찾을 수 없는 두 가지 경우가 있습니다.
|
| 147 |
+
* 너무 오래된 모델이므로 civitai에 SHA256이 저장되어 있지 않습니다.
|
| 148 |
+
* 모델 작성자가 모델 파일을 조용히 교체했지만 설명 및 버전을 수정하지 않았습니다. 따라서 웹 페이지에서는 확인할 수 없지만 civitai 및 로컬 모델 파일은 이미 다른 파일입니다.
|
| 149 |
+
|
| 150 |
+
이러한 경우에는 플러그인에서 모델 페이지 URL을 제공하여 모델 정보 파일을 얻을 수 있습니다
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
## 자주 묻는 질문
|
| 154 |
+
### 4개의 카드 버튼이 표시되지 않습니다.
|
| 155 |
+
#### 한국어 플러그인을 사용했습니다
|
| 156 |
+
새 버전을 다운로드하면, 최신 버전에서 한국어 번역으로 인한 문제가 해결되었습니다. 양방향 다국어 플러그인은 v1.6.1.1 이후 버전부터 지원됩니다.
|
| 157 |
+
|
| 158 |
+
#### 클라우드 기반 한국어 플러그인을 사용했습니다
|
| 159 |
+
클라우드 기반 한국어 플러그인을 사용한 경우 일반적인 한국어 플러그인으로 변경���십시오.
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
#### 다른 경우
|
| 163 |
+
먼저 "Refresh Civitai Helper" 버튼을 클릭하여 Civitai Helper를 새로고침했는지 확인하세요.
|
| 164 |
+
|
| 165 |
+
그런 다음 이 문제가 계속되는 경우, 유일한 이유는 최신 버전의 SD webui를 사용하지 않았기 때문입니다.
|
| 166 |
+
|
| 167 |
+
만약 SD webui의 파일을 수정했다면, 업데이트 작업이 실패할 수 있습니다. 업데이트가 제대로 이루어졌는지 확인하려면 git 명령 줄의 출력 정보를 확인해야 합니다.
|
| 168 |
+
|
| 169 |
+
git은 종종 업그레이드를 거부하고, 일부 충돌을 수동으로 해결해야 한다는 메시지를 보여줍니다. 명령 줄 출력을 확인하지 않으면 업그레이드가 성공했다고 잘못 생각할 수 있습니다.
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
### Request model info from civitai
|
| 173 |
+
이것은 Civitai에 연결하고 있음을 나타내며, 정보가 없으면 연결할 수 없으므로 프록시를 사용해야 합니다.
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
### 모델 정보 스캔 또는 가져오기 실패
|
| 177 |
+
이 플러그인은 이제 매우 안정적이므로, 이 문제의 원인은 대부분 Civitai가 연결 요청을 거부했기 때문입니다.
|
| 178 |
+
|
| 179 |
+
Civitai는 대형 웹사이트와 같이 안정적이지 않습니다. 웹사이트가 다운되거나 API 연결을 거부할 수 있고, API 요청을 실제 검증 페이지로 전환하여 차단할 수도 있습니다.
|
| 180 |
+
|
| 181 |
+
Civitai에는 연결 풀 설정이 있습니다. 이는 동시에 허용되는 최대 연결 수입니다. 이 수치에 도달하면 다음 API 연결 요청은 모두 거부됩니다. 이 때는 잠시 기다렸다가 다시 시도해야 합니다.
|
| 182 |
+
|
| 183 |
+
또한 국내 사용자들에게는 프록시 문제가 있습니다. 대개는 프록시를 사용해야만 연결할 수 있습니다.
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
### civitai에서 잘못된 모델 정보 및 미리보기 이미지 가져오기
|
| 187 |
+
안타깝게도, civitai의 데이터베이스에 일부 모델이 잘못된 sha256으로 저장되어 있습니다. 자세한 내용은 여기를 확인하십시오:
|
| 188 |
+
[https://github.com/civitai/civitai/issues/426](https://github.com/civitai/civitai/issues/426)
|
| 189 |
+
|
| 190 |
+
따라서 이 확장 프로그램은 해당 모델의 올바른 모델 정보나 미리보기 이미지를 가져올 수 없습니다.
|
| 191 |
+
|
| 192 |
+
이 경우 모델 정보 파일을 제거하고 이 확장 프로그램의 탭 페이지에서 civitai url로 올바른 모델 정보를 가져와야 합니다.
|
| 193 |
+
|
| 194 |
+
또한, 잘못된 sha256을 가진 해당 모델을 civitai에 신고할 수 있습니다.
|
| 195 |
+
[https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100](https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100)
|
| 196 |
+
|
| 197 |
+
civitai에 그 모델을 신고하여 수정할 수 있도록 해주시기 바랍니다.
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
### Colab 사용시 스캔 실패
|
| 201 |
+
먼저 보이는 오류 메시지를 Google에서 검색해보세요. 대개 Colab의 문제일 가능성이 높습니다.
|
| 202 |
+
|
| 203 |
+
그리고 Colab이 Google 드라이브에 연결되어 있다면, 파일에 대한 일회성 액세스 제한으로 인해 스캔이 실패할 수 있습니다. 이는 Google 드라이브의 제한 사항으로, 자세한 내용은 Google 검색을 통해 알아보세요.
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
|
Stable-Diffusion-Webui-Civitai-Helper/README.md
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### Language
|
| 2 |
+
[中文](README.cn.md)
|
| 3 |
+
[日本語](README.jp.md)
|
| 4 |
+
[한국어(ChatGPT)](README.kr.md)
|
| 5 |
+
|
| 6 |
+
## About Civitai Helper2: Model Info Helper
|
| 7 |
+
Civitai Helper 2 will be renamed to **ModelInfo Helper**. It is under development, you can watch its UI demo video to see how it gonna look like:
|
| 8 |
+
[YouTube](https://youtu.be/mPcKwQDDH8s)
|
| 9 |
+
|
| 10 |
+
# Notice
|
| 11 |
+
**This extension now is very stable and works well for many people. If you have an issue, check console log window's detail and read [common issue](#common-issue) part**
|
| 12 |
+
|
| 13 |
+
If you want to claim it doesn't work, check this first: [Claim Wall](claim_wall.md)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# Civitai Helper
|
| 17 |
+
Stable Diffusion Webui Extension for Civitai, to handle your models much more easily.
|
| 18 |
+
|
| 19 |
+
Civitai: [Civitai Url](https://civitai.com/models/16768/civitai-helper-sd-webui-civitai-extension)
|
| 20 |
+
|
| 21 |
+
# Features
|
| 22 |
+
* Scans all models to download model information and preview images from Civitai.
|
| 23 |
+
* Link local model to a civitai model by civitai model's url
|
| 24 |
+
* Download a model(with info+preview) by Civitai Url into SD's model folder or subfolder.
|
| 25 |
+
* Downloading can resume at break-point, which is good for large file.
|
| 26 |
+
* Checking all your local model's new version from Civitai
|
| 27 |
+
* Download a new version directly into SD model folder (with info+preview)
|
| 28 |
+
* Modified Built-in "Extra Network" cards, to add the following buttons on each card:
|
| 29 |
+
- 🖼️: Modified "replace preview" text into this icon
|
| 30 |
+
- 🌐: Open this model's Civitai url in a new tab
|
| 31 |
+
- 💡: Add this model's trigger words to prompt
|
| 32 |
+
- 🏷️: Use this model's preview image's prompt
|
| 33 |
+
* Above buttons support thumbnail mode of Extra Network
|
| 34 |
+
* Option to always show additional buttons, to work with touchscreen.
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
# Install
|
| 38 |
+
Go to SD webui's extension tab, go to `Install from url` sub-tab.
|
| 39 |
+
Copy this project's url into it, click install.
|
| 40 |
+
|
| 41 |
+
Alternatively, download this project as a zip file, and unzip it to `Your SD webui folder/extensions`.
|
| 42 |
+
|
| 43 |
+
Everytime you install or update this extension, you need to shutdown SD Webui and Relaunch it. Just "Reload UI" won't work for this extension.
|
| 44 |
+
|
| 45 |
+
Done.
|
| 46 |
+
|
| 47 |
+
# How to Use
|
| 48 |
+
|
| 49 |
+
## Update Your SD Webui
|
| 50 |
+
This extension need to get extra network's cards id. Which is added since **2023-02-06**.
|
| 51 |
+
**If your SD webui is an earlier version, you need to update it!**
|
| 52 |
+
|
| 53 |
+
## Scanning Models
|
| 54 |
+
Go to extension tab "Civitai Helper". There is a button called "Scan model".
|
| 55 |
+
|
| 56 |
+

|
| 57 |
+
|
| 58 |
+
Click it and the extension will scan all your models to generate SHA256 hashes, using them to retreive model information and preview images from Civitai.
|
| 59 |
+
|
| 60 |
+
**Scanning takes time, just wait it finish**
|
| 61 |
+
|
| 62 |
+
For each model, it will create a json file to save all model info from Civitai. This model info file will be "Your_model_name.civitai.info" in your model folder.
|
| 63 |
+
|
| 64 |
+

|
| 65 |
+
|
| 66 |
+
If a model info file already exists, it will be skipped. If a model cannot be found in Civitai, it will create an empty model info file, so the model won't be scanned twice.
|
| 67 |
+
|
| 68 |
+
### Adding New Models
|
| 69 |
+
When you have some new models, just click scan button again, to get new model's information and preview images. It won't scan the same model twice.
|
| 70 |
+
|
| 71 |
+
## Model Card
|
| 72 |
+
**(Use this only after scanning finished)**
|
| 73 |
+
Open SD webui's build-in "Extra Network" tab, to show model cards.
|
| 74 |
+
|
| 75 |
+

|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
Move your mouse on to the bottom of a model card. It will show 4 icon buttons:
|
| 79 |
+
- 🖼: Replace preview (a build-in button, modified from text to icon)
|
| 80 |
+
- 🌐: Open this model's Civitai url in a new tab
|
| 81 |
+
- 💡: Add this model's trigger words to prompt
|
| 82 |
+
- 🏷: Use this model's preview image's prompt
|
| 83 |
+
|
| 84 |
+

|
| 85 |
+
|
| 86 |
+
**If these additional buttons are not there**, click the `Refresh Civitai Helper` button to bring them back.
|
| 87 |
+
|
| 88 |
+

|
| 89 |
+
Everytime after Extra Network tab refreshed, it will remove all these additional buttons. So, you need to click `Refresh Civitai Helper` button to bring them back.
|
| 90 |
+
|
| 91 |
+
### Thumbnail Mode
|
| 92 |
+
Additional buttons work on thumbnail too, but due to SD webui's CSS issue, for now, they must be always displayed on thumbnail or don't display at all.
|
| 93 |
+

|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
## Download
|
| 97 |
+
To download a model by Civitai Model Page's Url, you need 3 steps:
|
| 98 |
+
* Fill url, click button to get model info
|
| 99 |
+
* It will show model name and type automatically. Just choose sub-folder and model version
|
| 100 |
+
* Click download.
|
| 101 |
+

|
| 102 |
+
|
| 103 |
+
Detail will be displayed on console log, with a progress bar.
|
| 104 |
+
Downloading can resume from break-point, so no fear for large file.
|
| 105 |
+
|
| 106 |
+
## Checking Model's New Version
|
| 107 |
+
You can checking your local model's new version from civitai by model types. You can select multiple model types.
|
| 108 |
+

|
| 109 |
+
|
| 110 |
+
The checking process has a "1 second delay" after each model's new version checking request. So it is a little slow.
|
| 111 |
+
|
| 112 |
+
This is to protect Civitai from issue like DDos from this extension. Some cloud service provider has a rule as "no more than 1 API request in a second for free user". Civitai doesn't have this rule yet, but we still need to protect it. There is no good for us if it is down.
|
| 113 |
+
|
| 114 |
+
**After checking process done**, it will display all new version's information on UI.
|
| 115 |
+
|
| 116 |
+
There are 3 urls for each new version.
|
| 117 |
+
* First one is model's civitai page.
|
| 118 |
+
* Second one is new version's download url.
|
| 119 |
+
* Third one is a button to download it into your SD's model folder with python.
|
| 120 |
+
With this one, output information is on "Download Model" section's log and console log. **One task at a time**.
|
| 121 |
+
|
| 122 |
+

|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
## Get Model Info By Url
|
| 126 |
+
This is used to force a local model links to a Civitai model. For example, you converted a model's format or pruned it. Then it can not be found on civitai when scanning.
|
| 127 |
+
|
| 128 |
+
In that case, if you still want to link it to a civitai model. You can use this funcion.
|
| 129 |
+
|
| 130 |
+
Choose this model from list, then offer a civitai model page's url.
|
| 131 |
+
|
| 132 |
+
After clicking button, extension will download that civitai model's info and preview image for the local file you picked.
|
| 133 |
+
|
| 134 |
+

|
| 135 |
+
|
| 136 |
+
## Proxy
|
| 137 |
+
**If you are updating to new version, you need to re-lanuch SD webui before using it.**
|
| 138 |
+
|
| 139 |
+
Proxy textbox is at the bottom of extension tab.
|
| 140 |
+
|
| 141 |
+
**Each time you fill or clear a proxy value, you need to save setting, and Re-load UI with setting tab's reload button.**
|
| 142 |
+
|
| 143 |
+
Then all requests to civitai will use the proxy.
|
| 144 |
+
|
| 145 |
+
For some sock5 proxy, need to be used as "socks5h://xxxxx".
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
## Other Setting
|
| 151 |
+
**The Save Setting button, will save both "Scan Model"'s setting and other setting.**
|
| 152 |
+
|
| 153 |
+
* "Always Display Button" is good for touch screen.
|
| 154 |
+
* "Show Buttons on Thumb Mode" will turn on/off additional Buttons on thumbnail.
|
| 155 |
+

|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
## Preview Image
|
| 161 |
+
Extra network uses both `model_file.png` and `model_file.preview.png` as preview image. But `model_file.png` has higher priority, because it is created by yourself.
|
| 162 |
+
|
| 163 |
+
When you don't have the higher priority one, it will use the other automatically.
|
| 164 |
+
|
| 165 |
+
## Prompt
|
| 166 |
+
When you click the button "Use prompt from preview image", it does not use the prompt from your own preview image. It uses the one from civitai's preview image.
|
| 167 |
+
|
| 168 |
+
On civitai, a model's preview images may not has prompt. This extension will check this model's all civitai preview images' information and use the first one has prompt in it.
|
| 169 |
+
|
| 170 |
+
## SHA256
|
| 171 |
+
To create a file SHA256, it need to read the whole file to generate a hash code. It gonna be slow for large files.
|
| 172 |
+
|
| 173 |
+
Also, extension uses Memory Optimized SHA256, which won't stuck your system and works with colab.
|
| 174 |
+
|
| 175 |
+
There are 2 cases this hash code can not find the model on civitai:
|
| 176 |
+
* Some old models, which do not have SHA256 code on civitai.
|
| 177 |
+
* The model's owner changed file on civitai, but does not change version name and description. So, the file on civitai is actually not the one on your manchine.
|
| 178 |
+
|
| 179 |
+
In these cases, you can always link a model to civitai by filling its URL in this extension.
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
## Feature Request
|
| 184 |
+
No new feature for v1.x after v1.5. All new feature will go to 2.x.
|
| 185 |
+
|
| 186 |
+
2.x will focus on custom model information and may change name to "Model Info Helper", because it is not just focus on Civitai anymore.
|
| 187 |
+
|
| 188 |
+
From v1.5, v1.x goes into maintenance phase.
|
| 189 |
+
|
| 190 |
+
Enjoy!
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
## Common Issue
|
| 194 |
+
### 4 Buttons on card didn't show
|
| 195 |
+
#### Localization
|
| 196 |
+
There was a Localization issue if you are not using English version of SD webui. This is fixed in the latest version of this extension. **Bilingual localization extension is supported by PR since v1.6.1.1.**
|
| 197 |
+
|
| 198 |
+
##### Using cloud based localization extension
|
| 199 |
+
Turn off cloud based localization extension, use normal localization extension.
|
| 200 |
+
|
| 201 |
+
#### Other case
|
| 202 |
+
First of all, make sure you clicked "Refresh Civitai Helper" button.
|
| 203 |
+
|
| 204 |
+
If issue is still there, then only reason is you are not using the latest SD webui. So, Make sure you updated it.
|
| 205 |
+
|
| 206 |
+
Your update could be failed if you have modified SD webui's file. You need to check git command's console log to make sure it is updated.
|
| 207 |
+
|
| 208 |
+
In many cases, git will just refuse to update and tell you there are some conflicts need you to handle manually. If you don't check the consloe log, you will think your SD webui is updated, but it is not.
|
| 209 |
+
|
| 210 |
+
### Request, Scan or Get model info failed
|
| 211 |
+
This extension is stable. So, the reason for this most likely is your internet connection to Civitai API service.
|
| 212 |
+
|
| 213 |
+
Civitai is not as stable as those rich websites, it can be down or refuse your API connection.
|
| 214 |
+
|
| 215 |
+
Civitai has a connection pool setting. Basicly, it's a max connection number that civitai can have at the same time. So, if there are already too manny connections on civitai, it will refuse your API connection.
|
| 216 |
+
|
| 217 |
+
In those cases, the only thing you can do is just wait a while then try again.
|
| 218 |
+
|
| 219 |
+
### Get Wrong model info and preview images from civitai
|
| 220 |
+
A bad news is, some models are saved with a wrong sha256 in civitai's database. Check here for more detail:
|
| 221 |
+
[https://github.com/civitai/civitai/issues/426](https://github.com/civitai/civitai/issues/426)
|
| 222 |
+
|
| 223 |
+
So, for those models, this extension can not get the right model info or preview images.
|
| 224 |
+
|
| 225 |
+
In this case, you have to remove the model info file and get the right model info by a civitai url on this extension's tab page.
|
| 226 |
+
|
| 227 |
+
Also, you can report those models with wrong sha256 to civitai at following page:
|
| 228 |
+
[https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100](https://discord.com/channels/1037799583784370196/1096271712959615100/1096271712959615100)
|
| 229 |
+
|
| 230 |
+
Please report that model to civitai, so they can fix it.
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
### Scanning fail when using colab
|
| 236 |
+
First of, search your error message with google. Most likely, it will be a colab issue.
|
| 237 |
+
|
| 238 |
+
If you are sure it is a out of memory issue when scanning models, and you are using this extension's latest version, then there is nothing we can do.
|
| 239 |
+
|
| 240 |
+
Since v1.5.5, we've already optimized the SHA256 function to the top. So the only 2 choices for you are:
|
| 241 |
+
* try again
|
| 242 |
+
* or use a pro account of colab.
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
# Change Log
|
| 249 |
+
## v1.6.4
|
| 250 |
+
* Add "Download All files" checkbox for downloading model section. Uncheck means only download 1 file.
|
| 251 |
+
|
| 252 |
+
## v1.6.3
|
| 253 |
+
* Support downloading multiple files, not avaiable when checking new version.
|
| 254 |
+
|
| 255 |
+
## v1.6.2.1
|
| 256 |
+
* when parsing civitai url, remove query string by PR
|
| 257 |
+
|
| 258 |
+
## v1.6.2
|
| 259 |
+
* When downloading, re-name file if file already exists
|
| 260 |
+
|
| 261 |
+
## v1.6.1.1
|
| 262 |
+
* Support bilingual localization extension by PR
|
| 263 |
+
|
| 264 |
+
## v1.6.1
|
| 265 |
+
* Fix Localization issue for 4 addtional buttons on cards. (Forgot that again...)
|
| 266 |
+
|
| 267 |
+
## v1.6.0
|
| 268 |
+
* Fix some UI issues to work with gradio 3.23.0
|
| 269 |
+
* Support Proxy when connecting to civitai. Check document for detail.
|
| 270 |
+
* check realpath when opening file, to fix error when using junction
|
| 271 |
+
* Fix multiple addtional buttons issue after switching tabs.
|
| 272 |
+
|
| 273 |
+
## v1.5.7
|
| 274 |
+
* Fix Localization issue for 4 addtional buttons on cards
|
| 275 |
+
|
| 276 |
+
## v1.5.6
|
| 277 |
+
* update error msg when can not connect to civitai API service
|
| 278 |
+
* update thumb mode for SD webui new version's metadata button
|
| 279 |
+
|
| 280 |
+
## v1.5.5
|
| 281 |
+
* update SHA256 function, now it just use the code from pip
|
| 282 |
+
|
| 283 |
+
## v1.5.4
|
| 284 |
+
* set sys.stdout to utf-8
|
| 285 |
+
* Add default header for requests to prevent from being blocked by civitai.
|
| 286 |
+
* merge other v1.5.x change log to v1.5.4
|
| 287 |
+
* When downloading a model by url, check if target model version is already existed in user selected sub-folder.
|
| 288 |
+
* Support scanning only selected model types.
|
| 289 |
+
* Force TI scanning delay 1 second to prevent from civitai treating this extension's requests as attacking.
|
| 290 |
+
|
| 291 |
+
## v1.5.0
|
| 292 |
+
* Download a model by Civitai model page's url
|
| 293 |
+
* Resume downloading from break-point
|
| 294 |
+
* Download new version into SD Webui's model folder
|
| 295 |
+
* Addtional button now works on thumbnail mode
|
| 296 |
+
* Option to always show addtion button, for touch screen.
|
| 297 |
+
|
| 298 |
+
## v1.4.2
|
| 299 |
+
* ignore .vae file in model folder when scanning
|
| 300 |
+
|
| 301 |
+
## v1.4.1
|
| 302 |
+
* When checking new versions, also searching and ignore already existed ones.
|
| 303 |
+
* Add version number to the bottom of this extension's tab
|
| 304 |
+
|
| 305 |
+
## v1.4
|
| 306 |
+
* Support checking model's new version, display the result in UI and offer download url
|
| 307 |
+
* Remove addintional sub tabs on extension tab. make ui simpler.
|
| 308 |
+
|
| 309 |
+
## v1.3
|
| 310 |
+
* Open url at client side
|
| 311 |
+
* Link selected model to civitai by url or model id
|
| 312 |
+
* Save and load extension setting to file
|
| 313 |
+
* Show button action's output to UI
|
| 314 |
+
* Code refactoring
|
| 315 |
+
|
| 316 |
+
## v1.2.1
|
| 317 |
+
* Add more error checking to work with different versions of SD webui.
|
| 318 |
+
|
| 319 |
+
## v1.2
|
| 320 |
+
* Support customer model folder
|
| 321 |
+
* Support readable model info file
|
| 322 |
+
* Support download preview image with max size
|
| 323 |
+
* Remove card buttons when extra network is in thumbnail mode
|
| 324 |
+
|
| 325 |
+
## v1.1
|
| 326 |
+
* Support subfolders
|
| 327 |
+
* Check if refresh is needed when clicking "Refresh Civitai Helper"
|
| 328 |
+
* Add space when adding trigger words
|
| 329 |
+
* Add memory Optimized sha256 as an option
|
Stable-Diffusion-Webui-Civitai-Helper/claim_wall.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Claim Wall
|
| 2 |
+
|
| 3 |
+
Since this extension got a little hot, some users come to **claim many other issues to this extension**.
|
| 4 |
+
|
| 5 |
+
Following is a wall, to show a few examples how they claim this extension doesn't work, because they don't read document or forget what they did before.
|
| 6 |
+
|
| 7 |
+
If you are looking for guideline, go to section [What you should do](#what-you-should-do)
|
| 8 |
+
|
| 9 |
+
# Wall
|
| 10 |
+
|
| 11 |
+
### Didn't even update SD Webui and claim "tried everything"
|
| 12 |
+
|
| 13 |
+

|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
### Havn't even scanned model
|
| 17 |
+
After 4 replies, find that out, and modified his comment.
|
| 18 |
+
|
| 19 |
+

|
| 20 |
+
|
| 21 |
+
### Claim "pretty sure" this extension breaks his UI, takes 2days to find out it is not
|
| 22 |
+
Then removed his comment from civitai, but his post on reddit is still there, so you can know what's really going on there.
|
| 23 |
+
|
| 24 |
+
1. Claim "pretty sure" this extension breaks his UI
|
| 25 |
+
|
| 26 |
+

|
| 27 |
+
|
| 28 |
+

|
| 29 |
+
|
| 30 |
+
2. Find out it is not, after 2 days
|
| 31 |
+
|
| 32 |
+

|
| 33 |
+
|
| 34 |
+
3. Still don't remember what he did with other extensions, until another user tells him, about 4 days later.
|
| 35 |
+
|
| 36 |
+

|
| 37 |
+
|
| 38 |
+
### **Blame SD Webui's modification to this extension**
|
| 39 |
+
Latest SD webui removed a button from UI, they claim this extension did that, and want it back by this extension
|
| 40 |
+
|
| 41 |
+

|
| 42 |
+
|
| 43 |
+
### Claim other extension's error to this extension
|
| 44 |
+
Just because both extensions have "Civitai" in extension's name
|
| 45 |
+
|
| 46 |
+

|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
### **Didn't even use this extension and request a feature it already has**
|
| 50 |
+
|
| 51 |
+

|
| 52 |
+
|
| 53 |
+
### **Renamed model folder's name carelessly and forgot that**
|
| 54 |
+
Takes about 8 hours to find out why this extension doesn't work on his SDwebui and ready to re-install SD webui from beginning.
|
| 55 |
+
|
| 56 |
+
1. claim this extension can not open civitai url on checkpoint models
|
| 57 |
+
|
| 58 |
+

|
| 59 |
+
|
| 60 |
+
2. I reply that model he mentioned works well in my SDwebui
|
| 61 |
+
|
| 62 |
+

|
| 63 |
+
|
| 64 |
+
3. After 6 hours' trying, find out his model folder's name is modified.
|
| 65 |
+
|
| 66 |
+

|
| 67 |
+
|
| 68 |
+

|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
# What you should do
|
| 72 |
+
Above are just a very small piece of this kind of claims. Those claims won't help you. If you have an issue, following is the guidline:
|
| 73 |
+
|
| 74 |
+
* If you want to make your extension work, read the document.
|
| 75 |
+
|
| 76 |
+
* If your SD webui is broken, before you claim it is caused by this extension, you can disable it and try again.
|
| 77 |
+
|
| 78 |
+
* If you followed document, but it still doesn't work well, you can check console log's msg to find out the reason. If you can not understand those msg, you can come and ask for help, with console log's msg or screenshot.
|
| 79 |
+
|
| 80 |
+
* If you are using colab, and get an error from colab, then search that error msg in google. Because it's a colab's issue or limitation.
|
| 81 |
+
|
| 82 |
+
* If you checked console log window's msg and understand what it means, you are welcome to submit your issue.
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
|
Stable-Diffusion-Webui-Civitai-Helper/icon/.keep
ADDED
|
File without changes
|