Commit | Line | Data |
---|---|---|
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 | ||
17 | import Image | |
8e5f9746 | 18 | import os |
93bdab9d | 19 | |
93bdab9d | 20 | from mediagoblin import mg_globals as mgg |
4535f759 JW |
21 | from mediagoblin.processing import BadMediaFail, \ |
22 | create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE | |
a180ca26 JW |
23 | from mediagoblin.tools.exif import exif_fix_image_orientation, \ |
24 | extract_exif, clean_exif, get_gps_data, get_useful | |
93bdab9d | 25 | |
063670e9 BS |
26 | MAX_FILENAME_LENGTH = 255 # the limit in VFAT -- seems like a good baseline |
27 | ||
28 | def resize_image(entry, filename, basename, file_tail, exif_tags, workdir, | |
29 | new_size, size_limits=None): | |
30 | """Store a resized version of an image and return its pathname. | |
31 | ||
32 | Arguments: | |
33 | entry -- the entry for the image to resize | |
34 | filename -- the filename of the original image being resized | |
35 | basename -- simple basename of the given filename | |
36 | file_tail -- ending string and extension for the resized filename | |
37 | exif_tags -- EXIF data for the original image | |
38 | workdir -- directory path for storing converted image files | |
39 | new_size -- 2-tuple size for the resized image | |
40 | size_limits (optional) -- image is only resized if it exceeds this size | |
41 | ||
42 | """ | |
43 | try: | |
44 | resized = Image.open(filename) | |
45 | except IOError: | |
46 | raise BadMediaFail() | |
47 | resized = exif_fix_image_orientation(resized, exif_tags) # Fix orientation | |
48 | ||
49 | if ((size_limits is None) or | |
50 | (resized.size[0] > size_limits[0]) or | |
51 | (resized.size[1] > size_limits[1])): | |
52 | resized.thumbnail(new_size, Image.ANTIALIAS) | |
53 | ||
54 | resized_filename = (basename[:MAX_FILENAME_LENGTH - len(file_tail)] + | |
55 | file_tail) | |
56 | resized_filepath = create_pub_filepath(entry, resized_filename) | |
57 | ||
58 | # Copy the new file to the conversion subdir, then remotely. | |
59 | tmp_resized_filename = os.path.join(workdir, resized_filename) | |
60 | with file(tmp_resized_filename, 'w') as resized_file: | |
61 | resized.save(resized_file) | |
62 | mgg.public_store.copy_local_to_storage( | |
63 | tmp_resized_filename, resized_filepath) | |
64 | return resized_filepath | |
65 | ||
93bdab9d JW |
66 | def process_image(entry): |
67 | """ | |
68 | Code to process an image | |
69 | """ | |
70 | workbench = mgg.workbench_manager.create_workbench() | |
8e5f9746 JW |
71 | # Conversions subdirectory to avoid collisions |
72 | conversions_subdir = os.path.join( | |
73 | workbench.dir, 'conversions') | |
74 | os.mkdir(conversions_subdir) | |
93bdab9d | 75 | |
8545cfc9 | 76 | queued_filepath = entry.queued_media_file |
93bdab9d JW |
77 | queued_filename = workbench.localized_file( |
78 | mgg.queue_store, queued_filepath, | |
79 | 'source') | |
80 | ||
58dd8d9e PUS |
81 | filename_bits = os.path.splitext(queued_filename) |
82 | basename = os.path.split(filename_bits[0])[1] | |
83 | extension = filename_bits[1].lower() | |
8e5f9746 | 84 | |
e8e444a8 JW |
85 | # EXIF extraction |
86 | exif_tags = extract_exif(queued_filename) | |
87 | gps_data = get_gps_data(exif_tags) | |
88 | ||
063670e9 BS |
89 | # Always create a small thumbnail |
90 | thumb_filepath = resize_image(entry, queued_filename, basename, | |
91 | '.thumbnail' + extension, exif_tags, | |
92 | conversions_subdir, THUMB_SIZE) | |
93bdab9d JW |
93 | |
94 | # If the size of the original file exceeds the specified size of a `medium` | |
063670e9 | 95 | # file, a `.medium.jpg` files is created and later associated with the media |
93bdab9d | 96 | # entry. |
063670e9 BS |
97 | medium_filepath = resize_image(entry, queued_filename, basename, |
98 | '.medium' + extension, exif_tags, | |
99 | conversions_subdir, MEDIUM_SIZE, MEDIUM_SIZE) | |
93bdab9d JW |
100 | |
101 | # we have to re-read because unlike PIL, not everything reads | |
102 | # things in string representation :) | |
103 | queued_file = file(queued_filename, 'rb') | |
104 | ||
105 | with queued_file: | |
58dd8d9e PUS |
106 | #create_pub_filepath(entry, queued_filepath[-1]) |
107 | original_filepath = create_pub_filepath(entry, basename + extension) | |
93bdab9d | 108 | |
8e5f9746 JW |
109 | with mgg.public_store.get_file(original_filepath, 'wb') \ |
110 | as original_file: | |
93bdab9d JW |
111 | original_file.write(queued_file.read()) |
112 | ||
e8e444a8 | 113 | # Remove queued media file from storage and database |
93bdab9d | 114 | mgg.queue_store.delete_file(queued_filepath) |
8545cfc9 | 115 | entry.queued_media_file = [] |
e8e444a8 JW |
116 | |
117 | # Insert media file information into database | |
93bdab9d JW |
118 | media_files_dict = entry.setdefault('media_files', {}) |
119 | media_files_dict['thumb'] = thumb_filepath | |
120 | media_files_dict['original'] = original_filepath | |
e8e444a8 JW |
121 | media_files_dict['medium'] = medium_filepath |
122 | ||
123 | # Insert exif data into database | |
124 | media_data = entry.setdefault('media_data', {}) | |
497d9279 E |
125 | |
126 | # TODO: Fix for sql media_data, when exif is in sql | |
127 | if media_data is not None: | |
128 | media_data['exif'] = { | |
129 | 'clean': clean_exif(exif_tags)} | |
130 | media_data['exif']['useful'] = get_useful( | |
131 | media_data['exif']['clean']) | |
ea200c32 E |
132 | |
133 | if len(gps_data): | |
134 | for key in list(gps_data.keys()): | |
135 | gps_data['gps_' + key] = gps_data.pop(key) | |
136 | entry.media_data_init(**gps_data) | |
93bdab9d JW |
137 | |
138 | # clean up workbench | |
139 | workbench.destroy_self() | |
e8e444a8 | 140 | |
e8e444a8 JW |
141 | if __name__ == '__main__': |
142 | import sys | |
143 | import pprint | |
144 | ||
145 | pp = pprint.PrettyPrinter() | |
146 | ||
147 | result = extract_exif(sys.argv[1]) | |
148 | gps = get_gps_data(result) | |
a180ca26 JW |
149 | clean = clean_exif(result) |
150 | useful = get_useful(clean) | |
e8e444a8 | 151 | |
e8e444a8 | 152 | print pp.pprint( |
a180ca26 | 153 | clean) |