Added user setting to select preview image thumbnail type ("JPEG", "WEBP" or "JPEG/WEBP").
- Default is "JPEG/WEBP", which will fall back to "JPEG" if preview image is neither type (e.g. "PNG").
This commit is contained in:
24
__init__.py
24
__init__.py
@@ -182,6 +182,7 @@ def ui_rules():
|
|||||||
Rule("model-preview-fallback-search-safetensors-thumbnail", False, bool),
|
Rule("model-preview-fallback-search-safetensors-thumbnail", False, bool),
|
||||||
Rule("model-show-add-button", True, bool),
|
Rule("model-show-add-button", True, bool),
|
||||||
Rule("model-show-copy-button", True, bool),
|
Rule("model-show-copy-button", True, bool),
|
||||||
|
Rule("model-preview-thumbnail-type", "JPEG/WEBP", str),
|
||||||
Rule("model-add-embedding-extension", False, bool),
|
Rule("model-add-embedding-extension", False, bool),
|
||||||
Rule("model-add-drag-strict-on-field", False, bool),
|
Rule("model-add-drag-strict-on-field", False, bool),
|
||||||
Rule("model-add-offset", 25, int),
|
Rule("model-add-offset", 25, int),
|
||||||
@@ -290,6 +291,16 @@ def image_format_is_equal(f1, f2):
|
|||||||
return f1 == f2 or (f1 == "JPG" and f2 == "JPEG") or (f1 == "JPEG" and f2 == "JPG")
|
return f1 == f2 or (f1 == "JPG" and f2 == "JPEG") or (f1 == "JPEG" and f2 == "JPG")
|
||||||
|
|
||||||
|
|
||||||
|
def is_auto_thumbnail_format(format):
|
||||||
|
return format in ["JPEG/WEBP", "WEBP/JPEG", "JPG/WEBP", "WEBP/JPG"]
|
||||||
|
|
||||||
|
|
||||||
|
def get_auto_thumbnail_format(original_format):
|
||||||
|
if original_format in ["JPEG", "WEBP", "JPG"]:
|
||||||
|
return original_format
|
||||||
|
return "JPEG" # default fallback
|
||||||
|
|
||||||
|
|
||||||
@server.PromptServer.instance.routes.get("/model-manager/preview/get")
|
@server.PromptServer.instance.routes.get("/model-manager/preview/get")
|
||||||
async def get_model_preview(request):
|
async def get_model_preview(request):
|
||||||
uri = request.query.get("uri")
|
uri = request.query.get("uri")
|
||||||
@@ -339,10 +350,13 @@ async def get_model_preview(request):
|
|||||||
image_format = image.format
|
image_format = image.format
|
||||||
if response_image_format is None:
|
if response_image_format is None:
|
||||||
response_image_format = image_format
|
response_image_format = image_format
|
||||||
elif not image_format_is_equal(response_image_format, image_format):
|
elif is_auto_thumbnail_format(response_image_format):
|
||||||
|
response_image_format = get_auto_thumbnail_format(image_format)
|
||||||
|
|
||||||
|
if not image_format_is_equal(response_image_format, image_format):
|
||||||
exif = image.getexif()
|
exif = image.getexif()
|
||||||
metadata = get_image_info(image)
|
metadata = get_image_info(image)
|
||||||
if response_image_format == 'JPEG' or response_image_format == 'JPG':
|
if response_image_format in ['JPEG', 'JPG']:
|
||||||
image = image.convert('RGB')
|
image = image.convert('RGB')
|
||||||
image_bytes = io.BytesIO()
|
image_bytes = io.BytesIO()
|
||||||
image.save(image_bytes, format=response_image_format, exif=exif, pnginfo=metadata, quality=quality)
|
image.save(image_bytes, format=response_image_format, exif=exif, pnginfo=metadata, quality=quality)
|
||||||
@@ -358,6 +372,9 @@ async def get_model_preview(request):
|
|||||||
image_format = image.format
|
image_format = image.format
|
||||||
if response_image_format is None:
|
if response_image_format is None:
|
||||||
response_image_format = image_format
|
response_image_format = image_format
|
||||||
|
elif is_auto_thumbnail_format(response_image_format):
|
||||||
|
response_image_format = get_auto_thumbnail_format(image_format)
|
||||||
|
|
||||||
w0, h0 = image.size
|
w0, h0 = image.size
|
||||||
if w is None:
|
if w is None:
|
||||||
w = (h * w0) // h0
|
w = (h * w0) // h0
|
||||||
@@ -387,13 +404,14 @@ async def get_model_preview(request):
|
|||||||
resampling_method = Image.Resampling.BICUBIC
|
resampling_method = Image.Resampling.BICUBIC
|
||||||
image.thumbnail((w, h), resample=resampling_method)
|
image.thumbnail((w, h), resample=resampling_method)
|
||||||
|
|
||||||
if not image_format_is_equal(image_format, response_image_format) and (response_image_format == 'JPEG' or response_image_format == 'JPG'):
|
if not image_format_is_equal(image_format, response_image_format) and response_image_format in ['JPEG', 'JPG']:
|
||||||
image = image.convert('RGB')
|
image = image.convert('RGB')
|
||||||
image_bytes = io.BytesIO()
|
image_bytes = io.BytesIO()
|
||||||
image.save(image_bytes, format=response_image_format, exif=exif, pnginfo=metadata, quality=quality)
|
image.save(image_bytes, format=response_image_format, exif=exif, pnginfo=metadata, quality=quality)
|
||||||
image_data = image_bytes.getvalue()
|
image_data = image_bytes.getvalue()
|
||||||
|
|
||||||
response_file_name = os.path.splitext(file_name)[0] + '.' + response_image_format.lower()
|
response_file_name = os.path.splitext(file_name)[0] + '.' + response_image_format.lower()
|
||||||
|
print(f"response_file_name: {response_file_name}")
|
||||||
return web.Response(
|
return web.Response(
|
||||||
headers={
|
headers={
|
||||||
"Content-Disposition": f"inline; filename={response_file_name}",
|
"Content-Disposition": f"inline; filename={response_file_name}",
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ function imageUri(imageSearchPath = undefined, dateImageModified = undefined, wi
|
|||||||
const PREVIEW_NONE_URI = imageUri();
|
const PREVIEW_NONE_URI = imageUri();
|
||||||
const PREVIEW_THUMBNAIL_WIDTH = 320;
|
const PREVIEW_THUMBNAIL_WIDTH = 320;
|
||||||
const PREVIEW_THUMBNAIL_HEIGHT = 480;
|
const PREVIEW_THUMBNAIL_HEIGHT = 480;
|
||||||
const PREVIEW_THUMBNAIL_FORMAT = "JPEG";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {(...args) => void} callback
|
* @param {(...args) => void} callback
|
||||||
@@ -230,6 +229,28 @@ function $checkbox(x = { $: (el) => {}, textContent: "", checked: false }) {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {HTMLLabelElement}
|
||||||
|
*/
|
||||||
|
function $select(x = { $: (el) => {}, textContent: "", options: [""] }) {
|
||||||
|
const text = x.textContent;
|
||||||
|
const select = $el("select", {
|
||||||
|
name: text ?? "select",
|
||||||
|
}, x.options.map((option) => {
|
||||||
|
return $el("option", {
|
||||||
|
value: option,
|
||||||
|
}, option);
|
||||||
|
}));
|
||||||
|
const label = $el("label", [
|
||||||
|
select,
|
||||||
|
text === "" || text === undefined || text === null ? "" : " " + text,
|
||||||
|
]);
|
||||||
|
if (x.$ !== undefined){
|
||||||
|
x.$(select);
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Any} attr
|
* @param {Any} attr
|
||||||
* @returns {HTMLDivElement}
|
* @returns {HTMLDivElement}
|
||||||
@@ -1654,6 +1675,7 @@ class ModelGrid {
|
|||||||
const addOffset = parseInt(settingsElements["model-add-offset"].value);
|
const addOffset = parseInt(settingsElements["model-add-offset"].value);
|
||||||
const showModelExtension = settingsElements["model-show-label-extensions"].checked;
|
const showModelExtension = settingsElements["model-show-label-extensions"].checked;
|
||||||
const removeEmbeddingExtension = !settingsElements["model-add-embedding-extension"].checked;
|
const removeEmbeddingExtension = !settingsElements["model-add-embedding-extension"].checked;
|
||||||
|
const previewThumbnailFormat = settingsElements["model-preview-thumbnail-type"].value;
|
||||||
if (models.length > 0) {
|
if (models.length > 0) {
|
||||||
return models.map((item) => {
|
return models.map((item) => {
|
||||||
const previewInfo = item.preview;
|
const previewInfo = item.preview;
|
||||||
@@ -1706,7 +1728,7 @@ class ModelGrid {
|
|||||||
previewInfo?.dateModified,
|
previewInfo?.dateModified,
|
||||||
PREVIEW_THUMBNAIL_WIDTH,
|
PREVIEW_THUMBNAIL_WIDTH,
|
||||||
PREVIEW_THUMBNAIL_HEIGHT,
|
PREVIEW_THUMBNAIL_HEIGHT,
|
||||||
PREVIEW_THUMBNAIL_FORMAT,
|
previewThumbnailFormat,
|
||||||
),
|
),
|
||||||
draggable: false,
|
draggable: false,
|
||||||
}),
|
}),
|
||||||
@@ -3221,7 +3243,8 @@ class SettingsView {
|
|||||||
case "range": setting.value = parseFloat(value); break;
|
case "range": setting.value = parseFloat(value); break;
|
||||||
case "textarea": setting.value = value; break;
|
case "textarea": setting.value = value; break;
|
||||||
case "number": setting.value = parseInt(value); break;
|
case "number": setting.value = parseInt(value); break;
|
||||||
default: console.warn("Unknown settings input type!");
|
case "select-one": setting.value = value; break;
|
||||||
|
default: console.warn(`Unknown settings input type '${type}'!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3253,6 +3276,7 @@ class SettingsView {
|
|||||||
case "range": value = el.value; break;
|
case "range": value = el.value; break;
|
||||||
case "textarea": value = el.value; break;
|
case "textarea": value = el.value; break;
|
||||||
case "number": value = el.value; break;
|
case "number": value = el.value; break;
|
||||||
|
case "select-one": value = el.value; break;
|
||||||
default: console.warn("Unknown settings input type!");
|
default: console.warn("Unknown settings input type!");
|
||||||
}
|
}
|
||||||
settingsData[setting] = value;
|
settingsData[setting] = value;
|
||||||
@@ -3365,6 +3389,11 @@ class SettingsView {
|
|||||||
$: (el) => (settings["model-show-copy-button"] = el),
|
$: (el) => (settings["model-show-copy-button"] = el),
|
||||||
textContent: "Show copy button",
|
textContent: "Show copy button",
|
||||||
}),
|
}),
|
||||||
|
$select({
|
||||||
|
$: (el) => (settings["model-preview-thumbnail-type"] = el),
|
||||||
|
textContent: "Preview thumbnail type",
|
||||||
|
options: ["JPEG/WEBP", "JPEG", "WEBP"],
|
||||||
|
}),
|
||||||
$el("h2", ["Model Add"]),
|
$el("h2", ["Model Add"]),
|
||||||
$checkbox({
|
$checkbox({
|
||||||
$: (el) => (settings["model-add-embedding-extension"] = el),
|
$: (el) => (settings["model-add-embedding-extension"] = el),
|
||||||
|
|||||||
Reference in New Issue
Block a user