Added resizing capabilities to the thumbnails

Fixed a problem with setting the presentation slides from the remote
This commit is contained in:
Felipe Polo-Wood 2013-10-29 11:38:28 -04:00
parent 9a07d6887b
commit 6d464dec4b
7 changed files with 56 additions and 20 deletions

View File

@ -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')

View File

@ -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):
"""

View File

@ -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)

View File

@ -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 = []

View File

@ -98,7 +98,7 @@ window.OpenLP = {
text += ("<div style='font-size:smaller;font-weight:normal'>" + slide["notes"] + "</div>");
text = text.replace(/\n/g, '<br />');
if (slide["img"])
text += "<img src='" + slide["img"] + "'>";
text += "<img src='" + slide["img"].replace("/thumbnails/", "/thumbnails80x80/") + "'>";
var li = $("<li data-icon=\"false\">").append(
$("<a href=\"#\">").attr("value", parseInt(idx, 10)).html(text));
if (slide["selected"]) {

View File

@ -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)

View File

@ -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)