diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py
index 67ac409df..0793e0644 100644
--- a/openlp/core/lib/__init__.py
+++ b/openlp/core/lib/__init__.py
@@ -144,12 +144,17 @@ def build_icon(icon):
return button_icon
-def image_to_byte(image):
+def image_to_byte(image, base_64=True):
"""
Resize an image to fit on the current screen for the web and returns it as a byte stream.
``image``
The image to converted.
+
+ ``base_64``
+ If True returns the image as Base64 bytes, otherwise
+ the image is returned as a byte array
+ To preserve original intention, this defaults to True
"""
log.debug('image_to_byte - start')
byte_array = QtCore.QByteArray()
@@ -158,6 +163,8 @@ def image_to_byte(image):
buffie.open(QtCore.QIODevice.WriteOnly)
image.save(buffie, "PNG")
log.debug('image_to_byte - end')
+ if not base_64:
+ return byte_array
# convert to base64 encoding so does not get missed!
return bytes(byte_array.toBase64()).decode('utf-8')
diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py
index 043838f36..e82cdc695 100644
--- a/openlp/core/ui/slidecontroller.py
+++ b/openlp/core/ui/slidecontroller.py
@@ -815,7 +815,7 @@ class SlideController(DisplayController):
self.update_preview()
else:
self.preview_widget.change_slide(index)
- self.slide_selected()
+ self.slide_selected()
def main_display_set_background(self):
"""
@@ -1046,7 +1046,7 @@ class SlideController(DisplayController):
else:
row = self.preview_widget.slide_count() - 1
self.preview_widget.change_slide(row)
- self.slide_selected()
+ self.slide_selected()
def on_slide_selected_previous(self):
"""
@@ -1069,7 +1069,7 @@ class SlideController(DisplayController):
else:
row = 0
self.preview_widget.change_slide(row)
- self.slide_selected()
+ self.slide_selected()
def on_toggle_loop(self):
"""
diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py
index 08f2d68dc..7480d3b1b 100644
--- a/openlp/plugins/presentations/lib/impresscontroller.py
+++ b/openlp/plugins/presentations/lib/impresscontroller.py
@@ -485,11 +485,11 @@ class ImpressDocument(PresentationDocument):
titles = []
notes = []
pages = self.document.getDrawPages()
- for slide_no in range(pages.getCount()):
+ for slide_no in range(1, pages.getCount() + 1):
titles.append(
- self.__get_text_from_page(slide_no+1, TextType.Title).
+ self.__get_text_from_page(slide_no, TextType.Title).
replace('\n', ' ') + '\n')
- note = self.__get_text_from_page(slide_no+1, TextType.Notes)
+ note = self.__get_text_from_page(slide_no, TextType.Notes)
if len(note) == 0:
note = ' '
notes.append(note)
diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py
index c31e98a21..5a037ec48 100644
--- a/openlp/plugins/presentations/lib/presentationcontroller.py
+++ b/openlp/plugins/presentations/lib/presentationcontroller.py
@@ -301,7 +301,7 @@ class PresentationDocument(object):
if os.path.exists(titles_file):
try:
with open(titles_file) as fi:
- titles = fi.read().splitlines(keepends=True)
+ titles = fi.read().splitlines()
except:
log.exception('Failed to open/read existing titles file')
titles = []
diff --git a/openlp/plugins/remotes/html/openlp.js b/openlp/plugins/remotes/html/openlp.js
index 3ca8806f2..4952878e3 100644
--- a/openlp/plugins/remotes/html/openlp.js
+++ b/openlp/plugins/remotes/html/openlp.js
@@ -98,7 +98,7 @@ window.OpenLP = {
text += ("
" + slide["notes"] + "
");
text = text.replace(/\n/g, '
');
if (slide["img"])
- text += "";
+ text += "";
var li = $("").append(
$("").attr("value", parseInt(idx, 10)).html(text));
if (slide["selected"]) {
diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py
index f3f8c8f7d..ac513a236 100644
--- a/openlp/plugins/remotes/lib/httprouter.py
+++ b/openlp/plugins/remotes/lib/httprouter.py
@@ -151,7 +151,7 @@ class HttpRouter(object):
('^/(stage)$', {'function': self.serve_file, 'secure': False}),
('^/(main)$', {'function': self.serve_file, 'secure': False}),
(r'^/files/(.*)$', {'function': self.serve_file, 'secure': False}),
- (r'^/(.*)/thumbnails/(.*)$', {'function': self.serve_thumbnail, 'secure': False}),
+ (r'^/(.*)/thumbnails([^/]+)?/(.*)$', {'function': self.serve_thumbnail, 'secure': False}),
(r'^/api/poll$', {'function': self.poll, 'secure': False}),
(r'^/main/poll$', {'function': self.main_poll, 'secure': False}),
(r'^/main/image$', {'function': self.main_image, 'secure': False}),
@@ -394,24 +394,38 @@ class HttpRouter(object):
self.send_header('Content-type', 'text/plain')
return ext
- def serve_thumbnail(self, controller_name=None, file_name=None):
+ def serve_thumbnail(self, controller_name=None, dimensions=None, file_name=None):
"""
Serve an image file. If not found return 404.
"""
- log.debug('serve thumbnail %s/thumbnails/%s' % (controller_name, file_name))
+ log.debug('serve thumbnail %s/thumbnails%s/%s' % (controller_name,
+ dimensions, file_name))
supported_controllers = ['presentations']
content = ''
if controller_name and file_name:
if controller_name in supported_controllers:
full_path = urllib.parse.unquote(file_name)
- if not '..' in full_path:
+ if not '..' in full_path: # no hacking please
+ width = 80
+ height = 80
+ if dimensions:
+ match = re.search('(\d+)x(\d+)',
+ dimensions)
+ if match:
+ width = int(match.group(1))
+ height = int(match.group(2))
+ # let's make sure that the dimensions are within reason
+ width = min(width,1000)
+ width = max(width,10)
+ height = min(height,1000)
+ height = max(height,10)
full_path = os.path.normpath(os.path.join(
AppLocation.get_section_data_path(controller_name),
'thumbnails/' + full_path))
if os.path.exists(full_path):
ext = self.send_appropriate_header(full_path)
- file_handle = open(full_path, 'rb')
- content = file_handle.read()
+ content = image_to_byte(resize_image(full_path, width,
+ height),False)
if len(content)==0:
content = self.do_not_found()
return content
@@ -514,7 +528,6 @@ class HttpRouter(object):
dataPath = AppLocation.get_data_path()
if frame['image'][0:len(dataPath)] == dataPath:
item['img'] = frame['image'][len(dataPath):]
- #'data:image/png;base64,' + str(image_to_byte(resize_image(frame['image'], 80, 80)))
item['text'] = str(frame['title'])
item['html'] = str(frame['title'])
item['selected'] = (self.live_controller.selected_row == index)
diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py
index f0c1a261b..e36c421b1 100644
--- a/tests/functional/openlp_plugins/remotes/test_router.py
+++ b/tests/functional/openlp_plugins/remotes/test_router.py
@@ -30,6 +30,7 @@
This module contains tests for the lib submodule of the Remotes plugin.
"""
import os
+import urllib.request
from unittest import TestCase
from tempfile import mkstemp
@@ -38,6 +39,7 @@ from PyQt4 import QtGui
from openlp.core.common import Settings
from openlp.plugins.remotes.lib.httpserver import HttpRouter
from mock import MagicMock, patch, mock_open
+from urllib.parse import urlparse
__default_settings__ = {
'remotes/twelve hour': True,
@@ -181,16 +183,30 @@ class TestRouter(TestCase):
self.router.send_header = MagicMock()
self.router.end_headers = MagicMock()
self.router.wfile = MagicMock()
+ file_name = 'another%20test/slide1.png'
+ full_path = os.path.normpath(os.path.join('thumbnails',file_name))
+ width = 120
+ height = 90
with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
patch('builtins.open', mock_open(read_data='123')), \
- patch('openlp.plugins.remotes.lib.httprouter.AppLocation') as mocked_location:
+ patch('openlp.plugins.remotes.lib.httprouter.AppLocation') \
+ as mocked_location, \
+ patch('openlp.plugins.remotes.lib.httprouter.resize_image') \
+ as mocked_resize, \
+ patch('openlp.plugins.remotes.lib.httprouter.image_to_byte')\
+ as mocked_image_to_byte:
mocked_exists.return_value = True
+ mocked_image_to_byte.return_value = '123'
mocked_location.get_section_data_path.return_value = ''
# WHEN: pass good controller and filename
result = self.router.serve_thumbnail('presentations',
- 'another%20test/slide1.png')
+ '{0}x{1}'.format(width, height),
+ file_name)
# THEN: a file should be returned
- self.assertEqual(len(self.router.send_header.mock_calls), 1,
+ self.assertEqual(self.router.send_header.call_count, 1,
'One header')
self.assertEqual(result, '123', 'The content should match \'123\'')
- mocked_exists.assert_called_with(os.path.normpath('thumbnails/another test/slide1.png'))
+ mocked_exists.assert_called_with(urllib.parse.unquote(full_path))
+ self.assertEqual(mocked_image_to_byte.call_count, 1, 'Called once')
+ mocked_resize.assert_called_once_with(
+ urllib.parse.unquote(full_path), width, height)