Fixes #382.
[redakcja.git] / apps / sorl / thumbnail / main.py
1 import os
2
3 from django.conf import settings
4 from django.utils.encoding import iri_to_uri, force_unicode
5
6 from sorl.thumbnail.base import Thumbnail
7 from sorl.thumbnail.processors import dynamic_import
8 from sorl.thumbnail import defaults
9
10
11 def get_thumbnail_setting(setting, override=None):
12     """
13     Get a thumbnail setting from Django settings module, falling back to the
14     default.
15
16     If override is not None, it will be used instead of the setting.
17     """
18     if override is not None:
19         return override
20     if hasattr(settings, 'THUMBNAIL_%s' % setting):
21         return getattr(settings, 'THUMBNAIL_%s' % setting)
22     else:
23         return getattr(defaults, setting)
24
25
26 def build_thumbnail_name(source_name, size, options=None,
27                          quality=None, basedir=None, subdir=None, prefix=None,
28                          extension=None):
29     quality = get_thumbnail_setting('QUALITY', quality)
30     basedir = get_thumbnail_setting('BASEDIR', basedir)
31     subdir = get_thumbnail_setting('SUBDIR', subdir)
32     prefix = get_thumbnail_setting('PREFIX', prefix)
33     extension = get_thumbnail_setting('EXTENSION', extension)
34     path, filename = os.path.split(source_name)
35     basename, ext = os.path.splitext(filename)
36     name = '%s%s' % (basename, ext.replace(os.extsep, '_'))
37     size = '%sx%s' % tuple(size)
38
39     # Handle old list format for opts.
40     options = options or {}
41     if isinstance(options, (list, tuple)):
42         options = dict([(opt, None) for opt in options])
43
44     opts = options.items()
45     opts.sort()   # options are sorted so the filename is consistent
46     opts = ['%s_' % (v is not None and '%s-%s' % (k, v) or k)
47             for k, v in opts]
48     opts = ''.join(opts)
49     extension = extension and '.%s' % extension
50     thumbnail_filename = '%s%s_%s_%sq%s%s' % (prefix, name, size, opts,
51                                               quality, extension)
52     return os.path.join(basedir, path, subdir, thumbnail_filename)
53
54
55 class DjangoThumbnail(Thumbnail):
56     imagemagick_file_types = get_thumbnail_setting('IMAGEMAGICK_FILE_TYPES')
57
58     def __init__(self, relative_source, requested_size, opts=None,
59                  quality=None, basedir=None, subdir=None, prefix=None,
60                  relative_dest=None, processors=None, extension=None):
61         relative_source = force_unicode(relative_source)
62         # Set the absolute filename for the source file
63         source = self._absolute_path(relative_source)
64
65         quality = get_thumbnail_setting('QUALITY', quality)
66         convert_path = get_thumbnail_setting('CONVERT')
67         wvps_path = get_thumbnail_setting('WVPS')
68         if processors is None:
69             processors = dynamic_import(get_thumbnail_setting('PROCESSORS'))
70
71         # Call super().__init__ now to set the opts attribute. generate() won't
72         # get called because we are not setting the dest attribute yet.
73         super(DjangoThumbnail, self).__init__(source, requested_size,
74             opts=opts, quality=quality, convert_path=convert_path,
75             wvps_path=wvps_path, processors=processors)
76
77         # Get the relative filename for the thumbnail image, then set the
78         # destination filename
79         if relative_dest is None:
80             relative_dest = \
81                self._get_relative_thumbnail(relative_source, basedir=basedir,
82                                             subdir=subdir, prefix=prefix,
83                                             extension=extension)
84         filelike = not isinstance(relative_dest, basestring)
85         if filelike:
86             self.dest = relative_dest
87         else:
88             self.dest = self._absolute_path(relative_dest)
89
90         # Call generate now that the dest attribute has been set
91         self.generate()
92
93         # Set the relative & absolute url to the thumbnail
94         if not filelike:
95             self.relative_url = \
96                 iri_to_uri('/'.join(relative_dest.split(os.sep)))
97             self.absolute_url = '%s%s' % (settings.MEDIA_URL,
98                                           self.relative_url)
99
100     def _get_relative_thumbnail(self, relative_source,
101                                 basedir=None, subdir=None, prefix=None,
102                                 extension=None):
103         """
104         Returns the thumbnail filename including relative path.
105         """
106         return build_thumbnail_name(relative_source, self.requested_size,
107                                     self.opts, self.quality, basedir, subdir,
108                                     prefix, extension)
109
110     def _absolute_path(self, filename):
111         absolute_filename = os.path.join(settings.MEDIA_ROOT, filename)
112         return absolute_filename.encode(settings.FILE_CHARSET)
113
114     def __unicode__(self):
115         return self.absolute_url