-
Notifications
You must be signed in to change notification settings - Fork 0
/
resize_image.py
137 lines (114 loc) · 5.55 KB
/
resize_image.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Adapted from: http://www.djangosnippets.org/snippets/636/
# ResizeImageField stands for ScalableAndRemovableImageField
from django import forms
from django.conf import settings
from django.db import models
from django.utils.translation import ugettext as _
import os
import Image # from PIL
ORIGINAL_NAME = os.path.basename(settings.PHOTO_DIR)
SCALED_NAME = getattr(settings, 'SCALED_NAME', 'scaled')
THUMB_NAME = getattr(settings, 'THUMB_NAME', 'thumb')
SCALED_SIZE = getattr(settings, 'SCALED_SIZE', (200, 200))
THUMB_SIZE = getattr(settings, 'SCALED_SIZE', (50, 50)) # height, width
class DeleteCheckboxWidget(forms.CheckboxInput):
def __init__(self, *args, **kwargs):
self.is_image = kwargs.pop('is_image')
self.value = kwargs.pop('initial')
super(DeleteCheckboxWidget, self).__init__(*args, **kwargs)
def render(self, name, value, attrs=None):
value = value or self.value
if value:
attrs['style'] = 'width:auto;'
s = u'<label for="%s">%s %s</label>' % (
attrs['id'],
super(DeleteCheckboxWidget, self).render(name, False, attrs),
_('Delete')
)
if self.is_image:
s += u'<br><img src="%s%s" height="100">' % (settings.MEDIA_URL, unicode(value).replace(ORIGINAL_NAME, SCALED_NAME, 1))
else:
s += u'<br><a href="%s%s">%s</a>' % (settings.MEDIA_URL, value, os.path.basename(value))
return s
else:
return u''
class RemovableFileFormWidget(forms.MultiWidget):
def __init__(self, is_image=False, initial=None, **kwargs):
widgets = (forms.FileInput(), DeleteCheckboxWidget(is_image=is_image, initial=initial))
super(RemovableFileFormWidget, self).__init__(widgets)
def decompress(self, value):
return [None, value]
class RemovableFileFormField(forms.MultiValueField):
widget = RemovableFileFormWidget
field = forms.FileField
is_image = False
def __init__(self, *args, **kwargs):
fields = [self.field(*args, **kwargs), forms.BooleanField(required=False)]
# Compatibility with form_for_instance
if kwargs.get('initial'):
initial = kwargs['initial']
else:
initial = None
self.widget = self.widget(is_image=self.is_image, initial=initial)
super(RemovableFileFormField, self).__init__(fields, label=kwargs.pop('label'), required=False)
def compress(self, data_list):
return data_list
class ResizeImageFormField(RemovableFileFormField):
field = forms.ImageField
is_image = True
class ResizeImageField(models.ImageField):
def delete_file(self, instance, *args, **kwargs):
'''Overwrite delete method. Delete scaled instances as well.'''
if getattr(instance, self.attname):
image = getattr(instance, '%s' % self.name)
file_name = image.path
# If the file exists and no other object of this type references it,
# delete it from the filesystem.
if os.path.exists(file_name) and \
not instance.__class__._default_manager.filter(**{'%s__exact' % self.name: getattr(instance, self.attname)}).exclude(pk=instance._get_pk_val()):
if os.path.exists(file_name):
os.remove(file_name)
scaled_name = file_name.replace(ORIGINAL_NAME, SCALED_NAME, 1)
if os.path.exists(scaled_name):
os.remove(scaled_name)
thumb_name = file_name.replace(ORIGINAL_NAME, THUMB_NAME, 1)
if os.path.exists(thumb_name):
os.remove(thumb_name)
def get_internal_type(self):
'''Copied from Django snippet example and probably incorrect.'''
return 'FileField'
def check_or_create_dir(self, full_path):
'''Create dir if it does not yet exist.'''
directory = os.path.dirname(full_path)
if not os.path.exists(directory):
os.makedirs(directory)
elif not os.path.isdir(directory):
raise IOError("%s exists and is not a directory." % directory)
def save_form_data(self, instance, data):
'''Save/replace or delete file. If saving, store scaled images as well.'''
if data and data[0]: # Replace file
self.delete_file(instance)
super(ResizeImageField, self).save_form_data(instance, data[0])
image = getattr(instance, '%s' % self.name)
file_path = image.path
img = Image.open(file_path)
self.resize(img, file_path, SCALED_NAME, SCALED_SIZE)
self.resize(img, file_path, THUMB_NAME, THUMB_SIZE)
if data and data[1]: # Delete file
self.delete_file(instance)
setattr(instance, self.name, None)
def resize(self, img, file_path, new_name, new_size):
'''Resize image, using PIL, and save.'''
new_path = file_path.replace(ORIGINAL_NAME, new_name, 1)
self.check_or_create_dir(new_path)
img.thumbnail(new_size, Image.ANTIALIAS)
try:
transparency = img.info['transparency']
img.save(new_path, transparency=transparency)
except:
img.save(new_path)
def formfield(self, **kwargs):
'''Django default.'''
defaults = {'form_class': ResizeImageFormField}
defaults.update(kwargs)
return super(ResizeImageField, self).formfield(**defaults)