Fixes: outpainting temp images show in gallery

This commit is contained in:
psychedelicious 2022-11-15 12:25:12 +11:00 committed by blessedcoolant
parent 4382cd0b91
commit c0ad1b3469
7 changed files with 96 additions and 67 deletions

View File

@ -10,7 +10,7 @@ import base64
import os import os
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from flask import Flask, redirect, send_from_directory, flash, request, url_for, jsonify from flask import Flask, redirect, send_from_directory, request, make_response
from flask_socketio import SocketIO from flask_socketio import SocketIO
from PIL import Image, ImageOps from PIL import Image, ImageOps
from PIL.Image import Image as ImageType from PIL.Image import Image as ImageType
@ -107,15 +107,22 @@ class InvokeAIWebServer:
@self.app.route("/upload", methods=["POST"]) @self.app.route("/upload", methods=["POST"])
def upload(): def upload():
try: try:
filename = ""
# check if the post request has the file part # check if the post request has the file part
if "file" not in request.files: if "file" in request.files:
return "No file part", 400 file = request.files["file"]
file = request.files["file"] # If the user does not select a file, the browser submits an
# empty file without a filename.
# If the user does not select a file, the browser submits an if file.filename == "":
# empty file without a filename. return make_response("No file selected", 400)
if file.filename == "": filename = file.filename
return "No selected file", 400 elif "dataURL" in request.form:
file = dataURL_to_bytes(request.form["dataURL"])
if "filename" not in request.form or request.form["filename"] == "":
return make_response("No filename provided", 400)
filename = request.form["filename"]
else:
return make_response("No file or dataURL", 400)
kind = request.form["kind"] kind = request.form["kind"]
@ -128,15 +135,15 @@ class InvokeAIWebServer:
elif kind == "mask": elif kind == "mask":
path = self.mask_image_path path = self.mask_image_path
else: else:
return f"Invalid upload kind: {kind}", 400 return make_response(f"Invalid upload kind: {kind}", 400)
if not self.allowed_file(file.filename): if not self.allowed_file(filename):
return ( return make_response(
f'Invalid file type, must be one of: {", ".join(self.ALLOWED_EXTENSIONS)}', f'Invalid file type, must be one of: {", ".join(self.ALLOWED_EXTENSIONS)}',
400, 400,
) )
secured_filename = secure_filename(file.filename) secured_filename = secure_filename(filename)
uuid = uuid4().hex uuid = uuid4().hex
truncated_uuid = uuid[:8] truncated_uuid = uuid[:8]
@ -146,7 +153,11 @@ class InvokeAIWebServer:
file_path = os.path.join(path, name) file_path = os.path.join(path, name)
file.save(file_path) if "dataURL" in request.form:
with open(file_path, "wb") as f:
f.write(file)
else:
file.save(file_path)
mtime = os.path.getmtime(file_path) mtime = os.path.getmtime(file_path)
(width, height) = Image.open(file_path).size (width, height) = Image.open(file_path).size
@ -160,7 +171,7 @@ class InvokeAIWebServer:
}, },
} }
return response, 200 return make_response(response, 200)
except Exception as e: except Exception as e:
self.socketio.emit("error", {"message": (str(e))}) self.socketio.emit("error", {"message": (str(e))})
@ -168,7 +179,7 @@ class InvokeAIWebServer:
traceback.print_exc() traceback.print_exc()
print("\n") print("\n")
return "Error uploading file", 500 return make_response("Error uploading file", 500)
self.load_socketio_listeners(self.socketio) self.load_socketio_listeners(self.socketio)
@ -916,11 +927,18 @@ class InvokeAIWebServer:
(width, height) = image.size (width, height) = image.size
generated_image_outdir = (
self.result_path
if generation_parameters["generation_mode"]
in ["txt2img", "img2img"]
else self.temp_image_path
)
path = self.save_result_image( path = self.save_result_image(
image, image,
command, command,
metadata, metadata,
self.result_path, generated_image_outdir,
postprocessing=postprocessing, postprocessing=postprocessing,
) )

View File

