#1826 Allow snapping to known resolutions for face/bg generations

This commit is contained in:
Cohee
2024-02-12 17:28:39 +02:00
parent 9d713825c2
commit b8387df15e
2 changed files with 62 additions and 21 deletions

View File

@ -206,6 +206,7 @@ const defaultSettings = {
expand: false, expand: false,
interactive_mode: false, interactive_mode: false,
multimodal_captioning: false, multimodal_captioning: false,
snap: false,
prompts: promptTemplates, prompts: promptTemplates,
@ -389,6 +390,7 @@ async function loadSettings() {
$('#sd_openai_quality').val(extension_settings.sd.openai_quality); $('#sd_openai_quality').val(extension_settings.sd.openai_quality);
$('#sd_comfy_url').val(extension_settings.sd.comfy_url); $('#sd_comfy_url').val(extension_settings.sd.comfy_url);
$('#sd_comfy_prompt').val(extension_settings.sd.comfy_prompt); $('#sd_comfy_prompt').val(extension_settings.sd.comfy_prompt);
$('#sd_snap').prop('checked', extension_settings.sd.snap);
for (const style of extension_settings.sd.styles) { for (const style of extension_settings.sd.styles) {
const option = document.createElement('option'); const option = document.createElement('option');
@ -398,23 +400,7 @@ async function loadSettings() {
$('#sd_style').append(option); $('#sd_style').append(option);
} }
// Find a closest resolution option match for the current width and height const resolutionId = getClosestKnownResolution();
let resolutionId = null, minAspectDiff = Infinity, minResolutionDiff = Infinity;
for (const [id, resolution] of Object.entries(resolutionOptions)) {
const aspectDiff = Math.abs((resolution.width / resolution.height) - (extension_settings.sd.width / extension_settings.sd.height));
const resolutionDiff = Math.abs(resolution.width * resolution.height - extension_settings.sd.width * extension_settings.sd.height);
if (resolutionDiff < minResolutionDiff || (resolutionDiff === minResolutionDiff && aspectDiff < minAspectDiff)) {
resolutionId = id;
minAspectDiff = aspectDiff;
minResolutionDiff = resolutionDiff;
}
if (resolutionDiff === 0 && aspectDiff === 0) {
break;
}
}
$('#sd_resolution').val(resolutionId); $('#sd_resolution').val(resolutionId);
toggleSourceControls(); toggleSourceControls();
@ -423,6 +409,32 @@ async function loadSettings() {
await loadSettingOptions(); await loadSettingOptions();
} }
/**
* Find a closest resolution option match for the current width and height.
*/
function getClosestKnownResolution() {
let resolutionId = null;
let minTotalDiff = Infinity;
const targetAspect = extension_settings.sd.width / extension_settings.sd.height;
const targetResolution = extension_settings.sd.width * extension_settings.sd.height;
const diffs = Object.entries(resolutionOptions).map(([id, resolution]) => {
const aspectDiff = Math.abs((resolution.width / resolution.height) - targetAspect) / targetAspect;
const resolutionDiff = Math.abs(resolution.width * resolution.height - targetResolution) / targetResolution;
return { id, totalDiff: aspectDiff + resolutionDiff };
});
for (const { id, totalDiff } of diffs) {
if (totalDiff < minTotalDiff) {
minTotalDiff = totalDiff;
resolutionId = id;
}
}
return resolutionId;
}
async function loadSettingOptions() { async function loadSettingOptions() {
return Promise.all([ return Promise.all([
loadSamplers(), loadSamplers(),
@ -475,6 +487,11 @@ function onMultimodalCaptioningInput() {
saveSettingsDebounced(); saveSettingsDebounced();
} }
function onSnapInput() {
extension_settings.sd.snap = !!$(this).prop('checked');
saveSettingsDebounced();
}
function onStyleSelect() { function onStyleSelect() {
const selectedStyle = String($('#sd_style').find(':selected').val()); const selectedStyle = String($('#sd_style').find(':selected').val());
const styleObject = extension_settings.sd.styles.find(x => x.name === selectedStyle); const styleObject = extension_settings.sd.styles.find(x => x.name === selectedStyle);
@ -1765,7 +1782,7 @@ function setTypeSpecificDimensions(generationType) {
const aspectRatio = extension_settings.sd.width / extension_settings.sd.height; const aspectRatio = extension_settings.sd.width / extension_settings.sd.height;
// Face images are always portrait (pun intended) // Face images are always portrait (pun intended)
if (generationType == generationMode.FACE && aspectRatio >= 1) { if ((generationType == generationMode.FACE || generationType == generationMode.FACE_MULTIMODAL) && aspectRatio >= 1) {
// Round to nearest multiple of 64 // Round to nearest multiple of 64
extension_settings.sd.height = Math.round(extension_settings.sd.width * 1.5 / 64) * 64; extension_settings.sd.height = Math.round(extension_settings.sd.width * 1.5 / 64) * 64;
} }
@ -1778,6 +1795,25 @@ function setTypeSpecificDimensions(generationType) {
} }
} }
if (extension_settings.sd.snap) {
// Force to use roughly the same pixel count as before rescaling
const prevPixelCount = prevSDHeight * prevSDWidth;
const newPixelCount = extension_settings.sd.height * extension_settings.sd.width;
const ratio = Math.sqrt(prevPixelCount / newPixelCount);
extension_settings.sd.height = Math.round(extension_settings.sd.height * ratio / 64) * 64;
extension_settings.sd.width = Math.round(extension_settings.sd.width * ratio / 64) * 64;
console.log(`Pixel counts after rescaling: ${prevPixelCount} -> ${newPixelCount} (ratio: ${ratio})`);
const resolution = resolutionOptions[getClosestKnownResolution()];
if (resolution) {
extension_settings.sd.height = resolution.height;
extension_settings.sd.width = resolution.width;
console.log('Snap to resolution', JSON.stringify(resolution));
} else {
console.warn('Snap to resolution failed, using custom dimensions');
}
}
return { height: prevSDHeight, width: prevSDWidth }; return { height: prevSDHeight, width: prevSDWidth };
} }
@ -2349,7 +2385,7 @@ async function onComfyOpenWorkflowEditorClick() {
`); `);
$('#sd_comfy_workflow_editor_placeholder_list_custom').append(el); $('#sd_comfy_workflow_editor_placeholder_list_custom').append(el);
el.find('.sd_comfy_workflow_editor_custom_find').val(placeholder.find); el.find('.sd_comfy_workflow_editor_custom_find').val(placeholder.find);
el.find('.sd_comfy_workflow_editor_custom_find').on('input', function() { el.find('.sd_comfy_workflow_editor_custom_find').on('input', function () {
placeholder.find = this.value; placeholder.find = this.value;
el.find('.sd_comfy_workflow_editor_custom_final').text(`"%${this.value}%"`); el.find('.sd_comfy_workflow_editor_custom_final').text(`"%${this.value}%"`);
el.attr('data-placeholder', `${this.value}`); el.attr('data-placeholder', `${this.value}`);
@ -2357,7 +2393,7 @@ async function onComfyOpenWorkflowEditorClick() {
saveSettingsDebounced(); saveSettingsDebounced();
}); });
el.find('.sd_comfy_workflow_editor_custom_replace').val(placeholder.replace); el.find('.sd_comfy_workflow_editor_custom_replace').val(placeholder.replace);
el.find('.sd_comfy_workflow_editor_custom_replace').on('input', function() { el.find('.sd_comfy_workflow_editor_custom_replace').on('input', function () {
placeholder.replace = this.value; placeholder.replace = this.value;
saveSettingsDebounced(); saveSettingsDebounced();
}); });
@ -2379,7 +2415,7 @@ async function onComfyOpenWorkflowEditorClick() {
addPlaceholderDom(placeholder); addPlaceholderDom(placeholder);
saveSettingsDebounced(); saveSettingsDebounced();
}); });
(extension_settings.sd.comfy_placeholders ?? []).forEach(placeholder=>{ (extension_settings.sd.comfy_placeholders ?? []).forEach(placeholder => {
addPlaceholderDom(placeholder); addPlaceholderDom(placeholder);
}); });
checkPlaceholders(); checkPlaceholders();
@ -2700,6 +2736,7 @@ jQuery(async () => {
$('#sd_openai_style').on('change', onOpenAiStyleSelect); $('#sd_openai_style').on('change', onOpenAiStyleSelect);
$('#sd_openai_quality').on('change', onOpenAiQualitySelect); $('#sd_openai_quality').on('change', onOpenAiQualitySelect);
$('#sd_multimodal_captioning').on('input', onMultimodalCaptioningInput); $('#sd_multimodal_captioning').on('input', onMultimodalCaptioningInput);
$('#sd_snap').on('input', onSnapInput);
$('.sd_settings .inline-drawer-toggle').on('click', function () { $('.sd_settings .inline-drawer-toggle').on('click', function () {
initScrollHeight($('#sd_prompt_prefix')); initScrollHeight($('#sd_prompt_prefix'));

View File

@ -26,6 +26,10 @@
<input id="sd_expand" type="checkbox" /> <input id="sd_expand" type="checkbox" />
Auto-enhance prompts Auto-enhance prompts
</label> </label>
<label for="sd_snap" class="checkbox_label" title="Snap generation requests with a forced aspect ratio (portraits, backgrounds) to the nearest known resolution, while trying to preserve the absolute pixel counts (recommended for SDXL).">
<input id="sd_snap" type="checkbox" />
Snap auto-adjusted resolutions
</label>
<label for="sd_source">Source</label> <label for="sd_source">Source</label>
<select id="sd_source"> <select id="sd_source">
<option value="extras">Extras API (local / remote)</option> <option value="extras">Extras API (local / remote)</option>