1
0
Fork 0

feat(api): embed image parameters in EXIF data (#383)

This commit is contained in:
Sean Sube 2023-06-26 07:03:06 -05:00
parent 9e58818ffb
commit 7e21b9539e
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
4 changed files with 81 additions and 24 deletions

View File

@ -14,7 +14,7 @@ def persist_disk(
_job: WorkerContext, _job: WorkerContext,
server: ServerContext, server: ServerContext,
_stage: StageParams, _stage: StageParams,
_params: ImageParams, params: ImageParams,
source: Image.Image, source: Image.Image,
*, *,
output: str, output: str,
@ -23,6 +23,6 @@ def persist_disk(
) -> Image.Image: ) -> Image.Image:
source = stage_source or source source = stage_source or source
dest = save_image(server, output, source) dest = save_image(server, output, source, params=params)
logger.info("saved image to %s", dest) logger.info("saved image to %s", dest)
return source return source

View File

@ -314,8 +314,7 @@ def run_txt2img_pipeline(
callback=progress, callback=progress,
) )
dest = save_image(server, output, image) dest = save_image(server, output, image, params, size, upscale=upscale, highres=highres)
save_params(server, output, params, size, upscale=upscale, highres=highres)
run_gc([job.get_device()]) run_gc([job.get_device()])
show_system_toast(f"finished txt2img job: {dest}") show_system_toast(f"finished txt2img job: {dest}")
@ -413,11 +412,12 @@ def run_img2img_pipeline(
loras, loras,
) )
size = Size(*source.size)
image = run_highres( image = run_highres(
job, job,
server, server,
params, params,
Size(source.width, source.height), size,
upscale, upscale,
highres, highres,
image, image,
@ -436,9 +436,7 @@ def run_img2img_pipeline(
callback=progress, callback=progress,
) )
dest = save_image(server, output, image) dest = save_image(server, output, image, params, size, upscale=upscale, highres=highres)
size = Size(*source.size)
save_params(server, output, params, size, upscale=upscale)
run_gc([job.get_device()]) run_gc([job.get_device()])
show_system_toast(f"finished img2img job: {dest}") show_system_toast(f"finished img2img job: {dest}")
@ -504,12 +502,11 @@ def run_inpaint_pipeline(
callback=progress, callback=progress,
) )
dest = save_image(server, outputs[0], image) dest = save_image(server, outputs[0], image, params, size, upscale=upscale, border=border)
save_params(server, outputs[0], params, size, upscale=upscale, border=border)
del image del image
run_gc([job.get_device()]) run_gc([job.get_device()])
show_system_toast(f"finished inpaint job: {dest}") show_system_toast(f"finished inpaint job: {dest}")
logger.info("finished inpaint job: %s", dest) logger.info("finished inpaint job: %s", dest)
@ -547,12 +544,11 @@ def run_upscale_pipeline(
loras, loras,
) )
dest = save_image(server, outputs[0], image) dest = save_image(server, outputs[0], image, params, size, upscale=upscale)
save_params(server, outputs[0], params, size, upscale=upscale)
del image del image
run_gc([job.get_device()]) run_gc([job.get_device()])
show_system_toast(f"finished upscale job: {dest}") show_system_toast(f"finished upscale job: {dest}")
logger.info("finished upscale job: %s", dest) logger.info("finished upscale job: %s", dest)
@ -586,11 +582,10 @@ def run_blend_pipeline(
job, server, stage, params, image, upscale=upscale, callback=progress job, server, stage, params, image, upscale=upscale, callback=progress
) )
dest = save_image(server, outputs[0], image) dest = save_image(server, outputs[0], image, params, size, upscale=upscale)
save_params(server, outputs[0], params, size, upscale=upscale)
del image del image
run_gc([job.get_device()]) run_gc([job.get_device()])
show_system_toast(f"finished blend job: {dest}") show_system_toast(f"finished blend job: {dest}")
logger.info("finished blend job: %s", dest) logger.info("finished blend job: %s", dest)

