Skip to content

Commit

Permalink
Added PyGTK as a screenshot taking module
Browse files Browse the repository at this point in the history
Fixes #1
  • Loading branch information
cristii006 authored and Mihai Pârvu committed Sep 11, 2018
1 parent b0c7b4a commit 258a563
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 26 deletions.
1 change: 1 addition & 0 deletions atest/resources/common.robot
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
*** Settings ***
Library ScreenCapLibrary
Library ScreenCapLibrary screenshot_module=PyGTK WITH NAME ScreenCapLibraryGtk
Library OperatingSystem
Library Collections

Expand Down
4 changes: 2 additions & 2 deletions atest/screenshot_directory.robot
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ ${FIRST_SCREENSHOT} = ${BASENAME}_1.png

*** Test Cases ***
Set Screenshot Directory
${old} = Set Screenshot Directory ${SCREENSHOT DIR}
${old} = ScreenCapLibrary.Set Screenshot Directory ${SCREENSHOT DIR}
Paths Should Be Equal ${OUTPUT DIR} ${old}
Take Screenshot
ScreenCapLibrary.Take Screenshot
Screenshot Should Exist ${FIRST SCREENSHOT}

*** Keywords ***
Expand Down
24 changes: 15 additions & 9 deletions atest/take_screenshot.robot
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ ${FIRST_CUSTOM_SCREENSHOT} ${OUTPUTDIR}${/}foo_1.png
${SECOND_CUSTOM_SCREENSHOT} ${OUTPUTDIR}${/}foo_2.png
${PNG_CUSTOM_SCREENSHOT} ${OUTPUTDIR}${/}foo.png
${JPG_CUSTOM_SCREENSHOT} ${OUTPUTDIR}${/}foo.jpg
${GTK_PNG_SCREENSHOT} ${OUTPUTDIR}${/}pygtk_png.png
${GTK_JPEG_SCREENSHOT} ${OUTPUTDIR}${/}pygtk_jpeg.jpeg

*** Test Cases ***
Screenshot Is Taken
Expand All @@ -23,43 +25,47 @@ Each Screenshot Gets Separate Index
Take Screenshot and Verify ${FIRST_SCREENSHOT} ${SECOND_SCREENSHOT}

Basename May Be Defined
Repeat Keyword 2 Take Screenshot foo
Repeat Keyword 2 ScreenCapLibrary.Take Screenshot foo
Screenshots Should Exist ${OUTPUTDIR} ${FIRST_CUSTOM_SCREENSHOT} ${SECOND_CUSTOM_SCREENSHOT}

Basename With Extension Turns Off Index Generation
Repeat Keyword 3 Take Screenshot xxx.jpg jpg
Repeat Keyword 2 Take Screenshot yyy.jpeg jpeg
Repeat Keyword 3 ScreenCapLibrary.Take Screenshot xxx.jpg jpg
Repeat Keyword 2 ScreenCapLibrary.Take Screenshot yyy.jpeg jpeg
Screenshots Should Exist ${OUTPUTDIR} ${OUTPUTDIR}${/}xxx.jpg ${OUTPUTDIR}${/}yyy.jpeg

Screenshot Width Can Be Given
Take Screenshot width=300px
ScreenCapLibrary.Take Screenshot width=300px
Screenshots Should Exist ${OUTPUTDIR} ${FIRST_SCREENSHOT}

Basename With Non-existing Directories Fails
[Documentation] FAIL Directory '${OUTPUTDIR}${/}non-existing' where to save the screenshot does not exist
Take Screenshot ${OUTPUTDIR}${/}non-existing${/}foo
ScreenCapLibrary.Take Screenshot ${OUTPUTDIR}${/}non-existing${/}foo

Without Embedding
Take Screenshot Without Embedding no_embed.png
ScreenCapLibrary.Take Screenshot Without Embedding no_embed.png

Png Screenshot Quality
Compare Size ${PNG_CUSTOM_SCREENSHOT} png

Jpg Screenshot Quality
Compare Size ${JPG_CUSTOM_SCREENSHOT} jpg

Png Screenshot Gtk
ScreenCapLibraryGtk.Take Screenshot ${GTK_PNG_SCREENSHOT} png
ScreenCapLibraryGtk.Take Screenshot ${GTK_JPEG_SCREENSHOT} jpeg

*** Keywords ***
Take Screenshot And Verify
[Arguments] @{expected files}
${path}= Take Screenshot format=png
${path}= ScreenCapLibrary.Take Screenshot format=png
Screenshots Should Exist ${OUTPUTDIR} @{expected files}
[Return] ${path}

Compare Size
[Arguments] ${screenshot_name} ${screenshot_format}
Take Screenshot ${screenshot_name} ${screenshot_format} quality=100
ScreenCapLibrary.Take Screenshot ${screenshot_name} ${screenshot_format} quality=100
${high_quality_size}= Get File Size ${screenshot_name}
Take Screenshot ${screenshot_name} ${screenshot_format} quality=0
ScreenCapLibrary.Take Screenshot ${screenshot_name} ${screenshot_format} quality=0
${low_quality_size}= Get File Size ${screenshot_name}
${decrease}= Evaluate ${high_quality_size} - ${low_quality_size}
${percentage_size_decrease}= Evaluate float(${decrease}) / float(${high_quality_size}) * 100
Expand Down
43 changes: 28 additions & 15 deletions src/ScreenCapLibrary/ScreenCapLibrary.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from robot.utils import get_link_path, abspath
from robot.libraries.BuiltIn import BuiltIn
from .version import VERSION
from .pygtk import _take_gtk_screenshot