@ -26,8 +26,8 @@ export const requestNewImages = createAction<GalleryCategory>(
export const cancelProcessing = createAction<undefined>( export const cancelProcessing = createAction<undefined>(
'socketio/cancelProcessing' 'socketio/cancelProcessing'
); );
export const uploadImage = createAction<InvokeAI.UploadImagePayload>('socketio/uploadImage'); // export const uploadImage = createAction<InvokeAI.UploadImagePayload>('socketio/uploadImage');
export const uploadMaskImage = createAction<File>('socketio/uploadMaskImage'); // export const uploadMaskImage = createAction<File>('socketio/uploadMaskImage');
export const requestSystemConfig = createAction<undefined>( export const requestSystemConfig = createAction<undefined>(
'socketio/requestSystemConfig' 'socketio/requestSystemConfig'

View File

@ -180,13 +180,13 @@ const makeSocketIOEmitters = (
emitCancelProcessing: () => { emitCancelProcessing: () => {
socketio.emit('cancel'); socketio.emit('cancel');
}, },
emitUploadImage: (payload: InvokeAI.UploadImagePayload) => { // emitUploadImage: (payload: InvokeAI.UploadImagePayload) => {
const { file, destination } = payload; // const { file, destination } = payload;
socketio.emit('uploadImage', file, file.name, destination); // socketio.emit('uploadImage', file, file.name, destination);
}, // },
emitUploadMaskImage: (file: File) => { // emitUploadMaskImage: (file: File) => {
socketio.emit('uploadMaskImage', file, file.name); // socketio.emit('uploadMaskImage', file, file.name);
}, // },
emitRequestSystemConfig: () => { emitRequestSystemConfig: () => {
socketio.emit('requestSystemConfig'); socketio.emit('requestSystemConfig');
}, },

View File

@ -103,20 +103,28 @@ const makeSocketIOListeners = (
onGenerationResult: (data: InvokeAI.ImageResultResponse) => { onGenerationResult: (data: InvokeAI.ImageResultResponse) => {
try { try {
const { shouldLoopback, activeTab } = getState().options; const { shouldLoopback, activeTab } = getState().options;
const { boundingBox: _, generationMode, ...rest } = data;
const newImage = { const newImage = {
uuid: uuidv4(), uuid: uuidv4(),
...data, ...rest,
category: 'result',
}; };
dispatch( if (['txt2img', 'img2img'].includes(generationMode)) {
addImage({ newImage.category = 'result';
category: 'result', dispatch(
image: newImage, addImage({
}) category: 'result',
); image: newImage,
})
);
}
if (data.generationMode === 'outpainting' && data.boundingBox) { if (
['inpainting', 'outpainting'].includes(generationMode) &&
data.boundingBox
) {
newImage.category = 'temp';
const { boundingBox } = data; const { boundingBox } = data;
dispatch( dispatch(
addImageToOutpainting({ addImageToOutpainting({
@ -140,6 +148,8 @@ const makeSocketIOListeners = (
} }
} }
dispatch(clearIntermediateImage());
dispatch( dispatch(
addLogEntry({ addLogEntry({
timestamp: dateFormat(new Date(), 'isoDateTime'), timestamp: dateFormat(new Date(), 'isoDateTime'),
@ -368,16 +378,16 @@ const makeSocketIOListeners = (
/** /**
* Callback to run when we receive a 'maskImageUploaded' event. * Callback to run when we receive a 'maskImageUploaded' event.
*/ */
onMaskImageUploaded: (data: InvokeAI.ImageUrlResponse) => { // onMaskImageUploaded: (data: InvokeAI.ImageUrlResponse) => {
const { url } = data; // const { url } = data;
dispatch(setMaskPath(url)); // dispatch(setMaskPath(url));
dispatch( // dispatch(
addLogEntry({ // addLogEntry({
timestamp: dateFormat(new Date(), 'isoDateTime'), // timestamp: dateFormat(new Date(), 'isoDateTime'),
message: `Mask image uploaded: ${url}`, // message: `Mask image uploaded: ${url}`,
}) // })
); // );
}, // },
onSystemConfig: (data: InvokeAI.SystemConfig) => { onSystemConfig: (data: InvokeAI.SystemConfig) => {
dispatch(setSystemConfig(data)); dispatch(setSystemConfig(data));
}, },

View File

@ -44,7 +44,7 @@ export const socketioMiddleware = () => {
onProcessingCanceled, onProcessingCanceled,
onImageDeleted, onImageDeleted,
// onImageUploaded, // onImageUploaded,
onMaskImageUploaded, // onMaskImageUploaded,
onSystemConfig, onSystemConfig,
onModelChanged, onModelChanged,
onModelChangeFailed, onModelChangeFailed,
@ -58,8 +58,8 @@ export const socketioMiddleware = () => {
emitRequestImages, emitRequestImages,
emitRequestNewImages, emitRequestNewImages,
emitCancelProcessing, emitCancelProcessing,
emitUploadImage, // emitUploadImage,
emitUploadMaskImage, // emitUploadMaskImage,
emitRequestSystemConfig, emitRequestSystemConfig,
emitRequestModelChange, emitRequestModelChange,
} = makeSocketIOEmitters(store, socketio); } = makeSocketIOEmitters(store, socketio);
@ -108,9 +108,9 @@ export const socketioMiddleware = () => {
// onImageUploaded(data); // onImageUploaded(data);
// }); // });
socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => { // socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => {
onMaskImageUploaded(data); // onMaskImageUploaded(data);
}); // });
socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => { socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => {
onSystemConfig(data); onSystemConfig(data);
@ -166,15 +166,15 @@ export const socketioMiddleware = () => {
break; break;
} }
case 'socketio/uploadImage': { // case 'socketio/uploadImage': {
emitUploadImage(action.payload); // emitUploadImage(action.payload);
break; // break;
} // }
case 'socketio/uploadMaskImage': { // case 'socketio/uploadMaskImage': {
emitUploadMaskImage(action.payload); // emitUploadMaskImage(action.payload);
break; // break;
} // }
case 'socketio/requestSystemConfig': { case 'socketio/requestSystemConfig': {
emitRequestSystemConfig(); emitRequestSystemConfig();

View File

@ -1,6 +1,6 @@
import Konva from 'konva'; import Konva from 'konva';
const layerToBlob = async (layer: Konva.Layer, stageScale: number) => { const layerToDataURL = (layer: Konva.Layer, stageScale: number) => {
const tempScale = layer.scale(); const tempScale = layer.scale();
const { x: relativeX, y: relativeY } = layer.getClientRect({ const { x: relativeX, y: relativeY } = layer.getClientRect({
@ -15,12 +15,12 @@ const layerToBlob = async (layer: Konva.Layer, stageScale: number) => {
const clientRect = layer.getClientRect(); const clientRect = layer.getClientRect();
const blob = await layer.toBlob(clientRect); const dataURL = layer.toDataURL(clientRect);
// Unscale the canvas // Unscale the canvas
layer.scale(tempScale); layer.scale(tempScale);
return { blob, relativeX, relativeY }; return { dataURL, relativeX, relativeY };
}; };
export default layerToBlob; export default layerToDataURL;

View File

@ -4,7 +4,7 @@ import Konva from 'konva';
import { MutableRefObject } from 'react'; import { MutableRefObject } from 'react';
import * as InvokeAI from 'app/invokeai'; import * as InvokeAI from 'app/invokeai';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import layerToBlob from './layerToBlob'; import layerToDataURL from './layerToDataURL';
export const mergeAndUploadCanvas = createAsyncThunk( export const mergeAndUploadCanvas = createAsyncThunk(
'canvas/mergeAndUploadCanvas', 'canvas/mergeAndUploadCanvas',
@ -25,16 +25,17 @@ export const mergeAndUploadCanvas = createAsyncThunk(
if (!canvasImageLayerRef.current) return; if (!canvasImageLayerRef.current) return;
const { blob, relativeX, relativeY } = await layerToBlob( const { dataURL, relativeX, relativeY } = layerToDataURL(
canvasImageLayerRef.current, canvasImageLayerRef.current,
stageScale stageScale
); );
if (!blob) return; if (!dataURL) return;
const formData = new FormData(); const formData = new FormData();
formData.append('file', blob as Blob, 'merged_canvas.png'); formData.append('dataURL', dataURL);
formData.append('filename', 'merged_canvas.png');
formData.append('kind', saveToGallery ? 'result' : 'temp'); formData.append('kind', saveToGallery ? 'result' : 'temp');
const response = await fetch(window.location.origin + '/upload', { const response = await fetch(window.location.origin + '/upload', {