From b0912947fc0f27f95fb9bb4a346d4944f5790846 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Tue, 4 Jul 2017 23:52:14 -0400 Subject: [PATCH] Give every libreoffice instance its own separate $HOME directory. Additionally give every libreoffice its own UserInstallation file in the $HOME directory. Works around Libre Office issue: https://bugs.documentfoundation.org/show_bug.cgi?id=37531 Solves or affects GitLab issues #393 #258 #198 #175 Signed-off-by: Roberto Rosario --- docs/releases/2.5.rst | 6 ++++ mayan/apps/converter/classes.py | 53 ++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/docs/releases/2.5.rst b/docs/releases/2.5.rst index 4a82e8e30a..4d93c6f09e 100644 --- a/docs/releases/2.5.rst +++ b/docs/releases/2.5.rst @@ -40,6 +40,12 @@ Other Changes - PDF compatibility improvements. - Improve the documentation of the document creation API endpoint. GitHub issue #255. Thanks to @lcerliani opening the issue. +- Libre Office conversion improvements. Give every libreoffice instance + its own separate $HOME directory. Additionally give every libreoffice + its own UserInstallation file in the $HOME directory. Works around + Libre Office issue: https://bugs.documentfoundation.org/show_bug.cgi?id=37531 + Solves or affects GitLab issues #393 #258 #198 #175 + Removals -------- diff --git a/mayan/apps/converter/classes.py b/mayan/apps/converter/classes.py index e02bcf2440..1e94f5c4d3 100644 --- a/mayan/apps/converter/classes.py +++ b/mayan/apps/converter/classes.py @@ -16,7 +16,7 @@ import yaml from django.utils.translation import string_concat, ugettext_lazy as _ from common.settings import setting_temporary_directory -from common.utils import fs_cleanup, mkstemp +from common.utils import fs_cleanup, mkdtemp, mkstemp from mimetype.api import get_mimetype from .exceptions import InvalidOfficeFormat, OfficeConversionError @@ -33,7 +33,7 @@ try: yaml.load(setting_graphics_backend_config.value).get( 'libreoffice_path', DEFAULT_LIBREOFFICE_PATH ) - ).bake('--headless', '--convert-to', 'pdf') + ).bake('--headless', '--convert-to', 'pdf:writer_pdf_Export') except sh.CommandNotFound: LIBREOFFICE = None @@ -118,7 +118,6 @@ class ConverterBase(object): """ Executes LibreOffice as a subprocess """ - if not LIBREOFFICE: raise OfficeConversionError( _('LibreOffice not installed or not found.') @@ -135,9 +134,17 @@ class ConverterBase(object): if self.mime_type == 'text/plain': libreoffice_filter = 'Text (encoded):UTF8,LF,,,' - args = (input_filepath, '--outdir', setting_temporary_directory.value) + libreoffice_home_directory = mkdtemp() + args = ( + input_filepath, '--outdir', setting_temporary_directory.value, + '-env:UserInstallation=file://{}'.format( + os.path.join( + libreoffice_home_directory, 'LibreOffice_Conversion' + ) + ), + ) - kwargs = {'_env': {'HOME': setting_temporary_directory.value}} + kwargs = {'_env': {'HOME': libreoffice_home_directory}} if libreoffice_filter: kwargs.update({'infilter': libreoffice_filter}) @@ -146,8 +153,12 @@ class ConverterBase(object): LIBREOFFICE(*args, **kwargs) except sh.ErrorReturnCode as exception: raise OfficeConversionError(exception) + except Exception as exception: + logger.error('Exception launching Libre Office; %s', exception) + raise finally: fs_cleanup(input_filepath) + fs_cleanup(libreoffice_home_directory) filename, extension = os.path.splitext( os.path.basename(input_filepath) @@ -173,25 +184,25 @@ class ConverterBase(object): fs_cleanup(converted_output) def get_page(self, output_format=DEFAULT_FILE_FORMAT, as_base64=False): - if not self.image: - self.seek(0) - image_buffer = StringIO() - new_mode = self.image.mode - - if output_format.upper() == 'JPEG': - if self.image.mode == 'P': - new_mode = 'RGB' - if 'transparency' in self.image.info: - new_mode = 'RGBA' - - self.image.convert(new_mode).save(image_buffer, format=output_format) - - if as_base64: - return 'data:{};base64,{}'.format(Image.MIME[output_format], base64.b64encode(image_buffer.getvalue())) + if not self.image: + self.seek(0) + self.convert(page_number=self.page_number) else: - image_buffer.seek(0) + new_mode = self.image.mode + + if output_format.upper() == 'JPEG': + # JPEG doesn't support transparency channel, convert the image to + # RGB. Removes modes: P and RGBA + new_mode = 'RGB' + + self.image.convert(new_mode).save(image_buffer, format=output_format) + + if as_base64: + return 'data:{};base64,{}'.format(Image.MIME[output_format], base64.b64encode(image_buffer.getvalue())) + else: + image_buffer.seek(0) return image_buffer