Today, I’m going to show you how I created a simple image browser for Nuke with the help of ChatGPT. Yes, you heard it right, I used AI to code this tool in just a few steps, and trust me—it’s super cool!”
If you’re into VFX, coding might not always be your thing, but tools like ChatGPT can really speed things up. Instead of spending days figuring out Python or Nuke scripting, I got this browser up and running in just a few hours.
As a compositor, I often need to work with a lot of image elements. And, searching through folders manually or using the basic file browser is not ideal. So I thought—why not build something to preview, load, and even import these images directly into Nuke as Read
nodes?
I could’ve spent hours trying to figure out the code myself, but instead, I used ChatGPT. It’s an AI that helped me write the Python code step-by-step. All I needed to do was describe what I wanted.
We started with setting up a basic PySide2 UI in Python. ChatGPT was quick to provide me with a framework to start building
The code is simple but powerful. It uses PySide2 for the UI, and it talks directly to Nuke’s API to create Read
nodes and load images. This is how it works behind the scenes
ChatGPT might generate code that will do exactly what you asked for you have to iterate it improvise it and fix a little bit ,to make the you want. You might need to have basic understanding in nuke and Python to create a workable tool
Here is the full code
import nuke
import os
from PySide2 import QtWidgets, QtCore, QtGui
class DraggableThumbnail(QtWidgets.QLabel):
"""A QLabel that supports drag and drop functionality."""
def __init__(self, image_path, parent=None):
super(DraggableThumbnail, self).__init__(parent)
self.image_path = image_path
self.setAcceptDrops(False)
def mousePressEvent(self, event):
"""Initiates the drag event when the thumbnail is clicked."""
if event.button() == QtCore.Qt.LeftButton:
drag = QtGui.QDrag(self)
mime_data = QtCore.QMimeData()
mime_data.setText(self.image_path) # Send image path as part of the drag event
drag.setMimeData(mime_data)
# Use a pixmap for the drag visual
pixmap = self.pixmap()
drag.setPixmap(pixmap.scaled(50, 50, QtCore.Qt.KeepAspectRatio))
# Start the drag
drag.exec_(QtCore.Qt.CopyAction)
class ImageBrowserUI(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageBrowserUI, self).__init__(parent)
# Set the window title
self.setWindowTitle("Image Browser")
# Initial path to the elements folder
self.elements_dir = "D:/symbolss" # Set default path
# Create a vertical layout for the window
self.layout = QtWidgets.QVBoxLayout()
# Create a path selector
self.path_selector_layout = QtWidgets.QHBoxLayout()
self.path_label = QtWidgets.QLabel("Images Directory:")
self.path_selector_layout.addWidget(self.path_label)
self.path_input = QtWidgets.QLineEdit(self.elements_dir)
self.path_selector_layout.addWidget(self.path_input)
self.browse_button = QtWidgets.QPushButton("Browse")
self.browse_button.clicked.connect(self.browse_directory)
self.path_selector_layout.addWidget(self.browse_button)
self.layout.addLayout(self.path_selector_layout)
# Create a reload button
self.reload_button = QtWidgets.QPushButton("Reload Images")
self.reload_button.clicked.connect(self.reload_elements)
self.layout.addWidget(self.reload_button)
# Create a scroll area for thumbnails
self.scroll_area = QtWidgets.QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area_widget = QtWidgets.QWidget()
self.scroll_area.setWidget(self.scroll_area_widget)
# Create a grid layout for thumbnails
self.grid_layout = QtWidgets.QGridLayout(self.scroll_area_widget)
self.grid_layout.setSpacing(10)
self.grid_layout.setContentsMargins(10, 10, 10, 10)
self.layout.addWidget(self.scroll_area)
# Create a widget to preview images
self.preview_label = QtWidgets.QLabel("Preview")
self.preview_label.setAlignment(QtCore.Qt.AlignCenter)
self.layout.addWidget(self.preview_label)
# Add an image label for previewing images
self.image_label = QtWidgets.QLabel()
self.image_label.setAlignment(QtCore.Qt.AlignCenter)
self.image_label.setFixedHeight(300) # Set height for preview
self.layout.addWidget(self.image_label)
# Create import button
self.import_button = QtWidgets.QPushButton("Import Image as Read Node")
self.import_button.clicked.connect(self.import_image_as_read_node)
self.layout.addWidget(self.import_button)
# Store the currently selected image path
self.current_image_path = None
# Set the layout for the main window
self.setLayout(self.layout)
# Load images from the default path or browse if the folder doesn't exist
if not os.path.exists(self.elements_dir):
self.browse_directory()
else:
self.reload_elements()
def browse_directory(self):
"""Allows the user to select a new images directory."""
new_dir = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Images Directory", self.elements_dir)
if new_dir:
self.path_input.setText(new_dir)
self.reload_elements() # Automatically reload images when directory changes
def reload_elements(self):
"""Reloads the images from the specified directory."""
self.elements_dir = self.path_input.text()
# Check if directory exists before reloading elements
if not os.path.exists(self.elements_dir):
QtWidgets.QMessageBox.warning(self, "Directory Not Found", f"The folder '{self.elements_dir}' was not found.")
return
# Remove all widgets from the grid layout manually
for i in reversed(range(self.grid_layout.count())):
widget = self.grid_layout.itemAt(i).widget()
if widget is not None:
widget.deleteLater()
# Get all images (e.g., jpg, png) from the directory
image_files = [f for f in os.listdir(self.elements_dir)
if f.lower().endswith(('.jpg', '.png', '.jpeg'))]
# Create thumbnails for each image
for index, image_file in enumerate(image_files):
image_path = os.path.join(self.elements_dir, image_file)
pixmap = QtGui.QPixmap(image_path)
thumbnail = pixmap.scaled(100, 100, QtCore.Qt.KeepAspectRatio)
# Create a draggable thumbnail widget
thumbnail_label = DraggableThumbnail(image_path)
thumbnail_label.setPixmap(thumbnail)
thumbnail_label.setToolTip(image_file) # Show filename on hover
# Connect the label's click event to the preview function
thumbnail_label.mousePressEvent = lambda event, path=image_path: self.preview_element(path)
# Add the thumbnail to the grid layout
row, col = divmod(index, 5) # Adjust the number of columns as needed
self.grid_layout.addWidget(thumbnail_label, row, col)
def preview_element(self, image_path):
"""Previews the selected image in the preview area."""
self.current_image_path = image_path
pixmap = QtGui.QPixmap(image_path)
self.image_label.setPixmap(pixmap.scaled(self.image_label.size(), QtCore.Qt.KeepAspectRatio))
def import_image_as_read_node(self):
"""Imports the currently selected image as a Read node in Nuke."""
if self.current_image_path:
# Replace backslashes with forward slashes
normalized_path = self.current_image_path.replace("\\", "/")
read_node = nuke.createNode("Read")
read_node["file"].setValue(normalized_path)
else:
QtWidgets.QMessageBox.warning(self, "No Image Selected", "Please select an image to import.")
def show_image_browser_ui():
global image_browser_window # Keep a reference to the window
image_browser_window = ImageBrowserUI()
image_browser_window.show()
# Uncomment the following line if you want to directly run the script in the Script Editor:
show_image_browser_ui()