Fixes save to gallery including empty area, adds download and copy image

This commit is contained in:
psychedelicious 2022-11-18 13:35:03 +11:00 committed by blessedcoolant
parent 635e7da05d
commit 19322fc1ec
6 changed files with 106 additions and 35 deletions

View File

@ -165,20 +165,16 @@ class InvokeAIWebServer:
pil_image = Image.open(file_path)
# visible_image_bbox = pil_image.getbbox()
# pil_image = pil_image.crop(visible_image_bbox)
# pil_image.save(file_path)
# if "cropVisible" in data and data["cropVisible"] == True:
# visible_image_bbox = pil_image.getbbox()
# pil_image = pil_image.crop(visible_image_bbox)
# pil_image.save(file_path)
if "cropVisible" in data and data["cropVisible"] == True:
visible_image_bbox = pil_image.getbbox()
pil_image = pil_image.crop(visible_image_bbox)
pil_image.save(file_path)
(width, height) = pil_image.size
response = {
"url": self.get_url_from_image_path(file_path),
"mtime": mtime,
# "bbox": visible_image_bbox,
"width": width,
"height": height,
}
@ -607,6 +603,12 @@ class InvokeAIWebServer:
actual_generation_mode = generation_parameters["generation_mode"]
original_bounding_box = None
progress = Progress(generation_parameters=generation_parameters)
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
eventlet.sleep(0)
"""
TODO:
If a result image is used as an init image, and then deleted, we will want to be
@ -658,8 +660,6 @@ class InvokeAIWebServer:
initial_image, mask_image
)
print(initial_image, mask_image)
"""
Apply the mask to the init image, creating a "mask" image with
transparency where inpainting should occur. This is the kind of
@ -708,11 +708,6 @@ class InvokeAIWebServer:
init_img_path = self.get_image_path_from_url(init_img_url)
generation_parameters["init_img"] = init_img_path
progress = Progress(generation_parameters=generation_parameters)
self.socketio.emit("progressUpdate", progress.to_formatted_dict())
eventlet.sleep(0)
def image_progress(sample, step):
if self.canceled.is_set():
raise CanceledException
@ -967,6 +962,8 @@ class InvokeAIWebServer:
eventlet.sleep(0)
progress.set_current_iteration(progress.current_iteration + 1)
print(generation_parameters)
self.generate.prompt2image(
**generation_parameters,

View File

@ -78,7 +78,6 @@ const IAICanvasOutpaintingControls = () => {
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
saveToGallery: false,
})
);
}}
@ -89,7 +88,11 @@ const IAICanvasOutpaintingControls = () => {
icon={<FaSave />}
onClick={() => {
dispatch(
mergeAndUploadCanvas({ canvasImageLayerRef, saveToGallery: true })
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
saveToGallery: true,
})
);
}}
/>
@ -97,11 +100,29 @@ const IAICanvasOutpaintingControls = () => {
aria-label="Copy Selection"
tooltip="Copy Selection"
icon={<FaCopy />}
onClick={() => {
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
copyAfterSaving: true,
})
);
}}
/>
<IAIIconButton
aria-label="Download Selection"
tooltip="Download Selection"
icon={<FaDownload />}
onClick={() => {
dispatch(
mergeAndUploadCanvas({
canvasImageLayerRef,
cropVisible: true,
downloadAfterSaving: true,
})
);
}}
/>
</ButtonGroup>
<ButtonGroup isAttached>

View File

@ -0,0 +1,34 @@
/**
* Copies an image to the clipboard by drawing it to a canvas and then
* calling toBlob() on the canvas.
*/
const copyImage = (url: string, width: number, height: number) => {
const imageElement = document.createElement('img');
imageElement.addEventListener('load', () => {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
if (!context) return;
context.drawImage(imageElement, 0, 0);
canvas.toBlob((blob) => {
blob &&
navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
});
canvas.remove();
imageElement.remove();
});
imageElement.src = url;
};
export default copyImage;

View File

@ -0,0 +1,14 @@
/**
* Downloads a file, given its URL.
*/
const downloadFile = (url: string) => {
const a = document.createElement('a');
a.href = url;
a.download = '';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
a.remove();
};
export default downloadFile;

View File

@ -5,17 +5,28 @@ import { MutableRefObject } from 'react';
import * as InvokeAI from 'app/invokeai';
import { v4 as uuidv4 } from 'uuid';
import layerToDataURL from './layerToDataURL';
import downloadFile from './downloadFile';
import copyImage from './copyImage';
export const mergeAndUploadCanvas = createAsyncThunk(
'canvas/mergeAndUploadCanvas',
async (
args: {
canvasImageLayerRef: MutableRefObject<Konva.Layer | null>;
saveToGallery: boolean;
cropVisible?: boolean;
saveToGallery?: boolean;
downloadAfterSaving?: boolean;
copyAfterSaving?: boolean;
},
thunkAPI
) => {
const { canvasImageLayerRef, saveToGallery } = args;
const {
canvasImageLayerRef,
saveToGallery,
downloadAfterSaving,
cropVisible,
copyAfterSaving,
} = args;
const { getState } = thunkAPI;
@ -40,7 +51,7 @@ export const mergeAndUploadCanvas = createAsyncThunk(
dataURL,
filename: 'merged_canvas.png',
kind: saveToGallery ? 'result' : 'temp',
cropVisible: saveToGallery,
cropVisible,
})
);
@ -52,12 +63,15 @@ export const mergeAndUploadCanvas = createAsyncThunk(
const { url, mtime, width, height } =
(await response.json()) as InvokeAI.ImageUploadResponse;
// const newBoundingBox = {
// x: bbox[0],
// y: bbox[1],
// width: bbox[2],
// height: bbox[3],
// };
if (downloadAfterSaving) {
downloadFile(url);
return;
}
if (copyAfterSaving) {
copyImage(url, width, height);
return;
}
const newImage: InvokeAI.Image = {
uuid: uuidv4(),
@ -72,7 +86,6 @@ export const mergeAndUploadCanvas = createAsyncThunk(
image: newImage,
kind: saveToGallery ? 'merged_canvas' : 'temp_merged_canvas',
originalBoundingBox,
// newBoundingBox,
};
}
);

View File

@ -29,7 +29,6 @@ export const uploadImage = createAsyncThunk(
kind: 'init',
})
);
// formData.append('kind', 'init');
const response = await fetch(window.location.origin + '/upload', {
method: 'POST',
@ -39,13 +38,6 @@ export const uploadImage = createAsyncThunk(
const { url, mtime, width, height } =
(await response.json()) as InvokeAI.ImageUploadResponse;
// const newBoundingBox = {
// x: bbox[0],
// y: bbox[1],
// width: bbox[2],
// height: bbox[3],
// };
const newImage: InvokeAI.Image = {
uuid: uuidv4(),
url,