Ticket #961: image_tags.py

File image_tags.py, 6.6 KB (added by Nebojša Đorđević - nesh <nesh@…>, 18 years ago)

img filter implementation

Line 
1# -*- coding: utf-8 -*-
2# vim:enc=utf8:fenc=utf8:ts=4:sts=4:sw=4:sta:et:nofen:si:ai:nowrap
3# (C) Djordjevic Nebojsa <nesh@studioquattro.co.yu> 2005
4# You're welcome to redistribute this software under the
5# terms of the GNU Library General Public Licence version 2.0
6# or, at your option, any higher version.
7#
8# You can read the complete GNU LGPL in the file COPYING
9# which should come along with this software, or visit
10# the Free Software Foundation's WEB site http://www.fsf.org
11#
12
13""" image related filters """
14
15import os, struct
16from django.utils.translation import gettext
17from django.conf.settings import DEBUG
18
19def _path(src):
20 from django.conf.settings import MEDIA_ROOT, MEDIA_URL
21
22 if src.startswith(MEDIA_URL):
23 return os.path.join(MEDIA_ROOT, src[len(MEDIA_URL):])
24 else:
25 return os.path.join(MEDIA_ROOT, src)
26#
27try:
28 import Image
29 HAS_PIL = True
30except ImportError:
31 HAS_PIL = False
32
33def _no_pil_image_size(fname):
34 """
35 Determine the image type of FNAME and return its size.
36 from draco
37 """
38 try:
39 filehandle = file(fname, 'rb')
40 except IOError:
41 return None
42 head = filehandle.read(24)
43 if len(head) != 24:
44 return
45 if head[:4] == '\x89PNG':
46 # PNG
47 check = struct.unpack('>i', head[4:8])[0]
48 if check != 0x0d0a1a0a:
49 return
50 width, height = struct.unpack('>ii', head[16:24])
51 elif head[:6] in ('GIF87a', 'GIF89a'):
52 # GIF
53 width, height = struct.unpack('<HH', head[6:10])
54 elif head[:4] == '\xff\xd8\xff\xe0' and head[6:10] == 'JFIF':
55 # JPEG
56 try:
57 filehandle.seek(0) # Read 0xff next
58 size = 2
59 filetype = 0
60 while not 0xc0 <= filetype <= 0xcf:
61 filehandle.seek(size, 1)
62 byte = filehandle.read(1)
63 while ord(byte) == 0xff:
64 byte = filehandle.read(1)
65 filetype = ord(byte)
66 size = struct.unpack('>H', filehandle.read(2))[0] - 2
67 # We are at a SOFn block
68 filehandle.seek(1, 1) # Skip `precision' byte.
69 height, width = struct.unpack('>HH', filehandle.read(4))
70 except:
71 raise
72 return
73 else:
74 return
75 return width, height
76#
77
78from contrib.utils import set_cached_file, get_cached_file
79
80def _image_size(path):
81 size = get_cached_file(path)
82 if size is None:
83 if HAS_PIL:
84 size = Image.open(path).size
85 else:
86 size = _no_pil_image_size(path)
87 set_cached_file(path, size)
88 #
89 return size
90#
91
92_THUMB_DIR = 'thumb'
93
94def thumbnail_file(filename):
95 from django.conf.settings import MEDIA_ROOT
96 basedir = os.path.dirname(filename)
97 name = os.path.basename(filename)
98 fname, ext = os.path.splitext(name)
99 ret = os.path.join(MEDIA_ROOT, basedir, _THUMB_DIR, fname + '.jpg')
100 if os.path.isfile(ret):
101 return ret
102 return None
103# thumbnail_file
104
105def remove_thumbnail(field):
106 th = thumbnail_file(field)
107 if th:
108 os.unlink(th)
109#
110
111def _make_thumb(path, width, height):
112 if not HAS_PIL:
113 return path
114
115 from django.conf.settings import MEDIA_ROOT
116 url = os.path.dirname(path)
117 path = _path(path)
118 # thumb dir
119 basedir = os.path.dirname(path)
120 thdir = os.path.join(MEDIA_ROOT, basedir, _THUMB_DIR)
121
122 # create dir if not exists
123 if not os.path.isdir(thdir):
124 os.mkdir(thdir)
125
126 name = os.path.basename(path)
127 fname, ext = os.path.splitext(name)
128 outfile = os.path.join(thdir, fname + '.jpg')
129
130 if os.path.isfile(outfile):
131 # thumbnail already exists
132 return '%s/thumb/%s.jpg' % (url, fname)
133
134 # make and save thumbnail
135 try:
136 im = Image.open(path)
137 w, h = im.size
138 if (h != height) or (w != width):
139 im.thumbnail((width, height), Image.ANTIALIAS)
140 im.save(outfile, "JPEG")
141 else:
142 return path
143 except:
144 return path
145
146 return '%s/thumb/%s.jpg' % (url, fname)
147# _make_thumb
148
149##################################################
150## FILTER ##
151
152from django.core.template import TemplateSyntaxError, TokenParser, Library
153register = Library()
154
155@register.filter()
156def img(value, args=''):
157 """ Create ``<img>`` tag with all required parameters.
158
159If image dimension is set and dimension is different from original
160image size and *thumbnail*\ [#]_ option is not ``False``
161it will make required **thumbnail**\ [#]_ and return link to it.
162
163.. [#] default is ``True``.
164.. [#] requires PIL_, if PIL_ is not found fails silently.
165.. _PIL: http://www.pythonware.com/products/pil/
166"""
167
168 kwargs = {}
169 if args:
170 for arg in args.split('|'):
171 arg = arg.strip()
172 if arg == '': continue
173 kw, val = arg.split('=', 1)
174 kw = kw.lower()
175 try:
176 val = int(val) # convert all ints
177 except ValueError:
178 pass
179 kwargs[kw] = val
180 # for
181 # if
182
183 path = _path(value)
184
185 # file exists?
186 if not value:
187 if DEBUG:
188 return '<div class="error"><p class="title">%s</p></div>' % gettext('no image')
189 else:
190 return ''
191 elif not os.path.isfile(path):
192 if DEBUG:
193 return '<div class="error"><p class="title">%s</p><p>%s</p></div>' \
194 % (gettext('no image'), gettext('image %s not found') % value)
195 else:
196 return ''
197
198 # no alt, use value
199 if 'alt' not in kwargs:
200 kwargs['alt'] = value
201 #
202
203 if kwargs.get('thumbnail', True) and HAS_PIL:
204 if ('width' in kwargs) or ('height' in kwargs):
205 size = _image_size(path)
206 if size is not None:
207 width, height = size
208 if 'width' in kwargs:
209 new_width = kwargs['width']
210 del kwargs['width']
211 else:
212 new_width = width
213 #
214 if 'height' in kwargs:
215 new_height = kwargs['height']
216 del kwargs['height']
217 else:
218 new_height = height
219 #
220 if (size is not None) and ((new_width != width) or (new_height != height)):
221 value = _make_thumb(value, new_width, new_height)
222 path = _path(value)
223 # if
224 # if
225 # if
226
227 size = _image_size(path)
228 if size is not None:
229 w, h = size
230 kwargs['width'] = '%d' % w
231 kwargs['height'] = '%d' % h
232 #
233
234 ret = ['src="%s"' % value] # TODO: escape
235 for k, v in kwargs.items():
236 ret.append('%s="%s"' % (k, v))
237 return '<img %s />' % ' '.join(ret)
238#
Back to Top