dream queueing now supported
- Image navigation shortcuts work for all simultaneously (probably not optimal) This is for #89. Some things should be ironed out, such as adding a cancel button for future jobs and an order indicator maybe? Signed-off-by: Victor Seiji Hariki <victorseijih@gmail.com>
This commit is contained in:
parent
e3be9010f2
commit
f279c8457b
2 changed files with 277 additions and 235 deletions
|
@ -1,4 +1,6 @@
|
||||||
let blockNewImages = false;
|
let blockNewImages = false;
|
||||||
|
let generationQueue = [];
|
||||||
|
let generationAreas = new Set();
|
||||||
let generating = false;
|
let generating = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,7 +120,50 @@ const _generate = async (
|
||||||
bb,
|
bb,
|
||||||
drawEvery = 0.2 / request.n_iter
|
drawEvery = 0.2 / request.n_iter
|
||||||
) => {
|
) => {
|
||||||
const requestCopy = {...request};
|
const requestCopy = JSON.parse(JSON.stringify(request));
|
||||||
|
|
||||||
|
// Block requests to identical areas
|
||||||
|
const areaid = `${bb.x}-${bb.y}-${bb.w}-${bb.h}`;
|
||||||
|
if (generationAreas.has(areaid)) return;
|
||||||
|
generationAreas.add(areaid);
|
||||||
|
|
||||||
|
// Await for queue
|
||||||
|
const waitQueue = async () => {
|
||||||
|
const stopQueueMarchingAnts = march(bb, {style: "#AAF"});
|
||||||
|
|
||||||
|
let qPromise = null;
|
||||||
|
let qResolve = null;
|
||||||
|
await new Promise((finish) => {
|
||||||
|
// Will be this request's (kind of) semaphore
|
||||||
|
qPromise = new Promise((r) => (qResolve = r));
|
||||||
|
generationQueue.push(qPromise);
|
||||||
|
|
||||||
|
// Wait for last generation to end
|
||||||
|
if (generationQueue.length > 1) {
|
||||||
|
(async () => {
|
||||||
|
await generationQueue[generationQueue.length - 2];
|
||||||
|
finish();
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
// If this is the first, just continue
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stopQueueMarchingAnts();
|
||||||
|
|
||||||
|
return {promise: qPromise, resolve: qResolve};
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextQueue = (queueEntry) => {
|
||||||
|
const generationIndex = generationQueue.findIndex(
|
||||||
|
(v) => v === queueEntry.promise
|
||||||
|
);
|
||||||
|
generationQueue.splice(generationIndex, 1);
|
||||||
|
queueEntry.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialQ = await waitQueue();
|
||||||
|
|
||||||
// Images to select through
|
// Images to select through
|
||||||
let at = 0;
|
let at = 0;
|
||||||
|
@ -253,6 +298,7 @@ const _generate = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeMore = async () => {
|
const makeMore = async () => {
|
||||||
|
const moreQ = await waitQueue();
|
||||||
try {
|
try {
|
||||||
stopProgress = _monitorProgress(bb);
|
stopProgress = _monitorProgress(bb);
|
||||||
interruptButton.disabled = false;
|
interruptButton.disabled = false;
|
||||||
|
@ -269,6 +315,8 @@ const _generate = async (
|
||||||
stopProgress();
|
stopProgress();
|
||||||
imageCollection.inputElement.removeChild(interruptButton);
|
imageCollection.inputElement.removeChild(interruptButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextQueue(moreQ);
|
||||||
};
|
};
|
||||||
|
|
||||||
const discardImg = async () => {
|
const discardImg = async () => {
|
||||||
|
@ -342,8 +390,9 @@ const _generate = async (
|
||||||
stopMarchingAnts();
|
stopMarchingAnts();
|
||||||
imageCollection.inputElement.removeChild(imageSelectMenu);
|
imageCollection.inputElement.removeChild(imageSelectMenu);
|
||||||
imageCollection.deleteLayer(layer);
|
imageCollection.deleteLayer(layer);
|
||||||
blockNewImages = false;
|
|
||||||
keyboard.listen.onkeyclick.clear(onarrow);
|
keyboard.listen.onkeyclick.clear(onarrow);
|
||||||
|
// Remove area from no-generate list
|
||||||
|
generationAreas.delete(areaid);
|
||||||
};
|
};
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
|
@ -414,6 +463,8 @@ const _generate = async (
|
||||||
saveImg();
|
saveImg();
|
||||||
});
|
});
|
||||||
imageSelectMenu.appendChild(savebtn);
|
imageSelectMenu.appendChild(savebtn);
|
||||||
|
|
||||||
|
nextQueue(initialQ);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -423,46 +474,75 @@ const _generate = async (
|
||||||
* @param {*} state
|
* @param {*} state
|
||||||
*/
|
*/
|
||||||
const dream_generate_callback = async (evn, state) => {
|
const dream_generate_callback = async (evn, state) => {
|
||||||
if (!blockNewImages) {
|
const bb = getBoundingBox(
|
||||||
const bb = getBoundingBox(
|
evn.x,
|
||||||
evn.x,
|
evn.y,
|
||||||
evn.y,
|
state.cursorSize,
|
||||||
state.cursorSize,
|
state.cursorSize,
|
||||||
state.cursorSize,
|
state.snapToGrid && basePixelCount
|
||||||
state.snapToGrid && basePixelCount
|
);
|
||||||
|
|
||||||
|
// Build request to the API
|
||||||
|
const request = {};
|
||||||
|
Object.assign(request, stableDiffusionData);
|
||||||
|
|
||||||
|
// Load prompt (maybe we should add some events so we don't have to do this)
|
||||||
|
request.prompt = document.getElementById("prompt").value;
|
||||||
|
request.negative_prompt = document.getElementById("negPrompt").value;
|
||||||
|
|
||||||
|
// Get visible pixels
|
||||||
|
const visibleCanvas = uil.getVisible(bb);
|
||||||
|
|
||||||
|
// Use txt2img if canvas is blank
|
||||||
|
if (isCanvasBlank(0, 0, bb.w, bb.h, visibleCanvas)) {
|
||||||
|
// Dream
|
||||||
|
_generate("txt2img", request, bb);
|
||||||
|
} else {
|
||||||
|
// Use img2img if not
|
||||||
|
|
||||||
|
// Temporary canvas for init image and mask generation
|
||||||
|
const auxCanvas = document.createElement("canvas");
|
||||||
|
auxCanvas.width = request.width;
|
||||||
|
auxCanvas.height = request.height;
|
||||||
|
const auxCtx = auxCanvas.getContext("2d");
|
||||||
|
|
||||||
|
auxCtx.fillStyle = "#000F";
|
||||||
|
|
||||||
|
// Get init image
|
||||||
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
auxCtx.drawImage(
|
||||||
|
visibleCanvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
request.width,
|
||||||
|
request.height
|
||||||
);
|
);
|
||||||
|
request.init_images = [auxCanvas.toDataURL()];
|
||||||
|
|
||||||
// Build request to the API
|
// Get mask image
|
||||||
const request = {};
|
auxCtx.fillStyle = "#000F";
|
||||||
Object.assign(request, stableDiffusionData);
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
if (state.invertMask) {
|
||||||
|
// overmasking by definition is entirely pointless with an inverted mask outpaint
|
||||||
|
// since it should explicitly avoid brushed masks too, we just won't even bother
|
||||||
|
auxCtx.globalCompositeOperation = "destination-in";
|
||||||
|
auxCtx.drawImage(
|
||||||
|
maskPaintCanvas,
|
||||||
|
bb.x,
|
||||||
|
bb.y,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
request.width,
|
||||||
|
request.height
|
||||||
|
);
|
||||||
|
|
||||||
// Load prompt (maybe we should add some events so we don't have to do this)
|
auxCtx.globalCompositeOperation = "destination-in";
|
||||||
request.prompt = document.getElementById("prompt").value;
|
|
||||||
request.negative_prompt = document.getElementById("negPrompt").value;
|
|
||||||
|
|
||||||
// Don't allow another image until is finished
|
|
||||||
blockNewImages = true;
|
|
||||||
|
|
||||||
// Get visible pixels
|
|
||||||
const visibleCanvas = uil.getVisible(bb);
|
|
||||||
|
|
||||||
// Use txt2img if canvas is blank
|
|
||||||
if (isCanvasBlank(0, 0, bb.w, bb.h, visibleCanvas)) {
|
|
||||||
// Dream
|
|
||||||
_generate("txt2img", request, bb);
|
|
||||||
} else {
|
|
||||||
// Use img2img if not
|
|
||||||
|
|
||||||
// Temporary canvas for init image and mask generation
|
|
||||||
const auxCanvas = document.createElement("canvas");
|
|
||||||
auxCanvas.width = request.width;
|
|
||||||
auxCanvas.height = request.height;
|
|
||||||
const auxCtx = auxCanvas.getContext("2d");
|
|
||||||
|
|
||||||
auxCtx.fillStyle = "#000F";
|
|
||||||
|
|
||||||
// Get init image
|
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
|
||||||
auxCtx.drawImage(
|
auxCtx.drawImage(
|
||||||
visibleCanvas,
|
visibleCanvas,
|
||||||
0,
|
0,
|
||||||
|
@ -474,82 +554,48 @@ const dream_generate_callback = async (evn, state) => {
|
||||||
request.width,
|
request.width,
|
||||||
request.height
|
request.height
|
||||||
);
|
);
|
||||||
request.init_images = [auxCanvas.toDataURL()];
|
} else {
|
||||||
|
auxCtx.globalCompositeOperation = "destination-in";
|
||||||
// Get mask image
|
auxCtx.drawImage(
|
||||||
auxCtx.fillStyle = "#000F";
|
visibleCanvas,
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
0,
|
||||||
if (state.invertMask) {
|
0,
|
||||||
// overmasking by definition is entirely pointless with an inverted mask outpaint
|
bb.w,
|
||||||
// since it should explicitly avoid brushed masks too, we just won't even bother
|
bb.h,
|
||||||
auxCtx.globalCompositeOperation = "destination-in";
|
0,
|
||||||
auxCtx.drawImage(
|
0,
|
||||||
maskPaintCanvas,
|
request.width,
|
||||||
bb.x,
|
request.height
|
||||||
bb.y,
|
);
|
||||||
bb.w,
|
// here's where to overmask to avoid including the brushed mask
|
||||||
bb.h,
|
// 99% of my issues were from failing to set source-over for the overmask blotches
|
||||||
0,
|
if (state.overMaskPx > 0) {
|
||||||
0,
|
// transparent to white first
|
||||||
request.width,
|
auxCtx.globalCompositeOperation = "destination-atop";
|
||||||
request.height
|
auxCtx.fillStyle = "#FFFF";
|
||||||
);
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
applyOvermask(auxCanvas, auxCtx, state.overMaskPx);
|
||||||
auxCtx.globalCompositeOperation = "destination-in";
|
|
||||||
auxCtx.drawImage(
|
|
||||||
visibleCanvas,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
bb.w,
|
|
||||||
bb.h,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.width,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
auxCtx.globalCompositeOperation = "destination-in";
|
|
||||||
auxCtx.drawImage(
|
|
||||||
visibleCanvas,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
bb.w,
|
|
||||||
bb.h,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.width,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
// here's where to overmask to avoid including the brushed mask
|
|
||||||
// 99% of my issues were from failing to set source-over for the overmask blotches
|
|
||||||
if (state.overMaskPx > 0) {
|
|
||||||
// transparent to white first
|
|
||||||
auxCtx.globalCompositeOperation = "destination-atop";
|
|
||||||
auxCtx.fillStyle = "#FFFF";
|
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
|
||||||
applyOvermask(auxCanvas, auxCtx, state.overMaskPx);
|
|
||||||
}
|
|
||||||
|
|
||||||
auxCtx.globalCompositeOperation = "destination-out"; // ???
|
|
||||||
auxCtx.drawImage(
|
|
||||||
maskPaintCanvas,
|
|
||||||
bb.x,
|
|
||||||
bb.y,
|
|
||||||
bb.w,
|
|
||||||
bb.h,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.width,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
auxCtx.globalCompositeOperation = "destination-atop";
|
|
||||||
auxCtx.fillStyle = "#FFFF";
|
auxCtx.globalCompositeOperation = "destination-out"; // ???
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
auxCtx.drawImage(
|
||||||
request.mask = auxCanvas.toDataURL();
|
maskPaintCanvas,
|
||||||
// Dream
|
bb.x,
|
||||||
_generate("img2img", request, bb);
|
bb.y,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
request.width,
|
||||||
|
request.height
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
auxCtx.globalCompositeOperation = "destination-atop";
|
||||||
|
auxCtx.fillStyle = "#FFFF";
|
||||||
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
request.mask = auxCanvas.toDataURL();
|
||||||
|
// Dream
|
||||||
|
_generate("img2img", request, bb);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const dream_erase_callback = (evn, state) => {
|
const dream_erase_callback = (evn, state) => {
|
||||||
|
@ -606,140 +652,135 @@ function applyOvermask(canvas, ctx, px) {
|
||||||
* Image to Image
|
* Image to Image
|
||||||
*/
|
*/
|
||||||
const dream_img2img_callback = (evn, state) => {
|
const dream_img2img_callback = (evn, state) => {
|
||||||
if (!blockNewImages) {
|
const bb = getBoundingBox(
|
||||||
const bb = getBoundingBox(
|
evn.x,
|
||||||
evn.x,
|
evn.y,
|
||||||
evn.y,
|
state.cursorSize,
|
||||||
state.cursorSize,
|
state.cursorSize,
|
||||||
state.cursorSize,
|
state.snapToGrid && basePixelCount
|
||||||
state.snapToGrid && basePixelCount
|
);
|
||||||
);
|
|
||||||
|
|
||||||
// Get visible pixels
|
// Get visible pixels
|
||||||
const visibleCanvas = uil.getVisible(bb);
|
const visibleCanvas = uil.getVisible(bb);
|
||||||
|
|
||||||
// Do nothing if no image exists
|
// Do nothing if no image exists
|
||||||
if (isCanvasBlank(0, 0, bb.w, bb.h, visibleCanvas)) return;
|
if (isCanvasBlank(0, 0, bb.w, bb.h, visibleCanvas)) return;
|
||||||
|
|
||||||
// Build request to the API
|
// Build request to the API
|
||||||
const request = {};
|
const request = {};
|
||||||
Object.assign(request, stableDiffusionData);
|
Object.assign(request, stableDiffusionData);
|
||||||
|
|
||||||
request.denoising_strength = state.denoisingStrength;
|
request.denoising_strength = state.denoisingStrength;
|
||||||
request.inpainting_fill = 1; // For img2img use original
|
request.inpainting_fill = 1; // For img2img use original
|
||||||
|
|
||||||
// Load prompt (maybe we should add some events so we don't have to do this)
|
// Load prompt (maybe we should add some events so we don't have to do this)
|
||||||
request.prompt = document.getElementById("prompt").value;
|
request.prompt = document.getElementById("prompt").value;
|
||||||
request.negative_prompt = document.getElementById("negPrompt").value;
|
request.negative_prompt = document.getElementById("negPrompt").value;
|
||||||
|
|
||||||
// Don't allow another image until is finished
|
// Use img2img
|
||||||
blockNewImages = true;
|
|
||||||
|
|
||||||
// Use img2img
|
// Temporary canvas for init image and mask generation
|
||||||
|
const auxCanvas = document.createElement("canvas");
|
||||||
|
auxCanvas.width = request.width;
|
||||||
|
auxCanvas.height = request.height;
|
||||||
|
const auxCtx = auxCanvas.getContext("2d");
|
||||||
|
|
||||||
// Temporary canvas for init image and mask generation
|
auxCtx.fillStyle = "#000F";
|
||||||
const auxCanvas = document.createElement("canvas");
|
|
||||||
auxCanvas.width = request.width;
|
|
||||||
auxCanvas.height = request.height;
|
|
||||||
const auxCtx = auxCanvas.getContext("2d");
|
|
||||||
|
|
||||||
|
// Get init image
|
||||||
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
auxCtx.drawImage(
|
||||||
|
visibleCanvas,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
request.width,
|
||||||
|
request.height
|
||||||
|
);
|
||||||
|
request.init_images = [auxCanvas.toDataURL()];
|
||||||
|
|
||||||
|
// Get mask image
|
||||||
|
auxCtx.fillStyle = state.invertMask ? "#FFFF" : "#000F";
|
||||||
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
auxCtx.globalCompositeOperation = "destination-out";
|
||||||
|
auxCtx.drawImage(
|
||||||
|
maskPaintCanvas,
|
||||||
|
bb.x,
|
||||||
|
bb.y,
|
||||||
|
bb.w,
|
||||||
|
bb.h,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
request.width,
|
||||||
|
request.height
|
||||||
|
);
|
||||||
|
|
||||||
|
auxCtx.globalCompositeOperation = "destination-atop";
|
||||||
|
auxCtx.fillStyle = state.invertMask ? "#000F" : "#FFFF";
|
||||||
|
auxCtx.fillRect(0, 0, request.width, request.height);
|
||||||
|
|
||||||
|
// Border Mask
|
||||||
|
if (state.keepBorderSize > 0) {
|
||||||
|
auxCtx.globalCompositeOperation = "source-over";
|
||||||
auxCtx.fillStyle = "#000F";
|
auxCtx.fillStyle = "#000F";
|
||||||
|
if (state.gradient) {
|
||||||
// Get init image
|
const lg = auxCtx.createLinearGradient(0, 0, state.keepBorderSize, 0);
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
lg.addColorStop(0, "#000F");
|
||||||
auxCtx.drawImage(
|
lg.addColorStop(1, "#0000");
|
||||||
visibleCanvas,
|
auxCtx.fillStyle = lg;
|
||||||
0,
|
|
||||||
0,
|
|
||||||
bb.w,
|
|
||||||
bb.h,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.width,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
request.init_images = [auxCanvas.toDataURL()];
|
|
||||||
|
|
||||||
// Get mask image
|
|
||||||
auxCtx.fillStyle = state.invertMask ? "#FFFF" : "#000F";
|
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
|
||||||
auxCtx.globalCompositeOperation = "destination-out";
|
|
||||||
auxCtx.drawImage(
|
|
||||||
maskPaintCanvas,
|
|
||||||
bb.x,
|
|
||||||
bb.y,
|
|
||||||
bb.w,
|
|
||||||
bb.h,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.width,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
|
|
||||||
auxCtx.globalCompositeOperation = "destination-atop";
|
|
||||||
auxCtx.fillStyle = state.invertMask ? "#000F" : "#FFFF";
|
|
||||||
auxCtx.fillRect(0, 0, request.width, request.height);
|
|
||||||
|
|
||||||
// Border Mask
|
|
||||||
if (state.keepBorderSize > 0) {
|
|
||||||
auxCtx.globalCompositeOperation = "source-over";
|
|
||||||
auxCtx.fillStyle = "#000F";
|
|
||||||
if (state.gradient) {
|
|
||||||
const lg = auxCtx.createLinearGradient(0, 0, state.keepBorderSize, 0);
|
|
||||||
lg.addColorStop(0, "#000F");
|
|
||||||
lg.addColorStop(1, "#0000");
|
|
||||||
auxCtx.fillStyle = lg;
|
|
||||||
}
|
|
||||||
auxCtx.fillRect(0, 0, state.keepBorderSize, request.height);
|
|
||||||
if (state.gradient) {
|
|
||||||
const tg = auxCtx.createLinearGradient(0, 0, 0, state.keepBorderSize);
|
|
||||||
tg.addColorStop(0, "#000F");
|
|
||||||
tg.addColorStop(1, "#0000");
|
|
||||||
auxCtx.fillStyle = tg;
|
|
||||||
}
|
|
||||||
auxCtx.fillRect(0, 0, request.width, state.keepBorderSize);
|
|
||||||
if (state.gradient) {
|
|
||||||
const rg = auxCtx.createLinearGradient(
|
|
||||||
request.width,
|
|
||||||
0,
|
|
||||||
request.width - state.keepBorderSize,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
rg.addColorStop(0, "#000F");
|
|
||||||
rg.addColorStop(1, "#0000");
|
|
||||||
auxCtx.fillStyle = rg;
|
|
||||||
}
|
|
||||||
auxCtx.fillRect(
|
|
||||||
request.width - state.keepBorderSize,
|
|
||||||
0,
|
|
||||||
state.keepBorderSize,
|
|
||||||
request.height
|
|
||||||
);
|
|
||||||
if (state.gradient) {
|
|
||||||
const bg = auxCtx.createLinearGradient(
|
|
||||||
0,
|
|
||||||
request.height,
|
|
||||||
0,
|
|
||||||
request.height - state.keepBorderSize
|
|
||||||
);
|
|
||||||
bg.addColorStop(0, "#000F");
|
|
||||||
bg.addColorStop(1, "#0000");
|
|
||||||
auxCtx.fillStyle = bg;
|
|
||||||
}
|
|
||||||
auxCtx.fillRect(
|
|
||||||
0,
|
|
||||||
request.height - state.keepBorderSize,
|
|
||||||
request.width,
|
|
||||||
state.keepBorderSize
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
auxCtx.fillRect(0, 0, state.keepBorderSize, request.height);
|
||||||
request.mask = auxCanvas.toDataURL();
|
if (state.gradient) {
|
||||||
request.inpaint_full_res = state.fullResolution;
|
const tg = auxCtx.createLinearGradient(0, 0, 0, state.keepBorderSize);
|
||||||
|
tg.addColorStop(0, "#000F");
|
||||||
// Dream
|
tg.addColorStop(1, "#0000");
|
||||||
_generate("img2img", request, bb);
|
auxCtx.fillStyle = tg;
|
||||||
|
}
|
||||||
|
auxCtx.fillRect(0, 0, request.width, state.keepBorderSize);
|
||||||
|
if (state.gradient) {
|
||||||
|
const rg = auxCtx.createLinearGradient(
|
||||||
|
request.width,
|
||||||
|
0,
|
||||||
|
request.width - state.keepBorderSize,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
rg.addColorStop(0, "#000F");
|
||||||
|
rg.addColorStop(1, "#0000");
|
||||||
|
auxCtx.fillStyle = rg;
|
||||||
|
}
|
||||||
|
auxCtx.fillRect(
|
||||||
|
request.width - state.keepBorderSize,
|
||||||
|
0,
|
||||||
|
state.keepBorderSize,
|
||||||
|
request.height
|
||||||
|
);
|
||||||
|
if (state.gradient) {
|
||||||
|
const bg = auxCtx.createLinearGradient(
|
||||||
|
0,
|
||||||
|
request.height,
|
||||||
|
0,
|
||||||
|
request.height - state.keepBorderSize
|
||||||
|
);
|
||||||
|
bg.addColorStop(0, "#000F");
|
||||||
|
bg.addColorStop(1, "#0000");
|
||||||
|
auxCtx.fillStyle = bg;
|
||||||
|
}
|
||||||
|
auxCtx.fillRect(
|
||||||
|
0,
|
||||||
|
request.height - state.keepBorderSize,
|
||||||
|
request.width,
|
||||||
|
state.keepBorderSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.mask = auxCanvas.toDataURL();
|
||||||
|
request.inpaint_full_res = state.fullResolution;
|
||||||
|
|
||||||
|
// Dream
|
||||||
|
_generate("img2img", request, bb);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -181,6 +181,7 @@ const stampTool = () =>
|
||||||
saveButton.addEventListener(
|
saveButton.addEventListener(
|
||||||
"click",
|
"click",
|
||||||
(evn) => {
|
(evn) => {
|
||||||
|
evn.stopPropagation();
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.width = resource.image.width;
|
canvas.width = resource.image.width;
|
||||||
canvas.height = resource.image.height;
|
canvas.height = resource.image.height;
|
||||||
|
|
Loading…
Reference in a new issue