Search code examples
pdfcommand-line-interfacelibreoffice

Set user defined variables/custom properties for LibreOffice document via CLI


So there are numerous questions how to convert ODT to PDF via command line. I successfully used

soffice --headless --convert-to pdf:"writer_pdf_Export:SelectPdfVersion=1" --outdir outdir testDocument.odt

However my document contains user defined variables that are injected into the text using fields. I would like to set such variable value via command line so that at PDF generation the correct text is contained. I have done similar stuff on MS Word, but how would this work in Writer?

And if it helps, I can move to custom properties instead of variables - but I would still have to set them on the CLI.

What failed for me was

soffice --headless --convert-to "odt:{\"Version\":{\"type\":\"string\",\"value\":\"1.0\"}}" ReadMe.odt 
convert /home/queeg/ReadMe.odt -> /home/queeg/ReadMe.odt using filter : {"Version":{"type":"string","value":"1.0"}}
Overwriting: /home/queeg/ReadMe.odt
Error: Please verify input parameters... (SfxBaseModel::impl_store <file:///home/queeg/ReadMe.odt> failed: 0x81a(Error Area:Io Class:Parameter Code:26) ./sfx2/source/doc/sfxbasemodel.cxx:3202 ./sfx2/source/doc/sfxbasemodel.cxx:1775)

This command did not error out but also seemed to have no effect on my document. It did neither set the custom property Version nor the custom variable Version:

soffice --headless --convert-to "pdf:draw_pdf_Export:{\“Version\”:{\“type\”:\“string\”,\“value\”:\“draft\”}}" ReadMe.odt 
convert /home/queeg/ReadMe.odt -> /home/queeg/ReadMe.pdf using filter : draw_pdf_Export:{\“Version\”:{\“type\”:\“string\”,\“value\”:\“draft\”}}
Overwriting: /home/queeg/ReadMe.pdf

Solution

  • So I found a solution based on https://python-ooo-dev-tools.readthedocs.io/en/latest/index.html that I want to share with others and my future self.

    It consists of a python script that can load a document, set user-defined properties and save the document back as ODT, or PDF or any other supported output format.

    For installation on a fresh Ubuntu system, run

    sudo apt-get install pip3
    sudo pip install ooo-dev-tools
    

    Then install this script:

    #!/bin/python3
    
    import sys
    from ooodev.utils.lo import Lo
    from ooodev.utils.info import Info
    from com.sun.star.beans import XPropertySet
    from com.sun.star.beans import XPropertyAccess
    
    doc = None
    
    def main() -> int:
      print (sys.argv)
    
      with Lo.Loader(Lo.ConnectSocket(headless=True)) as loader:
        i = 0
        while i < len(sys.argv):
          arg = sys.argv[i]
          match arg:
            case "--load":
              i=i+1
              docname = sys.argv[i]
              print("loading " + docname)
              doc = Lo.open_doc(fnm=docname, loader=loader)
            case "--set":
              i=i+1
              val = sys.argv[i]
              items = val.split("=")
              name = items[0]
              value = items[1]
              print("setting " + name + "=>" + value)
              
              user_props = Info.get_user_defined_props(doc) # XPropertyContainer
              ps = Lo.qi(XPropertySet, user_props, True)
              
              try:
                ps.setPropertyValue(name, value)
              except Exception:
                pa = Lo.qi(XPropertyAccess, user_props, True)
                names = []
                for propertyvalue in pa.getPropertyValues():
                  names.append(propertyvalue.Name)
                print ("Cannot set property '" + name + "'. Known properties are ", names)
                return 1
            case "--save":
              i=i+1
              docname = sys.argv[i]
              print("saving " + docname)
              Lo.save_doc(doc=doc, fnm=docname)
            case _:
              print (i, sys.argv[i])
          i=i+1
        return 0
      
    if __name__ == "__main__":
        raise SystemExit(main())
    

    Finally run the code like this:

    convert.py --load mydoc.odt --set propname=propvalue -save mydoc.pdf
    

    Be aware you can use all the options multiple times and they are evaluated from left to right. That means you can load a document, set multiple properties, save it into two output documents, load the next…