__version__ = VERSION

Expand All @@ -43,6 +44,8 @@ class ScreenCapLibrary:
- [https://pillow.readthedocs.io | Pillow] used on top of ``mss`` in order to save the screenshots in JPG/JPEG format.
- [http://pygtk.org/ | PyGTK] is an alternative to ``mss`` for taking screenshots when using VNC.
= Where screenshots are saved =
By default screenshots are saved into the same directory where the Robot
Expand All @@ -57,11 +60,14 @@ class ScreenCapLibrary:

ROBOT_LIBRARY_VERSION = __version__

def __init__(self, screenshot_directory=None, format='png', quality=50):
"""Configure where screenshots are saved.
def __init__(self, screenshot_module=None, screenshot_directory=None, format='png', quality=50):
"""
``screenshot_module`` specifies the module or tool to use when taking screenshots using this library.
If no tool or module is specified, ``mss`` will be used by default. For running
on Linux with VNC, use ``PyGTK``.
If ``screenshot_directory`` is not given, screenshots are saved into
same directory as the log file. The directory can also be set using
To configure where screenshots are saved use ``screenshot_directory``. If no value is given,
screenshots are saved into same directory as the log file. The directory can also be set using
`Set Screenshot Directory` keyword.
``format`` specifies the format in which the screenshots will be saved.
Expand All @@ -80,6 +86,7 @@ def __init__(self, screenshot_directory=None, format='png', quality=50):
| Library | Screenshot | format=jpg |
| Library | Screenshot | quality=0 |
"""
self._screenshot_module = screenshot_module
self._given_screenshot_dir = self._norm_path(screenshot_directory)
self._format = format
self._quality = quality
Expand Down Expand Up @@ -184,6 +191,23 @@ def _take_jpg_screenshot(self, name, format, quality):
img.save(path, quality=self._pil_quality_conversion(quality))
return path

def _take_screenshot(self, name, format, quality):
format = (format or self._format).lower()
quality = quality or self._quality
if self._screenshot_module and self._screenshot_module.lower() == 'pygtk':
format = 'jpeg' if format == 'jpg' else format
if format == 'png':
quality = self._compression_value_conversion(quality)
path = self._save_screenshot_path(name, format)
return _take_gtk_screenshot(path, format, quality)
else:
if format == 'png':
return self._take_png_screenshot(name, format, quality)
elif format in ['jpg', 'jpeg']:
return self._take_jpg_screenshot(name, format, quality)
else:
raise RuntimeError("Invalid screenshot format.")

def take_screenshot(self, name='screenshot', format=None, quality=None, width='800px'):
"""Takes a screenshot in the specified format at library import and
embeds it into the log file (PNG by default).
Expand Down Expand Up @@ -223,17 +247,6 @@ def take_screenshot(self, name='screenshot', format=None, quality=None, width='8
self._embed_screenshot(path, width)
return path

def _take_screenshot(self, name, format, quality):
format = (format or self._format).lower()
quality = quality or self._quality
if format == 'png':
path = self._take_png_screenshot(name, format, quality)
elif format in ['jpg', 'jpeg']:
path = self._take_jpg_screenshot(name, format, quality)
else:
raise RuntimeError("Invalid screenshot format.")
return path

def _embed_screenshot(self, path, width):
link = get_link_path(path, self._log_dir)
logger.info('<a href="%s"><img src="%s" width="%s"></a>' % (link, link, width), html=True)
Expand Down
71 changes: 71 additions & 0 deletions src/ScreenCapLibrary/pygtk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

try:
from gtk import gdk
except ImportError:
gdk = None

try:
from gi.repository import Gdk
except ImportError:
Gdk = None


def _gtk_quality(format, quality):
quality_setting = {}
if format == 'png':
quality_setting['compression'] = str(quality)
else:
quality_setting['quality'] = str(quality)
return quality_setting


def _take_gtk_screenshot(path, format, quality):
if not gdk and not Gdk:
raise RuntimeError('PyGTK not installed/supported on this platform.')
if gdk:
_take_gtk_screenshot_py2(path, format, quality)
elif Gdk:
_take_gtk_screenshot_py3(path, format, quality)


def _take_gtk_screenshot_py2(path, format, quality):
window = gdk.get_default_root_window()
if not window:
raise RuntimeError('Taking screenshot failed.')
width, height = window.get_size()
pb = gdk.Pixbuf(gdk.COLORSPACE_RGB, False, 8, width, height)
pb = pb.get_from_drawable(window, window.get_colormap(),
0, 0, 0, 0, width, height)
if not pb:
raise RuntimeError('Taking screenshot failed.')
quality_setting = _gtk_quality(format, quality)
pb.save(path, format, quality_setting)
return path


def _take_gtk_screenshot_py3(path, format, quality):
window = Gdk.get_default_root_window()
if not window:
raise RuntimeError('Taking screenshot failed.')
width = window.get_width()
height = window.get_height()
pb = Gdk.pixbuf_get_from_window(window, 0, 0, width, height)
if not pb:
raise RuntimeError('Taking screenshot failed.')
quality_setting = _gtk_quality(format, quality)
pb.savev(path, format, [list(quality_setting.keys())[0]], [list(quality_setting.values())[0]])
return path

0 comments on commit 258a563

Please sign in to comment.