Fix slow preview after fetching live image

This commit is contained in:
Daniel 2020-04-10 18:25:12 +00:00 committed by Tomas Groth
parent 92d67468e2
commit a02ca297d6
2 changed files with 41 additions and 24 deletions

View File

@ -206,7 +206,6 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
self.panel = QtWidgets.QWidget(self.main_window.control_splitter) self.panel = QtWidgets.QWidget(self.main_window.control_splitter)
self.slide_list = {} self.slide_list = {}
self.slide_count = 0 self.slide_count = 0
self.slide_image = None
self.controller_width = -1 self.controller_width = -1
# Layout for holding panel # Layout for holding panel
self.panel_layout = QtWidgets.QVBoxLayout(self.panel) self.panel_layout = QtWidgets.QVBoxLayout(self.panel)
@ -1198,38 +1197,35 @@ class SlideController(QtWidgets.QWidget, LogMixin, RegistryProperties):
if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay):
if self.is_live: if self.is_live:
# If live, grab screen-cap of main display now # If live, grab screen-cap of main display now
QtCore.QTimer.singleShot(500, self.grab_maindisplay) QtCore.QTimer.singleShot(500, self.display_maindisplay)
# but take another in a couple of seconds in case slide change is slow # but take another in a couple of seconds in case slide change is slow
QtCore.QTimer.singleShot(2500, self.grab_maindisplay) QtCore.QTimer.singleShot(2500, self.display_maindisplay)
else: else:
# If not live, use the slide's thumbnail/icon instead # If not live, use the slide's thumbnail/icon instead
image_path = Path(self.service_item.get_rendered_frame(self.selected_row)) image_path = Path(self.service_item.get_rendered_frame(self.selected_row))
# if self.service_item.is_capable(ItemCapabilities.HasThumbnails):
# image = self.image_manager.get_image(image_path, ImageSource.CommandPlugins)
# self.slide_image = QtGui.QPixmap.fromImage(image)
# else:
# self.slide_image = QtGui.QPixmap(image_path)
# self.slide_image.setDevicePixelRatio(self.main_window.devicePixelRatio())
# self.slide_preview.setPixmap(self.slide_image)
self.preview_display.set_single_image('#000', image_path) self.preview_display.set_single_image('#000', image_path)
else: else:
self.preview_display.go_to_slide(self.selected_row) self.preview_display.go_to_slide(self.selected_row)
self.slide_count += 1 self.slide_count += 1
def display_maindisplay(self):
"""
Gets an image of the display screen and updates the preview frame.
"""
display_image = self.grab_maindisplay()
base64_image = image_to_byte(display_image)
self.preview_display.set_single_image_data('#000', base64_image)
def grab_maindisplay(self): def grab_maindisplay(self):
""" """
Creates an image of the current screen and updates the preview frame. Creates an image of the current screen.
""" """
win_id = QtWidgets.QApplication.desktop().winId() win_id = QtWidgets.QApplication.desktop().winId()
screen = QtWidgets.QApplication.primaryScreen() screen = QtWidgets.QApplication.primaryScreen()
rect = ScreenList().current.display_geometry rect = ScreenList().current.display_geometry
win_image = screen.grabWindow(win_id, rect.x(), rect.y(), rect.width(), rect.height()) win_image = screen.grabWindow(win_id, rect.x(), rect.y(), rect.width(), rect.height())
win_image.setDevicePixelRatio(self.preview_display.devicePixelRatio()) win_image.setDevicePixelRatio(self.preview_display.devicePixelRatio())
# self.slide_preview.setPixmap(win_image) return win_image
self.slide_image = win_image
base64_image = image_to_byte(win_image)
self.preview_display.set_single_image_data('#000', base64_image)
return self.slide_image
def on_slide_selected_next_action(self, checked): def on_slide_selected_next_action(self, checked):
""" """

View File

