Skip to content

Commit

Permalink
[#7] Extract core image processing to backends.
Browse files Browse the repository at this point in the history
  • Loading branch information
riklaunim committed Dec 7, 2013
1 parent 6755dbc commit 1f083d1
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 40 deletions.
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ Required

(r'^ckeditor/', include('ckeditor.urls')),

#. Set ``CKEDITOR_IMAGE_BACKEND`` to one of supported backends to enable thumbnails in ckeditor gallery. Supported backends:

- ``pillow``: uses PIL or Pillow


Optional
~~~~~~~~
#. All uploaded files are slugified by defaults, to disable this feature set ``CKEDITOR_SLUGIFY_FILENAME`` to ``False``
Expand Down
Empty file added ckeditor/image/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions ckeditor/image/dummy_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def create_thumbnail(file_object, format):
raise NotImplementedError


def is_image(filepath):
return False
37 changes: 37 additions & 0 deletions ckeditor/image/pillow_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from io import BytesIO

from django.core.files.storage import default_storage

try:
from PIL import Image, ImageOps
except ImportError:
import Image
import ImageOps

THUMBNAIL_SIZE = (75, 75)


def create_thumbnail(file_object, format):
image = Image.open(file_object)

# Convert to RGB if necessary
# Thanks to Limodou on DjangoSnippets.org
# http://www.djangosnippets.org/snippets/20/
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')

# scale and crop to thumbnail
imagefit = ImageOps.fit(image, THUMBNAIL_SIZE, Image.ANTIALIAS)
thumbnail_io = BytesIO()
imagefit.save(thumbnail_io, format=format)
return thumbnail_io


def is_image(filepath):
image = default_storage.open(filepath)
try:
Image.open(image)
except IOError:
return False
else:
return True
11 changes: 11 additions & 0 deletions ckeditor/image_processing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.conf import settings


def get_backend():
backend = getattr(settings, "CKEDITOR_IMAGE_BACKEND", None)

if backend == "pillow":
from ckeditor.image import pillow_backend as backend
else:
from ckeditor.image import dummy_backend as backend
return backend
2 changes: 1 addition & 1 deletion ckeditor/templates/browse.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h2>No images found. Upload images using the 'Image Button' dialog's 'Upload' ta
{% for image in images %}
<li>
<a class="thumb" href="{{ image.src }}">
<img src="{{ image.thumb }}" />
<img src="{{ image.thumb }}" style="max-width: 75px;"/>
</a>
<div class="caption">
<div class="submit-row">
Expand Down
47 changes: 13 additions & 34 deletions ckeditor/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from datetime import datetime
import mimetypes
import os
from io import BytesIO

from django.conf import settings
from django.core.files.storage import default_storage
Expand All @@ -12,30 +11,14 @@
from django.template.defaultfilters import slugify
from django.template import RequestContext

try:
from PIL import Image, ImageOps
except ImportError:
import Image
import ImageOps


THUMBNAIL_SIZE = (75, 75)
from ckeditor import image_processing

CKEDITOR_UPLOAD_SLUGIFY_FILENAME = getattr(settings,
"CKEDITOR_UPLOAD_SLUGIFY_FILENAME",
True)


def is_image(filepath):
image = default_storage.open(filepath)
try:
Image.open(image)
except IOError:
return False
else:
return True


def slugify_filename(filename):
u""" Slugify filename """
name, ext = os.path.splitext(filename)
Expand All @@ -58,21 +41,11 @@ def get_image_format(extension):
def create_thumbnail(filename):
thumbnail_filename = get_thumb_filename(filename)
thumbnail_format = get_image_format(os.path.splitext(filename)[1])
pil_format = thumbnail_format.split('/')[1]
file_format = thumbnail_format.split('/')[1]

image = default_storage.open(filename)
image = Image.open(image)

# Convert to RGB if necessary
# Thanks to Limodou on DjangoSnippets.org
# http://www.djangosnippets.org/snippets/20/
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')

# scale and crop to thumbnail
imagefit = ImageOps.fit(image, THUMBNAIL_SIZE, Image.ANTIALIAS)
thumbnail_io = BytesIO()
imagefit.save(thumbnail_io, format=pil_format)
backend = image_processing.get_backend()
thumbnail_io = backend.create_thumbnail(image, file_format)

thumbnail = InMemoryUploadedFile(
thumbnail_io,
Expand Down Expand Up @@ -128,7 +101,8 @@ def upload(request):
upload_filename = get_upload_filename(upload.name, request.user)
saved_path = default_storage.save(upload_filename, upload)

if is_image(saved_path):
backend = image_processing.get_backend()
if backend.is_image(saved_path):
create_thumbnail(saved_path)

url = get_media_url(saved_path)
Expand Down Expand Up @@ -184,9 +158,14 @@ def get_image_browse_urls(user=None):
"""
images = []
for filename in get_image_files(user=user):
src = get_media_url(filename)
if getattr(settings, 'CKEDITOR_IMAGE_BACKEND', None):
thumb = get_media_url(get_thumb_filename(filename))
else:
thumb = src
images.append({
'thumb': get_media_url(get_thumb_filename(filename)),
'src': get_media_url(filename)
'thumb': thumb,
'src': src
})

return images
Expand Down
18 changes: 14 additions & 4 deletions ckeditor_demo/demo_application/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.conf import settings
from django.contrib.staticfiles.finders import find
from django.test import LiveServerTestCase
from django.test.utils import override_settings
from selenium.webdriver.firefox.webdriver import WebDriver


Expand Down Expand Up @@ -86,7 +87,8 @@ def _assert_image_uploaded(self):
assert os.path.isfile(expected_thumbnail_path)
self._assert_uploaded_image_did_not_changed(expected_image_path)
self._assert_thumbnail_is_not_empty(expected_thumbnail_path)
self._remove_uploads(expected_image_path, expected_thumbnail_path)
os.remove(expected_image_path)
os.remove(expected_thumbnail_path)

def _get_upload_directory(self):
date_path = datetime.now().strftime('%Y/%m/%d')
Expand All @@ -111,6 +113,14 @@ def _assert_thumbnail_is_not_empty(self, path):
size = os.path.getsize(path)
assert size > 0

def _remove_uploads(self, image, thumbnail):
os.remove(image)
os.remove(thumbnail)

@override_settings(CKEDITOR_IMAGE_BACKEND=None)
class TestAdminPanelWidgetForDummyImageBackend(TestAdminPanelWidget):
def _assert_image_uploaded(self):
upload_directory = self._get_upload_directory()
expected_image_path = os.path.join(upload_directory, 'close.png')
expected_thumbnail_path = os.path.join(upload_directory, 'close_thumb.png')
assert os.path.isfile(expected_image_path)
assert not os.path.isfile(expected_thumbnail_path)
self._assert_uploaded_image_did_not_changed(expected_image_path)
os.remove(expected_image_path)
1 change: 1 addition & 0 deletions ckeditor_demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,4 @@
MEDIA_ROOT = os.path.join(tempfile.gettempdir(), 'ck_media')

CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_IMAGE_BACKEND = "pillow"
1 change: 1 addition & 0 deletions ckeditor_demo_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
django==1.6.0
Pillow==2.2.1
selenium==2.38.1
tox==1.6.1
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ def get_source_files():
'ckeditor',
],
install_requires=[
'Pillow',
'Django',
],
classifiers=[
Expand Down

0 comments on commit 1f083d1

Please sign in to comment.