From 1786764e5fe49823e83119746eb0197f6c0454a3 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 12 Feb 2011 04:12:39 -0400 Subject: [PATCH] New abstracted options to adjust document conversion quality (default, low, high) --- apps/converter/api.py | 44 +++++++++++++++++++++++++-------- apps/converter/conf/settings.py | 3 +++ apps/documents/conf/settings.py | 2 +- apps/documents/urls.py | 5 +++- apps/documents/views.py | 12 ++++----- docs/Changelog.txt | 1 + docs/TODO | 2 ++ settings.py | 9 ++++++- 8 files changed, 59 insertions(+), 19 deletions(-) diff --git a/apps/converter/api.py b/apps/converter/api.py index 0f224507de..57260072dc 100755 --- a/apps/converter/api.py +++ b/apps/converter/api.py @@ -4,15 +4,29 @@ import subprocess import tempfile import shutil +from django.template.defaultfilters import slugify + + from documents.utils import from_descriptor_to_tempfile from converter.conf.settings import CONVERT_PATH from converter.conf.settings import OCR_OPTIONS +from converter.conf.settings import DEFAULT_OPTIONS +from converter.conf.settings import LOW_QUALITY_OPTIONS +from converter.conf.settings import HIGH_QUALITY_OPTIONS + #from converter.conf.settings import UNOCONV_PATH from converter import TEMPORARY_DIRECTORY +QUALITY_DEFAULT = 'quality_default' +QUALITY_LOW = 'quality_low' +QUALITY_HIGH = 'quality_high' + +QUALITY_SETTINGS = {QUALITY_DEFAULT:DEFAULT_OPTIONS, QUALITY_LOW:LOW_QUALITY_OPTIONS, + QUALITY_HIGH:HIGH_QUALITY_OPTIONS} + class ConvertError(Exception): def __init__(self, status, message): self.status = status @@ -37,8 +51,11 @@ def get_errors(error_string): #TODO: Timeout & kill child -def execute_convert(input_filepath, arguments, output_filepath): - command = [CONVERT_PATH, input_filepath] +def execute_convert(input_filepath, arguments, output_filepath, quality=QUALITY_DEFAULT): + command = [] + command.append(CONVERT_PATH) + command.extend(shlex.split(str(QUALITY_SETTINGS[quality]))) + command.append(input_filepath) command.extend(shlex.split(str(arguments))) command.append(output_filepath) @@ -64,26 +81,33 @@ def cache_cleanup(input_filepath, size, page=0, format='jpg'): pass -def create_image_cache_filename(input_filepath, size, page=0, format='jpg'): +def create_image_cache_filename(input_filepath, quality=QUALITY_DEFAULT, *args, **kwargs): if input_filepath: temp_filename, separator = os.path.splitext(os.path.basename(input_filepath)) temp_path = os.path.join(TEMPORARY_DIRECTORY, temp_filename) - return '%s_%s_%s%s%s' % (temp_path, page, size, os.extsep, format) + + final_filepath = [] + [final_filepath.append(str(arg)) for arg in args] + final_filepath.extend(['%s_%s' % (key, value) for key, value in kwargs.items()]) + final_filepath.append(QUALITY_SETTINGS[quality]) + + temp_path += slugify('_'.join(final_filepath)) + + return temp_path else: return None - -def in_image_cache(input_filepath, size, page=0, format='jpg'): - output_filepath = create_image_cache_filename(input_filepath, size, page, format) +def in_image_cache(input_filepath, size, page=0, format='jpg', quality=QUALITY_DEFAULT): + output_filepath = create_image_cache_filename(input_filepath, size=size, page=page, format=format, quality=quality) if os.path.exists(output_filepath): return output_filepath else: return None -def convert(input_filepath, size, cache=True, page=0, format='jpg', mimetype=None, extension=None): +def convert(input_filepath, size, quality=QUALITY_DEFAULT, cache=True, page=0, format='jpg', mimetype=None, extension=None): unoconv_output = None - output_filepath = create_image_cache_filename(input_filepath, size, page, format) + output_filepath = create_image_cache_filename(input_filepath, size=size, page=page, format=format, quality=quality) if os.path.exists(output_filepath): return output_filepath ''' @@ -100,7 +124,7 @@ def convert(input_filepath, size, cache=True, page=0, format='jpg', mimetype=Non #TODO: Check mimetype and use corresponding utility try: input_arg = '%s[%s]' % (input_filepath, page) - status, error_string = execute_convert(input_arg, '-resize %s' % size, output_filepath) + status, error_string = execute_convert(input_arg, '-resize %s' % size, '%s:%s' % (format, output_filepath), quality=quality) if status: errors = get_errors(error_string) raise ConvertError(status, errors) diff --git a/apps/converter/conf/settings.py b/apps/converter/conf/settings.py index 28ac04f8cb..6ef7cd996f 100755 --- a/apps/converter/conf/settings.py +++ b/apps/converter/conf/settings.py @@ -2,3 +2,6 @@ from django.conf import settings CONVERT_PATH = getattr(settings, 'CONVERTER_CONVERT_PATH', u'/usr/bin/convert') OCR_OPTIONS = getattr(settings, 'CONVERTER_OCR_OPTIONS', u'-colorspace Gray -depth 8 -resample 200x200') +DEFAULT_OPTIONS = getattr(settings, 'CONVERTER_DEFAULT_OPTIONS', u'') +LOW_QUALITY_OPTIONS = getattr(settings, 'CONVERTER_LOW_QUALITY_OPTIONS', u'') +HIGH_QUALITY_OPTIONS = getattr(settings, 'CONVERTER_HIGH_QUALITY_OPTIONS', u'-density 400') diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py index f35d48dc10..42314d2c78 100755 --- a/apps/documents/conf/settings.py +++ b/apps/documents/conf/settings.py @@ -37,7 +37,7 @@ STORAGE_DIRECTORY_NAME = getattr(settings, 'DOCUMENTS_STORAGE_DIRECTORY_NAME', ' # Usage PREVIEW_SIZE = getattr(settings, 'DOCUMENTS_PREVIEW_SIZE', '640x480') THUMBNAIL_SIZE = getattr(settings, 'DOCUMENTS_THUMBNAIL_SIZE', '50x50') -DISPLAY_SIZE = getattr(settings, 'DOCUMENTS_DISPLAY_SIZE', '1024x768') +DISPLAY_SIZE = getattr(settings, 'DOCUMENTS_DISPLAY_SIZE', '1200') #Groups GROUP_MAX_RESULTS = getattr(settings, 'DOCUMENTS_GROUP_MAX_RESULTS', 20) diff --git a/apps/documents/urls.py b/apps/documents/urls.py index cf28c9b487..fb3156e15b 100755 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -6,6 +6,9 @@ from documents.conf.settings import PREVIEW_SIZE from documents.conf.settings import THUMBNAIL_SIZE from documents.conf.settings import DISPLAY_SIZE +from converter.api import QUALITY_HIGH + + urlpatterns = patterns('documents.views', url(r'^document/list/$', 'document_list', (), 'document_list'), url(r'^document/create/from/local/single/$', 'document_create', {'multiple':False}, 'document_create'), @@ -18,7 +21,7 @@ urlpatterns = patterns('documents.views', url(r'^document/(?P\d+)/edit/metadata/$', 'document_edit_metadata', (), 'document_edit_metadata'), url(r'^document/(?P\d+)/preview/$', 'get_document_image', {'size':PREVIEW_SIZE}, 'document_preview'), url(r'^document/(?P\d+)/thumbnail/$', 'get_document_image', {'size':THUMBNAIL_SIZE}, 'document_thumbnail'), - url(r'^document/(?P\d+)/display/$', 'get_document_image', {'size':DISPLAY_SIZE}, 'document_display'), + url(r'^document/(?P\d+)/display/$', 'get_document_image', {'size':DISPLAY_SIZE,'quality':QUALITY_HIGH}, 'document_display'), url(r'^document/(?P\d+)/download/$', 'document_download', (), 'document_download'), url(r'^document/(?P\d+)/create/siblings/$', 'document_create_sibling', {'multiple':False}, 'document_create_sibling'), diff --git a/apps/documents/views.py b/apps/documents/views.py index 47739dd3ac..5468a89e08 100755 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -13,7 +13,7 @@ from django.utils.http import urlencode from django.template.defaultfilters import slugify from filetransfers.api import serve_file -from converter.api import convert, in_image_cache +from converter.api import convert, in_image_cache, QUALITY_DEFAULT from common.utils import pretty_size from utils import from_descriptor_to_tempfile @@ -374,20 +374,20 @@ def document_edit_metadata(request, document_id): }, context_instance=RequestContext(request)) -def get_document_image(request, document_id, size=PREVIEW_SIZE): +def get_document_image(request, document_id, size=PREVIEW_SIZE, quality=QUALITY_DEFAULT): document = get_object_or_404(Document, pk=document_id) try: - filepath = in_image_cache(document.checksum, size) - + filepath = in_image_cache(document.checksum, size=size, quality=quality) + if filepath: return serve_file(request, File(file=open(filepath, 'r'))) #Save to a temporary location document.file.open() desc = document.file.storage.open(document.file.path) filepath = from_descriptor_to_tempfile(desc, document.checksum) - output_file = convert(filepath, size) - return serve_file(request, File(file=open(output_file, 'r'))) + output_file = convert(filepath, size=size, format='jpg', quality=quality) + return serve_file(request, File(file=open(output_file, 'r')), content_type='image/jpeg') except Exception, e: if size == THUMBNAIL_SIZE: return serve_file(request, File(file=open('%simages/picture_error.png' % settings.MEDIA_ROOT, 'r'))) diff --git a/docs/Changelog.txt b/docs/Changelog.txt index 3bee993bda..f6cf3e2542 100644 --- a/docs/Changelog.txt +++ b/docs/Changelog.txt @@ -4,3 +4,4 @@ * If one document type exists, the create document wizard skips the first step. * Changed to a liquid css grid * Added the ability to group documents by their metadata +* New abstracted options to adjust document conversion quality (default, low, high) diff --git a/docs/TODO b/docs/TODO index 28cffe5641..60c6cadd7a 100755 --- a/docs/TODO +++ b/docs/TODO @@ -60,3 +60,5 @@ * Support spreadsheets, wordprocessing docs using openoffice in server mode * WebDAV support * Handle ziped or rar archives +* Display preferences (Rotation, default zoom) +* Gallery view for document groups diff --git a/settings.py b/settings.py index c5eeae4564..f4f981399e 100755 --- a/settings.py +++ b/settings.py @@ -189,7 +189,7 @@ LOGIN_EXEMPT_URLS = ( # Usage #DOCUMENTS_PREVIEW_SIZE = '640x480' #DOCUMENTS_THUMBNAIL_SIZE = '50x50' -#DOCUMENTS_DISPLAY_SIZE = '1024x768' +#DOCUMENTS_DISPLAY_SIZE = '1200' # Groups #DOCUMENTS_GROUP_MAX_RESULTS = 20 @@ -203,8 +203,15 @@ LOGIN_EXEMPT_URLS = ( # Misc #DOCUMENTS_TEMPORARY_DIRECTORY = u'/tmp' + +# Converter +#CONVERTER_DEFAULT_OPTIONS = u'' +#CONVERTER_LOW_QUALITY_OPTIONS = u'' +#CONVERTER_HIGH_QUALITY_OPTIONS = u'-density 400' #CONVERTER_CONVERT_PATH = u'/usr/bin/convert' #CONVERTER_OCR_OPTIONS = u'-colorspace Gray -depth 8 -resample 200x200' + +# OCR #OCR_TESSERACT_PATH = u'/usr/bin/tesseract' # Override