Moved document preview generation to model, implmented pre caching
This commit is contained in:
@@ -2,6 +2,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import validate_path
|
||||
from navigation.api import register_links, register_top_menu, \
|
||||
register_model_list_columns, register_multi_item_links, \
|
||||
register_sidebar_template
|
||||
@@ -24,8 +25,25 @@ from documents.literals import HISTORY_DOCUMENT_CREATED, \
|
||||
HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED
|
||||
from documents.conf.settings import ZOOM_MAX_LEVEL
|
||||
from documents.conf.settings import ZOOM_MIN_LEVEL
|
||||
from documents.conf.settings import CACHE_PATH
|
||||
from documents.widgets import document_thumbnail
|
||||
|
||||
# Document page links expressions
|
||||
def is_first_page(context):
|
||||
return context['object'].page_number <= 1
|
||||
|
||||
|
||||
def is_last_page(context):
|
||||
return context['object'].page_number >= context['object'].document.documentpage_set.count()
|
||||
|
||||
|
||||
def is_min_zoom(context):
|
||||
return context['zoom'] <= ZOOM_MIN_LEVEL
|
||||
|
||||
|
||||
def is_max_zoom(context):
|
||||
return context['zoom'] >= ZOOM_MAX_LEVEL
|
||||
|
||||
# Permission setup
|
||||
set_namespace_title('documents', _(u'Documents'))
|
||||
register_permission(PERMISSION_DOCUMENT_CREATE)
|
||||
@@ -48,23 +66,6 @@ register_history_type(HISTORY_DOCUMENT_CREATED)
|
||||
register_history_type(HISTORY_DOCUMENT_EDITED)
|
||||
register_history_type(HISTORY_DOCUMENT_DELETED)
|
||||
|
||||
|
||||
# Document page links expressions
|
||||
def is_first_page(context):
|
||||
return context['object'].page_number <= 1
|
||||
|
||||
|
||||
def is_last_page(context):
|
||||
return context['object'].page_number >= context['object'].document.documentpage_set.count()
|
||||
|
||||
|
||||
def is_min_zoom(context):
|
||||
return context['zoom'] <= ZOOM_MIN_LEVEL
|
||||
|
||||
|
||||
def is_max_zoom(context):
|
||||
return context['zoom'] >= ZOOM_MAX_LEVEL
|
||||
|
||||
document_list = {'text': _(u'all documents'), 'view': 'document_list', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
|
||||
document_list_recent = {'text': _(u'recent documents'), 'view': 'document_list_recent', 'famfam': 'page', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
|
||||
document_create_multiple = {'text': _(u'upload new documents'), 'view': 'document_create_multiple', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_CREATE]}
|
||||
@@ -198,3 +199,5 @@ register_sidebar_template(['document_type_list'], 'document_types_help.html')
|
||||
register_links(Document, [document_view_simple], menu_name='form_header', position=0)
|
||||
register_links(Document, [document_view_advanced], menu_name='form_header', position=1)
|
||||
register_links(Document, [document_history_view], menu_name='form_header')
|
||||
|
||||
validate_path(CACHE_PATH)
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
import hashlib
|
||||
import uuid
|
||||
import os
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from storage.backends.filebasedstorage import FileBasedStorage
|
||||
from smart_settings.api import register_settings
|
||||
@@ -38,5 +40,7 @@ register_settings(
|
||||
{'name': u'ZOOM_MAX_LEVEL', 'global_name': u'DOCUMENTS_ZOOM_MAX_LEVEL', 'default': 200, 'description': _(u'Maximum amount in percent (%) to allow user to zoom in a document page interactively.')},
|
||||
{'name': u'ZOOM_MIN_LEVEL', 'global_name': u'DOCUMENTS_ZOOM_MIN_LEVEL', 'default': 50, 'description': _(u'Minimum amount in percent (%) to allow user to zoom out a document page interactively.')},
|
||||
{'name': u'ROTATION_STEP', 'global_name': u'DOCUMENTS_ROTATION_STEP', 'default': 90, 'description': _(u'Amount in degrees to rotate a document page per user interaction.')},
|
||||
#
|
||||
{'name': u'CACHE_PATH', 'global_name': u'DOCUMENTS_CACHE_PATH', 'default': os.path.join(settings.PROJECT_ROOT, 'image_cache'), 'exists': True},
|
||||
]
|
||||
)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import os
|
||||
import tempfile
|
||||
import hashlib
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes import generic
|
||||
from django.contrib.comments.models import Comment
|
||||
from django.conf import settings
|
||||
|
||||
from python_magic import magic
|
||||
|
||||
@@ -13,12 +15,26 @@ from taggit.managers import TaggableManager
|
||||
from dynamic_search.api import register
|
||||
from converter.api import get_page_count
|
||||
from converter.api import get_available_transformations_choices
|
||||
from converter.api import create_image_cache_filename, convert
|
||||
from converter.exceptions import UnknownFormat, UnkownConvertError
|
||||
|
||||
from documents.conf.settings import CHECKSUM_FUNCTION
|
||||
from documents.conf.settings import UUID_FUNCTION
|
||||
from documents.conf.settings import STORAGE_BACKEND
|
||||
from documents.conf.settings import PREVIEW_SIZE
|
||||
from documents.conf.settings import THUMBNAIL_SIZE
|
||||
from documents.conf.settings import CACHE_PATH
|
||||
|
||||
from documents.managers import RecentDocumentManager, \
|
||||
DocumentPageTransformationManager
|
||||
from documents.utils import document_save_to_temp_dir
|
||||
from documents.literals import PICTURE_ERROR_SMALL, PICTURE_ERROR_MEDIUM, \
|
||||
PICTURE_UNKNOWN_SMALL, PICTURE_UNKNOWN_MEDIUM
|
||||
from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \
|
||||
DEFAULT_FILE_FORMAT, DEFAULT_PAGE_NUMBER
|
||||
|
||||
# document image cache name hash function
|
||||
HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest()
|
||||
|
||||
|
||||
def get_filename_from_uuid(instance, filename):
|
||||
@@ -201,8 +217,7 @@ class Document(models.Model):
|
||||
exists in storage
|
||||
"""
|
||||
return self.file.storage.exists(self.file.path)
|
||||
|
||||
|
||||
|
||||
def apply_default_transformations(self, transformations):
|
||||
#Only apply default transformations on new documents
|
||||
if reduce(lambda x, y: x + y, [page.documentpagetransformation_set.count() for page in self.documentpage_set.all()]) == 0:
|
||||
@@ -216,6 +231,29 @@ class Document(models.Model):
|
||||
)
|
||||
|
||||
page_transformation.save()
|
||||
|
||||
def get_image_cache_name(self, page):
|
||||
document_page = self.documentpage_set.get(page_number=page)
|
||||
transformations, warnings = document_page.get_transformation_list()
|
||||
hash_value = HASH_FUNCTION(u''.join([self.checksum, unicode(page), unicode(transformations)]))
|
||||
cache_file_path = os.path.join(CACHE_PATH, hash_value)
|
||||
if os.path.exists(cache_file_path):
|
||||
return cache_file_path
|
||||
else:
|
||||
document_file = document_save_to_temp_dir(self, self.checksum)
|
||||
return convert(document_file, output_filepath=cache_file_path, page=page, transformations=transformations)
|
||||
|
||||
def get_image(self, size=PREVIEW_SIZE, page=DEFAULT_PAGE_NUMBER, zoom=DEFAULT_ZOOM_LEVEL, rotation=DEFAULT_ROTATION):
|
||||
try:
|
||||
image_cache_name = self.get_image_cache_name(page=page)
|
||||
output_file = convert(image_cache_name, cleanup_files=False, size=size, zoom=zoom, rotation=rotation)
|
||||
except UnknownFormat:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_UNKNOWN_SMALL)
|
||||
except UnkownConvertError:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_SMALL)
|
||||
except Exception, e:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_SMALL)
|
||||
return output_file
|
||||
|
||||
|
||||
class DocumentTypeFilename(models.Model):
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
from converter.literals import QUALITY_HIGH, QUALITY_PRINT
|
||||
|
||||
from documents.conf.settings import PREVIEW_SIZE
|
||||
from documents.conf.settings import PRINT_SIZE
|
||||
from documents.conf.settings import THUMBNAIL_SIZE
|
||||
@@ -24,8 +22,8 @@ urlpatterns = patterns('documents.views',
|
||||
url(r'^(?P<document_id>\d+)/display/preview/$', 'get_document_image', {'size': PREVIEW_SIZE}, 'document_preview'),
|
||||
url(r'^(?P<document_id>\d+)/display/preview/multipage/$', 'get_document_image', {'size': MULTIPAGE_PREVIEW_SIZE}, 'document_preview_multipage'),
|
||||
url(r'^(?P<document_id>\d+)/display/thumbnail/$', 'get_document_image', {'size': THUMBNAIL_SIZE}, 'document_thumbnail'),
|
||||
url(r'^(?P<document_id>\d+)/display/$', 'get_document_image', {'size': DISPLAY_SIZE, 'quality': QUALITY_HIGH}, 'document_display'),
|
||||
url(r'^(?P<document_id>\d+)/display/print/$', 'get_document_image', {'size': PRINT_SIZE, 'quality': QUALITY_PRINT}, 'document_display_print'),
|
||||
url(r'^(?P<document_id>\d+)/display/$', 'get_document_image', {'size': DISPLAY_SIZE}, 'document_display'),
|
||||
url(r'^(?P<document_id>\d+)/display/print/$', 'get_document_image', {'size': PRINT_SIZE}, 'document_display_print'),
|
||||
|
||||
url(r'^(?P<document_id>\d+)/download/$', 'document_download', (), 'document_download'),
|
||||
url(r'^(?P<document_id>\d+)/create/siblings/$', 'document_create_siblings', (), 'document_create_siblings'),
|
||||
|
||||
@@ -20,11 +20,8 @@ from common.widgets import two_state_template
|
||||
from common.literals import PAGE_SIZE_DIMENSIONS, \
|
||||
PAGE_ORIENTATION_PORTRAIT, PAGE_ORIENTATION_LANDSCAPE
|
||||
from common.conf.settings import DEFAULT_PAPER_SIZE
|
||||
from converter.api import convert_document
|
||||
from converter.exceptions import UnkownConvertError, UnknownFormat
|
||||
from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \
|
||||
DEFAULT_FILE_FORMAT, QUALITY_PRINT, QUALITY_DEFAULT, \
|
||||
DEFAULT_PAGE_NUMBER
|
||||
DEFAULT_FILE_FORMAT, DEFAULT_PAGE_NUMBER
|
||||
from filetransfers.api import serve_file
|
||||
from grouping.utils import get_document_group_subtemplate
|
||||
from metadata.api import save_metadata_list, \
|
||||
@@ -287,7 +284,7 @@ def document_edit(request, document_id):
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def get_document_image(request, document_id, size=PREVIEW_SIZE, quality=QUALITY_DEFAULT):
|
||||
def get_document_image(request, document_id, size=PREVIEW_SIZE):
|
||||
check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW])
|
||||
|
||||
document = get_object_or_404(Document, pk=document_id)
|
||||
@@ -304,36 +301,7 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, quality=QUALITY_
|
||||
|
||||
rotation = int(request.GET.get('rotation', DEFAULT_ROTATION)) % 360
|
||||
|
||||
document_page = get_object_or_404(document.documentpage_set, page_number=page)
|
||||
transformations, warnings = document_page.get_transformation_list()
|
||||
|
||||
if warnings and (request.user.is_staff or request.user.is_superuser):
|
||||
for warning in warnings:
|
||||
messages.warning(request, _(u'Page transformation error: %s') % warning)
|
||||
|
||||
try:
|
||||
output_file = convert_document(document, size=size, file_format=DEFAULT_FILE_FORMAT, quality=quality, page=page, zoom=zoom, rotation=rotation, transformations=transformations)
|
||||
except UnkownConvertError, e:
|
||||
if request.user.is_staff or request.user.is_superuser:
|
||||
messages.error(request, e)
|
||||
if size == THUMBNAIL_SIZE:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_SMALL)
|
||||
else:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_MEDIUM)
|
||||
except UnknownFormat:
|
||||
if size == THUMBNAIL_SIZE:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_UNKNOWN_SMALL)
|
||||
else:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_UNKNOWN_MEDIUM)
|
||||
except Exception, e:
|
||||
if request.user.is_staff or request.user.is_superuser:
|
||||
messages.error(request, e)
|
||||
if size == THUMBNAIL_SIZE:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_SMALL)
|
||||
else:
|
||||
output_file = os.path.join(settings.MEDIA_ROOT, u'images', PICTURE_ERROR_MEDIUM)
|
||||
finally:
|
||||
return sendfile.sendfile(request, output_file)
|
||||
return sendfile.sendfile(request, document.get_image(size=size, page=page, zoom=zoom, rotation=rotation))
|
||||
|
||||
|
||||
def document_download(request, document_id):
|
||||
@@ -804,13 +772,14 @@ def document_print(request, document_id):
|
||||
|
||||
|
||||
def document_hard_copy(request, document_id):
|
||||
#TODO: FIXME
|
||||
check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW])
|
||||
|
||||
document = get_object_or_404(Document, pk=document_id)
|
||||
|
||||
RecentDocument.objects.add_document_for_user(request.user, document)
|
||||
|
||||
arguments, warnings = calculate_converter_arguments(document, size=PRINT_SIZE, file_format=DEFAULT_FILE_FORMAT, quality=QUALITY_PRINT)
|
||||
arguments, warnings = calculate_converter_arguments(document, size=PRINT_SIZE, file_format=DEFAULT_FILE_FORMAT)
|
||||
|
||||
# Pre-generate
|
||||
convert_document(document, **arguments)
|
||||
|
||||
Reference in New Issue
Block a user