Media type refractors, pep8, lint
[mediagoblin.git] / mediagoblin / media_types / image / processing.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import Image
18 import os
19 import logging
20
21 from mediagoblin import mg_globals as mgg
22 from mediagoblin.processing import BadMediaFail, \
23 create_pub_filepath
24 from mediagoblin.tools.exif import exif_fix_image_orientation, \
25 extract_exif, clean_exif, get_gps_data, get_useful
26
27 _log = logging.getLogger(__name__)
28
29 SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg']
30
31
32 def sniff_handler(media_file, **kw):
33 if kw.get('media') is not None: # That's a double negative!
34 name, ext = os.path.splitext(kw['media'].filename)
35 clean_ext = ext[1:].lower() # Strip the . from ext and make lowercase
36
37 _log.debug('name: {0}\next: {1}\nlower_ext: {2}'.format(
38 name,
39 ext,
40 clean_ext))
41
42 if clean_ext in SUPPORTED_FILETYPES:
43 _log.info('Found file extension in supported filetypes')
44 return True
45 else:
46 _log.debug('Media present, extension not found in {0}'.format(
47 SUPPORTED_FILETYPES))
48 else:
49 _log.warning('Need additional information (keyword argument \'media\')'
50 ' to be able to handle sniffing')
51
52 return False
53
54
55 def process_image(entry):
56 """
57 Code to process an image
58 """
59 workbench = mgg.workbench_manager.create_workbench()
60 # Conversions subdirectory to avoid collisions
61 conversions_subdir = os.path.join(
62 workbench.dir, 'conversions')
63 os.mkdir(conversions_subdir)
64
65 queued_filepath = entry.queued_media_file
66 queued_filename = workbench.localized_file(
67 mgg.queue_store, queued_filepath,
68 'source')
69
70 filename_bits = os.path.splitext(queued_filename)
71 basename = os.path.split(filename_bits[0])[1]
72 extension = filename_bits[1].lower()
73
74 # EXIF extraction
75 exif_tags = extract_exif(queued_filename)
76 gps_data = get_gps_data(exif_tags)
77
78 try:
79 thumb = Image.open(queued_filename)
80 except IOError:
81 raise BadMediaFail()
82
83 thumb = exif_fix_image_orientation(thumb, exif_tags)
84
85 thumb.thumbnail(
86 (mgg.global_config['media:thumb']['max_width'],
87 mgg.global_config['media:thumb']['max_height']),
88 Image.ANTIALIAS)
89
90 # Copy the thumb to the conversion subdir, then remotely.
91 thumb_filename = 'thumbnail' + extension
92 thumb_filepath = create_pub_filepath(entry, thumb_filename)
93
94 tmp_thumb_filename = os.path.join(
95 conversions_subdir, thumb_filename)
96
97 with file(tmp_thumb_filename, 'w') as thumb_file:
98 thumb.save(thumb_file)
99
100 mgg.public_store.copy_local_to_storage(
101 tmp_thumb_filename, thumb_filepath)
102
103 # If the size of the original file exceeds the specified size of a `medium`
104 # file, a `medium.jpg` files is created and later associated with the media
105 # entry.
106 medium = Image.open(queued_filename)
107
108 # Fix orientation
109 medium = exif_fix_image_orientation(medium, exif_tags)
110
111 if medium.size[0] > mgg.global_config['media:medium']['max_width'] \
112 or medium.size[1] > mgg.global_config['media:medium']['max_height']:
113 medium.thumbnail(
114 (mgg.global_config['media:medium']['max_width'],
115 mgg.global_config['media:medium']['max_height']),
116 Image.ANTIALIAS)
117
118 medium_filename = 'medium' + extension
119 medium_filepath = create_pub_filepath(entry, medium_filename)
120
121 tmp_medium_filename = os.path.join(
122 conversions_subdir, medium_filename)
123
124 with file(tmp_medium_filename, 'w') as medium_file:
125 medium.save(medium_file)
126
127 mgg.public_store.copy_local_to_storage(
128 tmp_medium_filename, medium_filepath)
129
130 # we have to re-read because unlike PIL, not everything reads
131 # things in string representation :)
132 queued_file = file(queued_filename, 'rb')
133
134 with queued_file:
135 #create_pub_filepath(entry, queued_filepath[-1])
136 original_filepath = create_pub_filepath(entry, basename + extension)
137
138 with mgg.public_store.get_file(original_filepath, 'wb') \
139 as original_file:
140 original_file.write(queued_file.read())
141
142 # Remove queued media file from storage and database
143 mgg.queue_store.delete_file(queued_filepath)
144 entry.queued_media_file = []
145
146 # Insert media file information into database
147 media_files_dict = entry.setdefault('media_files', {})
148 media_files_dict['thumb'] = thumb_filepath
149 media_files_dict['original'] = original_filepath
150 media_files_dict['medium'] = medium_filepath
151
152 # Insert exif data into database
153 media_data = entry.setdefault('media_data', {})
154 media_data['exif'] = {
155 'clean': clean_exif(exif_tags)}
156 media_data['exif']['useful'] = get_useful(
157 media_data['exif']['clean'])
158 media_data['gps'] = gps_data
159
160 # clean up workbench
161 workbench.destroy_self()
162
163 if __name__ == '__main__':
164 import sys
165 import pprint
166
167 pp = pprint.PrettyPrinter()
168
169 result = extract_exif(sys.argv[1])
170 gps = get_gps_data(result)
171 clean = clean_exif(result)
172 useful = get_useful(clean)
173
174 print pp.pprint(
175 clean)