From 515846321686424bb5e61ad9f1912c49c37903eb Mon Sep 17 00:00:00 2001 From: lllyasviel Date: Mon, 13 Nov 2023 23:44:15 -0800 Subject: [PATCH] js --- css/style.css | 99 ++++++++++++ fooocus_version.py | 2 +- javascript/imageviewer.js | 260 ++++++++++++++++++++++++++++++++ modules/ui_gradio_extensions.py | 2 + update_log.md | 6 +- webui.py | 4 +- 6 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 javascript/imageviewer.js diff --git a/css/style.css b/css/style.css index 48f7b9ad..f7b3d753 100644 --- a/css/style.css +++ b/css/style.css @@ -93,3 +93,102 @@ .styler { overflow:inherit !important; } + +/* fullpage image viewer */ + +#lightboxModal{ + display: none; + position: fixed; + z-index: 1001; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(20, 20, 20, 0.95); + user-select: none; + -webkit-user-select: none; + flex-direction: column; +} + +.modalControls { + display: flex; + position: absolute; + right: 0px; + left: 0px; + gap: 1em; + padding: 1em; + background-color:rgba(0,0,0,0); + z-index: 1; + transition: 0.2s ease background-color; +} +.modalControls:hover { + background-color:rgba(0,0,0,0.9); +} +.modalClose { + margin-left: auto; +} +.modalControls span{ + color: white; + text-shadow: 0px 0px 0.25em black; + font-size: 35px; + font-weight: bold; + cursor: pointer; + width: 1em; +} + +.modalControls span:hover, .modalControls span:focus{ + color: #999; + text-decoration: none; +} + +#lightboxModal > img { + display: block; + margin: auto; + width: auto; +} + +#lightboxModal > img.modalImageFullscreen{ + object-fit: contain; + height: 100%; + width: 100%; + min-height: 0; +} + +.modalPrev, +.modalNext { + cursor: pointer; + position: absolute; + top: 50%; + width: auto; + padding: 16px; + margin-top: -50px; + color: white; + font-weight: bold; + font-size: 20px; + transition: 0.6s ease; + border-radius: 0 3px 3px 0; + user-select: none; + -webkit-user-select: none; +} + +.modalNext { + right: 0; + border-radius: 3px 0 0 3px; +} + +.modalPrev:hover, +.modalNext:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +#imageARPreview { + position: absolute; + top: 0px; + left: 0px; + border: 2px solid red; + background: rgba(255, 0, 0, 0.3); + z-index: 900; + pointer-events: none; + display: none; +} diff --git a/fooocus_version.py b/fooocus_version.py index 36f0485f..efaa7e45 100644 --- a/fooocus_version.py +++ b/fooocus_version.py @@ -1 +1 @@ -version = '2.1.806' +version = '2.1.807' diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js new file mode 100644 index 00000000..511297b0 --- /dev/null +++ b/javascript/imageviewer.js @@ -0,0 +1,260 @@ +// From A1111 + +function closeModal() { + gradioApp().getElementById("lightboxModal").style.display = "none"; +} + +function showModal(event) { + const source = event.target || event.srcElement; + const modalImage = gradioApp().getElementById("modalImage"); + const lb = gradioApp().getElementById("lightboxModal"); + modalImage.src = source.src; + if (modalImage.style.display === 'none') { + lb.style.setProperty('background-image', 'url(' + source.src + ')'); + } + lb.style.display = "flex"; + lb.focus(); + + event.stopPropagation(); +} + +function negmod(n, m) { + return ((n % m) + m) % m; +} + +function updateOnBackgroundChange() { + const modalImage = gradioApp().getElementById("modalImage"); + if (modalImage && modalImage.offsetParent) { + let currentButton = selected_gallery_button(); + + if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) { + modalImage.src = currentButton.children[0].src; + if (modalImage.style.display === 'none') { + const modal = gradioApp().getElementById("lightboxModal"); + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + } + } +} + +function all_gallery_buttons() { + var allGalleryButtons = gradioApp().querySelectorAll('.image_gallery .thumbnails > .thumbnail-item.thumbnail-small'); + var visibleGalleryButtons = []; + allGalleryButtons.forEach(function(elem) { + if (elem.parentElement.offsetParent) { + visibleGalleryButtons.push(elem); + } + }); + return visibleGalleryButtons; +} + +function selected_gallery_button() { + return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null; +} + +function selected_gallery_index() { + return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected')); +} + +function modalImageSwitch(offset) { + var galleryButtons = all_gallery_buttons(); + + if (galleryButtons.length > 1) { + var currentButton = selected_gallery_button(); + + var result = -1; + galleryButtons.forEach(function(v, i) { + if (v == currentButton) { + result = i; + } + }); + + if (result != -1) { + var nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]; + nextButton.click(); + const modalImage = gradioApp().getElementById("modalImage"); + const modal = gradioApp().getElementById("lightboxModal"); + modalImage.src = nextButton.children[0].src; + if (modalImage.style.display === 'none') { + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + setTimeout(function() { + modal.focus(); + }, 10); + } + } +} + +function saveImage() { + +} + +function modalSaveImage(event) { + event.stopPropagation(); +} + +function modalNextImage(event) { + modalImageSwitch(1); + event.stopPropagation(); +} + +function modalPrevImage(event) { + modalImageSwitch(-1); + event.stopPropagation(); +} + +function modalKeyHandler(event) { + switch (event.key) { + case "s": + saveImage(); + break; + case "ArrowLeft": + modalPrevImage(event); + break; + case "ArrowRight": + modalNextImage(event); + break; + case "Escape": + closeModal(); + break; + } +} + +function setupImageForLightbox(e) { + if (e.dataset.modded) { + return; + } + + e.dataset.modded = true; + e.style.cursor = 'pointer'; + e.style.userSelect = 'none'; + + var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + + // For Firefox, listening on click first switched to next image then shows the lightbox. + // If you know how to fix this without switching to mousedown event, please. + // For other browsers the event is click to make it possiblr to drag picture. + var event = isFirefox ? 'mousedown' : 'click'; + + e.addEventListener(event, function(evt) { + if (evt.button == 1) { + open(evt.target.src); + evt.preventDefault(); + return; + } + if (evt.button != 0) return; + + modalZoomSet(gradioApp().getElementById('modalImage'), true); + evt.preventDefault(); + showModal(evt); + }, true); + +} + +function modalZoomSet(modalImage, enable) { + if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable); +} + +function modalZoomToggle(event) { + var modalImage = gradioApp().getElementById("modalImage"); + modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen')); + event.stopPropagation(); +} + +function modalTileImageToggle(event) { + const modalImage = gradioApp().getElementById("modalImage"); + const modal = gradioApp().getElementById("lightboxModal"); + const isTiling = modalImage.style.display === 'none'; + if (isTiling) { + modalImage.style.display = 'block'; + modal.style.setProperty('background-image', 'none'); + } else { + modalImage.style.display = 'none'; + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + + event.stopPropagation(); +} + +onAfterUiUpdate(function() { + var fullImg_preview = gradioApp().querySelectorAll('.image_gallery > div > img'); + if (fullImg_preview != null) { + fullImg_preview.forEach(setupImageForLightbox); + } + updateOnBackgroundChange(); +}); + +document.addEventListener("DOMContentLoaded", function() { + //const modalFragment = document.createDocumentFragment(); + const modal = document.createElement('div'); + modal.onclick = closeModal; + modal.id = "lightboxModal"; + modal.tabIndex = 0; + modal.addEventListener('keydown', modalKeyHandler, true); + + const modalControls = document.createElement('div'); + modalControls.className = 'modalControls gradio-container'; + modal.append(modalControls); + + const modalZoom = document.createElement('span'); + modalZoom.className = 'modalZoom cursor'; + modalZoom.innerHTML = '⤡'; + modalZoom.addEventListener('click', modalZoomToggle, true); + modalZoom.title = "Toggle zoomed view"; + modalControls.appendChild(modalZoom); + + const modalTileImage = document.createElement('span'); + modalTileImage.className = 'modalTileImage cursor'; + modalTileImage.innerHTML = '⊞'; + modalTileImage.addEventListener('click', modalTileImageToggle, true); + modalTileImage.title = "Preview tiling"; + modalControls.appendChild(modalTileImage); + + const modalSave = document.createElement("span"); + modalSave.className = "modalSave cursor"; + modalSave.id = "modal_save"; + modalSave.innerHTML = "🖫"; + modalSave.addEventListener("click", modalSaveImage, true); + modalSave.title = "Save Image(s)"; + modalControls.appendChild(modalSave); + + const modalClose = document.createElement('span'); + modalClose.className = 'modalClose cursor'; + modalClose.innerHTML = '×'; + modalClose.onclick = closeModal; + modalClose.title = "Close image viewer"; + modalControls.appendChild(modalClose); + + const modalImage = document.createElement('img'); + modalImage.id = 'modalImage'; + modalImage.onclick = closeModal; + modalImage.tabIndex = 0; + modalImage.addEventListener('keydown', modalKeyHandler, true); + modal.appendChild(modalImage); + + const modalPrev = document.createElement('a'); + modalPrev.className = 'modalPrev'; + modalPrev.innerHTML = '❮'; + modalPrev.tabIndex = 0; + modalPrev.addEventListener('click', modalPrevImage, true); + modalPrev.addEventListener('keydown', modalKeyHandler, true); + modal.appendChild(modalPrev); + + const modalNext = document.createElement('a'); + modalNext.className = 'modalNext'; + modalNext.innerHTML = '❯'; + modalNext.tabIndex = 0; + modalNext.addEventListener('click', modalNextImage, true); + modalNext.addEventListener('keydown', modalKeyHandler, true); + + modal.appendChild(modalNext); + + try { + gradioApp().appendChild(modal); + } catch (e) { + gradioApp().body.appendChild(modal); + } + + document.body.appendChild(modal); + +}); diff --git a/modules/ui_gradio_extensions.py b/modules/ui_gradio_extensions.py index d393027b..0d0df974 100644 --- a/modules/ui_gradio_extensions.py +++ b/modules/ui_gradio_extensions.py @@ -29,6 +29,7 @@ def javascript_html(): zoom_js_path = webpath('javascript/zoom.js') edit_attention_js_path = webpath('javascript/edit-attention.js') viewer_js_path = webpath('javascript/viewer.js') + image_viewer_js_path = webpath('javascript/imageviewer.js') head = f'\n' head += f'\n' head += f'\n' @@ -36,6 +37,7 @@ def javascript_html(): head += f'\n' head += f'\n' head += f'\n' + head += f'\n' return head diff --git a/update_log.md b/update_log.md index 89b05713..7f4220fb 100644 --- a/update_log.md +++ b/update_log.md @@ -1,6 +1,10 @@ +# 2.1.807 + +* Click on image to see it in full screen. + # 2.1.806 -* fix some lora problems related to clip. +* Fix some lora problems related to clip. # 2.1.805 diff --git a/webui.py b/webui.py index a918c19e..845f706a 100644 --- a/webui.py +++ b/webui.py @@ -81,11 +81,11 @@ with shared.gradio_root: progress_window = grh.Image(label='Preview', show_label=True, visible=False, height=768, elem_classes=['main_view']) progress_gallery = gr.Gallery(label='Finished Images', show_label=True, object_fit='contain', - height=768, visible=False, elem_classes=['main_view']) + height=768, visible=False, elem_classes=['main_view', 'image_gallery']) progress_html = gr.HTML(value=modules.html.make_progress_html(32, 'Progress 32%'), visible=False, elem_id='progress-bar', elem_classes='progress-bar') gallery = gr.Gallery(label='Gallery', show_label=False, object_fit='contain', visible=True, height=768, - elem_classes=['resizable_area', 'main_view', 'final_gallery'], + elem_classes=['resizable_area', 'main_view', 'final_gallery', 'image_gallery'], elem_id='final_gallery') with gr.Row(elem_classes='type_row'): with gr.Column(scale=17):