Pequeña introducción a la programación de scripts para OpenOffice.org. La receta incluye una macro para convertir a PDF desde línea de comandos.
OpenOffice.org está basado en una arquitectura de componentes llamada UNO, algo parecido a CORBA o ZeroC Ice. Hasta tal punto que los clientes y los componentes pueden estar en máquinas diferentes. Y también como en CORBA se pueden programar los componentes en varios lenguajes: OOBasic, C++, Java, JavaScript, BeanShell y… Python! El más popular de todos ellos es OOBasic, debido principalmente a que el propio OOo incorpora un IDE con depuración y todo. Pero como Basic es muy aburrido, yo elijo Python, que me gusta más 
Con UNO se pueden crear:
import uno 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") smgr = ctx.ServiceManager desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx) model = desktop.getCurrentComponent() text = model.Text cursor = text.createTextCursor() text.insertString(cursor, "Hello World", 0) ctx.ServiceManager
python-uno funciona como macro.
# HelloWorld python script for the scripting framework def HelloWorldPython( ): """Prints the string 'Hello World(in Python)' into the current document""" model = XSCRIPTCONTEXT.getDocument() text = model.Text tRange = text.End tRange.String = "Hello World (in Python)" return None
Partiendo de esta macro en OOBasic, la gran cantidad de ejemplos que hay en http://www.oooforum.org/, y sobre todo de la OOLib.py de Danny Brewer, más unas pequeñas modificaciones propias he escrito esta otra macro, que hace lo mismo, pero en Python (que mola más):
import os def serviceManager(): return XSCRIPTCONTEXT.getComponentContext().getServiceManager() # The CoreReflection object. It is cached in a global variable. goCoreReflection = None def getCoreReflection(): global goCoreReflection if not goCoreReflection: goCoreReflection = serviceManager().createInstance("com.sun.star.reflection.CoreReflection") return goCoreReflection def createUnoStruct(cTypeName): """Create a UNO struct and return it. Similar to the function of the same name in OOo Basic.""" # Get the IDL class for the type name oXIdlClass = getCoreReflection().forName(cTypeName) # Create the struct. oReturnValue, oStruct = oXIdlClass.createObject(None) return oStruct def pathnameToUrl(cPathname): """Convert a Windows or GNU/Linux pathname into an OOo URL.""" if len( cPathname ) > 1 and cPathname[1:2] == ":": cPathname = "/" + cPathname[0] + "|" + cPathname[2:] return "file://" + cPathname.replace("\\", "/") def openURL(cUrl, tProperties=()): """Open or Create a document from it's URL.""" oDesktop = XSCRIPTCONTEXT.getDesktop() return oDesktop.loadComponentFromURL(cUrl, "_blank", 0, tProperties) def MakePropertyValue( cName=None, uValue=None, nHandle=None, nState=None ): """Create a com.sun.star.beans.PropertyValue struct and return it.""" oPropertyValue = createUnoStruct("com.sun.star.beans.PropertyValue") if cName != None: oPropertyValue.Name = cName if uValue != None: oPropertyValue.Value = uValue if nHandle != None: oPropertyValue.Handle = nHandle if nState != None: oPropertyValue.State = nState return oPropertyValue def main(dummy): cSourceFile = os.environ['OOARG'] cSourceURL = pathnameToUrl( cSourceFile ) cTargetFile = os.path.splitext(cSourceFile)[0] + '.pdf' cTargetURL = pathnameToUrl( cTargetFile ) # Open the source document. # No filter necessary. OOo will figure it out from the .DOC extension. oDoc = openURL(cSourceURL, (MakePropertyValue("Hidden", True),)) # Save the newly opened document. oDoc.storeToURL(cTargetURL, (MakePropertyValue("FilterName","writer_pdf_Export"),)) oDoc.dispose() g_exportedScripts = main,
Tienes que escribir esto en un fichero que se llame ~/.openoffice.org2/user/Scripts/python/oo2pdf.py.
Pues “simplemente” tienes que ejecutar este comando:
$ OOARG=/home/usuario/fichero.odt soffice -invisible “vnd.sun.star.script:oo2pdf.py\$main?language=Python&location=user”
Obviamente lo mejor es escribir otro scriptillo para ejecutar ese engendro de comando.
#!/usr/bin/python import sys, os os.system('OOARG=%s soffice -invisible "vnd.sun.star.script:oo2pdf.py\$main?language=Python&location=user"' % os.path.abspath(sys.argv[1]))
Lo metes en ~/bin/oo2pdf, le das permisos de ejecución y lo puedes ejecutar con:
$ oo2pdf fichero.odt
También lo puedes transformar en un g-script para nautilus, pero lo realmente interesante es utilizarlo desde un Makefile o similar para convertir de forma automatizada miles de .odt de un plumazo. También convierte cualquier otro formato de OOo, incluido el .doc de MS (pero no se lo digas a nadie).
Estos ficheros los tienes en nuestro repositorio subversion
El fichero de entrada se especifica en la variable de entorno $OOARG, que luego se lee desde el script. Eso es porque no he conseguido averiguar cómo pasar argumentos al script desde la línea de comandos de soffice. Con OOBasic se puede hacer, pero está claro que OOo trata de modo muy diferente a las macros en OOBasic que las escritas en el resto de lenguajes. Si sabes cómo hacerlo, por favor, deja un comentario.
Comments
unoconv
unoconv es un programa muy interesante para convertir ficheros entre formatos soportados por OpenOffice. Utiliza UNO y está hecho en Python. Es para utilizarlo desde línea de comandos, de modo que el objetivo es muy parecido a lo que yo pretendía con el script de esta receta (Makefiles), aunque obviamente es mucho más ambicioso. Disponible como paquete Debian oficial.
No soy portavoz de ningún colectivo, grupo o facción. Mi opinión es personal e intransferible.