Automatyczne łączenie prezentacji w jedną
Automatyczne łączenie prezentacji w jedną
Potrzebuję łączyć (często, więc automatycznie) wiele prezentacji (PPT, ale ostatecznie może być ODP) w jedno. Najlepsze byłoby jakieś konsolowe narzędzie nie wymagające X-ów, ale ostatecznie rozwiązanie z wykorzystaniem LibreOffice też ujdzie, jak się go będzie dało jakoś wołać ze skryptu. Czy spotkaliście się z takim narzędziem? Albo wiecie jak to Librem zautomatyzować?
Re: Automatyczne łączenie prezentacji w jedną
Na poziomie łączenia ciągów slajdów w formacie pdf możesz skorzystać z pdftk.
Dla dokumentów odp/ppt da się bez większych trudności napisać coś w rodzaju:
for slajd in prezentacja2 { dołącz slajd do prezentacja1 }
ale powstanie masa pytań: co z odsyłaczami, nazwami stylów, dziedziczeniem stylów, pełną "multimedią" itp.
Dla dokumentów odp/ppt da się bez większych trudności napisać coś w rodzaju:
for slajd in prezentacja2 { dołącz slajd do prezentacja1 }
ale powstanie masa pytań: co z odsyłaczami, nazwami stylów, dziedziczeniem stylów, pełną "multimedią" itp.
JJ
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
Re: Automatyczne łączenie prezentacji w jedną
Nie ma odsyłaczy, to są proste slajdy z tekstami (głównie pieśni) i chodzi o komponowanie jednej prezentacji z gotowych cegiełek-pieśni. Nie może to być PDF, bo ostatecznie musi powstać PPT, a PDF nie przerobię do PPT. Stylów też nie używamy, bo style w prezentacjach to dno niestety I psińco się da tym zrobić, jakby ich nie było w ogóleJan_J pisze:Na poziomie łączenia ciągów slajdów w formacie pdf możesz skorzystać z pdftk.
Dla dokumentów odp/ppt da się bez większych trudności napisać coś w rodzaju:
for slajd in prezentacja2 { dołącz slajd do prezentacja1 }
ale powstanie masa pytań: co z odsyłaczami, nazwami stylów, dziedziczeniem stylów, pełną "multimedią" itp.
Odnośnie tego fora, to właśnie nie bardzo wiem, jak to oskryptować... Stąd moje pytanie. Jakoś wołać wsadowo LO (choć to o tyle marne, że wymaga Xów)? Bo jak rozumiem, zewnętrznego programiku pewnie nie znajdę, co to robi?
Re: Automatyczne łączenie prezentacji w jedną
Dobra, spróbuję w wolnej chwili szkicowy skrypt wysmażyć.
Jeżeli OO uruchomić w trybie serwera (--headless), to grafika nie będzie potrzebna.
Jeżeli OO uruchomić w trybie serwera (--headless), to grafika nie będzie potrzebna.
JJ
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
Re: Automatyczne łączenie prezentacji w jedną
Mówisz? Myśmy mieli kiedyś w szkole jakiś Dziennik Lekcyjny, co używał OOo do generowania papierków i kazali jakieś dump-Xy instalować...
Re: Automatyczne łączenie prezentacji w jedną
Jeżeli uruchamiasz OOo w trybie użytkownika i w nim zapuszczasz makropolecenie, to oczywiście środowisko graficzne jest potrzebne. Ale jeżeli działa w trybie serwera, z opcją --headless, to radzi sobie bez niego. Wtedy nie uruchamia się makr, tylko programy klienckie.
Pierwszy szkic ma postać makra w Basicu. Jest więc stosunkowo łatwy do przetestowania. Ale wymaga GUI, chyba że różnymi trickami uruchomimy makro w sesji działającej w trybie headless (nie próbowałem, ale nie widzę przeszkód).Słowo komentarza: uruchamiamy makro testMergeFiles, które zakłada nową prezentację, a potem po kolei dołącza do niej slajdy ze wskazanych plików. Na koniec usuwa pierwszy slajd, założony przy utworzeniu dokumentu, po czym zapisuje i zamyka całość.
Czas 1000 (1 sek.) być może da się skrócić, ale nie do zera, bo wtedy schowek "nie zdąży" otrzymać danych przed zmianą fokusu kontrolera, i nici z operacji.
Nazwy plików są zakodowane na sztywno i nie są przetwarzane w pętli tylko osobnymi wywołaniami, ale to jest tylko test demonstrujący ideę.
Drugi szkic został napisany w Pythonie. Oto on:I kilka zdań komentarza:
funkcja asMacro() jest w miarę dokładnym odpowiednikiem Basicowego testMergeFiles(). Ale ... nie działa; konkretnie -- generuje dokument z jednym pustym slajdem. Przypuszczam, że time.sleep pracuje w tym samym wątku co office'owy dispatcher, w przeciwieństwie do Basicowej funkcji wait. Ale to by wymagało dokładniejszego sprawdzenia.
Funkcja asService jest przeznaczona do współpracy z procesem serwerowym Open/LibreOffce'a. Jest kilka metod uruchomienia takiego procesu, ja używałem komunikacji przez port tcp 2002. Office startował z polecenia(nazwę pliku wykonywalnego należy w razie czego poprzedzić ścieżką, zależnie od szczegółów instalacji pakietu).
Skrypt jest zorganizowany tak, że uruchamia funkcję asService automatycznie. Wymagany do uruchomienia wiersz poleceń ma postaćco oznacza, że:
Testowałem pod Windowsem; otwieranie plików daje efekty wizualne. Jeżeli serwer pracuje na Linuksie bez X-ów, zdarzyć się to nie może siłą rzeczy.
Skrypt kopiuje zawartość tekstową i graficzną poszczególnych stron, ale ignoruje tzw. Master Pages (czyli wzorce stron) i być może style (nie sprawdzałem dokładnie). W każdym razie robi tyle samo, co ręczne Copy&Paste.
Przy rozbudowie warto pamiętać, że LO ma wbudowanego Pythona 3.x, a Apache OO pozostaje wciąż z wersją 2.x.
// edit
W trybie headless na Linuksie skrypt pracuje, ale jakby nie wszystko kopiował. Czyżby .uno:Copy/Paste bazowały na schowku GUI? nie mogę wykluczyć...
Jakimś rozwiązaniem zawsze pozostaje lekki serwer X w stylu xvfb albo vncserver. Chociaż chciałoby się zrobić to całkiem po cichu.
Pierwszy szkic ma postać makra w Basicu. Jest więc stosunkowo łatwy do przetestowania. Ale wymaga GUI, chyba że różnymi trickami uruchomimy makro w sesji działającej w trybie headless (nie próbowałem, ale nie widzę przeszkód).
Kod: Zaznacz cały
sub testMergeFiles()
doc = StarDesktop.loadComponentFromURL("private:factory/simpress", "_blank", 0, Array())
mergeFromURL(doc, "file:///c:/users/my_user/slides1.odp")
mergeFromURL(doc, "file:///c:/users/my_user/slides2.odp")
doc.DrawPages.remove(doc.DrawPages.getByIndex(0))
doc.storeAsURL("file:///c:/users/my_user/output.odp", Array())
doc.close(true)
end sub
sub mergeFromURL(doc1, url)
dsp = createUnoService( "com.sun.star.frame.DispatchHelper")
dt = 1000
ctr1 = doc1.getCurrentController()
frame1 = ctr1.Frame
doc2 = StarDesktop.loadComponentFromURL(url, "_blank", 0, Array())
ctr2 = doc2.getCurrentController()
frame2 = ctr2.Frame
dsp.executeDispatch(frame1, ".uno:DiaMode", "", 0, Array())
dsp.executeDispatch(frame2, ".uno:DiaMode", "", 0, Array())
for i = 0 to doc2.DrawPages.Count-1
page2 = doc2.DrawPages.getByIndex(i)
ctr2.setCurrentPage(page2)
dsp.executeDispatch(frame2, ".uno:Copy", "", 0, Array())
wait(dt)
page1 = doc1.DrawPages.getByIndex(doc1.Drawpages.Count-1)
ctr1.setCurrentPage(page1)
dsp.executeDispatch(frame1, ".uno:Paste", "", 0, Array())
wait(dt)
next i
dsp.executeDispatch(frame1, ".uno:DrawingMode", "", 0, Array())
doc2.close(false)
end sub
Czas 1000 (1 sek.) być może da się skrócić, ale nie do zera, bo wtedy schowek "nie zdąży" otrzymać danych przed zmianą fokusu kontrolera, i nici z operacji.
Nazwy plików są zakodowane na sztywno i nie są przetwarzane w pętli tylko osobnymi wywołaniami, ale to jest tylko test demonstrujący ideę.
Drugi szkic został napisany w Pythonie. Oto on:
Kod: Zaznacz cały
# coding: utf8
import sys
import os
import time
import uno
import pyuno
def mergeFromURL(desk, dispatcher, doc1, url, dt = 1.0):
ctr1 = doc1.getCurrentController()
frame1 = ctr1.Frame
doc2 = desk.loadComponentFromURL(url, "_blank", 0, ())
ctr2 = doc2.getCurrentController()
frame2 = ctr2.Frame
dispatcher.executeDispatch(frame1, ".uno:DiaMode", "", 0, ())
dispatcher.executeDispatch(frame2, ".uno:DiaMode", "", 0, ())
for i in range(doc2.DrawPages.Count):
page2 = doc2.DrawPages.getByIndex(i)
ctr2.setCurrentPage(page2)
dispatcher.executeDispatch(frame2, ".uno:Copy", "", 0, ())
time.sleep(dt)
page1 = doc1.DrawPages.getByIndex(doc1.DrawPages.Count-1)
ctr1.setCurrentPage(page1)
dispatcher.executeDispatch(frame1, ".uno:Paste", "", 0, ())
time.sleep(dt)
dispatcher.executeDispatch(frame1, ".uno:DrawingMode", "", 0, ())
doc2.close(False)
def fileNameToUrl(fname):
if fname[0:7] != 'file://':
fname = os.path.realpath(fname)
return pyuno.systemPathToFileUrl(fname)
else:
return fname
def mergeFiles(ctx, desk, filelist, outname):
doc = desk.loadComponentFromURL("private:factory/simpress", "_blank", 0, ())
dispatcher = ctx.ServiceManager.createInstanceWithContext("com.sun.star.frame.DispatchHelper", ctx)
for fname in filelist:
mergeFromURL(desk, dispatcher, doc, fileNameToUrl(fname))
doc.DrawPages.remove(doc.DrawPages.getByIndex(0))
doc.storeAsURL(fileNameToUrl(outname), ())
doc.close(False)
def asMacro():
ctx = XSCRIPTCONTEXT.getComponentContext()
desk = XSCRIPTCONTEXT.getDesktop()
infiles = [
"c:/users/my_user/slides1.odp",
"c:/users/my_user/slides2.odp",
]
outfile = "c:/users/my_user/output.odp"
mergeFiles(ctx, desk, infiles, outfile)
def asService():
assert len(sys.argv) >= 2
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
desk = ctx.ServiceManager.createInstanceWithContext( "com.sun.star.frame.Desktop", ctx)
infiles = sys.argv[1 : -1]
outfile = sys.argv[-1]
# infiles = [
# "c:/users/my_user/slides1.odp",
# "c:/users/my_user/slides2.odp",
# ]
# outfile = "c:/users/my_user/output.odp"
mergeFiles(ctx, desk, infiles, outfile)
if __name__ == '__main__':
asService()
funkcja asMacro() jest w miarę dokładnym odpowiednikiem Basicowego testMergeFiles(). Ale ... nie działa; konkretnie -- generuje dokument z jednym pustym slajdem. Przypuszczam, że time.sleep pracuje w tym samym wątku co office'owy dispatcher, w przeciwieństwie do Basicowej funkcji wait. Ale to by wymagało dokładniejszego sprawdzenia.
Funkcja asService jest przeznaczona do współpracy z procesem serwerowym Open/LibreOffce'a. Jest kilka metod uruchomienia takiego procesu, ja używałem komunikacji przez port tcp 2002. Office startował z polecenia
Kod: Zaznacz cały
libreoffice.exe -headless "-accept=socket,host=localhost,port=2002;urp;"
Skrypt jest zorganizowany tak, że uruchamia funkcję asService automatycznie. Wymagany do uruchomienia wiersz poleceń ma postać
Kod: Zaznacz cały
"scieżka do libreoffice\python.exe" skrypt.py plik1.odp plik2.odp ... plikN.odp output.odp
- uruchamiany Python powinien należeć do instalacji Open/LibreOffice. Chyba że pracujesz na Linuksie, a Libre jest zainstalowany z paczki przygotowanej przez Twoje distro -- wtedy Python systemowy jest OK;
- skrypt.py to nazwa pliku ze skryptem. W zasadzie dowolna;
- dalej następują argumenty wywołania. Wszystkie, z wyjątkiem ostatniego, są ścieżkami do łączonych dokumentów. Ostatni jest ścieżką pliku wynikowego. Skrypt zamieni je na ścieżki bezwzględne, a następnie na URL-e;
- w związku z tym argument wywołania musi być co najmniej jeden -- co jest sprawdzane.
Testowałem pod Windowsem; otwieranie plików daje efekty wizualne. Jeżeli serwer pracuje na Linuksie bez X-ów, zdarzyć się to nie może siłą rzeczy.
Skrypt kopiuje zawartość tekstową i graficzną poszczególnych stron, ale ignoruje tzw. Master Pages (czyli wzorce stron) i być może style (nie sprawdzałem dokładnie). W każdym razie robi tyle samo, co ręczne Copy&Paste.
Przy rozbudowie warto pamiętać, że LO ma wbudowanego Pythona 3.x, a Apache OO pozostaje wciąż z wersją 2.x.
// edit
W trybie headless na Linuksie skrypt pracuje, ale jakby nie wszystko kopiował. Czyżby .uno:Copy/Paste bazowały na schowku GUI? nie mogę wykluczyć...
Jakimś rozwiązaniem zawsze pozostaje lekki serwer X w stylu xvfb albo vncserver. Chociaż chciałoby się zrobić to całkiem po cichu.
JJ
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)
LO (7.6|24.2) ∙ Python (3.12|3.10) ∙ Unicode 15 ∙ LᴬTEX 2ε ∙ XML ∙ Unix tools ∙ Linux (Rocky|CentOS)