IC Python API:Screenshotting

From Reallusion Wiki!
Jump to: navigation, search
Main article: RL Python Samples.
grabWindow() location starts from the top left corner (positional coordinates) and expands outward according to its size (width and height).

Qt provides QtCore.QScreen.grabWindow() function which has the ability to create and return a pixmap constructed by grabbing the contents of a given window within an area (x, y, width, height).

A pixmap is one of four classes provided by Qt for handling image data.  It is designed and optimized for showing images on screen by using a QLabel or one of QAbstractButton's sub-classes such as QPushbutton and QToolButton.

Necessary Modules and Global Variables

Besides the fundamental Reallusion Python module, we'll also need PySide2 an os to read and implement a .ui onto a custom window interface. We'll also need a global variable to house the ID for the screen that is currently selected e.g. the screen that is focused on.

import RLPy
import os
from PySide2 import *
from PySide2 import shiboken2


# Global variables
current_screen = None

User Interface

Ic python api screenshotting 02.png

Next, create a user interface for switching between the available screen displays and specify the x and y coordinates for screenshotting. The capture will exists in a 256x256 area which is a QLabel with a pixmap background. You can download the Screenshot.ui file from here (right-click and "save as").

# Create a dialog window
window = RLPy.RUi.CreateRDialog()
window.SetWindowTitle("Realtime Screenshot")

# Create Pyside layout for RDialog
dialog = shiboken2.wrapInstance(int(window.GetWindow()), QtWidgets.QDialog)
dialog.setFixedWidth(300)

# Read and set the QT ui file from the script location
qt_ui_file = QtCore.QFile(os.path.dirname(__file__) + "/Screenshot.ui")
qt_ui_file.open(QtCore.QFile.ReadOnly)
widget = QtUiTools.QUiLoader().load(qt_ui_file)
qt_ui_file.close()
dialog.layout().addWidget(widget)


for screen in QtWidgets.QApplication.screens():
    widget.screens.addItem(screen.name())

window.Show()

Noticed that the available screen monitors are added to the Screen Display list.

Switching Screens

We'll need a function for switching between the available screen monitors and assigning it to the global variable. The screen switch event will also reset the screen coordinates to (0, 0).

def change_screen():
    global current_screen

    index = widget.screens.currentIndex()
    current_screen = QtWidgets.QApplication.screens()[index]
    rect = current_screen.availableGeometry()

    # Set the maximum position values to the screen size minus the grab size
    widget.positionX.setMaximum(rect.width() - 256)
    widget.positionY.setMaximum(rect.height() - 256)

    widget.positionX.setValue(0)
    widget.positionY.setValue(0)
    screenshot()

Screenshotting

We'll also need a function for taking the actual screenshot as a 256x256 pixmap and assign it to the QLabel in the center of the interface window.

def screenshot():
    global current_screen

    rect = current_screen.availableGeometry()
    main_window_address = RLPy.RUi.GetMainWindow()
    main_window = shiboken2.wrapInstance(int(main_window_address), QtWidgets.QWidget)
    pixmap = current_screen.grabWindow(0, widget.positionX.value() + rect.x(), widget.positionY.value() + rect.y(), 256, 256)
    widget.image.setPixmap(pixmap)

Button Assignments

Finally, we'll assign the aforementioned functions to their respective buttons, and call the screenshot() command to initialize the first screenshot.

# Connect functions to UI signals
widget.positionX.valueChanged.connect(screenshot)
widget.positionY.valueChanged.connect(screenshot)
widget.screens.currentIndexChanged.connect(change_screen)

change_screen()  # Take the first screenshot to get started

Everything Put Together

Screen looping is a phenomenon that can occur when the screen-captures start to stack upon each other.

You can copy and paste the following code into a PY file and load it into iClone via Script > Load Python. Make sure to download the Screenshot.ui file that accompanies this lesson and place it in the same directory as the script file. You can find this file under under the User Interface section.

import RLPy
import os
from PySide2 import *
from PySide2 import shiboken2


# Global variables
current_screen = None

# Create a dialog window
window = RLPy.RUi.CreateRDialog()
window.SetWindowTitle("Realtime Screenshot")

# Create Pyside layout for RDialog
dialog = shiboken2.wrapInstance(int(window.GetWindow()), QtWidgets.QDialog)
dialog.setFixedWidth(300)

# Read and set the QT ui file from the script location
qt_ui_file = QtCore.QFile(os.path.dirname(__file__) + "/Screenshot.ui")
qt_ui_file.open(QtCore.QFile.ReadOnly)
widget = QtUiTools.QUiLoader().load(qt_ui_file)
qt_ui_file.close()
dialog.layout().addWidget(widget)


for screen in QtWidgets.QApplication.screens():
    widget.screens.addItem(screen.name())

window.Show()


def change_screen():
    global current_screen

    index = widget.screens.currentIndex()
    current_screen = QtWidgets.QApplication.screens()[index]
    rect = current_screen.availableGeometry()

    # Set the maximum position values to the screen size minus the grab size
    widget.positionX.setMaximum(rect.width() - 256)
    widget.positionY.setMaximum(rect.height() - 256)

    widget.positionX.setValue(0)
    widget.positionY.setValue(0)
    screenshot()


def screenshot():
    global current_screen

    rect = current_screen.availableGeometry()
    main_window_address = RLPy.RUi.GetMainWindow()
    main_window = shiboken2.wrapInstance(int(main_window_address), QtWidgets.QWidget)
    pixmap = current_screen.grabWindow(0, widget.positionX.value() + rect.x(), widget.positionY.value() + rect.y(), 256, 256)
    widget.image.setPixmap(pixmap)


# Connect functions to UI signals
widget.positionX.valueChanged.connect(screenshot)
widget.positionY.valueChanged.connect(screenshot)
widget.screens.currentIndexChanged.connect(change_screen)

change_screen()  # Take the first screenshot to get started

APIs Used

You can research the following references for the APIs deployed in this code.