mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Fixes: outpainting temp images show in gallery
This commit is contained in:
parent
4382cd0b91
commit
c0ad1b3469
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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'
|
||||||
|
@ -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');
|
||||||
},
|
},
|
||||||
|
@ -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));
|
||||||
},
|
},
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
@ -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', {
|
||||||
|
Loading…
Reference in New Issue
Block a user