diff --git a/geonode/base/models.py b/geonode/base/models.py
index 0915bd78717..fd619e89b07 100644
--- a/geonode/base/models.py
+++ b/geonode/base/models.py
@@ -1741,8 +1741,7 @@ def save_thumbnail(self, filename, image):
url = storage_manager.url(upload_path)
try:
# Optimize the Thumbnail size and resolution
- _default_thumb_size = getattr(
- settings, 'THUMBNAIL_GENERATOR_DEFAULT_SIZE', {'width': 240, 'height': 200})
+ _default_thumb_size = settings.THUMBNAIL_SIZE
im = Image.open(storage_manager.open(actual_name))
im.thumbnail(
(_default_thumb_size['width'], _default_thumb_size['height']),
diff --git a/geonode/documents/renderers.py b/geonode/documents/renderers.py
deleted file mode 100644
index dda0fc3e736..00000000000
--- a/geonode/documents/renderers.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#########################################################################
-#
-# Copyright (C) 2017 OSGeo
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-#########################################################################
-
-import io
-import os
-import subprocess
-import traceback
-import tempfile
-
-from django.conf import settings
-from threading import Timer
-from mimetypes import guess_type
-from urllib.request import pathname2url
-
-
-class ConversionError(Exception):
- """Raise when conversion was unsuccessful."""
- pass
-
-
-class MissingPILError(Exception):
- """Raise when could not import PIL package."""
- pass
-
-
-def guess_mimetype(document_path):
- """Guess mime type for a file in local filesystem.
-
- Return string containing valid mime type.
- """
- document_url = pathname2url(document_path)
- return guess_type(document_url)[0]
-
-
-def render_document(document_path, extension="png"):
- """Render document using `unconv` converter.
-
- Package `unoconv` has to be installed and available on system
- path. Return `NamedTemporaryFile` instance.
- """
-
- # workaround: https://github.com/dagwieers/unoconv/issues/167
- # first convert a document to PDF and continue
- dispose_input = False
- if extension != "pdf" and guess_mimetype(document_path) != 'application/pdf':
- document_path = render_document(document_path, extension="pdf")
- dispose_input = True
-
- # spawn subprocess and render the document
- output_path = None
- if settings.UNOCONV_ENABLE:
- timeout = None
- _, output_path = tempfile.mkstemp(suffix=f".{extension}")
- try:
- unoconv = subprocess.Popen(
- [settings.UNOCONV_EXECUTABLE, "-v", "-e", "PageRange=1-2",
- "-f", extension, "-o", output_path, document_path],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE
- )
- timeout = Timer(settings.UNOCONV_TIMEOUT, unoconv.kill)
- timeout.start()
- stdout, stderr = unoconv.communicate()
- except Exception as e:
- traceback.print_exc()
- raise ConversionError(str(e))
- finally:
- if timeout:
- timeout.cancel()
- if dispose_input and document_path is not None:
- os.remove(document_path)
- else:
- raise NotImplementedError("unoconv is disabled. Set 'UNOCONV_ENABLE' to enable.")
-
- return output_path
-
-
-def generate_thumbnail_content(image_path, size=(200, 150)):
- """Generate thumbnail content from an image file.
-
- Return the entire content of the image file.
- """
-
- try:
- from PIL import Image, ImageOps
- except ImportError:
- raise MissingPILError()
-
- try:
- image = Image.open(image_path)
- source_width, source_height = image.size
- target_width, target_height = size
-
- if source_width != target_width or source_width != target_height:
- image = ImageOps.fit(image, size, Image.ANTIALIAS)
-
- with io.BytesIO() as output:
- image.save(output, format='PNG')
- content = output.getvalue()
- output.close()
- return content
- except Exception as e:
- raise e
diff --git a/geonode/documents/tasks.py b/geonode/documents/tasks.py
index 1cd21e6bb74..d9968e8bbb9 100644
--- a/geonode/documents/tasks.py
+++ b/geonode/documents/tasks.py
@@ -16,6 +16,10 @@
# along with this program. If not, see .
#
#########################################################################
+import io
+
+from PIL import Image
+
from celery.utils.log import get_task_logger
from geonode.celery_app import app
@@ -23,7 +27,6 @@
from ..base.models import ResourceBase
from .models import Document
-from .renderers import (generate_thumbnail_content)
logger = get_task_logger(__name__)
@@ -61,9 +64,13 @@ def create_document_thumbnail(self, object_id):
image_file = storage_manager.open(dname, 'rb')
try:
- thumbnail_content = generate_thumbnail_content(image_file)
+ image = Image.open(image_file)
+ with io.BytesIO() as output:
+ image.save(output, format='PNG')
+ thumbnail_content = output.getvalue()
+ output.close()
except Exception as e:
- logger.debug(f"Could not generate thumbnail, setting thumbnail_url to None: {e}")
+ logger.debug(f"Could not generate thumbnail: {e}")
finally:
if image_file is not None:
image_file.close()
diff --git a/geonode/documents/tests.py b/geonode/documents/tests.py
index 9674da4d8a5..f5311351710 100644
--- a/geonode/documents/tests.py
+++ b/geonode/documents/tests.py
@@ -31,6 +31,7 @@
from io import BytesIO
from unittest.mock import patch
+from urllib.parse import urlparse
from django.urls import reverse
from django.conf import settings
@@ -95,6 +96,7 @@ def tearDownClass(cls):
def setUp(self):
super().setUp()
create_models('map')
+ self.project_root = os.path.abspath(os.path.dirname(__file__))
self.imgfile = io.BytesIO(
b'GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00ccc,\x00'
b'\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;')
@@ -266,6 +268,42 @@ def test_replace_document(self):
# Remove document
d.delete()
+ def test_non_image_documents_thumbnail(self):
+ self.client.login(username='admin', password='admin')
+ try:
+ with open(os.path.join(f"{self.project_root}", "tests/data/text.txt"), "rb") as f:
+ data = {
+ 'title': "Non img File Doc",
+ 'doc_file': f,
+ 'extension': 'txt'
+ }
+ self.client.post(reverse('document_upload'), data=data)
+ d = Document.objects.get(title='Non img File Doc')
+ self.assertIsNone(d.thumbnail_url)
+ finally:
+ Document.objects.filter(title='Non img File Doc').delete()
+
+ def test_image_documents_thumbnail(self):
+ self.client.login(username='admin', password='admin')
+ try:
+ with open(os.path.join(f"{self.project_root}", "tests/data/img.gif"), "rb") as f:
+ data = {
+ 'title': "img File Doc",
+ 'doc_file': f,
+ 'extension': 'gif',
+ }
+ with self.settings(THUMBNAIL_SIZE={'width': 400, 'height': 200}):
+ self.client.post(reverse('document_upload'), data=data)
+ d = Document.objects.get(title='img File Doc')
+ self.assertIsNotNone(d.thumbnail_url)
+ thumb_file = os.path.join(
+ settings.MEDIA_ROOT, f"thumbs/{os.path.basename(urlparse(d.thumbnail_url).path)}"
+ )
+ file = Image.open(thumb_file)
+ self.assertEqual(file.size, (400, 200))
+ finally:
+ Document.objects.filter(title='img File Doc').delete()
+
def test_upload_document_form_size_limit(self):
form_data = {
'title': 'GeoNode Map',
diff --git a/geonode/documents/tests/data/text.txt b/geonode/documents/tests/data/text.txt
new file mode 100644
index 00000000000..2a02d41ce21
--- /dev/null
+++ b/geonode/documents/tests/data/text.txt
@@ -0,0 +1 @@
+TEST
diff --git a/geonode/settings.py b/geonode/settings.py
index a695558f362..ded3d6e80b8 100644
--- a/geonode/settings.py
+++ b/geonode/settings.py
@@ -1997,7 +1997,7 @@ def get_geonode_catalogue_service():
'THUMBNAIL_GENERATOR', 'geonode.thumbs.thumbnails.create_gs_thumbnail_geonode')
THUMBNAIL_SIZE = {
- 'width': int(os.environ.get('THUMBNAIL_GENERATOR_DEFAULT_SIZE_WIDTH', 240)),
+ 'width': int(os.environ.get('THUMBNAIL_GENERATOR_DEFAULT_SIZE_WIDTH', 500)),
'height': int(os.environ.get('THUMBNAIL_GENERATOR_DEFAULT_SIZE_HEIGHT', 200))
}