Skip to content

Commit 835f1b2

Browse files
Smart, semantic exception handling for image resizing. refs #3379
1 parent 9ec2750 commit 835f1b2

File tree

5 files changed

+41
-25
lines changed

5 files changed

+41
-25
lines changed

ckeditor/fields.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from django.db import models
22
from django import forms
3+
from django.core.exceptions import ValidationError
4+
from ckeditor.utils.image_resize import ImageResizeError
35

4-
import ckeditor.signals as signals
56
from ckeditor.widgets import CKEditorWidget
7+
from ckeditor.utils.image_resize import resize_images
68

79

810
class RichTextField(models.TextField):
@@ -11,6 +13,13 @@ def __init__(self, *args, **kwargs):
1113
self.dynamic_resize = kwargs.pop("dynamic_resize",False)
1214
super(RichTextField, self).__init__(*args, **kwargs)
1315

16+
def validate(self, value, model_instance):
17+
super(RichTextField, self).validate(value, model_instance)
18+
try:
19+
resize_images(value)
20+
except ImageResizeError as e:
21+
raise ValidationError(unicode(e))
22+
1423
def formfield(self, **kwargs):
1524
defaults = {
1625
'form_class': RichTextFormField,
@@ -19,10 +28,6 @@ def formfield(self, **kwargs):
1928
defaults.update(kwargs)
2029
return super(RichTextField, self).formfield(**defaults)
2130

22-
def contribute_to_class(self, cls, name):
23-
super(RichTextField, self).contribute_to_class(cls, name)
24-
if self.dynamic_resize:
25-
signals.add_dynamic_resize(cls, name)
2631

2732
class RichTextFormField(forms.fields.Field):
2833
def __init__(self, config_name='default', *args, **kwargs):

ckeditor/signals.py

Lines changed: 0 additions & 14 deletions
This file was deleted.

ckeditor/static/tests/opaque.gif

2.01 KB
Loading

ckeditor/static/tests/transparent.gif

53.3 KB
Loading

ckeditor/utils/image_resize.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import uuid
21
import os
3-
import shutil
2+
import sys
43
import urlparse
54
import re
65
import hashlib
6+
import logging
77

88
from lxml import html
99
from PIL import Image, ImageFile
@@ -16,6 +16,11 @@
1616

1717
ImageFile.MAXBLOCKS = 10000000
1818

19+
logger = logging.getLogger(__name__)
20+
21+
class ImageResizeError(Exception):
22+
pass
23+
1924

2025
def match_or_none(string, rx):
2126
"""
@@ -174,6 +179,9 @@ def transcode_to_jpeg(image, path, width, height):
174179
new_image.save(new_path, quality=80, optimize=1)
175180
return new_path
176181

182+
def _get_resize_error_message(path):
183+
return 'There was a problem resizing this image: {0}'.format(os.path.split(path)[1])
184+
177185
def re_render(path, width, height):
178186
"""
179187
Given an original image, width, and height, creates a thumbnailed image
@@ -193,6 +201,7 @@ def re_render(path, width, height):
193201
@return: Path to the 'rendered' image.
194202
@rtype: "/path/to/image"
195203
"""
204+
196205
try:
197206
image = Image.open(path)
198207
except IOError:
@@ -230,15 +239,21 @@ def re_render(path, width, height):
230239
return new_path
231240

232241
# Re-render the image, optimizing for filesize
233-
new_image = image.resize((width, height), Image.ANTIALIAS)
242+
try:
243+
new_image = image.resize((width, height), Image.ANTIALIAS)
244+
except TypeError:
245+
raise ImageResizeError(_get_resize_error_message(path)), None, sys.exc_info()[2]
234246

235247
image_params = {}
236248
if image.format != "GIF":
237249
image_params = dict(
238250
quality = 80,
239251
optimize = 1,
240252
)
241-
new_image.save(new_path, **image_params)
253+
try:
254+
new_image.save(new_path, **image_params)
255+
except IOError:
256+
raise ImageResizeError(_get_resize_error_message(path)), None, sys.exc_info()[2]
242257
return new_path
243258

244259
def get_html_tree(content):
@@ -258,17 +273,27 @@ def resize_images(post_content):
258273
@return: Modified contents.
259274
@rtype: basestring
260275
"""
276+
261277
# Get tree
262278
tree = get_html_tree(post_content)
263-
264279
# Get images
265280
imgs = tree.xpath('//img[starts-with(@src, "%s")]' % settings.STATIC_URL)
266281
for img in imgs:
267282
orig_url = img.attrib['src']
268283
orig_path = get_local_path(orig_url)
269284

270285
width, height = get_dimensions(img)
271-
rendered_path = re_render(orig_path, width, height)
286+
try:
287+
rendered_path = re_render(orig_path, width, height)
288+
except ImageResizeError:
289+
raise
290+
except Exception as e:
291+
# If something goes wrong, just use the original path so as not to
292+
# interrupt the user. However, log it, because it's still a real problem.
293+
logger.error(e, exc_info=True, extra={
294+
'stack': True,
295+
})
296+
rendered_path = orig_path
272297

273298
# If we haven't changed the image, move along.
274299
if rendered_path == orig_path:

0 commit comments

Comments
 (0)