Merge branch 'keynote-ppt-mac' into 'master'

Add support for presentation with Keynote and PowerPoint on Mac

See merge request openlp/openlp!205
This commit is contained in:
Raoul Snyman 2020-09-13 14:49:02 +00:00
commit fdf5cce5f2
6 changed files with 971 additions and 1 deletions

View File

@ -34,7 +34,7 @@ install:
# Install Windows only dependencies
- cmd: python -m pip install pyodbc pypiwin32
# Mac only dependencies
- sh: python -m pip install pyobjc-core pyobjc-framework-Cocoa
- sh: python -m pip install pyobjc-core pyobjc-framework-Cocoa py-applescript
build: off

View File

@ -286,6 +286,8 @@ class Settings(QtCore.QSettings):
'presentations/Impress': QtCore.Qt.Checked,
'presentations/Powerpoint': QtCore.Qt.Checked,
'presentations/Pdf': QtCore.Qt.Checked,
'presentations/Keynote': QtCore.Qt.Checked,
'presentations/PowerPointMac': QtCore.Qt.Checked,
'presentations/presentations files': [],
'presentations/thumbnail_scheme': '',
'presentations/powerpoint slide click advance': QtCore.Qt.Unchecked,

View File

@ -0,0 +1,310 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
This module is a base to be used for Mac OS X presentation modules using applescript
to control presentation application, such as keynote and powerpoint for mac
"""
import logging
import applescript
from openlp.core.common import is_macosx
from openlp.core.display.screens import ScreenList
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
log = logging.getLogger(__name__)
DEFAULT_APPLESCRIPT = """
on check_available()
return false
end check_available
"""
class AppleScriptBaseController(PresentationController):
"""
Class to control interactions with a Presentation program like Keynote or Powerpoint.
It uses py-applescript to compile and execute applescript to Load and Close the Presentation.
As well as triggering the correct activities based on the users input.
"""
log.info('ApplescriptController loaded')
base_class = True
def __init__(self, plugin, name, doc):
"""
Initialise the class
"""
super(AppleScriptBaseController, self).__init__(plugin, name, doc)
# Script expected to be overwritten by subclasses
self.applescript = applescript.AppleScript(DEFAULT_APPLESCRIPT)
def check_available(self):
"""
Program is able to run on this machine.
"""
log.debug('check_available')
if not is_macosx():
return False
try:
return self.applescript.call('check_available')
except Exception:
log.exception('script execution failed')
return False
def start_process(self):
"""
Loads the presentation application
"""
log.debug('start_process')
try:
self.applescript.call('start_application')
except Exception:
log.exception('script execution failed')
def kill(self):
"""
Called at system exit to clean up any running presentations.
"""
log.debug('Kill presentation program')
while self.docs:
self.docs[0].close_presentation()
try:
self.applescript.call('stop_application')
except Exception:
log.exception('script execution failed')
class AppleScriptBaseDocument(PresentationDocument):
"""
Class which holds information and controls a single presentation.
"""
def __init__(self, controller, document_path):
"""
Constructor, store information about the file and initialise.
:param controller:
:param pathlib.Path document_path: Path to the document to load
:rtype: None
"""
log.debug('Init Presentation Applescript')
super().__init__(controller, document_path)
self.presentation_loaded = False
self.is_blanked = False
self.slide_count = 0
def load_presentation(self):
"""
Called when a presentation is added to the SlideController. Opens the presentation file.
"""
log.debug('load_presentation')
# check if there already exists thumbnails etc. If so skip loading the presentation.
files = self.get_thumbnail_folder().glob('*')
if len(list(files)) > 0:
self.presentation_loaded = True
return self.presentation_loaded
try:
self.controller.applescript.call('create_thumbs', str(self.file_path), str(self.get_thumbnail_folder()))
self.presentation_loaded = True
except Exception:
log.exception('script execution failed')
self.presentation_loaded = False
return self.presentation_loaded
def create_thumbnails(self):
"""
Create the thumbnail images for the current presentation.
"""
log.debug('create_thumbnails')
# No need to do anything, already created thumbs in load_presentation
def close_presentation(self):
"""
Close presentation and clean up objects. This is triggered by a new object being added to SlideController or
OpenLP being shut down.
"""
log.debug('close_presentation')
if self.presentation_loaded:
try:
self.controller.applescript.call('close_presentation')
except Exception:
log.exception('script execution failed')
self.presentation_loaded = False
self.controller.remove_doc(self)
def is_loaded(self):
"""
Returns ``True`` if a presentation is loaded.
"""
self.presentation_loaded = False
log.debug('is_loaded')
try:
self.presentation_loaded = self.controller.applescript.call('is_loaded', str(self.file_path))
except Exception:
log.exception('script execution failed')
return self.presentation_loaded
def is_active(self):
"""
Returns ``True`` if a presentation is currently active.
"""
log.debug('is_active')
if not self.is_loaded():
return False
try:
return self.controller.applescript.call('is_active')
except Exception:
log.exception('script execution failed')
return False
def unblank_screen(self):
"""
Unblanks (restores) the presentation.
"""
log.debug('unblank_screen')
try:
self.controller.applescript.call('unblank')
except Exception:
log.exception('script execution failed')
self.is_blanked = False
def blank_screen(self):
"""
Blanks the screen.
"""
log.debug('blank_screen')
try:
self.controller.applescript.call('blank')
except Exception:
log.exception('script execution failed')
def is_blank(self):
"""
Returns ``True`` if screen is blank.
"""
log.debug('is_blank')
return self.is_blanked
def stop_presentation(self):
"""
Stops the current presentation and hides the output. Used when blanking to desktop.
"""
try:
self.controller.applescript.call('stop_presentation')
except Exception:
log.exception('script execution failed')
def start_presentation(self):
"""
Starts a presentation from the beginning.
"""
log.debug('start_presentation')
try:
fullscreen = (ScreenList().current.custom_geometry is None)
size = ScreenList().current.display_geometry
self.controller.applescript.call('start_presentation', str(self.file_path), size.top(), size.left(),
size.width(), size.height(), fullscreen)
except Exception:
log.exception('script execution failed')
def get_slide_number(self):
"""
Returns the current slide number.
"""
log.debug('get_slide_number')
ret = 0
try:
ret = int(self.controller.applescript.call('get_current_slide'))
except Exception:
log.exception('script execution failed')
return ret
def get_slide_count(self):
"""
Returns total number of slides.
"""
log.debug('get_slide_count')
return self.slide_count
def goto_slide(self, slide_no):
"""
Moves to a specific slide in the presentation.
:param slide_no: The slide the text is required for, starting at 1
"""
log.debug('goto_slide')
try:
self.controller.applescript.call('goto_slide', slide_no)
except Exception:
log.exception('script execution failed')
def next_step(self):
"""
Triggers the next effect of slide on the running presentation.
"""
log.debug('next_step')
past_end = False
try:
self.controller.applescript.call('next_slide')
# TODO: detect past end
except Exception:
log.exception('script execution failed')
return past_end
def previous_step(self):
"""
Triggers the previous slide on the running presentation.
"""
log.debug('previous_step')
before_start = False
try:
self.controller.applescript.call('previous_slide')
# TODO: detect before start
except Exception:
log.exception('script execution failed')
return before_start
def get_slide_text(self, slide_no):
"""
Returns the text on the slide.
:param slide_no: The slide the text is required for, starting at 1
"""
return ''
def get_slide_notes(self, slide_no):
"""
Returns the text on the slide.
:param slide_no: The slide the text is required for, starting at 1
"""
return ''
def create_titles_and_notes(self):
"""
Writes the list of titles (one per slide)
to 'titles.txt'
and the notes to 'slideNotes[x].txt'
in the thumbnails directory
"""
# Already done in create thumbs
pass

View File

@ -0,0 +1,307 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
This module is for controlling keynote.
"""
import logging
import shutil
import applescript
from openlp.plugins.presentations.lib.applescriptbasecontroller import AppleScriptBaseController,\
AppleScriptBaseDocument
log = logging.getLogger(__name__)
KEYNOTE_APPLESCRIPT = """
on check_available()
try
set appID to "com.apple.iWork.Keynote"
if exists application id appID then
return true
end if
return false
on error
return false
end try
end check_available
on get_version()
return (version of application "Keynote")
end get_version
on start_application()
tell application "Keynote"
launch
end tell
end start_application
on close_presentation()
try
tell application "Keynote"
-- close presentation
close front document
end tell
end try
end close_presentation
on create_thumbs(documentName, outputPath)
set outputPathHfs to POSIX file outputPath
tell application "Keynote"
if playing is true then tell the front document to stop
-- Open document
open documentName
-- hide keynote
tell application "System Events"
set visible of application process "Keynote" to false
end tell
-- Export slides to png
export front document as slide images to file outputPathHfs with properties ¬
{image format:PNG, skipped slides:false}
-- Get the Presentation Notes and slide title
set the slideTitles to ""
tell the front document
repeat with i from 1 to the count of slides
tell slide i
set noteFilename to outputPath & "/slideNotes" & (slide number as string) & ".txt"
if skipped is false then
-- Save the notes to file
set noteText to presenter notes of it
set noteFile to open for access noteFilename with write permission
write noteText to noteFile
close access noteFile
-- if title is available, save it
if title showing is true then
set the slideTitle to object text of default title item
set the slideTitles to slideTitles & slideTitle & return
else
set the slideTitles to "slide " & (slide number as string) & return
end if
end if
end tell
end repeat
end tell
-- Save the titles to file
set titlesFilename to outputPath & "/titles.txt"
set titlesFile to open for access titlesFilename with write permission
write slideTitles to titlesFile
close access titlesFile
-- close presentation
close front document
end tell
end create_thumbs
--create_thumbs("/Users/tgc/Downloads/keynote-pres.key", "/Users/tgc/Downloads/tmp/")
on start_presentation(documentName, new_top, new_left_pos, new_width, new_height, fullscreen)
tell application "Keynote"
if playing is true then tell the front document to stop
-- Open document
open documentName
--start front document from the first slide of front document
--activate
end tell
-- There seems to be no applescript command to start presentation in window mode
-- so we that by faking mouse clicks (requires accessability rights)
tell application "System Events"
tell process "Keynote"
click (menu bar item 10 of menu bar 1)
click menu item 2 of menu 1 of menu bar item 10 of menu bar 1
end tell
end tell
tell application "Keynote"
-- set the size and postion on presentation window
if fullscreen is true then
-- move window to right screen
set bounds of front window to {new_top, new_left_pos, new_width, new_height}
-- put it in fullscreen mode
tell application "System Events" to tell process "Keynote"
set value of attribute "AXFullScreen" of front window to true
end tell
else
set bounds of front window to {new_top, new_left_pos, new_width, new_height}
end if
activate
end tell
end start_presentation
--start_presentation("Users:solva_a:Downloads:tomas:applescript:keynote-pres.key", 10, 10, 640, 480, false)
on stop_presentation()
tell application "Keynote"
--activate
-- stop presenting
if playing is true then tell the front document to stop
-- close presentation
close front document
-- hide keynote
tell application "System Events"
set visible of application process "Keynote" to false
end tell
end tell
end stop_presentation
on is_loaded(documentPath)
set documentOldStylePath to POSIX file documentPath as alias
tell application "Keynote"
return (file of front document as string is (documentOldStylePath as string))
end tell
end is_loaded
on is_active()
tell application "Keynote"
-- print(?) true/false playing state
return playing
end tell
end is_active
on next_slide()
tell application "Keynote"
--activate
if playing is false then start front document from the first slide of front document
show next
-- Print(?) slide number
slide number
end tell
end next_slide
on previous_slide()
tell application "Keynote"
if playing is false then start front document from the first slide of front document
show previous
-- Print(?) slide number
slide number
end tell
end previous_slide
on goto_slide(slideNumber)
tell application "Keynote"
if playing is false then
start front document from slide slideNumber of front document
else
set the current slide to the first slide whose slide number is slideNumber
end if
end tell
end goto_slide
on get_current_slide()
tell application "Keynote"
-- Print(?) slide number
slide number
end tell
end get_current_slide
on blank()
tell application "Keynote"
tell application "System Events" to keystroke "b"
end tell
end blank
on unblank()
tell application "Keynote"
tell application "System Events" to keystroke "b"
end tell
end blank
"""
class KeynoteController(AppleScriptBaseController):
"""
Class to control interactions with Keynote.
As well as triggering the correct activities based on the users input.
"""
log.info('KeynoteController loaded')
base_class = False
def __init__(self, plugin):
"""
Initialise the class
"""
log.debug('Initialising')
super(KeynoteController, self).__init__(plugin, 'Keynote', KeynoteDocument)
# Compiled script expected to be set by subclasses
try:
self.applescript = applescript.AppleScript(KEYNOTE_APPLESCRIPT)
except applescript.ScriptError:
log.exception('Compilation of Keynote applescript failed')
self.supports = ['key']
self.also_supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
def check_available(self):
"""
Program is able to run on this machine.
"""
ret = super().check_available()
if ret:
# Powerpoint is available! now check if the version is 10.1 or above
try:
version = self.applescript.call('get_version')
except Exception:
log.exception('script execution failed')
return False
try:
versions = version.split('.')
major_version = int(versions[0])
if major_version == 10:
minor_version = int(versions[1])
if minor_version >= 1:
return True
elif major_version > 10:
return True
except ValueError:
pass
return False
class KeynoteDocument(AppleScriptBaseDocument):
"""
Class which holds information and controls a single presentation.
"""
def __init__(self, controller, document_path):
"""
Constructor, store information about the file and initialise.
:param controller:
:param pathlib.Path document_path: Path to the document to load
:rtype: None
"""
log.debug('Init Presentation KeynoteDocument')
super().__init__(controller, document_path)
self.presentation_loaded = False
self.is_blank = False
def load_presentation(self):
ret = super().load_presentation()
if ret:
# Keynote will name the thumbnails in the format: <sha256>.001.png, we need to convert to slide1.png
old_images = list(self.get_thumbnail_folder().glob('*.png'))
# if the convertion was already done, don't do it again
if self.get_thumbnail_folder() / 'slide1.png' in old_images:
return True
self.slide_count = len(old_images)
for old_image in old_images:
# get the image name in format 001.png
number_name = old_image.name.split('.', 1)[1]
# get the image name in format 1.png
number_name = number_name.lstrip('0')
new_name = 'slide' + number_name
shutil.move(old_image, self.get_thumbnail_folder() / new_name)
return ret

