Безголовый LibreOffice очень медленно экспортирует в PDF на Windows (в 6 раз медленнее, чем на Linux) - PullRequest
0 голосов
/ 26 апреля 2020

Мне часто нужно экспортировать много документов (> 1000) .docx в PDF с помощью LibreOffice. Вот пример документа: test.docx . Следующий код работает, но он довольно медленный на Windows (в среднем 3,3 секунды для каждого документа PDF):

import subprocess, docx, time   # first do: pip install python-docx 
for i in range(10):
    doc = docx.Document('test.docx')
    for paragraph in doc.paragraphs:
        paragraph.text = paragraph.text.replace('{{num}}', str(i))
    doc.save('test%i.docx' % i)   # these 4 previous lines are super fast - a few ms
    t0 = time.time()
    subprocess.call(r'C:\Program Files\LibreOffice\program\soffice.exe --headless --convert-to pdf test%i.docx --outdir . --nocrashreport --nodefault --nofirststartwizard --nolockcheck --nologo --norestore"' % i)
    print('PDF generated in %.1f sec' % (time.time()-t0))

    # for linux:
    # (0.54 seconds on average, so it's 6 times better than on Windows!)
    # subprocess.call(['/usr/bin/soffice', '--headless', '--convert-to', 'pdf', '--outdir', '/home/user', 'test%i.docx' % i])  

Как ускорить этот экспорт PDF на Windows?

Я подозреваю, что много времени будет потрачено впустую на "Start LibreOffice/Writer, (do the job), Close LibreOffice" "Start LibreOffice/Writer, (do the job), Close LibreOffice" "Start LibreOffice/Writer, (do the job), Close LibreOffice" et c.

Примечания:

  • Как сравнение: здесь: https://bugs.documentfoundation.org/show_bug.cgi?id=92274 говорят, что время экспорта составляет 90 мс или 810 мс.

  • soffice.exe заменено на swriter.exe: та же проблема: 3.3 в среднем в секунду

    subprocess.call(r'C:\Program Files\LibreOffice\program\swriter.exe --headless --convert-to pdf test%i.docx --outdir ."' % i)
    

1 Ответ

0 голосов
/ 27 апреля 2020

Действительно, все время затрачивается на запуск / выход из LibreOffice. Вместо этого мы можем передать много документов docx за один вызов из soffice.exe:

import subprocess, docx
for i in range(1000):
    doc = docx.Document('test.docx')
    for paragraph in doc.paragraphs:
        paragraph.text = paragraph.text.replace('{{num}}', str(i))
    doc.save('test%i.docx' % i)

# all PDFs in one pass:
subprocess.call(['C:\Program Files\LibreOffice\program\swriter.exe', 
    '--headless', '--convert-to', 'pdf', '--outdir', '.'] + ['test%i.docx' % i for i in range(1000)])

107 секунд, так что в среднем это составляет ~ 107 мс на PDF, что намного лучше!

Примечания:

  • Он не работает с 10 000 документов, поскольку длина аргументов командной строки будет превышать 32 000 символов, как объяснено 1014 *

  • Интересно, можно ли иметь более интерактивный способ работы с LibreOffice без головы:

    • Запустите Writer без головы, продолжайте его
    • отправьте действие, подобное open test1.docx к этому процессу
    • отправить действие export to pdf и закрыть docx
    • отправить open test2.docx, затем экспортировать, et c.
    • ...
    • выход из Writer без головы

    Это работает с COM (объектная модель компонентов) с MS Office: .do c в PDF, используя python, но мне интересно, если что-то подобное существует с LibreOffice. Похоже, что нет: Поддерживает ли LibreOffice / OpenOffice модель COM

...