@ -826,7 +826,7 @@ def test_update_preview_live(mocked_singleShot, mocked_image_manager, registry):
slide_controller.screens.current = {'primary': ''} slide_controller.screens.current = {'primary': ''}
slide_controller.displays = [MagicMock()] slide_controller.displays = [MagicMock()]
slide_controller.display.preview.return_value = QtGui.QImage() slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock() slide_controller.display_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock() slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0 slide_controller.slide_count = 0
@ -836,7 +836,7 @@ def test_update_preview_live(mocked_singleShot, mocked_image_manager, registry):
# THEN: A screen_grab should have been called # THEN: A screen_grab should have been called
assert 0 == slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called' assert 0 == slide_controller.slide_preview.setPixmap.call_count, 'setPixmap should not be called'
assert 0 == slide_controller.display.preview.call_count, 'display.preview() should not be called' assert 0 == slide_controller.display.preview.call_count, 'display.preview() should not be called'
assert 2 == mocked_singleShot.call_count, 'Timer to grab_maindisplay should have been called 2 times' assert 2 == mocked_singleShot.call_count, 'Timer to display_maindisplay should have been called 2 times'
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager not be called' assert 0 == mocked_image_manager.get_image.call_count, 'image_manager not be called'
@ -867,7 +867,7 @@ def test_update_preview_pres(mocked_singleShot, mocked_image_manager, registry):
slide_controller.screens.current = {'primary': ''} slide_controller.screens.current = {'primary': ''}
slide_controller.displays = [MagicMock()] slide_controller.displays = [MagicMock()]
slide_controller.display.preview.return_value = QtGui.QImage() slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock() slide_controller.display_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock() slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0 slide_controller.slide_count = 0
slide_controller.preview_display = MagicMock() slide_controller.preview_display = MagicMock()
@ -877,7 +877,7 @@ def test_update_preview_pres(mocked_singleShot, mocked_image_manager, registry):
# THEN: setPixmap and the image_manager should have been called # THEN: setPixmap and the image_manager should have been called
assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called' assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called'
assert 0 == mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called' assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@ -908,7 +908,7 @@ def test_update_preview_media(mocked_singleShot, mocked_image_manager, registry)
slide_controller.screens.current = {'primary': ''} slide_controller.screens.current = {'primary': ''}
slide_controller.displays = [MagicMock()] slide_controller.displays = [MagicMock()]
slide_controller.display.preview.return_value = QtGui.QImage() slide_controller.display.preview.return_value = QtGui.QImage()
slide_controller.grab_maindisplay = MagicMock() slide_controller.display_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock() slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0 slide_controller.slide_count = 0
slide_controller.preview_display = MagicMock() slide_controller.preview_display = MagicMock()
@ -918,7 +918,7 @@ def test_update_preview_media(mocked_singleShot, mocked_image_manager, registry)
# THEN: setPixmap should have been called # THEN: setPixmap should have been called
assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called' assert 1 == slide_controller.preview_display.set_single_image.call_count, 'set_single_image should be called'
assert 0 == mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called' assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called' assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called'
@ -949,7 +949,7 @@ def test_update_preview_image(mocked_singleShot, mocked_image_manager, registry)
slide_controller.screens = MagicMock() slide_controller.screens = MagicMock()
slide_controller.screens.current = {'primary': ''} slide_controller.screens.current = {'primary': ''}
slide_controller.displays = [MagicMock()] slide_controller.displays = [MagicMock()]
slide_controller.grab_maindisplay = MagicMock() slide_controller.display_maindisplay = MagicMock()
slide_controller.slide_preview = MagicMock() slide_controller.slide_preview = MagicMock()
slide_controller.slide_count = 0 slide_controller.slide_count = 0
slide_controller.preview_display = MagicMock() slide_controller.preview_display = MagicMock()
@ -959,10 +959,31 @@ def test_update_preview_image(mocked_singleShot, mocked_image_manager, registry)
# THEN: setPixmap and display.preview should have been called # THEN: setPixmap and display.preview should have been called
assert 1 == slide_controller.preview_display.go_to_slide.call_count, 'go_to_slide should be called' assert 1 == slide_controller.preview_display.go_to_slide.call_count, 'go_to_slide should be called'
assert 0 == mocked_singleShot.call_count, 'Timer to grab_maindisplay should not be called' assert 0 == mocked_singleShot.call_count, 'Timer to display_maindisplay should not be called'
assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called' assert 0 == mocked_image_manager.get_image.call_count, 'image_manager should not be called'
@patch(u'openlp.core.ui.slidecontroller.image_to_byte')
def test_display_maindisplay(mocked_image_to_byte, registry):
"""
Test the display_maindisplay method
Here a string is substituted for what would be a screen capture of the display
The `image_to_byte` mocked funtion just adds " bytified" to the string
"""
# GIVEN: A mocked slide controller, with mocked functions
slide_controller = SlideController(None)
slide_controller.grab_maindisplay = MagicMock(return_value='placeholder')
slide_controller.preview_display = MagicMock()
mocked_image_to_byte.side_effect = lambda x: '{} bytified'.format(x)
# WHEN: display_maindisplay is called
slide_controller.display_maindisplay()
# THEN: Should have grabbed the maindisplay and set to placeholder with a black background
slide_controller.grab_maindisplay.assert_called_once()
slide_controller.preview_display.set_single_image_data.assert_called_once_with('#000', 'placeholder bytified')
def test_paint_event_text_fits(): def test_paint_event_text_fits():
""" """
Test the paintEvent method when text fits the label Test the paintEvent method when text fits the label