diff options
Diffstat (limited to 'macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f')
7 files changed, 1555 insertions, 0 deletions
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf Binary files differnew file mode 100644 index 0000000000..06c4f78b97 --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf Binary files differnew file mode 100644 index 0000000000..1e09286df2 --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf Binary files differnew file mode 100644 index 0000000000..0107c921d2 --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf Binary files differnew file mode 100644 index 0000000000..487baf938b --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py new file mode 100755 index 0000000000..b7efcb3d2e --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py @@ -0,0 +1,574 @@ +#!/usr/bin/env python3 +# coding: utf-8 +# +# Copyright 2021-2022 (C) Pablo Rodríguez +# +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA or see <http://www.gnu.org/licenses/gpl.html>. + +import os, sys, shutil +import xml.etree.ElementTree as ET +import cairo +import gi +gi.require_version("Gtk", "3.0") +gi.require_version("Gst", "1.0") +from gi.repository import Gtk, Gdk, GObject, GLib, Gst, GdkPixbuf +gi.require_version('Poppler', '0.18') +from gi.repository import Poppler + +Gst.init(sys.argv) + +class gvoz: + def __init__(self): + + self.execname = os.path.splitext(os.path.basename(sys.argv[0]))[0] + self.real_path = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) + self.program_version = "0.9.9.2" + + if(len(sys.argv) < 2): + self.on_file_selection() + print("") + print(" " + self.execname + "-" + self.program_version + + " (https://gvoz.presvoz.tk)") + print(" Written by Pablo Rodríguez") + print(" Usage: " + self.execname + " presentation.pdf") + print("") + + if len(sys.argv) > 1: + self.main_filename = sys.argv[1] + elif self.dialog_filename != "": + self.main_filename = self.dialog_filename + + self.filename = os.path.splitext(self.main_filename)[0] + + if os.path.splitext(self.main_filename)[1] != (".pdf" or ".PDF"): + self.pdffilename = os.path.splitext(self.main_filename)[0] + ".pdf" + if os.path.isfile(self.pdffilename) == False: + self.pdffilename = os.path.splitext(self.main_filename)[0] + ".PDF" + if os.path.isfile(self.pdffilename) == False: + self.on_file_selection() + elif os.path.isfile(self.pdffilename) == False: + self.on_file_selection() + else: + self.pdffilename = self.main_filename + + self.define_soundtimesnames() + + self.uri = Gst.filename_to_uri(os.path.abspath(self.pdffilename)) + + self.document = Poppler.Document.new_from_file(self.uri, None) + self.n_pages = self.document.get_n_pages() + self.page_selector = self.document.get_page(0) + self.current_page = 0 + + self.win = Gtk.Window() + self.win.set_icon_from_file(self.real_path + '/gvoz.svg') + self.doc_title = self.document.get_title() or "χαλεπὰ τὰ καλά" + self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title) + + self.win.set_default_size(500, 500) + self.win.set_position(Gtk.WindowPosition.CENTER_ALWAYS) + + self.box = Gtk.Box() + + self.area = Gtk.DrawingArea() + self.area.connect("draw", self.on_draw) + + self.box.pack_start(self.area, True, True, 0) + + self.win.add(self.box) + self.win.connect("destroy", Gtk.main_quit) + self.win.show_all() + + self.win.connect('key-press-event', self.key_press_event) + + self.width, self.height = self.win.get_size() + self.page_width, self.page_height= self.page_selector.get_size() + + self.surface = cairo.ImageSurface(cairo.FORMAT_RGB24, + int(self.width), + int(self.height)) + + if sys.platform.startswith('win'): + self.player = Gst.parse_launch("wasapisrc low-latency=true ! audio/x-raw,format=F32LE ! wavenc ! filesink location=\"" + self.audiofilename + "\"") + else: + self.player = Gst.parse_launch("autoaudiosrc ! audio/x-raw,format=F32LE,rate=48000,channels=1 ! wavenc ! filesink location=\"" + self.audiofilename + "\"") + + bus = self.player.get_bus() + bus.add_signal_watch() + bus.connect('message', self.on_message) + + xmp = self.document.get_metadata() + if xmp != None and xmp != "": + xmp_root = ET.fromstring(xmp) + for language in xmp_root.findall(".//{http://purl.org/dc/elements/1.1/}language"): + doc_lang = language.text + else: + print("The PDF document has no language information") + + title_separator = ". " + + self.sound_metadata = { "title" : "The Title" } + self.sound_metadata["genre"] = "Other/Presentation" + self.sound_metadata["application-name"] = "GVoz" + self.sound_metadata["encoder"] = self.sound_metadata["application-name"] + self.sound_metadata["encoder-version"] = self.program_version + self.sound_metadata["datetime"] = Gst.DateTime.new_now_local_time() + self.sound_metadata["date"] = GLib.Date.new_dmy(self.sound_metadata["datetime"].get_day(), + self.sound_metadata["datetime"].get_month(), self.sound_metadata["datetime"].get_year()) + + try: + doc_lang + except NameError: + print("\n\"" + os.path.basename(self.pdffilename) + + "\" contains no language information.") + self.doc_lang = None + else: + if doc_lang != None and doc_lang != "": + self.sound_metadata["language-code"] = doc_lang + self.sound_metadata["language-name"] = GstTag.tag_get_language_name(language_code) + if doc_lang.startswith('en'): + title_separator = ": " + else: + title_separator = ". " + + if self.document.get_subject() != None and self.document.get_subject() != "": + self.sound_metadata["comment"] = self.document.get_subject() + elif self.document.get_title() != None and self.document.get_title() != "": + self.sound_metadata["title"] = self.document.get_title() + if self.document.get_keywords() != None and self.document.get_keywords() != "": + self.sound_metadata["keywords"] = self.document.get_keywords() + if self.document.get_author() != None and self.document.get_author() != "": + self.sound_metadata["artist"] = self.document.get_author() + self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + " " + self.document.get_author() + else: + self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + + self.taglist = Gst.TagList.new_empty() + + self.mp3_converter = Gst.parse_launch("filesrc location=\"" + self.audiofilename + "\" ! decodebin ! audioconvert ! audioresample ! lamemp3enc mono=true cbr=true target=bitrate bitrate=32 ! id3v2mux ! filesink location=\"" + self.mp3_audio + "\"") + + mp3_bus = self.mp3_converter.get_bus() + mp3_bus.add_signal_watch() + mp3_bus.connect('message', self.on_mp3_message) + + self.mp3_metadata = True + + tagsetter = self.mp3_converter.get_by_interface(Gst.TagSetter) + for tag_key, tag_value in self.sound_metadata.items(): + try: + self.taglist.add_value(Gst.TagMergeMode.REPLACE, tag_key, tag_value) + except ValueError: + print("WARNING: skipping tag %s; value %s is not valid" % (tag_key, tag_value)) + if not self.taglist.is_empty() and self.mp3_metadata: + tagsetter.merge_tags(self.taglist, Gst.TagMergeMode.REPLACE_ALL) + print(type(self.mp3_metadata)) + print(self.taglist.to_string() + "\n") + else: + print("<<<< WARNING: Could not find element to set tags. >>>") + + # ~ self.opus_converter = Gst.parse_launch("filesrc location=\"" + self.audiofilename + "\" ! decodebin ! audioconvert ! audioresample ! opusenc audio-type=voice bitrate=16000 ! oggmux ! filesink location=\"" + self.opus_audio + "\"") + + # ~ opus_bus = self.opus_converter.get_bus() + # ~ opus_bus.add_signal_watch() + # ~ opus_bus.connect('message', self.on_opus_message) + + # ~ self.opus_metadata = True + + # ~ tagsetter = self.opus_converter.get_by_interface(Gst.TagSetter) + # ~ if not self.taglist.is_empty() and self.opus_metadata: + # ~ tagsetter.merge_tags(self.taglist, Gst.TagMergeMode.REPLACE_ALL) + # ~ else: + # ~ print("<<<< WARNING: Could not find element to set tags. >>>") + + self.use_presvoz = True + + def on_message(self, bus, message): + t = message.type + if t == Gst.MessageType.EOS: + self.player.set_state(Gst.State.NULL) + # ~ Gtk.main_quit() + elif t == Gst.MessageType.ERROR: + err, debug = message.parse_error() + print ("Error: %s" % err, debug) + self.player.set_state(Gst.State.NULL) + + def on_mp3_message(self, mp3_bus, message): + t = message.type + if t == Gst.MessageType.EOS: + self.mp3_converter.set_state(Gst.State.NULL) + self.generate_presentation() + Gtk.main_quit() + elif t == Gst.MessageType.ERROR: + err, debug = message.parse_error() + print ("Error: %s" % err, debug) + self.mp3_converter.set_state(Gst.State.NULL) + + # ~ def on_opus_message(self, opus_bus, message): + # ~ t = message.type + # ~ if t == Gst.MessageType.EOS: + # ~ self.opus_converter.set_state(Gst.State.NULL) + # ~ Gtk.main_quit() + # ~ elif t == Gst.MessageType.ERROR: + # ~ err, debug = message.parse_error() + # ~ print ("Error: %s" % err, debug) + # ~ self.opus_converter.set_state(Gst.State.NULL) + + def generate_presentation (self): + if shutil.which("context") != None and shutil.which("context") != "" and self.use_presvoz: + os.system("context --purgeall --extra=third-presvoz " + self.pdffilename) + if os.path.isfile(self.js_timesfilename): + os.remove(self.js_timesfilename) + + def define_soundtimesnames (self): + if sys.platform.startswith('win'): + self.audiofilename = self.filename.replace("\\", "/") + "-audio.wav" + self.mp3_audio = self.filename.replace("\\", "/") + "-audio.mp3" + self.opus_audio = self.filename.replace("\\", "/") + "-audio.opus" + else: + self.audiofilename = self.filename + "-audio.wav" + self.mp3_audio = self.filename + "-audio.mp3" + self.opus_audio = self.filename + "-audio.opus" + + self.times = [] + self.timesfilename = self.filename + '-times.txt' + self.js_timesfilename = self.filename + '-times.js' + + def on_metadata_info (self): + if self.document.get_title() != None and self.document.get_title() != "": + metadata_info = "\n<b>Title:</b> <i>" + self.document.get_title() + "</i>" + if self.document.get_author() != None and self.document.get_author() != "": + metadata_info += "\n\n<b>Author:</b> <i>" + self.document.get_author() + "</i>" + if self.document.get_subject() != None and self.document.get_subject() != "": + metadata_info += "\n\n<b>Comments:</b> <i>" + self.document.get_subject() + "</i>" + if self.document.get_keywords() != None and self.document.get_keywords() != "": + metadata_info += "\n\n<b>Keywords:</b> <i>" + self.document.get_keywords() + "</i>" + if self.doc_lang != None and self.doc_lang != "": + metadata_info += "\n\n<b>Language:</b> <i>" + self.sound_metadata['language-name'] + "</i>" + else: + metadata_info = "\nThe PDF document contains no metadata" + + + self.sound_metadata["comment"] = self.document.get_subject() + if self.document.get_author() != None and self.document.get_author() != "": + self.sound_metadata["artist"] = self.document.get_author() + self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + " " + self.document.get_author() + else: + self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + text="Metadata from PDF Document", + ) + + dialog.format_secondary_text(metadata_info) + + dialog.props.secondary_use_markup = True + + dialog.run() + + dialog.destroy() + + def on_keys_info (self): + keys_info = "\n<b>space</b>\t\tGo to next slide and write its time" + keys_info += "\n\t\t\tThis starts and finishes sound recording" + keys_info += "\n\t\t\tAfter that, <i>PresVoz</i> will generate the presentation" + keys_info += "\n\n<b>a</b>\t\t\tAbout <i>GVoz</i>" + keys_info += "\n\n<b>c</b>\t\t\tDon’t generate PDF and <i>Flash</i> presentations with <i>PresVoz</i>" + keys_info += "\n\n<b>d</b>\t\t\tShow metadata imported from the PDF document" + keys_info += "\n\n<b>h</b>\t\t\tShow key information" + keys_info += "\n\n<b>m</b>\t\t\tEnable mouse–click to advance slides" + keys_info += "\n\n<b>p</b>\t\t\tPause / unpause sound and times recording" + keys_info += "\n\t\t\tWith paused recording, <i>GVoz</i> will exit full–screen" + keys_info += "\n\t\t\tWith recording started again, <i>GVoz</i> will go full–screen" + # ~ keys_info += "\n\n<b>x</b>\t\t\tRemove metadata in MP3 file\n\t\t\tTitle and author are read from the PDF document\n\t\t\tDates and times are set from the recording" + keys_info += "\n\n<b>q</b>\t\t\tQuit <i>GVoz</i> (presentation won’t be generated)" + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + text="Keyboard Info", + ) + dialog.format_secondary_text( + keys_info + ) + + dialog.props.secondary_use_markup = True + + dialog.run() + + dialog.destroy() + + def on_presvoz_info (self): + presvoz_info = "\nPresentation won’t be generated after sound and times recording." + presvoz_info += "\n\nIf you want to generate it, just use <i>Presvoz</i> after <i>GVoz</i> finishes." + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + text="Presentation Disabled", + ) + dialog.format_secondary_text( + presvoz_info + ) + + dialog.props.secondary_use_markup = True + + dialog.run() + + dialog.destroy() + + def on_mouse_info (self): + mouse_info = "\nMouse has been activated to advance slides." + mouse_info += "\n\nMouse–clicks have been enabled to advance slides." + mouse_info += "\n\nThere is no way to disable the mouse again." + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + text="Mouse Enabled", + ) + dialog.format_secondary_text(mouse_info) + + dialog.props.secondary_use_markup = True + + dialog.run() + + dialog.destroy() + + def on_presvoz_presentation (self): + presvoz_presentation = "\nThe selected PDF document is already a presentation with voice." + presvoz_presentation += "\n\nPlease, select other PDF document not already generated by <i>PresVoz</i>." + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + text="<big><b><i>PresVoz</i> Presentation Detected</b></big>", + ) + + dialog.format_secondary_text(presvoz_presentation) + + dialog.props.use_markup = True + dialog.props.secondary_use_markup = True + + response = dialog.run() + if response == Gtk.ResponseType.OK: + self.on_file_selection() + + dialog.run() + + dialog.destroy() + + def on_existing_files (self): + already_recorded_files = "\nVoice and times have already been recorded in a previous session." + already_recorded_files += "\n\nIf you proceed, <tt>" + os.path.basename(self.audiofilename) + "</tt> and <tt>" + os.path.basename(self.timesfilename) + "</tt> will be lost forever." + already_recorded_files += "\n\nIf you cancel, you will quit <i>GVoz</i>." + already_recorded_files += "\n\nIf you want to keep <tt>" + os.path.basename(self.audiofilename) + "</tt> and <tt>" + os.path.basename(self.timesfilename) + "</tt>, please quit and rename them or move them to another directory." + already_recorded_files += "\n\nDo you really want to proceed?\n" + + dialog = Gtk.MessageDialog( + # ~ transient_for=self, + flags=0, + message_type=Gtk.MessageType.WARNING, + buttons=Gtk.ButtonsType.YES_NO, + text="Existing Sound and Times", + ) + + dialog.format_secondary_text(already_recorded_files) + + dialog.set_default_response(Gtk.ResponseType.NO) + + dialog.props.secondary_use_markup = True + + response = dialog.run() + if response == Gtk.ResponseType.YES: + if os.path.isfile(self.audiofilename): + os.remove(self.audiofilename) + if os.path.isfile(self.timesfilename): + os.remove(self.timesfilename) + if os.path.isfile(self.mp3_audio): + os.remove(self.mp3_audio) + if os.path.isfile(self.opus_audio): + os.remove(self.opus_audio) + elif response == Gtk.ResponseType.NO: + Gtk.main_quit() + + dialog.destroy() + + def button_press_event(self, widget, event): + if event.button == 1: + self.record_and_advance() + + def key_press_event(self, widget, event): + if event.keyval != Gdk.keyval_from_name("a"): + if event.keyval != Gdk.keyval_from_name("h"): + if event.keyval != Gdk.keyval_from_name("q"): + if event.keyval != Gdk.keyval_from_name("x"): + if event.keyval != Gdk.keyval_from_name("c"): + if event.keyval != Gdk.keyval_from_name("m"): + if event.keyval != Gdk.keyval_from_name("d"): + if self.player.get_state(0)[1] == Gst.State.NULL and self.current_page + 1 <= self.n_pages: + if os.path.exists(self.audiofilename) or os.path.exists(self.timesfilename): + self.on_existing_files() + elif self.document.get_subject() != None: + if self.document.get_subject().endswith('🤞🐞 – https://www.presvoz.tk'): + self.on_presvoz_presentation() + if event.keyval == Gdk.keyval_from_name("h"): + self.on_keys_info() + if event.keyval == Gdk.keyval_from_name("a"): + self.about_info() + if event.keyval == Gdk.keyval_from_name("q"): + if self.player.get_state(0)[1] == Gst.State.PLAYING or self.player.get_state(0)[1] == Gst.State.PAUSED: + self.player.set_state(Gst.State.NULL) + self.file_times.close() + if os.path.isfile(self.audiofilename): + self.mp3_converter.set_state(Gst.State.PLAYING) + self.win.set_title (self.execname + " — Converting sound to MP3 format…") + Gtk.main_quit() + if event.keyval == Gdk.keyval_from_name("x"): + self.mp3_metadata = False + self.opus_metadata = False + if event.keyval == Gdk.keyval_from_name("c"): + self.use_presvoz = False + self.on_presvoz_info() + if event.keyval == Gdk.keyval_from_name("d"): + self.on_metadata_info() + if event.keyval == Gdk.keyval_from_name("m"): + self.win.connect('button-press-event', self.button_press_event) + self.on_mouse_info() + if event.keyval == Gdk.keyval_from_name("p"): + if self.player.get_state(0)[1] == Gst.State.PLAYING: + self.win.unfullscreen() + self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title) + self.player.set_state(Gst.State.PAUSED) + elif self.player.get_state(0)[1] == Gst.State.PAUSED: + self.win.fullscreen() + self.player.set_state(Gst.State.PLAYING) + if event.keyval == Gdk.keyval_from_name("space"): + self.record_and_advance() + + def record_and_advance(self): + if self.player.get_state(0)[1] == Gst.State.NULL and self.current_page + 1 <= self.n_pages: + self.win.fullscreen() + self.player.set_state(Gst.State.PLAYING) + self.file_times = open(self.timesfilename, 'w') + elif self.player.get_state(0)[1] == Gst.State.PLAYING: + if self.current_page + 1 < self.n_pages: + self.current_page += 1 + self.page_selector = self.document.get_page(self.current_page) + self.area.set_size_request(int(self.width),int(self.height)) + self.area.queue_draw() + self.file_times.write(str(int(self.player.get_pipeline_clock().get_time()/1000000)) + "\n") + elif self.current_page + 1 == self.n_pages: + self.win.unfullscreen() + self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title) + self.player.send_event(Gst.Event.new_eos()) + self.file_times.write(str(int(self.player.get_pipeline_clock().get_time()/1000000))) + self.file_times.close() + self.current_page += 1 + self.mp3_converter.set_state(Gst.State.PLAYING) + self.win.set_title (self.execname + " — Converting sound to MP3 format…") + if shutil.which("context") != None and shutil.which("context") != "" and self.use_presvoz: + self.win.set_title (self.execname + " — Generating presentation…") + # ~ self.opus_converter.set_state(Gst.State.PLAYING) + # ~ self.win.set_title (self.execname + " — Converting sound to Opus format…") + + def on_file_selection(self): + dialog = Gtk.FileChooserDialog( + title="Please choose a PDF document", action=Gtk.FileChooserAction.OPEN + ) + dialog.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_OPEN, + Gtk.ResponseType.OK, + ) + + self.add_filters(dialog) + + response = dialog.run() + if response == Gtk.ResponseType.OK: + self.dialog_filename = dialog.get_filename() + self.pdffilename = self.dialog_filename + self.filename = os.path.splitext(self.dialog_filename)[0] + self.define_soundtimesnames() + + dialog.destroy() + + def add_filters(self, dialog): + filter_pdf = Gtk.FileFilter() + filter_pdf.set_name("PDF documents") + filter_pdf.add_mime_type("application/pdf") + dialog.add_filter(filter_pdf) + + def on_draw(self, widget, cairo_context): + add_x = 0 + add_y = 0 + + if (self.area.get_allocated_width()/self.page_width) < (self.area.get_allocated_height()/self.page_height): + self.scale = self.area.get_allocated_width()/self.page_width + add_y = (((self.area.get_allocated_height()-(self.page_height*self.scale))/2)/self.scale) + else: + self.scale = self.area.get_allocated_height()/self.page_height + add_x = (((self.area.get_allocated_width()-(self.page_width*self.scale))/2)/self.scale) + + # ~ cr = Gdk.cairo_create(self.win.get_window()) # deprecated + # ~ cairo_context = cairo.Context(self.surface) # new, seems not required + + cairo_context.set_source_surface(self.surface) + cairo_context.set_source_rgba(1, 1, 1) + + if self.scale != 1: + cairo_context.scale(self.scale, self.scale) + + cairo_context.translate(add_x, add_y) + cairo_context.rectangle(0, 0, self.page_width, self.page_height) + cairo_context.fill() + self.page_selector.render(cairo_context) + + def about_info (self): + dialog = Gtk.AboutDialog() + dialog.set_program_name("GVoz") + dialog.set_version(self.program_version) + dialog.set_comments("Record and create presentations with voice") + dialog.set_website("https://gvoz.presvoz.tk") + dialog.set_website_label("https://gvoz.presvoz.tk") + dialog.set_authors(["Pablo Rodríguez"]) + dialog.set_copyright("© 2021-2022 Pablo Rodríguez") + dialog.set_license_type(Gtk.License.GPL_2_0) + dialog.set_wrap_license = True + dialog.set_logo(GdkPixbuf.Pixbuf.new_from_file(self.real_path + "/gvoz.svg")) + dialog.connect('response', lambda dialog, data: dialog.destroy()) + dialog.show_all() + + def gtk_main_quit(self, widget, event): + Gtk.main_quit() + + def main(self): + Gtk.main() + +gv = gvoz() +gv.main() diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex new file mode 100644 index 0000000000..2e9fc84a53 --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex @@ -0,0 +1,798 @@ +%D \module +%D [ file=mtx-context-third-presvoz, +%D version=2022.02.02, +%D title=PresVoz, +%D subtitle=Presentations with Voice, +%D author=Pablo Rodríguez, +%D date=\currentdate, +%D copyright={Michal Vlásak \&\ Pablo Rodríguez}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C copyrighted by its authors. + +\starttext +\startlmtxmode +\def\Presentation{\getdocumentfilename{1}} + +\startluacode +if file.extname(document.files[1]) == "" then + document.main_file = file.addsuffix(document.files[1],"pdf") +else + document.main_file = document.files[1] +end + +if file.pathpart(document.main_file) == "" then + document.main_filename = file.nameonly(document.main_file) +else + document.main_filename = file.pathpart(document.main_file):gsub(io.fileseparator, "/") .. "/" .. file.nameonly(document.main_file) +end + +document.original_times = document.main_filename .. "-times.txt" + +document.uncompressed_audio = document.main_filename .. "-audio.wav" + +document.audio_mp3 = document.main_filename .. "-audio.mp3" + +document.audio_opus = document.main_filename .. "-audio.opus" -- opus might work later + +document.compressed_audio = document.audio_mp3 + +--twolame is not an option: gives wrong sizes + +if io.exists(document.uncompressed_audio) and not(io.exists(document.audio_mp3)) and os.which('lame') then + os.execute('lame -m m -b 32 "' .. document.uncompressed_audio .. '" "' .. document.audio_mp3 .. '"') +elseif io.exists(document.uncompressed_audio) and not(io.exists(document.compressed_audio)) then + if os.which('opusenc') then os.execute('opusenc --downmix-mono --bitrate 16 "' .. document.uncompressed_audio .. '" "' .. document.audio_opus .. '"') end +end + +presvoz_name = document.main_filename .. "-presvoz.pdf" + +if not(io.exists(document.original_times)) or not(io.exists(document.compressed_audio)) then + context.enablemode({"missing-files"}) +end +\stopluacode + +\startmode[missing-files] +\setupinteractionscreen[option=max] +\setupbodyfont[pagella] +\startTEXpage[offset=2em, align=center] + \bf\color[darkred]{{\bi PresVoz} requires\\ + {\tt\cldcontext{document.original_times}} and {\tt\cldcontext{document.uncompressed_audio}}\\ + to do its magic with {\tt\cldcontext{document.main_file}}.} +\stopTEXpage +\stopmode + +\startnotmode[missing-files] +\startluacode +document.timeline_filename = document.main_filename .. "-times.js" + +document.slides_swf = document.main_filename .. ".swf" + +document.presentation_script = document.main_filename .. "-presentation.sc" + +document.presentation_swf = document.main_filename .. "-presentation.swf" + +document.presentation_filename = file.nameonly(document.main_file) .. "-presentation.swf" + +document.first_slide_swf = document.main_filename .. "-first.swf" + +document.loader_script = document.main_filename .. "-loader.sc" + +document.loader_swf = document.main_filename .. "-loader.swf" + +function document.transfer_metadata(name) + local main_doc = lpdf.epdf.load(name) + lpdf.addtocatalog("Lang", lpdf.unicode(main_doc.Catalog.Lang), lpdf.string(main_doc.Catalog.Lang)) + if main_doc.Catalog.Lang == "en" then + document.separate_subtitle = ": " + else + document.separate_subtitle = ". " + end + if main_doc.Info.Subject ~= nil and main_doc.Info.Subject ~= "" then + context.setupinteraction{ title = main_doc.Info.Title .. document.separate_subtitle .. main_doc.Info.Subject } + else + context.setupinteraction{ title = main_doc.Info.Title } + end + if main_doc.Catalog.Lang == "es" then + document.presvoz_banner = "Hecho con «PresVoz» 🤞🐞" + elseif main_doc.Catalog.Lang == "pt" then + document.presvoz_banner = "Feito con «PresVoz» 🤞🐞" + elseif main_doc.Catalog.Lang == "it" then + document.presvoz_banner = "Fatto con «PresVoz» 🤞🐞" + elseif main_doc.Catalog.Lang == "fr" then + document.presvoz_banner = "Fait avec « PresVoz » 🤞🐞" + elseif main_doc.Catalog.Lang == "de" then + document.presvoz_banner = "Erezeugt mit »PresVoz« 🤞🐞" + elseif main_doc.Catalog.Lang == "nl" then + document.presvoz_banner = "Gedaan med „PresVoz” 🤞🐞" + elseif main_doc.Catalog.Lang == "nl" then + document.presvoz_banner = "Gedaan med „PresVoz” 🤞🐞" + else + document.presvoz_banner = "Done with “PresVoz” 🤞🐞" + end + context.setupinteraction{ subtitle = document.presvoz_banner .. " – https://www.presvoz.tk" } + if main_doc.Info.Author ~= nil and main_doc.Info.Author ~= "" then + context.setupinteraction{ author = main_doc.Info.Author } + end + if main_doc.Info.ModDate ~=nil and main_doc.Info.ModDate ~= "" then + original_Doc_date = main_doc.Info.ModDate:sub(3,6) .. "-" .. + main_doc.Info.ModDate:sub(7,8) .. "-" .. + main_doc.Info.ModDate:sub(9,10) .. "T" .. + main_doc.Info.ModDate:sub(11,12) .. ":" .. + main_doc.Info.ModDate:sub(13,14) .. ":" .. + main_doc.Info.ModDate:sub(15,22):gsub("'", ":") + directives.enable('backend.date=' .. original_Doc_date .. "'") + end + lpdf.epdf.unload(name) +end + +document.transfer_metadata(document.main_file) +\stopluacode + +\startbuffer[flash-presentation] + \startluacode + local raw_times = io.open(document.original_times) + local swf_times = io.open(document.presentation_script, "w") + + swf_times:write([[# Presentation script, generated by PresVoz + # + # Copyright (C) 2003 Leonard Lin + # Copyright (C) 2007-2008 Sergio Costas + # Copyright (C) 2009-2021 Pablo Rodríguez + # + # 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 <http://www.gnu.org/licenses>. + # + # Additional permission under GNU GPL version 3 section 7 + # + # As a special exception, if you create a document which uses this + # script, and compile this script or a modified version of it in the + # document, this script does not by itself cause the resulting document + # to be covered by the GNU General Public License. This exception does + # not however invalidate any other reasons why the document might be + # covered by the GNU General Public License. + + .flash filename="]] .. document.presentation_swf .. [[" version=8 fps=12 + + .swf slides "]] .. document.slides_swf .. [[" + .sound audio "]] .. document.audio_mp3 .. [[" + + .action: + var times=new Array(); + var maxtimes; + var position; + var mode; + var sound_position; + var sound_length; + var show_slide; + + var contextual = new ContextMenu(); + function ssurl(){ + getURL("https://www.presvoz.tk", "_blank"); + } + + switch (System.capabilities.language) { + case "en" : + ss_message = "Done with PresVoz 🤞🐞"; + break; + case "es" : + ss_message = "Hecho con PresVoz 🤞🐞"; + break; + case "gl" : + ss_message = "Feito con PresVoz 🤞🐞"; + break; + case "pt" : + ss_message = "Feito con PresVoz 🤞🐞"; + break; + case "it" : + ss_message = "Fatto con PresVoz 🤞🐞"; + break; + case "fr" : + ss_message = "Fait avec PresVoz 🤞🐞"; + break; + case "de" : + ss_message = "Erezeugt mit PresVoz 🤞🐞"; + break; + case "nl" : + ss_message = "Gedaan med PresVoz 🤞🐞"; + break; + case "el" : + ss_message = "Kατασκευασμένος με PresVoz 🤞🐞"; + break; + default: + ss_message = "Made with PresVoz 🤞🐞"; + break; + } + + contextual.hideBuiltInItems(); + ss_url = new ContextMenuItem(ss_message, ssurl); + contextual.customItems.push(ss_url); + _root.menu = contextual; + + snd = new Sound(this); + snd.attachSound("audio"); + sound_length=snd.duration; + position = 0; + + show_slide = false; + times[0] = 0;]] .. "\n") + + line_number = 0 + while true do + line = raw_times:read() + if line == nil then break end + if line:match("%D") == nil then + line_number = line_number + 1 + print ("times["..line_number.."] = " .. line .. ";") + swf_times:write(" times["..line_number.."] = " .. line .. ";") + swf_times:write("\n") + end + end + + swf_times:write("\n" .. [[ + maxtimes = times.length - 1; + + function pause_or_play() { + if (mode==0) { + snd.start(snd.position/1000.0,0); + mode=1; + } else if (mode==1) { + snd.stop(); + mode=0; + } + } + + function previous_slide() { + if (mode<2) { + if (mode==0) { mode=1; } + snd.stop(); + if (position>0) { + sound_position=times[position-1]; + } else { + sound_position=0; + } + snd.start(sound_position/1000.0,0); + } + } + + function next_slide() { + if (mode<2) { + if (mode==0) { mode=1; } + snd.stop(); + sound_position = times[position+1]; + if (sound_position>sound_length) { + sound_position=sound_length-500; + } + snd.start(sound_position/1000.0,0); + } + } + + function first_slide() { + snd.stop(); + snd.start(0,0); + slides.gotoAndStop(1); + position=0; + mode=1; + show_slide=true; + } + + function last_slide() { + snd.stop(); + sound_position = times[maxtimes-1]; + slides.gotoAndStop(maxtimes); + show_slide=false; + snd.start(sound_position/1000.0,0); + } + + function toogle_fullscreen() { + if(Stage.displayState == "normal"){ + Stage.displayState="fullScreen"; + } else { + Stage.displayState="normal"; + } + } + + Mouse.onMouseDown = function() { + if ((getTimer() - lastClick) < 400) { + pause_or_play(); + } else { + lastClick = getTimer(); + } + }; + + + key_listen=new Object(); + + key_listen.onKeyDown = function() { + switch (Key.getCode()) { + case 32: + pause_or_play(); + break; + case 37: + previous_slide(); + break; + case 38: + first_slide(); + break; + case 39: + next_slide(); + break; + case 40: + last_slide(); + break; + case 70: + toogle_fullscreen(); + break; + } + }; + + function check_time() { + if (mode==1) { + if ( sound_position + 50 > sound_length) { + snd.stop(); + mode=2; + if(Stage.displayState == "fullScreen"){ + Stage.displayState="normal"; + } + } else { + if ((snd.position>=times[position])&&(snd.position<times[position+1])) { + if (show_slide) { + slides.gotoAndStop(position+1); + show_slide=false; + } + } else { + if (position>maxtimes) { + snd.stop(); + mode=2; + } else { + if (snd.position<times[position]) { + position-=1; + } else { + position+=1; + } + show_slide=true; + } + } + } + } + } + + setInterval(check_time, 10); + + mode=1; + snd.start(0,0); + Stage["displayState"] = "fullScreen"; + Mouse.addListener(Mouse); + Key.addListener(key_listen); + + .end + + .frame 1 + .put slides + .stop slides + + .end + ]]) + + raw_times:close() + swf_times:close() + + os.execute('pdf2swf -f -T 8 -s filloverlap -s linksopennewwindow "' .. document.main_file .. '" -o "' .. document.slides_swf .. '"') + os.execute('swfc "' .. document.presentation_script .. '"') + if io.exists(document.presentation_swf) then os.remove(document.presentation_script) os.remove(document.slides_swf) end + \stopluacode +\stopbuffer + +\startbuffer[flash-loader] + \startluacode + local raw_times = io.open(document.original_times) + local loader_times = io.open(document.loader_script, "w") + + fig = figures.getinfo(document.main_file) + function dimension_bp(dimension) + return math.floor(dimension*number.dimenfactors.bp) + end + + loader_times:write([[# Preloader script, generated by PresVoz + # + # Copyright (C) 2009-2021 Pablo Rodríguez + # + # 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 <http://www.gnu.org/licenses>. + # + # Additional permission under GNU GPL version 3 section 7 + # + # As a special exception, if you create a document which uses this + # script, and compile this script or a modified version of this script + # into the document, this script does not by itself cause the resulting + # document to be covered by the GNU General Public License. + # This exception does not however invalidate any other reasons why + # the document might be covered by the GNU General Public License. + + .flash filename="]] .. document.loader_swf .. [[" version=8 fps=12" + .font roman "]] .. resolvers.findfile("iRaccoonShowBold.otf") .. [[" glyphs=" %()KB0123456789/:,.CPDNuk[]resntiocanbld!" + .edittext newloader font=roman color=#ffff00 size=30% width=350 height=30 border=none align="center" noselect variable=load_text + .box placeholder width=]] .. dimension_bp(fig.used.width) .. [[ height=]] .. dimension_bp(fig.used.height) .. "\n" .. [[ + .box fsarea fill=#ffffff00 color=#ffffff00 width=]] .. dimension_bp(fig.used.width) .. [[ height=]] .. dimension_bp(fig.used.height) .. "\n" .. [[ + .outline fscreen_outline: M 62.78125 18.703125 L 43.367188 23.734375 L 38.390625 43.09375 L 42.109375 39.375 L 48.671875 45.9375 L 65.625 29.039062 L 59.0625 22.421875 L 62.78125 18.703125 z M 199.71875 18.703125 L 203.4375 22.421875 L 196.875 29.039062 L 213.773438 45.9375 L 220.390625 39.375 L 224.109375 43.09375 L 219.132812 23.734375 L 199.71875 18.703125 z M 83.125 45.9375 C 73.429688 45.9375 65.625 53.742188 65.625 63.4375 L 65.625 133.4375 C 65.625 143.132812 73.429688 150.9375 83.125 150.9375 L 179.375 150.9375 C 189.070312 150.9375 196.875 143.132812 196.875 133.4375 L 196.875 63.4375 C 196.875 53.742188 189.070312 45.9375 179.375 45.9375 L 83.125 45.9375 z M 48.726562 150.9375 L 42.109375 157.5 L 38.390625 153.78125 L 43.367188 173.140625 L 62.78125 178.171875 L 59.0625 174.453125 L 65.625 167.835938 L 48.726562 150.9375 z M 213.773438 150.9375 L 196.875 167.835938 L 203.4375 174.453125 L 199.71875 178.171875 L 219.132812 173.140625 L 224.109375 153.78125 L 220.390625 157.5 L 213.773438 150.9375 z .end + .outline fulls_outline: M 17.5 0 L 245 0 C 254.695312 0 262.5 7.804688 262.5 17.5 L 262.5 179.375 C 262.5 189.070312 254.695312 196.875 245 196.875 L 17.5 196.875 C 7.804688 196.875 0 189.070312 0 179.375 L 0 17.5 C 0 7.804688 7.804688 0 17.5 0 z .end + .filled fscreen outline=fscreen_outline fill=#969696ff color=#969696ff + .filled fulls outline=fulls_outline fill=#64646496 color=#64646496 + + .button fscr_button + .show fscreen as=idle + .show fscreen as=area + .show fscreen as=hover + .show fscreen as=pressed + .end + + .button fs_area + .show fsarea as=idle + .show fsarea as=area + .show fsarea as=hover + .show fsarea as=pressed + .on_release: + fullscreen_button._visible = 0; + fs_area._visible = 0; + Stage["displayState"] = "fullScreen"; + _root.load_text = "[Click to start]"; + _root.dlprogress_mvclip._visible = true; + the_presentation = "./]] .. document.presentation_filename .. [["; + this.loadMovie(the_presentation, this.placeholder); + .end + .end + + .sprite fullscreen_button + .put fscreen + .put fulls + .end + + .swf first_slide "]] .. document.first_slide_swf .. [[" + .frame 1 + .put first_slide + .stop first_slide + .put fullscreen_button + .stop fullscreen_button + .put fs_area + .stop fs_area + + .action: + slide_height=Stage.height; + slide_width=Stage.width; + + var contextual = new ContextMenu(); + function ssurl(){ getURL("https://www.presvoz.tk", "_blank"); } + + switch (System.capabilities.language) { + case "en" : + ss_message = "Done with PresVoz 🤞🐞"; + break; + case "es" : + ss_message = "Hecho con PresVoz 🤞🐞"; + break; + case "gl" : + ss_message = "Feito con PresVoz 🤞🐞"; + break; + case "pt" : + ss_message = "Feito con PresVoz 🤞🐞"; + break; + case "it" : + ss_message = "Fatto con PresVoz 🤞🐞"; + break; + case "fr" : + ss_message = "Fait avec PresVoz 🤞🐞"; + break; + case "de" : + ss_message = "Erezeugt mit PresVoz 🤞🐞"; + break; + case "nl" : + ss_message = "Gedaan med PresVoz 🤞🐞"; + break; + case "el" : + ss_message = "Kατασκευασμένος με PresVoz 🤞🐞"; + break; + default: + ss_message = "Made with PresVoz 🤞🐞"; + break; + } + + contextual.hideBuiltInItems(); + ss_url = new ContextMenuItem(ss_message, ssurl); + contextual.customItems.push(ss_url); + _root.menu = contextual; + + counter_percent=(slide_width/800)*100; + newloader._xscale=counter_percent; + newloader._yscale=counter_percent; + newloader._x = (slide_width-(newloader._width))/2; + newloader._y = (slide_height-newloader._height)/2; + + button_percent = (slide_width/600)*100; + fullscreen_button._xscale = button_percent; + fullscreen_button._yscale = button_percent; + fullscreen_button._x = (slide_width-(fullscreen_button._width))/2; + fullscreen_button._y = (slide_height-fullscreen_button._height)/2; + + _root.createEmptyMovieClip("dlprogress_mvclip", 0); + dlprogress_mvclip.createEmptyMovieClip("bar", 1); + dlprogress_mvclip.createEmptyMovieClip("stroke", 2); + + with (dlprogress_mvclip.stroke) { + lineStyle(0, 0xFF0000, 30); + moveTo(0, 0); + lineTo(300, 0); + lineTo(300, 40); + lineTo(0, 40); + lineTo(0, 0); + } + with (dlprogress_mvclip.bar) { + beginFill(0xFF0000, 30); + moveTo(0, 0); + lineTo(300, 0); + lineTo(300, 40); + lineTo(0, 40); + lineTo(0, 0); + endFill(); + _xscale = 0; + } + dlprogress_mvclip._x = (slide_width-dlprogress_mvclip._width)/2; + dlprogress_mvclip._y = (slide_height-dlprogress_mvclip._height)/2; + + dlprogress_mvclip._visible = false; + fs_listen=new Object(); + + fs_listen.onKeyDown = function() { + if (Key.isDown(13)) { + if(Stage.displayState == "normal"){ + Stage.displayState="fullScreen"; + } else { + Stage.displayState="normal"; + } + } + }; + + Key.addListener(fs_listen); + + + .end + + .sprite images + .put placeholder alpha=0% + .action: + the_presentation = "./]] .. document.presentation_filename .. [["; + first_loading = new Object(); + first_loading.onMouseDown = function () { + load_swf = new MovieClipLoader(); + load_swf.loadClip(the_presentation, placeholder); + listen_loading = new Object(); + listen_loading.onLoadStart = function(target) { + _root.dlprogress_mvclip.bar._xscale = 0; + _starttime = gettimer(); + }; + listen_loading.onLoadError = function(){ + _root.load_text = "Presentation cannot be loaded!"; + }; + listen_loading.onLoadProgress = function(target, bytesLoaded, bytesTotal) { + downldtime = (gettimer() - _starttime) / 1000; + _root.load_text = (String (Math.round ((bytesLoaded * 100) / bytesTotal)) + "% (" + Math.round((bytesLoaded / 1024) / downldtime) + " KB/s)"); + _root.dlprogress_mvclip.bar._xscale = Math.round(bytesLoaded/bytesTotal*100); + keeping_awake = setInterval(function(){}, 1000); + }; + listen_loading.onLoadComplete = function(target) { + clearInterval(keeping_awake); + _root.load_text = ""; + _root.dlprogress_mvclip._visible = 0; + _root.dlprogress_mvclip.bar._visible = 0; + _root.first_slide._visible = 0; + }; + load_swf.addListener(listen_loading); + }; + Mouse.addListener(first_loading); + .end + .end + + .put newloader + .stop newloader + .end]]) + + raw_times:close() + loader_times:close() + + os.execute('pdf2swf -f -p 1 -T 8 -s filloverlap -s linksopennewwindow "' .. document.main_file .. '" -o "' .. document.first_slide_swf .. '"') + os.execute('swfc "' .. document.loader_script .. '"') + if io.exists(document.loader_swf) then os.remove(document.loader_script) os.remove(document.first_slide_swf) end + \stopluacode +\stopbuffer + +\def\TimeLine#1% + {\cldcontext{ document.timeline_filename }} + +\def\SoundFile#1% + {\cldcontext{ document.compressed_audio }} + +\startbuffer[generate-timeline] + \startluacode + local raw_times = io.open(document.original_times) + local js_times = io.open(document.timeline_filename, "w") + + js_times:write("\\startJSpreamble times used now") + js_times:write("\n") + js_times:write("var times = [];") + js_times:write("\n") + js_times:write("var maxtimes = times[times.length - 1];") + js_times:write("\n") + js_times:write("times[0] = 0;") + js_times:write("\n") + line_number = 0 + while true do + line = raw_times:read() + if line == nil then break end + if line:match("%D") == nil then + line_number = line_number + 1 + print ("times["..line_number.."] = " .. line .. ";") + js_times:write("times["..line_number.."] = " .. line .. ";") + js_times:write("\n") + end + end + + js_times:write("\\stopJSpreamble") + + raw_times:close() + js_times:close() + \stopluacode +\stopbuffer + +\startmode[*first] +\getbuffer[generate-timeline] +\doiftext + {\ctxlua{if os.which('pdf2swf') and os.which('swfc') then context("a") end}} + {\getbuffer[flash-presentation] + \getbuffer[flash-loader]} +\stopmode + +\getfiguredimensions[\Presentation] + +\setupexternalfigures[interaction=all] + +\setupinteraction + [state=start, + color=, + contrastcolor=, + style=, + focus=standard] + +\useJSscripts[presvoz.mkxl] +\startnotmode[*first] + \useJSscripts[\TimeLine{\Presentation}] +\stopnotmode + +\definefontfamily + [mainface] + [rm] + [Latin Modern Sans] + +\definefontfamily + [mainface] + [ss] + [Flechitas] + +\setupbodyfont + [mainface, 25pt] + +\setupmakeup + [page] + [pagestate=start, + style=\bfd, + color=white, + footerstate=start, + align=center] + +\definecolor[transparent-gray] + [r=.45, g=.45, b=.45] + +\defineviewerlayer[fullscreen][state=start] +\defineviewerlayer[unfullscreen][state=stop] +\defineviewerlayer[play][state=start] +\defineviewerlayer[pause][state=stop] + +\definecolor[transparent][r=1, a=1, t=0] + +\startbuffer[fullscreen-button] + \startoverlay + {\viewerlayer[fullscreen]{C}} + {\viewerlayer[unfullscreen]{I}} + {\goto{\color[transparent]{C}}[JS(SwitchFS{})]} + \stopoverlay +\stopbuffer + +\startbuffer[play-pause-button] + \startoverlay + {\viewerlayer[play]{R}} + {\viewerlayer[pause]{H}} + {\goto{\color[transparent]{C}}[JS(PlayPauseSound{})]} + \stopoverlay +\stopbuffer + +\def\SlideNavigationButtons{% + \goto{F}[JS(GoToFirstSlide{})]\,% + \goto{B}[JS(GoToPreviousSlide{})]\,% + \inlinebuffer[play-pause-button]\,% + \goto{S}[JS(StopSound{})]\,% + \goto{N}[JS(GoToNextSlide{})]\,% + \goto{L}[JS(GoToLastSlide{})]\quad + \null\inlinebuffer[fullscreen-button]% + } + +\definelayer[player-buttons] + [x=.5\dimexpr\figurewidth\relax, + y=.9525\dimexpr\figureheight\relax, + location=middle, + state=repeat] + +\definelayer[placesound] + +\startbuffer[placesound] + \definerenderingwindow[soundplace] + [width=0pt, height=0pt, frame=on] + +\doiftextelse{\ctxlua{if document.compressed_audio == document.audio_opus then context("opus") end}} + {\userendering[mainsound][audio/opus][\SoundFile{\Presentation}][embed=yes, list=no]} + {\userendering[mainsound][audio/mp3][\SoundFile{\Presentation}][embed=yes, list=no]} + + \placerenderingwindow[soundplace][mainsound] +\stopbuffer + +\setupbackgrounds + [page] + [background={foreground, placesound, player-buttons}] + + +\setlayer[player-buttons] + {\switchtobodyfont[sans, \cldcontext{tex.dimen.paperwidth/1000000}pt]\color[transparent-gray]{\SlideNavigationButtons}} + +\resetpagenumber + +\dorecurse{\noffigurepages}{\startTEXpage[pagestate=start] +\ifnum\recurselevel=1 \setlayer[placesound]{\getbuffer[placesound]}\fi +\externalfigure[\Presentation][page=\recurselevel] +\stopTEXpage} +\stopnotmode + +\startluacode +luatex.wrapup( + function() + os.remove(presvoz_name) + os.rename(tex.jobname .. ".pdf", presvoz_name) + end +) +\stopluacode +\stoptext +\stoplmtxmode + +\startmkivmode +\setupinteractionscreen[option=max] +\startTEXpage[offset=2em, align=center] + \ssbf\color[darkgreen]{\LMTX\ required,\\I’m afraid.} +\stopTEXpage +\stopmkivmode +\stoptext diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl new file mode 100644 index 0000000000..8d8ecd3cde --- /dev/null +++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl @@ -0,0 +1,183 @@ +\startJSpreamble PresVoz used now +var ocgs = this.getOCGs(0); +this.pageNum = 0; + +var label = "mainsound" ; +var rendition = this.media.getRendition(label) ; +var screen = this.media.getAnnot({nPage: 0, cAnnotTitle: label}) ; +var main_sound_player; + +function ToogleFSButton() { + if (app.fs.isFullScreen) { + ocgs[0].state = false; + ocgs[3].state = true; + } else { + ocgs[0].state = true; + ocgs[3].state = false; + } +} + +function TooglePlayPauseButton() { + if (main_sound_player.isPlaying) { + ocgs[1].state = true; + ocgs[2].state = false; + } else { + ocgs[1].state = false; + ocgs[2].state = true; + } +} + +function timer_resume() { + check_time = app.setInterval("advance_slide()", 10); +} + +function timer_pause() { + app.clearInterval(check_time); +} + +function jump() { + if (!main_sound_player.isOpen) { main_sound_player.open(); } + + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + if (this.pageNum < times.length) { + if (!main_sound_player.isPlaying) { + timer_resume(); + } + + var jump_time = times[this.pageNum] / 1000; + + main_sound_player.pause(); + main_sound_player.seek({time: jump_time}); + main_sound_player.play(); + } + } +} + +function advance_slide() { + if (!main_sound_player.isOpen) { main_sound_player.open(); } + if ( typeof main_sound_player.where() != "undefined") { + var current_offset = 1000 * main_sound_player.where().time; + + if (current_offset >= times[this.pageNum + 1]) { + this.pageNum += 1; + } else if (current_offset <= times[this.pageNum - 1]) { + this.pageNum -= 1; + } + } +} + +function start_player() { + main_sound_player = app.media.createPlayer({ + rendition: rendition, + annot: screen, + settings: { + autoPlay: false, + }, + events: { + onDone: function() { + timer_pause(); + app.fs.isFullScreen = false; + ToogleFSButton(); + this.pageNum = this.numPages - 1; + }, + afterDone: function() { + main_sound_player.pause(); + TooglePlayPauseButton(); + main_sound_player.seek({time: maxtimes}); + this.pageNum = this.numPages - 1; + }, + onEscape: function() { + app.fs.isFullScreen = false; + ToogleFSButton(); + }, + afterEscape: function() { + main_sound_player.pause(); + TooglePlayPauseButton(); + }, + afterPause: function() { + timer_pause(); + TooglePlayPauseButton(); + }, + onPlay: function() { + app.fs.isFullScreen = true; + ToogleFSButton(); + }, + afterPlay: function() { + timer_resume(); + TooglePlayPauseButton(); + }, + afterReady: function() { + main_sound_player.play(); + }, + }, + }); + main_sound_player.open(); +} + +function GoToFirstSlide(label) { + this.pageNum = 0; + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + if ( main_sound_player.isPlaying ) { jump(); } + } +} + +function PlayPauseSound() { + if ( typeof main_sound_player == "undefined" ) { + start_player(); + } else if ( !main_sound_player.isPlaying ) { + if (!main_sound_player.isOpen) { main_sound_player.open(); } + if ( typeof main_sound_player.where() != "undefined" && main_sound_player.where().time == 0 ) + { this.pageNum = 0; } + timer_resume(); + main_sound_player.play(); + } else if ( main_sound_player.isPlaying ) { + timer_pause(); + main_sound_player.pause(); + } +} + +function StopSound() { + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + main_sound_player.pause(); + main_sound_player.seek({time: 0}); + } + this.pageNum = 0; +} + +function GoToLastSlide(label) { + this.pageNum = this.numPages - 1; + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + if ( main_sound_player.isPlaying ) { jump(); } + } +} + +function GoToNextSlide(label) { + ++this.pageNum; + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + if ( main_sound_player.isPlaying ) { jump(); } + } +} + +function GoToPreviousSlide(label) { + --this.pageNum; + if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) { + if ( main_sound_player.isPlaying ) { jump(); } + } +} + +function SwitchFS() { + if (app.fs.isFullScreen == false) { + app.fs.isFullScreen = true; + if (app.fs.isFullScreen) { + ocgs[0].state = false; + ocgs[3].state = true; + } + } else { + app.fs.isFullScreen = false; + if (!app.fs.isFullScreen) { + ocgs[0].state = true; + ocgs[3].state = false; + } + } +} +\stopJSpreamble |