View File

@ -0,0 +1,347 @@
# -*- coding: utf-8 -*-
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2020 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
This module is for controlling keynote.
"""
import logging
import applescript
try:
import fitz
PYMUPDF_AVAILABLE = True
except ImportError:
PYMUPDF_AVAILABLE = False
from openlp.plugins.presentations.lib.applescriptbasecontroller import AppleScriptBaseController,\
AppleScriptBaseDocument
log = logging.getLogger(__name__)
POWERPOINT_MAC_APPLESCRIPT = """
on check_available()
set appID to "com.microsoft.PowerPoint"
set doesExist to false
try
tell application "Finder" to get application file id appID
set doesExist to true
end try
return doesExist
end check_available
on get_version()
return (version of application "Microsoft PowerPoint")
end get_version
on start_application()
tell application "Microsoft PowerPoint"
launch
-- Wait for powerpoint to start
tell application "System Events"
repeat while true
set PowerPointUp to (count of (every process whose name is "Microsoft PowerPoint")) > 0
if PowerPointUp then
exit repeat
else
delay 0.2
end if
end repeat
end tell
end tell
end start_application
-- helper function to write text to files
on write_file(fileName, theData)
set fileDescriptor to open for access the fileName with write permission
write theData to fileDescriptor as «class utf8»
close access fileDescriptor
end write_file
-- helper function to create empty file
on create_empty_file(f)
write_file(f, "")
return (POSIX path of f) as POSIX file
end create_empty_file
on create_thumbs(documentName, outputPath)
tell application "Microsoft PowerPoint"
-- Open document
open documentName
-- wait for document to load
repeat until document window 1 exists
delay 0.2
end repeat
-- Export slides to jpg
--save active presentation in outputPath as save as PNG
-- Export slides to pdf
save active presentation in my create_empty_file(outputPath & "/tmp.pdf") as save as PDF
-- Get the Presentation Notes and slide title
set the slideTitles to ""
set titleTypes to {placeholder type title placeholder, placeholder type center title placeholder, ¬
placeholder type vertical title placeholder}
repeat with tSlide in (get slides of active presentation)
-- Only handle non-hidden slides
if hidden of slide show transition of tSlide is false then
--text = slide.Shapes.Title.TextFrame.TextRange.Text
-- Get the title of the current slide
repeat with currentShape in (get shapes of tSlide)
tell currentShape to if has text frame then tell its text frame to if has text then
set aType to placeholder type of currentShape
if aType is not missing value and aType is in titleTypes then
set slideTitles to slideTitles & (content of its text range) & return
exit repeat
end if
end if
end repeat
set the noteText to ""
repeat with t_shape in (get shapes of notes page of tSlide)
tell t_shape to if has text frame then tell its text frame to if has text then
-- get the note of this slide
set the noteText to (content of its text range)
exit repeat
end if
end repeat
-- Save note to file
set noteFilename to outputPath & "/slideNotes" & (slide index of tSlide as string) & ".txt"
my write_file(noteFilename, noteText)
end if
end repeat
-- Save the titles to file
set titlesFilename to outputPath & "/titles.txt"
my write_file(titlesFilename, slideTitles)
close active presentation
end tell
end create_thumbs
on close_presentation()
tell application "Microsoft PowerPoint"
-- close presentation
close active presentation
-- Hide powerpoint
tell application "System Events"
set visible of application process "Microsoft PowerPoint" to false
end tell
end tell
end close_presentation
on start_presentation(documentName, new_top, new_left_pos, new_width, new_height, fullscreen)
tell application "Microsoft PowerPoint"
-- Open document
open documentName
-- wait for document to load
repeat until document window 1 exists
delay 0.2
end repeat
-- disable presenter console
set showpresenterview of slide show settings of active presentation to 0
-- set presentation to show presentation in window
set show type of slide show settings of active presentation to slide show type window
-- start presentation
run slide show slide show settings of active presentation
-- set the size and postion on presentation window
set top of slide show window of active presentation to new_top
set left position of slide show window of active presentation to new_left_pos
if fullscreen is true then
-- put it in fullscreen mode
tell application "System Events" to tell process "Microsoft PowerPoint"
set value of attribute "AXFullScreen" of front window to true
end tell
else
set height of slide show window of active presentation to new_height
set width of slide show window of active presentation to new_width
end if
-- move to the front
activate
end tell
end start_presentation
on stop_presentation()
tell application "Microsoft PowerPoint"
-- stop presenting - self.presentation.SlideShowWindow.View.Exit()
exit slide show slide show view of slide show window 1
-- close presentation
close active presentation
-- Hide powerpoint
tell application "System Events"
set visible of application process "Microsoft PowerPoint" to false
end tell
end tell
end stop_presentation
on is_loaded(documentPath)
tell application "Microsoft PowerPoint"
return (full name of active presentation is (documentPath as string))
end tell
end is_loaded
on is_active()
tell application "Microsoft PowerPoint"
-- when the presentation window is out of focus it is paused, so check for both paused and running
return (slide state of slide show view of slide show window of active presentation is ¬
slide show state running) ¬
or (slide state of slide show view of slide show window of active presentation is ¬
slide show state paused)
end tell
end is_active
on next_slide()
tell application "Microsoft PowerPoint"
--activate
-- self.presentation.SlideShowWindow.View.Next()
go to next slide slide show view of slide show window 1
-- Print(?) slide number
-- slide number of slide of slideshow view of slide show window of active presentation
end tell
end next_slide
on previous_slide()
tell application "Microsoft PowerPoint"
--activate
go to previous slide slide show view of slide show window 1
-- Print(?) slide number
-- self.presentation.SlideShowWindow.View.Slide.SlideNumber
-- slide number of slide of view of slide show window of active presentation
end tell
end previous_slide
on goto_slide(slideNumber)
tell application "Microsoft PowerPoint"
activate
-- self.presentation.SlideShowWindow.View.GotoSlide(slideNumber)
--go to slide slideNumber of slide show window of active presentation
-- there seems to be no applescipt-way of going to a specific slide, so send keystroke
tell application "System Events"
keystroke (slideNumber as string)
key code 36
end tell
end tell
end goto_slide
on get_current_slide()
tell application "Microsoft PowerPoint"
--activate
-- Print(?) slide number
return slide number of slide of slide show view of slide show window of active presentation
end tell
end get_current_slide
on blank()
tell application "Microsoft PowerPoint"
--activate
-- self.presentation.SlideShowWindow.View.State = 3
--set state of slide of view of slide show window of active presentation to 3
set slide state of slide show view of slide show window 1 to slide show state black screen
end tell
end blank
on unblank()
tell application "Microsoft PowerPoint"
--activate
-- self.presentation.SlideShowWindow.View.State = 1
set slide state of slide show view of slide show window 1 to slide show state running
end tell
end unblank
"""
class PowerPointMacController(AppleScriptBaseController):
"""
Class to control interactions with a Powerpoint for Mac.
As well as triggering the correct activities based on the users input.
"""
log.info('PowerPointMacController loaded')
base_class = False
def __init__(self, plugin):
"""
Initialise the class
"""
log.debug('Initialising')
super(PowerPointMacController, self).__init__(plugin, 'PowerPointMac', PowerPointMacDocument)
# Compiled script expected to be set by subclasses
try:
self.applescript = applescript.AppleScript(POWERPOINT_MAC_APPLESCRIPT)
except applescript.ScriptError:
log.exception('Compilation of Powerpoint applescript failed')
self.supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
self.also_supports = ['odp']
def check_available(self):
"""
Program is able to run on this machine.
"""
ret = super().check_available()
if ret:
# Powerpoint is available! now check if the version is 15 (Powerpoint 2016) or above
try:
version = self.applescript.call('get_version')
except Exception:
log.exception('script execution failed')
return False
try:
major_version = int(version.split('.')[0])
except ValueError:
return False
if major_version >= 15:
return True
class PowerPointMacDocument(AppleScriptBaseDocument):
"""
Class which holds information and controls a single presentation.
"""
def __init__(self, controller, document_path):
"""
Constructor, store information about the file and initialise.
:param controller:
:param pathlib.Path document_path: Path to the document to load
:rtype: None
"""
log.debug('Init Presentation Applescript')
super().__init__(controller, document_path)
self.presentation_loaded = False
self.is_blank = False
def load_presentation(self):
ret = super().load_presentation()
if ret:
# we make powerpoint export to PDF and then convert the pdf to thumbnails
if PYMUPDF_AVAILABLE:
pdf_file = self.get_thumbnail_folder() / 'tmp.pdf'
# if the pdf file does not exists anymore it is assume the convertion has been done
if not pdf_file.exists():
return True
log.debug('converting pdf to png thumbnails using PyMuPDF')
pdf = fitz.open(str(pdf_file))
for i, page in enumerate(pdf, start=1):
src_size = page.bound().round()
# keep aspect ratio
scale = min(640 / src_size.width, 480 / src_size.height)
m = fitz.Matrix(scale, scale)
page.getPixmap(m, alpha=False).writeImage(str(self.get_thumbnail_folder() /
'slide{num}.png'.format(num=i)))
pdf.close()
# delete pdf
pdf_file.unlink()
return ret

View File

@ -120,6 +120,10 @@ class PresentationPlugin(Plugin):
extension_loader(glob_pattern, ['presentationcontroller.py'])
controller_classes = PresentationController.__subclasses__()
for controller_class in controller_classes:
# Don't use classes marked as base
if hasattr(controller_class, 'base_class') and controller_class.base_class:
controller_classes.extend(controller_class.__subclasses__())
continue
controller = controller_class(self)
self.register_controllers(controller)
return bool(self.controllers)