diff --git a/apps/converter/api.py b/apps/converter/api.py
index fb8b189745..f05c05f69b 100644
--- a/apps/converter/api.py
+++ b/apps/converter/api.py
@@ -9,6 +9,7 @@ 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 PRINT_QUALITY_OPTIONS
from converter.conf.settings import GRAPHICS_BACKEND
from converter.conf.settings import UNOCONV_PATH
@@ -26,9 +27,14 @@ DEFAULT_OCR_FILE_FORMAT = u'tif'
QUALITY_DEFAULT = u'quality_default'
QUALITY_LOW = u'quality_low'
QUALITY_HIGH = u'quality_high'
+QUALITY_PRINT = u'quality_print'
-QUALITY_SETTINGS = {QUALITY_DEFAULT: DEFAULT_OPTIONS,
- QUALITY_LOW: LOW_QUALITY_OPTIONS, QUALITY_HIGH: HIGH_QUALITY_OPTIONS}
+QUALITY_SETTINGS = {
+ QUALITY_DEFAULT: DEFAULT_OPTIONS,
+ QUALITY_LOW: LOW_QUALITY_OPTIONS,
+ QUALITY_HIGH: HIGH_QUALITY_OPTIONS,
+ QUALITY_PRINT: PRINT_QUALITY_OPTIONS
+}
CONVERTER_OFFICE_FILE_EXTENSIONS = [
u'ods', u'docx', u'doc'
@@ -177,6 +183,15 @@ def get_page_count(input_filepath):
return 1
+def get_document_dimensions(document, *args, **kwargs):
+ document_filepath = create_image_cache_filename(document.checksum, *args, **kwargs)
+ if os.path.exists(document_filepath):
+ options = [u'-format', u'%w %h']
+ return [int(dimension) for dimension in backend.execute_identify(unicode(document_filepath), options).split()]
+ else:
+ return [0, 0]
+
+
def convert_document_for_ocr(document, page=DEFAULT_PAGE_INDEX_NUMBER, file_format=DEFAULT_OCR_FILE_FORMAT):
#Extract document file
input_filepath = document_save_to_temp_dir(document, document.uuid)
diff --git a/apps/converter/backends/graphicsmagick.py b/apps/converter/backends/graphicsmagick.py
index 52f298033b..a1a0bc5797 100644
--- a/apps/converter/backends/graphicsmagick.py
+++ b/apps/converter/backends/graphicsmagick.py
@@ -9,11 +9,12 @@ CONVERTER_ERROR_STRING_NO_DECODER = u'No decode delegate for this image format'
CONVERTER_ERROR_STARTS_WITH = u'starts with'
-def execute_identify(input_filepath, arguments=u''):
+def execute_identify(input_filepath, arguments=None):
command = []
command.append(unicode(GM_PATH))
command.append(u'identify')
- command.extend(unicode(arguments).split())
+ if arguments:
+ command.extend(arguments)
command.append(unicode(input_filepath))
proc = subprocess.Popen(command, close_fds=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
return_code = proc.wait()
diff --git a/apps/converter/backends/imagemagick.py b/apps/converter/backends/imagemagick.py
index c60f6bc341..a2b99b2c96 100644
--- a/apps/converter/backends/imagemagick.py
+++ b/apps/converter/backends/imagemagick.py
@@ -9,10 +9,11 @@ from converter.exceptions import ConvertError, UnknownFormat, \
CONVERTER_ERROR_STRING_NO_DECODER = u'no decode delegate for this image format'
-def execute_identify(input_filepath, arguments=u''):
+def execute_identify(input_filepath, arguments=None):
command = []
command.append(unicode(IM_IDENTIFY_PATH))
- command.extend(unicode(arguments).split())
+ if arguments:
+ command.extend(arguments)
command.append(unicode(input_filepath))
proc = subprocess.Popen(command, close_fds=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
diff --git a/apps/converter/conf/settings.py b/apps/converter/conf/settings.py
index 2a4e417431..7b23e72243 100644
--- a/apps/converter/conf/settings.py
+++ b/apps/converter/conf/settings.py
@@ -14,6 +14,7 @@ OCR_OPTIONS = getattr(settings, 'CONVERTER_OCR_OPTIONS', u'-colorspace Gray -dep
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')
+PRINT_QUALITY_OPTIONS = getattr(settings, 'CONVERTER_HIGH_QUALITY_OPTIONS', u'-density 500')
setting_description = {
diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py
index 5f7a287198..d0b4c5db09 100644
--- a/apps/documents/__init__.py
+++ b/apps/documents/__init__.py
@@ -52,6 +52,7 @@ document_find_duplicates = {'text': _(u'find duplicates'), 'view': 'document_fin
document_find_all_duplicates = {'text': _(u'find all duplicates'), 'view': 'document_find_all_duplicates', 'famfam': 'page_refresh', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}, 'description': _(u'Search all the documents\' checksums and return a list of the exact matches.')}
document_clear_transformations = {'text': _(u'clear all transformations'), 'view': 'document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
document_multiple_clear_transformations = {'text': _(u'clear all transformations'), 'view': 'document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
+document_print = {'text': _(u'print'), 'view': 'document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
document_page_transformation_list = {'text': _(u'page transformations'), 'class': 'no-parent-history', 'view': 'document_page_transformation_list', 'args': 'object.id', 'famfam': 'pencil_go', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
document_page_transformation_create = {'text': _(u'create new transformation'), 'class': 'no-parent-history', 'view': 'document_page_transformation_create', 'args': 'object.id', 'famfam': 'pencil_add', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
@@ -82,7 +83,7 @@ metadata_group_create_sibling = {'text': _(u'upload new document using same meta
staging_file_preview = {'text': _(u'preview'), 'class': 'fancybox-noscaling', 'view': 'staging_file_preview', 'args': 'object.id', 'famfam': 'drive_magnify'}
staging_file_delete = {'text': _(u'delete'), 'view': 'staging_file_delete', 'args': 'object.id', 'famfam': 'drive_delete'}
-register_links(Document, [document_view_simple, document_view, document_edit, document_edit_metadata, document_delete, document_download, document_find_duplicates, document_clear_transformations])
+register_links(Document, [document_view_simple, document_view, document_edit, document_edit_metadata, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations])
register_links(Document, [document_create_sibling], menu_name='sidebar')
register_multi_item_links(['metadatagroup_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_edit_metadata, document_multiple_delete])
diff --git a/apps/documents/conf/settings.py b/apps/documents/conf/settings.py
index aa518b5dd5..6ea4c16070 100644
--- a/apps/documents/conf/settings.py
+++ b/apps/documents/conf/settings.py
@@ -59,6 +59,7 @@ STORAGE_BACKEND = getattr(settings, 'DOCUMENTS_STORAGE_BACKEND', FileBasedStorag
# Usage
PREVIEW_SIZE = getattr(settings, 'DOCUMENTS_PREVIEW_SIZE', '640x480')
+PRINT_SIZE = getattr(settings, 'DOCUMENTS_PREVIEW_SIZE', '1400')
MULTIPAGE_PREVIEW_SIZE = getattr(settings, 'DOCUMENTS_MULTIPAGE_PREVIEW_SIZE', '160x120')
THUMBNAIL_SIZE = getattr(settings, 'DOCUMENTS_THUMBNAIL_SIZE', '50x50')
DISPLAY_SIZE = getattr(settings, 'DOCUMENTS_DISPLAY_SIZE', '1200')
diff --git a/apps/documents/templates/document_print.html b/apps/documents/templates/document_print.html
new file mode 100644
index 0000000000..bd5cc3d648
--- /dev/null
+++ b/apps/documents/templates/document_print.html
@@ -0,0 +1,54 @@
+{% load project_tags %}
+{% load printing_tags %}
+
+
+
+
+
+ {% project_name %}
+
+
+
+
+
+
+ {% get_document_size object %}
+ {{ document_width }} {{ document_height }}
+
document_height %}width="100%"{% else %}height="100%"{% endif %} />
+
+
diff --git a/apps/documents/templatetags/__init__.py b/apps/documents/templatetags/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/documents/templatetags/printing_tags.py b/apps/documents/templatetags/printing_tags.py
new file mode 100644
index 0000000000..aa59a40c3a
--- /dev/null
+++ b/apps/documents/templatetags/printing_tags.py
@@ -0,0 +1,24 @@
+from django.template import TemplateSyntaxError, Library, \
+ VariableDoesNotExist, Node, Variable
+from converter.api import get_document_dimensions, QUALITY_PRINT
+from documents.views import calculate_converter_arguments
+from documents.conf.settings import PRINT_SIZE
+
+register = Library()
+
+
+class GetImageSizeNode(Node):
+ def __init__(self, document):
+ self.document = document
+
+ def render(self, context):
+ document = Variable(self.document).resolve(context)
+ arguments, warnings = calculate_converter_arguments(document, size=PRINT_SIZE, quality=QUALITY_PRINT)
+ context[u'document_width'], context['document_height'] = get_document_dimensions(document, **arguments)
+ return u''
+
+@register.tag
+def get_document_size(parser, token):
+ tag_name, arg = token.contents.split(None, 1)
+
+ return GetImageSizeNode(document=arg)
diff --git a/apps/documents/urls.py b/apps/documents/urls.py
index dbf8e1dd4d..c85e714815 100644
--- a/apps/documents/urls.py
+++ b/apps/documents/urls.py
@@ -1,12 +1,13 @@
from django.conf.urls.defaults import patterns, url
from documents.conf.settings import PREVIEW_SIZE
+from documents.conf.settings import PRINT_SIZE
from documents.conf.settings import THUMBNAIL_SIZE
from documents.conf.settings import DISPLAY_SIZE
from documents.conf.settings import MULTIPAGE_PREVIEW_SIZE
from documents.conf.settings import ENABLE_SINGLE_DOCUMENT_UPLOAD
-from converter.api import QUALITY_HIGH
+from converter.api import QUALITY_HIGH, QUALITY_PRINT
urlpatterns = patterns('documents.views',
url(r'^document/list/$', 'document_list', (), 'document_list'),
@@ -22,11 +23,13 @@ urlpatterns = patterns('documents.views',
url(r'^document/(?P\d+)/edit/$', 'document_edit', (), 'document_edit'),
url(r'^document/(?P\d+)/edit/metadata/$', 'document_edit_metadata', (), 'document_edit_metadata'),
url(r'^document/multiple/edit/metadata/$', 'document_multiple_edit_metadata', (), 'document_multiple_edit_metadata'),
+ url(r'^document/(?P\d+)/print/$', 'document_print', (), 'document_print'),
url(r'^document/(?P\d+)/display/preview/$', 'get_document_image', {'size': PREVIEW_SIZE}, 'document_preview'),
url(r'^document/(?P\d+)/display/preview/multipage/$', 'get_document_image', {'size': MULTIPAGE_PREVIEW_SIZE}, 'document_preview_multipage'),
url(r'^document/(?P\d+)/display/thumbnail/$', 'get_document_image', {'size': THUMBNAIL_SIZE}, 'document_thumbnail'),
url(r'^document/(?P\d+)/display/$', 'get_document_image', {'size': DISPLAY_SIZE, 'quality': QUALITY_HIGH}, 'document_display'),
+ url(r'^document/(?P\d+)/display/print/$', 'get_document_image', {'size': PRINT_SIZE, 'quality': QUALITY_PRINT}, 'document_display_print'),
url(r'^document/(?P\d+)/download/$', 'document_download', (), 'document_download'),
url(r'^document/(?P\d+)/create/siblings/$', 'document_create_sibling', {'multiple': True if ENABLE_SINGLE_DOCUMENT_UPLOAD == False else False}, 'document_create_sibling'),
diff --git a/apps/documents/views.py b/apps/documents/views.py
index 4d053d3f28..a8a9fac285 100644
--- a/apps/documents/views.py
+++ b/apps/documents/views.py
@@ -27,6 +27,8 @@ from permissions.api import check_permissions
from navigation.utils import resolve_to_name
from tags.utils import get_tags_subtemplate
from document_comments.utils import get_comments_subtemplate
+from converter.api import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \
+ DEFAULT_FILE_FORMAT
from documents.conf.settings import DELETE_STAGING_FILE_AFTER_UPLOAD
from documents.conf.settings import USE_STAGING_DIRECTORY
@@ -537,6 +539,30 @@ def document_multiple_edit_metadata(request):
return document_edit_metadata(request, document_id_list=request.GET.get('id_list', []))
+def calculate_converter_arguments(document, *args, **kwargs):
+ size = kwargs.pop('size', PREVIEW_SIZE)
+ quality = kwargs.pop('quality', QUALITY_DEFAULT)
+ page = kwargs.pop('page', 1)
+ file_format = kwargs.pop('file_format', DEFAULT_FILE_FORMAT)
+ zoom = kwargs.pop('zoom', DEFAULT_ZOOM_LEVEL)
+ rotation = kwargs.pop('rotation', DEFAULT_ROTATION)
+
+ document_page = DocumentPage.objects.get(document=document, page_number=page)
+ transformation_string, warnings = document_page.get_transformation_string()
+
+ arguments = {
+ 'size': size,
+ 'file_format': file_format,
+ 'quality': quality,
+ 'extra_options': transformation_string,
+ 'page': page - 1,
+ 'zoom': zoom,
+ 'rotation': rotation
+ }
+
+ return arguments, warnings
+
+
def get_document_image(request, document_id, size=PREVIEW_SIZE, quality=QUALITY_DEFAULT):
check_permissions(request.user, 'documents', [PERMISSION_DOCUMENT_VIEW])
@@ -544,24 +570,24 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, quality=QUALITY_
page = int(request.GET.get('page', 1))
+ zoom = int(request.GET.get('zoom', 100))
+
+ if zoom < ZOOM_MIN_LEVEL:
+ zoom = ZOOM_MIN_LEVEL
+
+ if zoom > ZOOM_MAX_LEVEL:
+ zoom = ZOOM_MAX_LEVEL
+
+ rotation = int(request.GET.get('rotation', 0)) % 360
+
+ arguments, warnings = calculate_converter_arguments(document, size=size, file_format=DEFAULT_FILE_FORMAT, quality=quality, page=page, zoom=zoom, rotation=rotation)
+
+ 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:
- document_page = DocumentPage.objects.get(document=document, page_number=page)
- transformation_string, warnings = document_page.get_transformation_string()
- 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)
-
- zoom = int(request.GET.get('zoom', 100))
-
- if zoom < ZOOM_MIN_LEVEL:
- zoom = ZOOM_MIN_LEVEL
-
- if zoom > ZOOM_MAX_LEVEL:
- zoom = ZOOM_MAX_LEVEL
-
- rotation = int(request.GET.get('rotation', 0)) % 360
-
- output_file = convert_document(document, size=size, file_format=u'jpg', quality=quality, extra_options=transformation_string, page=page - 1, zoom=zoom, rotation=rotation)
+ output_file = convert_document(document, **arguments)
except UnkownConvertError, e:
if request.user.is_staff or request.user.is_superuser:
messages.error(request, e)
@@ -1126,3 +1152,15 @@ def metadatagroup_view(request, document_id, metadata_group_id):
'hide_links': True,
'ref_object': document
}, context_instance=RequestContext(request))
+
+
+def document_print(request, document_id):
+ check_permissions(request.user, 'documents', [PERMISSION_DOCUMENT_VIEW])
+
+ document = get_object_or_404(Document.objects.select_related(), pk=document_id)
+
+ RecentDocument.objects.add_document_for_user(request.user, document)
+
+ return render_to_response('document_print.html', {
+ 'object': document,
+ }, context_instance=RequestContext(request))
diff --git a/site_media/packages/jquery.printElement.min.js b/site_media/packages/jquery.printElement.min.js
new file mode 100644
index 0000000000..d1aba537e3
--- /dev/null
+++ b/site_media/packages/jquery.printElement.min.js
@@ -0,0 +1,28 @@
+///
+/*
+* Print Element Plugin 1.2
+*
+* Copyright (c) 2010 Erik Zaadi
+*
+* Inspired by PrintArea (http://plugins.jquery.com/project/PrintArea) and
+* http://stackoverflow.com/questions/472951/how-do-i-print-an-iframe-from-javascript-in-safari-chrome
+*
+* Home Page : http://projects.erikzaadi/jQueryPlugins/jQuery.printElement
+* Issues (bug reporting) : http://github.com/erikzaadi/jQueryPlugins/issues/labels/printElement
+* jQuery plugin page : http://plugins.jquery.com/project/printElement
+*
+* Thanks to David B (http://github.com/ungenio) and icgJohn (http://www.blogger.com/profile/11881116857076484100)
+* For their great contributions!
+*
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+* Note, Iframe Printing is not supported in Opera and Chrome 3.0, a popup window will be shown instead
+*/
+;(function(g){function k(c){c&&c.printPage?c.printPage():setTimeout(function(){k(c)},50)}function l(c){c=a(c);a(":checked",c).each(function(){this.setAttribute("checked","checked")});a("input[type='text']",c).each(function(){this.setAttribute("value",a(this).val())});a("select",c).each(function(){var b=a(this);a("option",b).each(function(){b.val()==a(this).val()&&this.setAttribute("selected","selected")})});a("textarea",c).each(function(){var b=a(this).attr("value");if(a.browser.b&&this.firstChild)this.firstChild.textContent=
+b;else this.innerHTML=b});return a("").append(c.clone()).html()}function m(c,b){var i=a(c);c=l(c);var d=[];d.push(""+b.pageTitle+"");if(b.overrideElementCSS){if(b.overrideElementCSS.length>0)for(var f=0;f'):d.push('')}}else a("link",j).filter(function(){return a(this).attr("rel").toLowerCase()==
+"stylesheet"}).each(function(){d.push('')});d.push('');d.push('');d.push(''+c+"
");d.push('