2022-11-29 20:08:43 -06:00
//TODO FIND OUT WHY I HAVE TO RESIZE A TEXTBOX AND THEN START USING IT TO AVOID THE 1px WHITE LINE ON LEFT EDGES DURING IMG2IMG
//...lmao did setting min width 200 on info div fix that accidentally? once the canvas is infinite and the menu bar is hideable it'll probably be a problem again
2022-12-18 21:03:26 -06:00
/ * *
* Workaround for Firefox bug # 733698
2022-12-18 21:04:24 -06:00
*
2022-12-18 21:03:26 -06:00
* https : //bugzilla.mozilla.org/show_bug.cgi?id=733698
2022-12-18 21:04:24 -06:00
*
2022-12-18 21:03:26 -06:00
* Workaround by https : //github.com/subzey on https://gist.github.com/subzey/2030480
2022-12-18 21:04:24 -06:00
*
2022-12-18 21:03:26 -06:00
* Replaces and handles NS _ERROR _FAILURE errors triggered by 733698.
* /
2022-12-18 21:04:24 -06:00
( function ( ) {
2022-12-18 21:03:26 -06:00
var FakeTextMetrics ,
proto ,
fontSetterNative ,
measureTextNative ,
fillTextNative ,
strokeTextNative ;
if (
! window . CanvasRenderingContext2D ||
! window . TextMetrics ||
! ( proto = window . CanvasRenderingContext2D . prototype ) ||
! proto . hasOwnProperty ( "font" ) ||
! proto . hasOwnProperty ( "mozTextStyle" ) ||
2022-12-18 21:04:24 -06:00
typeof proto . _ _lookupSetter _ _ !== "function" ||
2022-12-18 21:03:26 -06:00
! ( fontSetterNative = proto . _ _lookupSetter _ _ ( "font" ) )
2022-12-18 21:04:24 -06:00
) {
return ;
2022-12-18 21:03:26 -06:00
}
2022-12-18 21:04:24 -06:00
proto . _ _defineSetter _ _ ( "font" , function ( value ) {
2022-12-18 21:03:26 -06:00
try {
return fontSetterNative . call ( this , value ) ;
2022-12-18 21:04:24 -06:00
} catch ( e ) {
if ( e . name !== "NS_ERROR_FAILURE" ) {
throw e ;
2022-12-18 21:03:26 -06:00
}
}
} ) ;
measureTextNative = proto . measureText ;
2022-12-18 21:04:24 -06:00
FakeTextMetrics = function ( ) {
2022-12-18 21:03:26 -06:00
this . width = 0 ;
this . isFake = true ;
this . _ _proto _ _ = window . TextMetrics . prototype ;
} ;
2022-12-18 21:04:24 -06:00
proto . measureText = function ( $0 ) {
2022-12-18 21:03:26 -06:00
try {
return measureTextNative . apply ( this , arguments ) ;
} catch ( e ) {
2022-12-18 21:04:24 -06:00
if ( e . name !== "NS_ERROR_FAILURE" ) {
throw e ;
2022-12-18 21:03:26 -06:00
} else {
2022-12-18 21:04:24 -06:00
return new FakeTextMetrics ( ) ;
2022-12-18 21:03:26 -06:00
}
}
} ;
fillTextNative = proto . fillText ;
2022-12-18 21:04:24 -06:00
proto . fillText = function ( $0 , $1 , $2 , $3 ) {
2022-12-18 21:03:26 -06:00
try {
fillTextNative . apply ( this , arguments ) ;
} catch ( e ) {
2022-12-18 21:04:24 -06:00
if ( e . name !== "NS_ERROR_FAILURE" ) {
throw e ;
2022-12-18 21:03:26 -06:00
}
}
} ;
strokeTextNative = proto . strokeText ;
2022-12-18 21:04:24 -06:00
proto . strokeText = function ( $0 , $1 , $2 , $3 ) {
2022-12-18 21:03:26 -06:00
try {
strokeTextNative . apply ( this , arguments ) ;
} catch ( e ) {
2022-12-18 21:04:24 -06:00
if ( e . name !== "NS_ERROR_FAILURE" ) {
throw e ;
2022-12-18 21:03:26 -06:00
}
}
} ;
} ) ( ) ;
2022-12-19 19:23:24 -06:00
// Parse url parameters
const urlParams = new URLSearchParams ( window . location . search ) ;
2022-11-29 20:08:43 -06:00
window . onload = startup ;
var stableDiffusionData = {
//includes img2img data but works for txt2img just fine
prompt : "" ,
negative _prompt : "" ,
seed : - 1 ,
cfg _scale : null ,
sampler _index : "DDIM" ,
steps : null ,
denoising _strength : 1 ,
mask _blur : 0 ,
batch _size : null ,
width : 512 ,
height : 512 ,
n _iter : null , // batch count
mask : "" ,
init _images : [ ] ,
inpaint _full _res : false ,
2023-01-03 15:52:56 -06:00
inpainting _fill : 1 ,
outpainting _fill : 2 ,
2022-11-29 20:08:43 -06:00
enable _hr : false ,
2022-12-28 21:37:18 -06:00
restore _faces : false ,
2023-01-02 13:50:28 -06:00
//firstphase_width: 0,
//firstphase_height: 0, //20230102 welp looks like the entire way HRfix is implemented has become bonkersly different
hr _scale : 2.0 ,
hr _upscaler : "None" ,
2023-01-04 20:00:51 -06:00
hr _second _pass _steps : 0 ,
hr _resize _x : 0 ,
hr _resize _y : 0 ,
2023-01-04 23:27:02 -06:00
hr _square _aspect : false ,
2022-12-02 11:31:49 -06:00
styles : [ ] ,
2022-11-29 20:08:43 -06:00
// here's some more fields that might be useful
// ---txt2img specific:
// "enable_hr": false, // hires fix
// "denoising_strength": 0, // ok this is in both txt and img2img but txt2img only applies it if enable_hr == true
// "firstphase_width": 0, // hires fp w
// "firstphase_height": 0, // see above s/w/h/
// ---img2img specific
// "init_images": [ // imageS!??!? wtf maybe for batch img2img?? i just dump one base64 in here
// "string"
// ],
// "resize_mode": 0,
// "denoising_strength": 0.75, // yeah see
// "mask": "string", // string is just a base64 image
// "mask_blur": 4,
// "inpainting_fill": 0, // 0- fill, 1- orig, 2- latent noise, 3- latent nothing
// "inpaint_full_res": true,
// "inpaint_full_res_padding": 0, // px
// "inpainting_mask_invert": 0, // bool??????? wtf
// "include_init_images": false // ??????
} ;
// stuff things use
var host = "" ;
var url = "/sdapi/v1/" ;
const basePixelCount = 64 ; //64 px - ALWAYS 64 PX
2023-01-07 14:06:37 -06:00
var focused = true ;
2023-02-04 10:34:26 -06:00
let defaultScripts = { } ;
2023-02-19 09:49:48 -06:00
let userScripts = { } ;
2022-11-29 20:08:43 -06:00
function startup ( ) {
testHostConfiguration ( ) ;
loadSettings ( ) ;
const hostEl = document . getElementById ( "host" ) ;
2022-11-30 15:47:30 -06:00
testHostConnection ( ) . then ( ( checkConnection ) => {
hostEl . onchange = ( ) => {
host = hostEl . value . endsWith ( "/" )
? hostEl . value . substring ( 0 , hostEl . value . length - 1 )
: hostEl . value ;
hostEl . value = host ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/host" , host ) ;
2022-11-30 15:47:30 -06:00
checkConnection ( ) ;
} ;
} ) ;
2022-11-29 20:08:43 -06:00
drawBackground ( ) ;
changeMaskBlur ( ) ;
2022-12-06 15:22:22 -06:00
changeSmoothRendering ( ) ;
2022-11-29 20:08:43 -06:00
changeSeed ( ) ;
changeHiResFix ( ) ;
2023-01-05 17:42:50 -06:00
changeHiResSquare ( ) ;
2022-12-28 21:37:18 -06:00
changeRestoreFaces ( ) ;
2022-12-12 18:25:02 -06:00
changeSyncCursorSize ( ) ;
2023-01-07 14:06:37 -06:00
checkFocus ( ) ;
2023-02-19 09:49:48 -06:00
refreshScripts ( ) ;
2022-11-29 20:08:43 -06:00
}
2022-12-20 10:43:57 -06:00
function setFixedHost ( h , changePromptMessage ) {
2022-12-21 15:29:11 -06:00
console . info ( ` [index] Fixed host to ' ${ h } ' ` ) ;
2022-12-19 19:23:24 -06:00
const hostInput = document . getElementById ( "host" ) ;
2022-12-20 10:43:57 -06:00
host = h ;
hostInput . value = h ;
2022-12-19 19:23:24 -06:00
hostInput . readOnly = true ;
hostInput . style . cursor = "default" ;
hostInput . style . backgroundColor = "#ddd" ;
2023-02-14 20:44:37 -06:00
hostInput . addEventListener ( "dblclick" , async ( ) => {
if ( await notifications . dialog ( "Host is Locked" , changePromptMessage ) ) {
2022-12-19 19:23:24 -06:00
hostInput . style . backgroundColor = null ;
hostInput . style . cursor = null ;
hostInput . readOnly = false ;
hostInput . focus ( ) ;
}
} ) ;
}
2022-11-29 20:08:43 -06:00
/ * *
* Initial connection checks
* /
function testHostConfiguration ( ) {
/ * *
* Check host configuration
* /
const hostEl = document . getElementById ( "host" ) ;
2022-12-19 12:45:09 -06:00
hostEl . value = localStorage . getItem ( "openoutpaint/host" ) ;
2022-11-29 20:08:43 -06:00
const requestHost = ( prompt , def = "http://127.0.0.1:7860" ) => {
2022-12-19 19:23:24 -06:00
let value = null ;
if ( ! urlParams . has ( "noprompt" ) ) value = window . prompt ( prompt , def ) ;
if ( value === null ) value = def ;
2022-11-29 20:08:43 -06:00
value = value . endsWith ( "/" ) ? value . substring ( 0 , value . length - 1 ) : value ;
host = value ;
hostEl . value = host ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/host" , host ) ;
2022-11-29 20:08:43 -06:00
} ;
2022-12-19 12:45:09 -06:00
const current = localStorage . getItem ( "openoutpaint/host" ) ;
2022-11-29 20:08:43 -06:00
if ( current ) {
if ( ! current . match ( /^https?:\/\/[a-z0-9][a-z0-9.]+[a-z0-9](:[0-9]+)?$/i ) )
requestHost (
"Host seems to be invalid! Please fix your host here:" ,
current
) ;
2022-11-29 20:54:09 -06:00
else
host = current . endsWith ( "/" )
? current . substring ( 0 , current . length - 1 )
: current ;
2022-11-29 20:08:43 -06:00
} else {
requestHost (
"This seems to be the first time you are using openOutpaint! Please set your host here:"
) ;
}
}
2022-11-30 15:47:30 -06:00
async function testHostConnection ( ) {
2022-11-29 20:54:09 -06:00
class CheckInProgressError extends Error { }
2022-11-29 20:08:43 -06:00
const connectionIndicator = document . getElementById (
"connection-status-indicator"
) ;
let connectionStatus = false ;
let firstTimeOnline = true ;
const setConnectionStatus = ( status ) => {
2022-12-02 11:31:49 -06:00
const connectionIndicatorText = document . getElementById (
"connection-status-indicator-text"
) ;
2022-11-29 20:08:43 -06:00
const statuses = {
online : ( ) => {
connectionIndicator . classList . add ( "online" ) ;
connectionIndicator . classList . remove (
2022-12-10 18:46:14 -06:00
"webui-issue" ,
2022-11-29 20:08:43 -06:00
"offline" ,
2022-11-30 15:47:30 -06:00
"before" ,
2022-11-29 20:08:43 -06:00
"server-error"
) ;
2022-12-02 11:31:49 -06:00
connectionIndicatorText . textContent = connectionIndicator . title =
"Connected" ;
2022-11-29 20:08:43 -06:00
connectionStatus = true ;
} ,
error : ( ) => {
connectionIndicator . classList . add ( "server-error" ) ;
2022-11-30 15:47:30 -06:00
connectionIndicator . classList . remove (
"online" ,
"offline" ,
"before" ,
2022-12-10 18:46:14 -06:00
"webui-issue"
2022-11-30 15:47:30 -06:00
) ;
2022-12-02 11:31:49 -06:00
connectionIndicatorText . textContent = "Error" ;
2022-11-29 20:08:43 -06:00
connectionIndicator . title =
"Server is online, but is returning an error response" ;
connectionStatus = false ;
} ,
corsissue : ( ) => {
2022-12-10 18:46:14 -06:00
connectionIndicator . classList . add ( "webui-issue" ) ;
2022-11-29 20:08:43 -06:00
connectionIndicator . classList . remove (
"online" ,
"offline" ,
2022-11-30 15:47:30 -06:00
"before" ,
2022-11-29 20:08:43 -06:00
"server-error"
) ;
2022-12-02 11:31:49 -06:00
connectionIndicatorText . textContent = "CORS" ;
2022-11-29 20:08:43 -06:00
connectionIndicator . title =
"Server is online, but CORS is blocking our requests" ;
connectionStatus = false ;
} ,
2022-12-10 18:46:14 -06:00
apiissue : ( ) => {
connectionIndicator . classList . add ( "webui-issue" ) ;
connectionIndicator . classList . remove (
"online" ,
"offline" ,
"before" ,
"server-error"
) ;
connectionIndicatorText . textContent = "API" ;
connectionIndicator . title =
"Server is online, but the API seems to be disabled" ;
connectionStatus = false ;
} ,
2022-11-29 20:08:43 -06:00
offline : ( ) => {
connectionIndicator . classList . add ( "offline" ) ;
connectionIndicator . classList . remove (
2022-12-10 18:46:14 -06:00
"webui-issue" ,
2022-11-29 20:08:43 -06:00
"online" ,
2022-11-30 15:47:30 -06:00
"before" ,
2022-11-29 20:08:43 -06:00
"server-error"
) ;
2022-12-02 11:31:49 -06:00
connectionIndicatorText . textContent = "Offline" ;
2022-11-29 20:08:43 -06:00
connectionIndicator . title =
"Server seems to be offline. Please check the console for more information." ;
connectionStatus = false ;
} ,
2022-11-30 15:47:30 -06:00
before : ( ) => {
connectionIndicator . classList . add ( "before" ) ;
connectionIndicator . classList . remove (
2022-12-10 18:46:14 -06:00
"webui-issue" ,
2022-11-30 15:47:30 -06:00
"online" ,
"offline" ,
"server-error"
) ;
2022-12-02 11:31:49 -06:00
connectionIndicatorText . textContent = "Waiting" ;
2022-11-30 15:47:30 -06:00
connectionIndicator . title = "Waiting for check to complete." ;
connectionStatus = false ;
} ,
2022-11-29 20:08:43 -06:00
} ;
2022-12-21 09:07:29 -06:00
statuses [ status ] &&
( ( ) => {
statuses [ status ] ( ) ;
global . connection = status ;
} ) ( ) ;
2022-11-29 20:08:43 -06:00
} ;
2022-11-30 15:47:30 -06:00
setConnectionStatus ( "before" ) ;
2022-11-29 20:08:43 -06:00
let checkInProgress = false ;
2023-01-07 14:06:37 -06:00
const checkConnection = async (
notify = false ,
simpleProgressStatus = false
) => {
const apiIssueResult = ( ) => {
setConnectionStatus ( "apiissue" ) ;
2023-02-14 20:44:37 -06:00
const message = ` The host is online, but the API seems to be disabled.<br>Have you run the webui with the flag '--api', or is the flag '--gradio-debug' currently active? ` ;
2023-01-07 14:06:37 -06:00
console . error ( message ) ;
2023-02-14 20:44:37 -06:00
if ( notify )
notifications . notify ( message , {
type : NotificationType . ERROR ,
timeout : config . notificationTimeout * 2 ,
} ) ;
2023-01-07 14:06:37 -06:00
} ;
const offlineResult = ( ) => {
setConnectionStatus ( "offline" ) ;
const message = ` The connection with the host returned an error: ${ response . status } - ${ response . statusText } ` ;
console . error ( message ) ;
2023-02-14 20:44:37 -06:00
if ( notify )
notifications . notify ( message , {
type : NotificationType . ERROR ,
timeout : config . notificationTimeout * 2 ,
} ) ;
2023-01-07 14:06:37 -06:00
} ;
2022-11-29 20:08:43 -06:00
if ( checkInProgress )
throw new CheckInProgressError (
"Check is currently in progress, please try again"
) ;
checkInProgress = true ;
var url = document . getElementById ( "host" ) . value + "/startup-events" ;
// Attempt normal request
try {
2023-01-07 14:06:37 -06:00
if ( simpleProgressStatus ) {
const response = await fetch (
document . getElementById ( "host" ) . value + "/sdapi/v1/progress" // seems to be the "lightest" endpoint?
) ;
switch ( response . status ) {
case 200 : {
setConnectionStatus ( "online" ) ;
break ;
}
case 404 : {
apiIssueResult ( ) ;
break ;
}
default : {
offlineResult ( ) ;
2022-12-10 18:46:14 -06:00
}
}
2023-01-07 14:06:37 -06:00
} else {
// Check if API is available
const response = await fetch (
document . getElementById ( "host" ) . value + "/sdapi/v1/options"
) ;
const optionsdata = await response . json ( ) ;
if ( optionsdata [ "use_scale_latent_for_hires_fix" ] ) {
2023-02-14 20:44:37 -06:00
const message = ` You are using an outdated version of A1111 webUI.<br>The HRfix options will not work until you update to at least commit ef27a18 or newer.<br>(https://github.com/AUTOMATIC1111/stable-diffusion-webui/commit/ef27a18b6b7cb1a8eebdc9b2e88d25baf2c2414d)<br>HRfix will fallback to half-resolution only. ` ;
2023-01-07 14:06:37 -06:00
console . warn ( message ) ;
2023-02-14 20:44:37 -06:00
if ( notify )
notifications . notify ( message , {
type : NotificationType . WARN ,
timeout : config . notificationTimeout * 4 ,
} ) ;
2023-01-07 14:06:37 -06:00
// Hide all new hrfix options
document
. querySelectorAll ( ".hrfix" )
. forEach ( ( el ) => ( el . style . display = "none" ) ) ;
// We are using old HRFix
global . isOldHRFix = true ;
stableDiffusionData . enable _hr = false ;
2022-12-10 18:46:14 -06:00
}
2023-01-07 14:06:37 -06:00
switch ( response . status ) {
case 200 : {
setConnectionStatus ( "online" ) ;
// Load data as soon as connection is first stablished
if ( firstTimeOnline ) {
getConfig ( ) ;
getStyles ( ) ;
getSamplers ( ) ;
getUpscalers ( ) ;
getModels ( ) ;
firstTimeOnline = false ;
}
break ;
}
case 404 : {
apiIssueResult ( ) ;
break ;
}
default : {
offlineResult ( ) ;
}
2022-11-29 20:08:43 -06:00
}
}
} catch ( e ) {
try {
2022-11-30 15:47:30 -06:00
if ( e instanceof DOMException ) throw "offline" ;
2022-11-29 20:08:43 -06:00
// Tests if problem is CORS
await fetch ( url , { mode : "no-cors" } ) ;
setConnectionStatus ( "corsissue" ) ;
2022-12-02 11:31:49 -06:00
const message = ` CORS is blocking our requests. Try running the webui with the flag '--cors-allow-origins= ${ window . location . protocol } // ${ window . location . host } /' ` ;
2022-11-29 20:08:43 -06:00
console . error ( message ) ;
2023-02-14 20:44:37 -06:00
if ( notify )
notifications . notify ( message , {
type : NotificationType . ERROR ,
timeout : config . notificationTimeout * 2 ,
} ) ;
2022-11-29 20:08:43 -06:00
} catch ( e ) {
setConnectionStatus ( "offline" ) ;
const message = ` The server seems to be offline. Is host ' ${
document . getElementById ( "host" ) . value
} ' correct ? ` ;
console . error ( message ) ;
2023-02-14 20:44:37 -06:00
if ( notify )
notifications . notify ( message , {
type : NotificationType . ERROR ,
timeout : config . notificationTimeout * 2 ,
} ) ;
2022-11-29 20:08:43 -06:00
}
}
checkInProgress = false ;
return status ;
} ;
2023-01-07 18:22:39 -06:00
if ( focused || firstTimeOnline ) {
2023-01-07 14:06:37 -06:00
await checkConnection ( ! urlParams . has ( "noprompt" ) ) ;
}
2022-11-29 20:08:43 -06:00
// On click, attempt to refresh
connectionIndicator . onclick = async ( ) => {
try {
await checkConnection ( true ) ;
checked = true ;
} catch ( e ) {
console . debug ( "Already refreshing" ) ;
}
} ;
2023-01-07 14:06:37 -06:00
// Checks every 5 seconds if offline, 60 seconds if online
2022-11-29 20:08:43 -06:00
const checkAgain = ( ) => {
2023-01-08 10:11:33 -06:00
checkFocus ( ) ;
2023-01-07 18:22:39 -06:00
if ( focused || firstTimeOnline ) {
2023-01-07 14:06:37 -06:00
setTimeout (
async ( ) => {
let simple = ! firstTimeOnline ;
await checkConnection ( false , simple ) ;
checkAgain ( ) ;
} ,
connectionStatus ? 60000 : 5000
) ;
} else {
setTimeout ( ( ) => {
2022-11-29 20:08:43 -06:00
checkAgain ( ) ;
2023-01-07 14:06:37 -06:00
} , 60000 ) ;
}
2022-11-29 20:08:43 -06:00
} ;
2023-01-07 18:22:39 -06:00
checkAgain ( ) ;
2022-11-30 15:47:30 -06:00
return ( ) => {
checkConnection ( ) . catch ( ( ) => { } ) ;
} ;
2022-11-29 20:08:43 -06:00
}
function newImage ( evt ) {
clearPaintedMask ( ) ;
2022-12-04 13:22:35 -06:00
uil . layers . forEach ( ( { layer } ) => {
2023-01-24 20:37:38 -06:00
commands . runCommand (
"eraseImage" ,
"Clear Canvas" ,
{
... layer . bb ,
ctx : layer . ctx ,
} ,
{
extra : {
log : ` Cleared Canvas ` ,
} ,
}
) ;
2022-11-29 20:08:43 -06:00
} ) ;
}
function clearPaintedMask ( ) {
2022-12-16 19:57:28 -06:00
maskPaintLayer . clear ( ) ;
2022-11-29 20:08:43 -06:00
}
2022-12-05 09:26:52 -06:00
function march ( bb , options = { } ) {
defaultOpt ( options , {
2022-12-21 09:07:29 -06:00
title : null ,
titleStyle : "#FFF5" ,
2022-12-05 09:26:52 -06:00
style : "#FFFF" ,
width : "2px" ,
filter : null ,
} ) ;
2022-11-29 20:54:09 -06:00
const expanded = { ... bb } ;
expanded . x -- ;
expanded . y -- ;
expanded . w += 2 ;
expanded . h += 2 ;
// Get temporary layer to draw marching ants
const layer = imageCollection . registerLayer ( null , {
bb : expanded ,
2022-12-21 09:07:29 -06:00
category : "display" ,
2022-11-29 20:54:09 -06:00
} ) ;
layer . canvas . style . imageRendering = "pixelated" ;
2022-11-29 20:08:43 -06:00
let offset = 0 ;
const interval = setInterval ( ( ) => {
2022-12-05 09:26:52 -06:00
drawMarchingAnts ( layer . ctx , bb , offset ++ , options ) ;
2022-11-29 20:54:09 -06:00
offset %= 12 ;
2022-11-29 20:08:43 -06:00
} , 20 ) ;
2022-11-29 20:54:09 -06:00
return ( ) => {
clearInterval ( interval ) ;
imageCollection . deleteLayer ( layer ) ;
} ;
2022-11-29 20:08:43 -06:00
}
2022-12-05 09:26:52 -06:00
function drawMarchingAnts ( ctx , bb , offset , options ) {
ctx . save ( ) ;
2022-11-29 20:54:09 -06:00
ctx . clearRect ( 0 , 0 , bb . w + 2 , bb . h + 2 ) ;
2022-12-21 09:07:29 -06:00
// Draw Tool Name
if ( bb . h > 40 && options . title ) {
ctx . font = ` bold 20px Open Sans ` ;
ctx . textAlign = "left" ;
ctx . fillStyle = options . titleStyle ;
ctx . fillText ( options . title , 10 , 30 , bb . w ) ;
}
2022-12-05 09:26:52 -06:00
ctx . strokeStyle = options . style ;
ctx . strokeWidth = options . width ;
ctx . filter = options . filter ;
2022-11-29 20:54:09 -06:00
ctx . setLineDash ( [ 4 , 2 ] ) ;
ctx . lineDashOffset = - offset ;
ctx . strokeRect ( 1 , 1 , bb . w , bb . h ) ;
2022-12-05 09:26:52 -06:00
ctx . restore ( ) ;
2022-11-29 20:08:43 -06:00
}
const makeSlider = (
label ,
el ,
lsKey ,
min ,
max ,
step ,
defaultValue ,
2022-12-03 04:50:23 -06:00
textStep = null ,
2022-11-29 20:08:43 -06:00
valuecb = null
) => {
2023-01-28 23:15:39 -06:00
const local = lsKey && localStorage . getItem ( ` openoutpaint/ ${ lsKey } ` ) ;
2022-11-29 20:08:43 -06:00
const def = parseFloat ( local === null ? defaultValue : local ) ;
2022-12-03 06:53:12 -06:00
let cb = ( v ) => {
stableDiffusionData [ lsKey ] = v ;
2023-01-28 23:15:39 -06:00
if ( lsKey ) localStorage . setItem ( ` openoutpaint/ ${ lsKey } ` , v ) ;
2022-12-03 06:53:12 -06:00
} ;
if ( valuecb ) {
cb = ( v ) => {
valuecb ( v ) ;
2023-01-28 23:15:39 -06:00
localStorage . setItem ( ` openoutpaint/ ${ lsKey } ` , v ) ;
2022-12-03 06:53:12 -06:00
} ;
}
2022-11-29 20:08:43 -06:00
return createSlider ( label , el , {
2022-12-03 06:53:12 -06:00
valuecb : cb ,
2022-11-29 20:08:43 -06:00
min ,
max ,
step ,
defaultValue : def ,
2022-12-03 04:50:23 -06:00
textStep ,
2022-11-29 20:08:43 -06:00
} ) ;
} ;
2023-01-14 16:33:39 -06:00
let modelAutoComplete = createAutoComplete (
2022-12-08 15:23:17 -06:00
"Model" ,
2023-01-15 10:31:27 -06:00
document . getElementById ( "models-ac-select" ) ,
{ } ,
document . getElementById ( "refreshModelsBtn" ) ,
"refreshable"
2022-12-08 15:23:17 -06:00
) ;
2022-12-30 05:26:28 -06:00
modelAutoComplete . onchange . on ( ( { value } ) => {
2023-02-04 14:28:01 -06:00
/ * *
* TODO implement optional API call to check model unet channel count
* extension users guaranteed to have it as of
* https : //github.com/zero01101/openOutpaint-webUI-extension/commit/1f22f5ea5b860c6e91f77edfb47743a124596dec
* but still need a fallback check like below
* /
2022-12-30 05:26:28 -06:00
if ( value . toLowerCase ( ) . includes ( "inpainting" ) )
document . querySelector (
"#models-ac-select input.autocomplete-text"
) . style . backgroundColor = "#cfc" ;
else
document . querySelector (
"#models-ac-select input.autocomplete-text"
) . style . backgroundColor = "#fcc" ;
} ) ;
2022-12-08 15:23:17 -06:00
const samplerAutoComplete = createAutoComplete (
"Sampler" ,
document . getElementById ( "sampler-ac-select" )
) ;
const upscalerAutoComplete = createAutoComplete (
"Upscaler" ,
document . getElementById ( "upscaler-ac-select" )
) ;
2023-01-02 13:50:28 -06:00
const hrFixUpscalerAutoComplete = createAutoComplete (
"HRfix Upscaler" ,
document . getElementById ( "hrFixUpscaler" )
) ;
2023-01-03 15:54:05 -06:00
2023-01-02 13:50:28 -06:00
hrFixUpscalerAutoComplete . onchange . on ( ( { value } ) => {
stableDiffusionData . hr _upscaler = value ;
2023-01-02 18:13:46 -06:00
localStorage . setItem ( ` openoutpaint/hr_upscaler ` , value ) ;
2023-01-02 13:50:28 -06:00
} ) ;
2022-12-12 16:25:49 -06:00
const resSlider = makeSlider (
2022-12-03 06:53:12 -06:00
"Resolution" ,
document . getElementById ( "resolution" ) ,
"resolution" ,
2022-12-12 17:09:27 -06:00
128 ,
2022-12-12 16:25:49 -06:00
2048 ,
2022-12-12 17:09:27 -06:00
128 ,
2022-12-03 06:53:12 -06:00
512 ,
2 ,
( v ) => {
stableDiffusionData . width = stableDiffusionData . height = v ;
2022-12-28 23:39:32 -06:00
toolbar . currentTool &&
toolbar . currentTool . redraw &&
toolbar . currentTool . redraw ( ) ;
2022-12-03 06:53:12 -06:00
}
) ;
2022-11-29 20:08:43 -06:00
makeSlider (
"CFG Scale" ,
document . getElementById ( "cfgScale" ) ,
"cfg_scale" ,
2023-01-02 01:35:54 -06:00
localStorage . getItem ( "openoutpaint/settings.min-cfg" ) || 1 ,
2023-01-02 00:45:03 -06:00
localStorage . getItem ( "openoutpaint/settings.max-cfg" ) || 25 ,
2022-11-29 20:08:43 -06:00
0.5 ,
2022-12-03 04:50:23 -06:00
7.0 ,
0.1
2022-11-29 20:08:43 -06:00
) ;
makeSlider (
"Batch Size" ,
document . getElementById ( "batchSize" ) ,
"batch_size" ,
1 ,
8 ,
1 ,
2
) ;
makeSlider (
"Iterations" ,
document . getElementById ( "batchCount" ) ,
"n_iter" ,
1 ,
8 ,
1 ,
2
) ;
2022-12-06 21:12:10 -06:00
makeSlider (
"Upscale X" ,
document . getElementById ( "upscaleX" ) ,
"upscale_x" ,
1.0 ,
4.0 ,
0.1 ,
2.0 ,
0.1
) ;
2022-11-29 20:08:43 -06:00
2023-01-02 00:45:03 -06:00
makeSlider (
"Steps" ,
document . getElementById ( "steps" ) ,
"steps" ,
1 ,
localStorage . getItem ( "openoutpaint/settings.max-steps" ) || 70 ,
5 ,
30 ,
1
) ;
2022-11-29 20:08:43 -06:00
2023-01-02 13:50:28 -06:00
// 20230102 grumble grumble
2023-01-03 21:41:03 -06:00
const hrFixScaleSlider = makeSlider (
2023-01-02 13:50:28 -06:00
"HRfix Scale" ,
document . getElementById ( "hrFixScale" ) ,
"hr_scale" ,
1.0 ,
4.0 ,
0.1 ,
2.0 ,
0.1
2022-12-30 23:40:45 -06:00
) ;
2023-01-02 17:18:50 -06:00
makeSlider (
"HRfix Denoising" ,
document . getElementById ( "hrDenoising" ) ,
2023-01-02 23:36:42 -06:00
"hr_denoising_strength" ,
2022-12-30 23:40:45 -06:00
0.0 ,
2023-01-02 17:18:50 -06:00
1.0 ,
2023-01-02 18:13:46 -06:00
0.05 ,
2023-01-02 17:18:50 -06:00
0.7 ,
0.01
2022-12-30 23:40:45 -06:00
) ;
2023-01-03 21:41:03 -06:00
const lockPxSlider = makeSlider (
"HRfix Autoscale Lock Px." ,
document . getElementById ( "hrFixLockPx" ) ,
"hr_fix_lock_px" ,
0 ,
1024 ,
256 ,
0 ,
1
) ;
2023-01-04 20:00:51 -06:00
const hrStepsSlider = makeSlider (
"HRfix Steps" ,
document . getElementById ( "hrFixSteps" ) ,
"hr_second_pass_steps" ,
0 ,
localStorage . getItem ( "openoutpaint/settings.max-steps" ) || 70 ,
5 ,
2023-01-05 17:42:50 -06:00
0 ,
2023-01-04 20:00:51 -06:00
1
) ;
2022-11-29 20:08:43 -06:00
function changeMaskBlur ( ) {
2022-12-01 15:10:30 -06:00
stableDiffusionData . mask _blur = parseInt (
document . getElementById ( "maskBlur" ) . value
) ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/mask_blur" , stableDiffusionData . mask _blur ) ;
2022-11-29 20:08:43 -06:00
}
function changeSeed ( ) {
stableDiffusionData . seed = document . getElementById ( "seed" ) . value ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/seed" , stableDiffusionData . seed ) ;
2022-11-29 20:08:43 -06:00
}
2023-01-04 20:00:51 -06:00
function changeHRFX ( ) {
stableDiffusionData . hr _resize _x =
document . getElementById ( "hr_resize_x" ) . value ;
}
function changeHRFY ( ) {
stableDiffusionData . hr _resize _y =
document . getElementById ( "hr_resize_y" ) . value ;
}
2022-11-29 20:08:43 -06:00
function changeHiResFix ( ) {
stableDiffusionData . enable _hr = Boolean (
document . getElementById ( "cbxHRFix" ) . checked
) ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/enable_hr" , stableDiffusionData . enable _hr ) ;
2023-01-04 20:00:51 -06:00
// var hrfSlider = document.getElementById("hrFixScale");
// var hrfOpotions = document.getElementById("hrFixUpscaler");
// var hrfLabel = document.getElementById("hrFixLabel");
// var hrfDenoiseSlider = document.getElementById("hrDenoising");
// var hrfLockPxSlider = document.getElementById("hrFixLockPx");
2023-01-02 13:50:28 -06:00
if ( stableDiffusionData . enable _hr ) {
2023-01-04 20:00:51 -06:00
document
. querySelectorAll ( ".hrfix" )
. forEach ( ( el ) => el . classList . remove ( "invisible" ) ) ;
2023-01-02 13:50:28 -06:00
} else {
2023-01-04 20:00:51 -06:00
document
. querySelectorAll ( ".hrfix" )
. forEach ( ( el ) => el . classList . add ( "invisible" ) ) ;
2023-01-02 13:50:28 -06:00
}
2022-11-29 20:08:43 -06:00
}
2022-12-12 18:25:02 -06:00
2023-01-04 23:27:02 -06:00
function changeHiResSquare ( ) {
stableDiffusionData . hr _square _aspect = Boolean (
document . getElementById ( "cbxHRFSquare" ) . checked
) ;
}
2022-12-28 21:37:18 -06:00
function changeRestoreFaces ( ) {
stableDiffusionData . restore _faces = Boolean (
document . getElementById ( "cbxRestoreFaces" ) . checked
) ;
localStorage . setItem (
"openoutpaint/restore_faces" ,
stableDiffusionData . restore _faces
) ;
}
2022-12-12 18:25:02 -06:00
function changeSyncCursorSize ( ) {
2022-12-28 23:39:32 -06:00
global . syncCursorSize = Boolean (
2022-12-12 18:25:02 -06:00
document . getElementById ( "cbxSyncCursorSize" ) . checked
) ;
2022-12-28 23:39:32 -06:00
localStorage . setItem ( "openoutpaint/sync_cursor_size" , global . syncCursorSize ) ;
2022-12-12 18:25:02 -06:00
}
2022-12-04 13:22:35 -06:00
function changeSmoothRendering ( ) {
const layers = document . getElementById ( "layer-render" ) ;
2023-03-30 17:49:59 -05:00
if ( localStorage . getItem ( "openoutpaint/settings.smooth" ) === "true" ) {
2022-12-04 13:22:35 -06:00
layers . classList . remove ( "pixelated" ) ;
} else {
layers . classList . add ( "pixelated" ) ;
}
}
2022-11-29 20:08:43 -06:00
2022-12-04 13:22:35 -06:00
function isCanvasBlank ( x , y , w , h , canvas ) {
2022-11-29 20:08:43 -06:00
return ! canvas
. getContext ( "2d" )
. getImageData ( x , y , w , h )
. data . some ( ( channel ) => channel !== 0 ) ;
}
function drawBackground ( ) {
2023-01-18 17:55:04 -06:00
{
// Existing Canvas BG
const canvas = document . createElement ( "canvas" ) ;
canvas . width = config . gridSize * 2 ;
canvas . height = config . gridSize * 2 ;
const ctx = canvas . getContext ( "2d" ) ;
ctx . fillStyle = theme . grid . dark ;
ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
ctx . fillStyle = theme . grid . light ;
ctx . fillRect ( 0 , 0 , config . gridSize , config . gridSize ) ;
ctx . fillRect (
config . gridSize ,
config . gridSize ,
config . gridSize ,
config . gridSize
) ;
canvas . toBlob ( ( blob ) => {
const url = window . URL . createObjectURL ( blob ) ;
console . debug ( url ) ;
bgLayer . canvas . style . backgroundImage = ` url( ${ url } ) ` ;
} ) ;
}
2022-11-29 20:08:43 -06:00
}
2023-01-21 23:48:56 -06:00
async function exportWorkspaceState ( ) {
return {
defaultLayer : {
id : uil . layerIndex . default . id ,
name : uil . layerIndex . default . name ,
} ,
bb : {
x : imageCollection . bb . x ,
y : imageCollection . bb . y ,
w : imageCollection . bb . w ,
h : imageCollection . bb . h ,
} ,
history : await commands . export ( ) ,
} ;
}
async function importWorkspaceState ( state ) {
// Start from zero, effectively
2023-01-26 22:39:08 -06:00
await commands . clear ( ) ;
2023-01-21 23:48:56 -06:00
// Setup initial layer
const layer = uil . layerIndex . default ;
layer . deletable = true ;
await commands . runCommand (
"addLayer" ,
"Temporary Layer" ,
{ name : "Temporary Layer" , key : "tmp" } ,
{ recordHistory : false }
) ;
await commands . runCommand (
"deleteLayer" ,
"Deleted Layer" ,
{
layer ,
} ,
{ recordHistory : false }
) ;
await commands . runCommand (
"addLayer" ,
"Initial Layer Creation" ,
{
id : state . defaultLayer . id ,
name : state . defaultLayer . name ,
key : "default" ,
deletable : false ,
} ,
{ recordHistory : false }
) ;
await commands . runCommand (
"deleteLayer" ,
"Deleted Layer" ,
{
layer : uil . layerIndex . tmp ,
} ,
{ recordHistory : false }
) ;
// Resize canvas to match original size
const sbb = new BoundingBox ( state . bb ) ;
const bb = imageCollection . bb ;
let eleft = 0 ;
if ( bb . x > sbb . x ) eleft = bb . x - sbb . x ;
let etop = 0 ;
if ( bb . y > sbb . y ) etop = bb . y - sbb . y ;
let eright = 0 ;
if ( bb . tr . x < sbb . tr . x ) eright = sbb . tr . x - bb . tr . x ;
let ebottom = 0 ;
if ( bb . br . y < sbb . br . y ) ebottom = sbb . br . y - bb . br . y ;
imageCollection . expand ( eleft , etop , eright , ebottom ) ;
// Run commands in order
for ( const command of state . history ) {
await commands . import ( command ) ;
2022-11-29 20:08:43 -06:00
}
}
2023-01-21 23:48:56 -06:00
async function saveWorkspaceToFile ( ) {
const workspace = await exportWorkspaceState ( ) ;
const blob = new Blob ( [ JSON . stringify ( workspace ) ] , {
type : "application/json" ,
} ) ;
const url = URL . createObjectURL ( blob ) ;
var link = document . createElement ( "a" ) ; // Or maybe get it from the current document
link . href = url ;
link . download = ` ${ new Date ( ) . toISOString ( ) } _openOutpaint_workspace.json ` ;
link . click ( ) ;
}
2022-12-08 15:23:17 -06:00
async function getUpscalers ( ) {
2023-01-24 16:55:45 -06:00
var url = document . getElementById ( "host" ) . value + "/sdapi/v1/upscalers" ;
let upscalers = [ ] ;
2022-11-29 20:08:43 -06:00
2022-12-08 15:23:17 -06:00
try {
2023-01-24 16:55:45 -06:00
const response = await fetch ( url , {
method : "GET" ,
headers : {
Accept : "application/json" ,
"Content-Type" : "application/json" ,
} ,
2023-01-02 13:50:28 -06:00
} ) ;
2023-01-24 16:55:45 -06:00
const data = await response . json ( ) ;
for ( var i = 0 ; i < data . length ; i ++ ) {
if ( data [ i ] . name . includes ( "None" ) ) {
continue ;
}
upscalers . push ( data [ i ] . name ) ;
}
2022-12-08 15:23:17 -06:00
} catch ( e ) {
console . warn ( "[index] Failed to fetch upscalers:" ) ;
console . warn ( e ) ;
2023-01-24 16:55:45 -06:00
upscalers = [
"Lanczos" ,
"Nearest" ,
"LDSR" ,
"SwinIR" ,
"R-ESRGAN General 4xV3" ,
"R-ESRGAN General WDN 4xV3" ,
"R-ESRGAN AnimeVideo" ,
"R-ESRGAN 4x+" ,
"R-ESRGAN 4x+ Anime6B" ,
"R-ESRGAN 2x+" ,
] ;
2022-12-08 15:23:17 -06:00
}
2023-01-24 16:55:45 -06:00
const upscalersPlusNone = [ ... upscalers ] ;
upscalersPlusNone . unshift ( "None" ) ;
upscalersPlusNone . push ( "Latent" ) ;
upscalersPlusNone . push ( "Latent (antialiased)" ) ;
upscalersPlusNone . push ( "Latent (bicubic)" ) ;
upscalersPlusNone . push ( "Latent (bicubic, antialiased)" ) ;
upscalersPlusNone . push ( "Latent (nearest)" ) ;
upscalerAutoComplete . options = upscalers . map ( ( u ) => {
return { name : u , value : u } ;
} ) ;
hrFixUpscalerAutoComplete . options = upscalersPlusNone . map ( ( u ) => {
return { name : u , value : u } ;
} ) ;
2022-12-08 15:23:17 -06:00
2023-01-24 16:55:45 -06:00
upscalerAutoComplete . value = upscalers [ 0 ] ;
hrFixUpscalerAutoComplete . value =
localStorage . getItem ( "openoutpaint/hr_upscaler" ) === null
? "None"
: localStorage . getItem ( "openoutpaint/hr_upscaler" ) ;
2022-11-29 20:08:43 -06:00
}
2023-01-14 17:08:02 -06:00
async function getModels ( refresh = false ) {
2023-01-02 18:43:33 -06:00
const url = document . getElementById ( "host" ) . value + "/sdapi/v1/sd-models" ;
let opt = null ;
2022-12-08 16:11:08 -06:00
try {
const response = await fetch ( url ) ;
const data = await response . json ( ) ;
2022-11-29 20:08:43 -06:00
2023-01-02 18:43:33 -06:00
opt = data . map ( ( option ) => ( {
2022-12-08 16:11:08 -06:00
name : option . title ,
value : option . title ,
2022-12-30 05:26:28 -06:00
optionelcb : ( el ) => {
if ( option . title . toLowerCase ( ) . includes ( "inpainting" ) )
el . classList . add ( "inpainting" ) ;
} ,
2022-12-08 16:11:08 -06:00
} ) ) ;
2022-11-29 20:08:43 -06:00
2023-01-02 18:43:33 -06:00
modelAutoComplete . options = opt ;
2022-12-08 16:11:08 -06:00
try {
const optResponse = await fetch (
document . getElementById ( "host" ) . value + "/sdapi/v1/options"
) ;
const optData = await optResponse . json ( ) ;
const model = optData . sd _model _checkpoint ;
2022-11-29 20:08:43 -06:00
console . log ( "Current model: " + model ) ;
2023-01-14 17:08:02 -06:00
if ( modelAutoComplete . value !== model ) modelAutoComplete . value = model ;
2022-12-08 16:11:08 -06:00
} catch ( e ) {
console . warn ( "[index] Failed to fetch current model:" ) ;
console . warn ( e ) ;
}
} catch ( e ) {
console . warn ( "[index] Failed to fetch models:" ) ;
console . warn ( e ) ;
}
2022-11-29 20:08:43 -06:00
2023-01-14 17:08:02 -06:00
if ( ! refresh )
modelAutoComplete . onchange . on ( async ( { value } ) => {
console . log ( ` [index] Changing model to [ ${ value } ] ` ) ;
const payload = {
sd _model _checkpoint : value ,
} ;
const url = document . getElementById ( "host" ) . value + "/sdapi/v1/options/" ;
try {
await fetch ( url , {
method : "POST" ,
headers : {
"Content-Type" : "application/json" ,
} ,
body : JSON . stringify ( payload ) ,
} ) ;
2023-02-14 20:44:37 -06:00
notifications . notify ( ` Model changed to [ ${ value } ] ` , { type : "success" } ) ;
2023-01-14 17:08:02 -06:00
} catch ( e ) {
console . warn ( "[index] Error changing model" ) ;
console . warn ( e ) ;
2022-12-08 15:23:17 -06:00
2023-02-14 20:44:37 -06:00
notifications . notify (
"Error changing model, please check console for additional information" ,
{
type : NotificationType . ERROR ,
timeout : config . notificationTimeout * 2 ,
}
2023-01-14 17:08:02 -06:00
) ;
}
} ) ;
2023-01-02 18:43:33 -06:00
// If first time running, ask if user wants to switch to an inpainting model
if ( global . firstRun && ! modelAutoComplete . value . includes ( "inpainting" ) ) {
const inpainting = opt . find ( ( { name } ) => name . includes ( "inpainting" ) ) ;
let message =
" It seems this is your first time using openOutpaint . It is highly recommended that you switch to an inpainting model . \
These are highlighted as green in the model selector . " ;
if ( inpainting ) {
2023-02-14 20:44:37 -06:00
message += ` <br><br>We have found the inpainting model<br><br> - ${ inpainting . name } <br><br>available in the webui. Do you want to switch to it? ` ;
if ( await notifications . dialog ( "Automatic Model Switch" , message ) ) {
2023-01-02 18:43:33 -06:00
modelAutoComplete . value = inpainting . value ;
}
} else {
2023-02-14 20:44:37 -06:00
message += ` <br><br>No inpainting model seems to be available in the webui. It is recommended that you download an inpainting model, or outpainting results may not be optimal. ` ;
notifications . notify ( message , {
type : NotificationType . WARN ,
timeout : null ,
} ) ;
2023-01-02 18:43:33 -06:00
}
}
2022-11-29 20:08:43 -06:00
}
2022-12-07 15:55:41 -06:00
async function getConfig ( ) {
var url = document . getElementById ( "host" ) . value + "/sdapi/v1/options" ;
let message =
"The following options for the AUTOMATIC1111's webui are not recommended to use with this software:" ;
try {
const response = await fetch ( url ) ;
const data = await response . json ( ) ;
let wrong = false ;
// Check if img2img color correction is disabled and inpainting mask weight is set to one
// TODO: API Seems bugged for retrieving inpainting mask weight - returning 0 for all values different than 1.0
if ( data . img2img _color _correction ) {
2023-02-14 20:44:37 -06:00
message += "<br> - Image to Image Color Correction: false recommended" ;
2022-12-07 15:55:41 -06:00
wrong = true ;
}
if ( data . inpainting _mask _weight < 1.0 ) {
2023-02-14 20:44:37 -06:00
message += ` <br> - Inpainting Conditioning Mask Strength: 1.0 recommended ` ;
2022-12-07 15:55:41 -06:00
wrong = true ;
}
2023-02-14 20:44:37 -06:00
message +=
"<br><br>Should these values be changed to the recommended ones?" ;
2022-12-07 15:55:41 -06:00
if ( ! wrong ) {
console . info ( "[index] WebUI Settings set as recommended." ) ;
return ;
}
console . info (
"[index] WebUI Settings not set as recommended. Prompting for changing settings automatically."
) ;
2023-02-14 20:44:37 -06:00
if ( ! ( await notifications . dialog ( "Recommended Settings" , message ) ) ) return ;
2022-12-07 15:55:41 -06:00
try {
await fetch ( url , {
method : "POST" ,
headers : {
"Content-Type" : "application/json" ,
} ,
body : JSON . stringify ( {
img2img _color _correction : false ,
inpainting _mask _weight : 1.0 ,
} ) ,
} ) ;
} catch ( e ) {
console . warn ( "[index] Failed to fetch WebUI Configuration" ) ;
console . warn ( e ) ;
}
} catch ( e ) {
console . warn ( "[index] Failed to fetch WebUI Configuration" ) ;
console . warn ( e ) ;
}
}
2022-12-02 11:31:49 -06:00
function changeStyles ( ) {
/** @type {HTMLSelectElement} */
const styleSelectEl = document . getElementById ( "styleSelect" ) ;
const selected = Array . from ( styleSelectEl . options ) . filter (
( option ) => option . selected
) ;
2022-12-02 23:47:47 -06:00
let selectedString = selected . map ( ( option ) => option . value ) ;
if ( selectedString . find ( ( selected ) => selected === "None" ) ) {
selectedString = [ ] ;
Array . from ( styleSelectEl . options ) . forEach ( ( option ) => {
if ( option . value !== "None" ) option . selected = false ;
} ) ;
}
2022-12-02 11:31:49 -06:00
2022-12-19 12:45:09 -06:00
localStorage . setItem (
"openoutpaint/promptStyle" ,
JSON . stringify ( selectedString )
) ;
2022-12-02 11:31:49 -06:00
// change the model
2022-12-02 23:47:47 -06:00
if ( selectedString . length > 0 )
console . log ( ` [index] Changing styles to ${ selectedString . join ( ", " ) } ` ) ;
else console . log ( ` [index] Clearing styles ` ) ;
2022-12-02 11:31:49 -06:00
stableDiffusionData . styles = selectedString ;
}
2022-12-08 15:23:17 -06:00
async function getSamplers ( ) {
2022-11-29 20:08:43 -06:00
var url = document . getElementById ( "host" ) . value + "/sdapi/v1/samplers" ;
2022-12-08 15:23:17 -06:00
try {
const response = await fetch ( url ) ;
const data = await response . json ( ) ;
2022-12-21 09:07:29 -06:00
samplerAutoComplete . onchange . on ( ( { value } ) => {
stableDiffusionData . sampler _index = value ;
localStorage . setItem ( "openoutpaint/sampler" , value ) ;
} ) ;
2022-12-08 15:23:17 -06:00
samplerAutoComplete . options = data . map ( ( sampler ) => ( {
name : sampler . name ,
value : sampler . name ,
} ) ) ;
// Initial sampler
2022-12-19 12:45:09 -06:00
if ( localStorage . getItem ( "openoutpaint/sampler" ) != null ) {
samplerAutoComplete . value = localStorage . getItem ( "openoutpaint/sampler" ) ;
2022-12-08 15:23:17 -06:00
} else {
samplerAutoComplete . value = data [ 0 ] . name ;
2022-12-19 12:45:09 -06:00
localStorage . setItem ( "openoutpaint/sampler" , samplerAutoComplete . value ) ;
2022-12-08 15:23:17 -06:00
}
2022-12-21 09:07:29 -06:00
stableDiffusionData . sampler _index = samplerAutoComplete . value ;
2022-12-08 15:23:17 -06:00
} catch ( e ) {
console . warn ( "[index] Failed to fetch samplers" ) ;
console . warn ( e ) ;
}
2022-11-29 20:08:43 -06:00
}
async function upscaleAndDownload ( ) {
// Future improvements: some upscalers take a while to upscale, so we should show a loading bar or something, also a slider for the upscale amount
// get cropped canvas, send it to upscaler, download result
2022-12-19 12:45:09 -06:00
var upscale _factor = localStorage . getItem ( "openoutpaint/upscale_x" )
? localStorage . getItem ( "openoutpaint/upscale_x" )
2022-12-06 21:12:10 -06:00
: 2 ;
2022-12-08 15:23:17 -06:00
var upscaler = upscalerAutoComplete . value ;
2022-12-04 20:19:34 -06:00
var croppedCanvas = cropCanvas (
uil . getVisible ( {
x : 0 ,
y : 0 ,
w : imageCollection . size . w ,
h : imageCollection . size . h ,
} )
) ;
2022-11-29 20:08:43 -06:00
if ( croppedCanvas != null ) {
var url =
document . getElementById ( "host" ) . value + "/sdapi/v1/extra-single-image/" ;
2022-12-01 20:00:33 -06:00
var imgdata = croppedCanvas . canvas . toDataURL ( "image/png" ) ;
2022-11-29 20:08:43 -06:00
var data = {
"resize-mode" : 0 , // 0 = just resize, 1 = crop and resize, 2 = resize and fill i assume based on theimg2img tabs options
upscaling _resize : upscale _factor ,
upscaler _1 : upscaler ,
image : imgdata ,
} ;
console . log ( data ) ;
await fetch ( url , {
method : "POST" ,
headers : {
Accept : "application/json" ,
"Content-Type" : "application/json" ,
} ,
body : JSON . stringify ( data ) ,
} )
. then ( ( response ) => response . json ( ) )
. then ( ( data ) => {
console . log ( data ) ;
var link = document . createElement ( "a" ) ;
link . download =
new Date ( )
. toISOString ( )
. slice ( 0 , 19 )
. replace ( "T" , " " )
. replace ( ":" , " " ) +
" openOutpaint image upscaler_" +
upscaler +
2022-12-06 21:12:10 -06:00
"_x" +
2022-12-06 21:17:02 -06:00
upscale _factor +
2022-11-29 20:08:43 -06:00
".png" ;
link . href = "data:image/png;base64," + data [ "image" ] ;
link . click ( ) ;
} ) ;
}
}
function loadSettings ( ) {
// set default values if not set
var _mask _blur =
2022-12-19 12:45:09 -06:00
localStorage . getItem ( "openoutpaint/mask_blur" ) == null
2022-11-29 20:08:43 -06:00
? 0
2022-12-19 12:45:09 -06:00
: localStorage . getItem ( "openoutpaint/mask_blur" ) ;
2023-01-28 23:15:39 -06:00
var _seed =
localStorage . getItem ( "openoutpaint/seed" ) == null
? - 1
: localStorage . getItem ( "openoutpaint/seed" ) ;
2022-12-13 08:24:22 -06:00
let _enable _hr =
2022-12-19 12:45:09 -06:00
localStorage . getItem ( "openoutpaint/enable_hr" ) === null
2022-11-29 20:08:43 -06:00
? false
2022-12-19 12:45:09 -06:00
: localStorage . getItem ( "openoutpaint/enable_hr" ) === "true" ;
2022-12-28 21:37:18 -06:00
let _restore _faces =
localStorage . getItem ( "openoutpaint/restore_faces" ) === null
? false
: localStorage . getItem ( "openoutpaint/restore_faces" ) === "true" ;
2022-12-13 08:24:22 -06:00
let _sync _cursor _size =
2022-12-19 12:45:09 -06:00
localStorage . getItem ( "openoutpaint/sync_cursor_size" ) === null
2022-12-13 08:16:26 -06:00
? true
2022-12-19 12:45:09 -06:00
: localStorage . getItem ( "openoutpaint/sync_cursor_size" ) === "true" ;
2022-12-13 08:24:22 -06:00
2023-01-02 18:13:46 -06:00
let _hrfix _scale =
localStorage . getItem ( "openoutpaint/hr_scale" ) === null
? 2.0
: localStorage . getItem ( "openoutpaint/hr_scale" ) ;
let _hrfix _denoising =
2023-01-02 23:36:42 -06:00
localStorage . getItem ( "openoutpaint/hr_denoising_strength" ) === null
2023-01-02 18:13:46 -06:00
? 0.7
2023-01-02 23:36:42 -06:00
: localStorage . getItem ( "openoutpaint/hr_denoising_strength" ) ;
2023-01-03 21:41:03 -06:00
let _hrfix _lock _px =
localStorage . getItem ( "openoutpaint/hr_fix_lock_px" ) === null
? 0
: localStorage . getItem ( "openoutpaint/hr_fix_lock_px" ) ;
2022-11-29 20:08:43 -06:00
// set the values into the UI
document . getElementById ( "maskBlur" ) . value = Number ( _mask _blur ) ;
2023-01-28 23:15:39 -06:00
document . getElementById ( "seed" ) . value = Number ( _seed ) ;
2022-11-29 20:08:43 -06:00
document . getElementById ( "cbxHRFix" ) . checked = Boolean ( _enable _hr ) ;
2022-12-28 21:37:18 -06:00
document . getElementById ( "cbxRestoreFaces" ) . checked = Boolean ( _restore _faces ) ;
2022-12-12 18:25:02 -06:00
document . getElementById ( "cbxSyncCursorSize" ) . checked =
Boolean ( _sync _cursor _size ) ;
2023-01-02 18:13:46 -06:00
document . getElementById ( "hrFixScale" ) . value = Number ( _hrfix _scale ) ;
document . getElementById ( "hrDenoising" ) . value = Number ( _hrfix _denoising ) ;
2023-01-03 21:41:03 -06:00
document . getElementById ( "hrFixLockPx" ) . value = Number ( _hrfix _lock _px ) ;
2022-11-29 20:08:43 -06:00
}
2022-11-29 20:54:09 -06:00
imageCollection . element . addEventListener (
"wheel" ,
( evn ) => {
evn . preventDefault ( ) ;
} ,
{ passive : false }
) ;
imageCollection . element . addEventListener (
"contextmenu" ,
( evn ) => {
evn . preventDefault ( ) ;
} ,
{ passive : false }
) ;
2022-12-01 20:31:49 -06:00
2023-02-14 20:44:37 -06:00
async function resetToDefaults ( ) {
if (
await notifications . dialog (
"Clear Settings" ,
"Are you sure you want to clear your settings?"
)
) {
2022-12-01 20:31:49 -06:00
localStorage . clear ( ) ;
}
}
2023-01-07 14:06:37 -06:00
document . addEventListener ( "visibilitychange" , ( ) => {
checkFocus ( ) ;
} ) ;
2023-01-07 18:22:39 -06:00
window . addEventListener ( "blur" , ( ) => {
checkFocus ( ) ;
} ) ;
window . addEventListener ( "focus" , ( ) => {
checkFocus ( ) ;
} ) ;
2023-01-07 14:06:37 -06:00
function checkFocus ( ) {
2023-01-07 18:22:39 -06:00
let hasFocus = document . hasFocus ( ) ;
if ( document . hidden || ! hasFocus ) {
2023-01-07 14:06:37 -06:00
focused = false ;
2023-01-07 18:22:39 -06:00
} else {
focused = true ;
2023-01-07 14:06:37 -06:00
}
}
2023-01-22 13:29:24 -06:00
2023-02-19 09:49:48 -06:00
function refreshScripts ( ) {
selector = document . getElementById ( "script-selector" ) ;
selector . innerHTML = "" ;
createBaseScriptOptions ( ) ;
loadDefaultScripts ( ) ;
2023-02-25 07:30:52 -06:00
// loadUserScripts();
2023-02-19 09:49:48 -06:00
}
function createBaseScriptOptions ( ) {
selector = document . getElementById ( "script-selector" ) ;
var noScript = document . createElement ( "option" ) ;
noScript . id = "no_selected_script" ;
noScript . value = "" ;
2023-02-26 08:56:08 -06:00
noScript . innerHTML = "(disabled)" ;
2023-02-19 09:49:48 -06:00
selector . appendChild ( noScript ) ;
var customScript = document . createElement ( "option" ) ;
customScript . id = "custom" ;
customScript . value = "custom" ;
customScript . innerHTML = "Custom" ;
selector . appendChild ( customScript ) ;
}
2023-02-04 10:34:26 -06:00
async function loadDefaultScripts ( ) {
selector = document . getElementById ( "script-selector" ) ;
const response = await fetch ( "./defaultscripts.json" ) ;
const json = await response . json ( ) ;
for ( const key in json . defaultScripts ) {
var opt = document . createElement ( "option" ) ;
opt . value = opt . innerHTML = key ;
selector . appendChild ( opt ) ;
}
defaultScripts = json ;
}
2023-02-25 07:30:52 -06:00
// async function loadUserScripts() {
// selector = document.getElementById("script-selector");
// const response = await fetch("./userdefinedscripts.json");
// const json = await response.json();
// for (const key in json.userScripts) {
// var opt = document.createElement("option");
// opt.value = opt.innerHTML = key;
// selector.appendChild(opt);
// }
// userScripts = json;
// }
2023-02-19 09:49:48 -06:00
function changeScript ( event ) {
2023-01-22 17:25:06 -06:00
let enable = ( ) => {
scriptName . disabled = false ;
2023-02-25 07:30:52 -06:00
// saveScriptButton.disabled = false;
2023-01-22 17:25:06 -06:00
} ;
let disable = ( ) => {
scriptName . disabled = true ;
2023-02-25 07:30:52 -06:00
// saveScriptButton.disabled = true;
2023-01-22 17:25:06 -06:00
} ;
2023-02-19 09:49:48 -06:00
let selected = event . target . value ;
2023-01-22 13:29:24 -06:00
let scriptName = document . getElementById ( "script-name-input" ) ;
let scriptArgs = document . getElementById ( "script-args-input" ) ;
2023-02-25 07:30:52 -06:00
// let saveScriptButton = document.getElementById("save-custom-script");
2023-01-22 17:25:06 -06:00
scriptName . value = selected ;
2023-02-19 09:49:48 -06:00
scriptArgs . title = "" ;
2023-01-22 17:25:06 -06:00
disable ( ) ;
2023-01-22 13:29:24 -06:00
switch ( selected ) {
2023-01-22 17:25:06 -06:00
case "custom" : {
2023-02-25 07:30:52 -06:00
let _script _name _input =
localStorage . getItem ( "openoutpaint/script_name_input" ) === null
? ""
: localStorage . getItem ( "openoutpaint/script_name_input" ) ;
let _script _args _input =
localStorage . getItem ( "openoutpaint/script_args_input" ) === null
? "[]"
: localStorage . getItem ( "openoutpaint/script_args_input" ) ;
scriptName . value = _script _name _input ;
scriptArgs . value = _script _args _input ;
2023-01-22 17:50:49 -06:00
scriptArgs . title = "" ;
2023-01-22 17:25:06 -06:00
enable ( ) ;
2023-01-22 13:29:24 -06:00
break ;
}
2023-02-04 10:34:26 -06:00
case "" : {
// specifically no selected script
2023-01-22 13:29:24 -06:00
scriptArgs . value = "" ;
2023-02-04 10:34:26 -06:00
break ;
}
default : {
scriptName . value = selected ;
2023-02-19 09:49:48 -06:00
// check default scripts for selected script
if ( selected in defaultScripts . defaultScripts ) {
scriptArgs . value = defaultScripts . defaultScripts [ selected ] . scriptValues ;
scriptArgs . title = defaultScripts . defaultScripts [ selected ] . titleText ;
}
2023-02-25 07:30:52 -06:00
// FURTHER TODO see if this is even plausible as i don't think JS can arbitrarily save data to files without downloading
2023-02-04 10:34:26 -06:00
// if not found, check user scripts
2023-02-19 09:49:48 -06:00
// TODO yknow what check userscripts first; if customizations have been made load those instead of defaults, i'm too stupid to do that right now
2023-02-25 07:30:52 -06:00
// else if (selected in userScripts.userScripts) {
// scriptArgs.value = userScripts.userScripts[selected].scriptValues;
// enable();
// }
2023-02-04 10:34:26 -06:00
// if not found, wtf
2023-01-22 13:29:24 -06:00
}
}
}
2023-02-09 19:21:40 -06:00
2023-02-25 07:30:52 -06:00
// async function saveCustomScript() {
// let selector = document.getElementById("script-name-input");
// let selected = selector.value;
// let args = document.getElementById("script-args-input").value;
// if (selected.trim() != "") {
// if (selected in userScripts.userScripts) {
// userScripts.userScripts[selected].scriptValues = args;
// } else {
// }
// }
// }
2023-02-19 09:49:48 -06:00
2023-02-04 14:28:01 -06:00
function togglePix2PixImgCfg ( value ) {
// super hacky
// actually doesn't work at all yet so i'm leaving it here to taunt and remind me of my failures
2023-02-25 07:30:52 -06:00
// try {
// if (value.toLowerCase().includes("pix2pix")) {
// document
// .querySelector(".instruct-pix2pix-img-cfg")
// .classList.remove("invisible");
// } else {
// document
// .querySelector(".instruct-pix2pix-img-cfg")
// .classList.add("invisible");
// }
// } catch (e) {
// // highly likely not currently using img2img tool, do nothing
// }
}
2023-02-04 14:28:01 -06:00
2023-02-25 07:30:52 -06:00
function storeUserscriptVal ( evt , type ) {
let currentScript = document . getElementById ( "script-selector" ) . value ;
if ( currentScript === "custom" ) {
console . log ( type ) ;
console . log ( evt ) ;
let val = ( currentScript = document . getElementById (
"script-" + type + "-input"
) . value ) ;
localStorage . setItem ( "openoutpaint/script_" + type + "_input" , val ) ;
2023-02-04 14:28:01 -06:00
}
}