View File

@ -6,7 +6,9 @@ from struct import pack
from time import time from time import time
from typing import Any, List, Optional from typing import Any, List, Optional
from PIL import Image from piexif import ExifIFD, ImageIFD, dump
from piexif.helper import UserComment
from PIL import Image, PngImagePlugin
from .params import Border, HighresParams, ImageParams, Param, Size, UpscaleParams from .params import Border, HighresParams, ImageParams, Param, Size, UpscaleParams
from .server import ServerContext from .server import ServerContext
@ -46,23 +48,37 @@ def json_params(
json["params"]["model"] = path.basename(params.model) json["params"]["model"] = path.basename(params.model)
json["params"]["scheduler"] = params.scheduler json["params"]["scheduler"] = params.scheduler
output_size = size
if border is not None: if border is not None:
json["border"] = border.tojson() json["border"] = border.tojson()
size = size.add_border(border) output_size = output_size.add_border(border)
if highres is not None: if highres is not None:
json["highres"] = highres.tojson() json["highres"] = highres.tojson()
size = highres.resize(size) output_size = highres.resize(output_size)
if upscale is not None: if upscale is not None:
json["upscale"] = upscale.tojson() json["upscale"] = upscale.tojson()
size = upscale.resize(size) output_size = upscale.resize(output_size)
json["size"] = size.tojson() json["input_size"] = size.tojson()
json["size"] = output_size.tojson()
return json return json
def str_params(
params: ImageParams,
size: Size,
) -> str:
return (
f"{params.input_prompt}. Negative prompt: {params.input_negative_prompt}."
f"Steps: {params.steps}, Sampler: {params.scheduler}, CFG scale: {params.cfg}, "
f"Seed: {params.seed}, Size: {size.width}x{size.height}, Model hash: TODO, Model: {params.model}, "
f"Version: TODO, Tool: onnx-web"
)
def make_output_name( def make_output_name(
server: ServerContext, server: ServerContext,
mode: str, mode: str,
@ -99,9 +115,54 @@ def make_output_name(
] ]
def save_image(server: ServerContext, output: str, image: Image.Image) -> str: def save_image(
server: ServerContext,
output: str,
image: Image.Image,
params: Optional[ImageParams] = None,
size: Optional[Size] = None,
upscale: Optional[UpscaleParams] = None,
border: Optional[Border] = None,
highres: Optional[HighresParams] = None,
) -> str:
path = base_join(server.output_path, output) path = base_join(server.output_path, output)
image.save(path, format=server.image_format)
if server.image_format == "png":
exif = PngImagePlugin.PngInfo()
if params is not None:
exif.add_text("Parameters", str_params([output], params, size))
exif.add_text(
"JSON Parameters",
json_params(
[output],
params,
size,
upscale=upscale,
border=border,
highres=highres,
),
)
image.save(path, format=server.image_format, pnginfo=exif)
else:
exif = dump(
{
"0th": {
ExifIFD.UserComment: UserComment.dump(
str_params([output], params, size), encoding="unicode"
),
ImageIFD.Make: "onnx-web",
ImageIFD.Model: "TODO",
# TODO: add JSON params
}
}
)
image.save(path, format=server.image_format, exif=exif)
if params is not None:
save_params(server, output, params, size, upscale=upscale, border=border, highres=highres)
logger.debug("saved output image to: %s", path) logger.debug("saved output image to: %s", path)
return path return path

View File

@ -28,6 +28,7 @@ boto3==1.26.69
flask==2.2.2 flask==2.2.2
flask-cors==3.0.10 flask-cors==3.0.10
jsonschema==4.17.3 jsonschema==4.17.3
piexif==1.1.3
pyyaml==6.0 pyyaml==6.0
setproctitle==1.3.2 setproctitle==1.3.2
waitress==2.1.2 waitress==2.1.2