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):