Media type refractors, pep8, lint
[mediagoblin.git] / mediagoblin / media_types / image / processing.py
CommitLineData
93bdab9d 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
93bdab9d
JW
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
17import Image
8e5f9746 18import os
92f129b5 19import logging
93bdab9d 20
93bdab9d 21from mediagoblin import mg_globals as mgg
4535f759 22from mediagoblin.processing import BadMediaFail, \
c56d4b55 23 create_pub_filepath
a180ca26
JW
24from mediagoblin.tools.exif import exif_fix_image_orientation, \
25 extract_exif, clean_exif, get_gps_data, get_useful
93bdab9d 26
92f129b5
JW
27_log = logging.getLogger(__name__)
28
29SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg']
30
c56d4b55 31
ec4261a4 32def sniff_handler(media_file, **kw):
e2caf574 33 if kw.get('media') is not None: # That's a double negative!
92f129b5
JW
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:
10085b77 46 _log.debug('Media present, extension not found in {0}'.format(
92f129b5
JW
47 SUPPORTED_FILETYPES))
48 else:
49 _log.warning('Need additional information (keyword argument \'media\')'
50 ' to be able to handle sniffing')
51
ec4261a4
JW
52 return False
53
c56d4b55 54
93bdab9d
JW
55def process_image(entry):
56 """
57 Code to process an image
58 """
59 workbench = mgg.workbench_manager.create_workbench()
8e5f9746
JW
60 # Conversions subdirectory to avoid collisions
61 conversions_subdir = os.path.join(
62 workbench.dir, 'conversions')
63 os.mkdir(conversions_subdir)
93bdab9d 64
8545cfc9 65 queued_filepath = entry.queued_media_file
93bdab9d
JW
66 queued_filename = workbench.localized_file(
67 mgg.queue_store, queued_filepath,
68 'source')
69
58dd8d9e
PUS
70 filename_bits = os.path.splitext(queued_filename)
71 basename = os.path.split(filename_bits[0])[1]
72 extension = filename_bits[1].lower()
8e5f9746 73
e8e444a8
JW
74 # EXIF extraction
75 exif_tags = extract_exif(queued_filename)
76 gps_data = get_gps_data(exif_tags)
77
93bdab9d
JW
78 try:
79 thumb = Image.open(queued_filename)
80 except IOError:
81 raise BadMediaFail()
82
e8e444a8
JW
83 thumb = exif_fix_image_orientation(thumb, exif_tags)
84
c56d4b55
JW
85 thumb.thumbnail(
86 (mgg.global_config['media:thumb']['max_width'],
87 mgg.global_config['media:thumb']['max_height']),
88 Image.ANTIALIAS)
93bdab9d 89
8e5f9746
JW
90 # Copy the thumb to the conversion subdir, then remotely.
91 thumb_filename = 'thumbnail' + extension
92 thumb_filepath = create_pub_filepath(entry, thumb_filename)
63bd7c04 93
8e5f9746
JW
94 tmp_thumb_filename = os.path.join(
95 conversions_subdir, thumb_filename)
63bd7c04 96
8e5f9746
JW
97 with file(tmp_thumb_filename, 'w') as thumb_file:
98 thumb.save(thumb_file)
63bd7c04 99
8e5f9746
JW
100 mgg.public_store.copy_local_to_storage(
101 tmp_thumb_filename, thumb_filepath)
93bdab9d
JW
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)
63bd7c04
JW
107
108 # Fix orientation
e8e444a8 109 medium = exif_fix_image_orientation(medium, exif_tags)
93bdab9d 110
c56d4b55
JW
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)
93bdab9d 117
e8e444a8
JW
118 medium_filename = 'medium' + extension
119 medium_filepath = create_pub_filepath(entry, medium_filename)
63bd7c04 120
e8e444a8
JW
121 tmp_medium_filename = os.path.join(
122 conversions_subdir, medium_filename)
93bdab9d 123
e8e444a8
JW
124 with file(tmp_medium_filename, 'w') as medium_file:
125 medium.save(medium_file)
93bdab9d 126
e8e444a8
JW
127 mgg.public_store.copy_local_to_storage(
128 tmp_medium_filename, medium_filepath)
93bdab9d
JW
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:
58dd8d9e 135 #create_pub_filepath(entry, queued_filepath[-1])
c56d4b55 136 original_filepath = create_pub_filepath(entry, basename + extension)
93bdab9d 137
8e5f9746
JW
138 with mgg.public_store.get_file(original_filepath, 'wb') \
139 as original_file:
93bdab9d
JW
140 original_file.write(queued_file.read())
141
e8e444a8 142 # Remove queued media file from storage and database
93bdab9d 143 mgg.queue_store.delete_file(queued_filepath)
8545cfc9 144 entry.queued_media_file = []
e8e444a8
JW
145
146 # Insert media file information into database
93bdab9d
JW
147 media_files_dict = entry.setdefault('media_files', {})
148 media_files_dict['thumb'] = thumb_filepath
149 media_files_dict['original'] = original_filepath
e8e444a8
JW
150 media_files_dict['medium'] = medium_filepath
151
152 # Insert exif data into database
153 media_data = entry.setdefault('media_data', {})
a180ca26
JW
154 media_data['exif'] = {
155 'clean': clean_exif(exif_tags)}
156 media_data['exif']['useful'] = get_useful(
157 media_data['exif']['clean'])
e8e444a8 158 media_data['gps'] = gps_data
93bdab9d
JW
159
160 # clean up workbench
161 workbench.destroy_self()
e8e444a8 162
e8e444a8
JW
163if __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)
a180ca26
JW
171 clean = clean_exif(result)
172 useful = get_useful(clean)
e8e444a8 173
e8e444a8 174 print pp.pprint(
a180ca26 175 clean)