Commit | Line | Data |
---|---|---|
76918e52 AN |
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 os | |
12a10467 | 18 | import json |
76918e52 | 19 | import logging |
12a10467 | 20 | import subprocess |
76918e52 AN |
21 | |
22 | from mediagoblin import mg_globals as mgg | |
23 | from mediagoblin.processing import create_pub_filepath, \ | |
24 | FilenameBuilder | |
25 | ||
26 | from mediagoblin.media_types.stl import model_loader | |
27 | ||
28 | ||
29 | _log = logging.getLogger(__name__) | |
30 | SUPPORTED_FILETYPES = ['stl', 'obj'] | |
31 | ||
32 | ||
33 | def sniff_handler(media_file, **kw): | |
34 | if kw.get('media') is not None: | |
35 | name, ext = os.path.splitext(kw['media'].filename) | |
36 | clean_ext = ext[1:].lower() | |
37 | ||
38 | if clean_ext in SUPPORTED_FILETYPES: | |
39 | _log.info('Found file extension in supported filetypes') | |
40 | return True | |
41 | else: | |
42 | _log.debug('Media present, extension not found in {0}'.format( | |
43 | SUPPORTED_FILETYPES)) | |
44 | else: | |
45 | _log.warning('Need additional information (keyword argument \'media\')' | |
46 | ' to be able to handle sniffing') | |
47 | ||
48 | return False | |
49 | ||
50 | ||
12a10467 AN |
51 | def blender_render(config): |
52 | """ | |
53 | Called to prerender a model. | |
54 | """ | |
55 | arg_string = "blender -b blender_render.blend -F " | |
56 | arg_string +="JPEG -P blender_render.py" | |
57 | env = {"RENDER_SETUP" : json.dumps(config), "DISPLAY":":0"} | |
58 | subprocess.call(arg_string.split(" "), env=env) | |
59 | ||
60 | ||
76918e52 AN |
61 | def process_stl(entry): |
62 | """ | |
63 | Code to process an stl or obj model. | |
64 | """ | |
65 | ||
66 | workbench = mgg.workbench_manager.create_workbench() | |
67 | # Conversions subdirectory to avoid collisions | |
68 | conversions_subdir = os.path.join( | |
69 | workbench.dir, 'conversions') | |
70 | os.mkdir(conversions_subdir) | |
71 | queued_filepath = entry.queued_media_file | |
72 | queued_filename = workbench.localized_file( | |
73 | mgg.queue_store, queued_filepath, 'source') | |
74 | name_builder = FilenameBuilder(queued_filename) | |
75 | ||
76 | ext = queued_filename.lower().strip()[-4:] | |
77 | if ext.startswith("."): | |
78 | ext = ext[1:] | |
79 | else: | |
80 | ext = None | |
81 | ||
82 | # Attempt to parse the model file and divine some useful | |
83 | # information about it. | |
84 | with open(queued_filename, 'rb') as model_file: | |
85 | model = model_loader.auto_detect(model_file, ext) | |
86 | ||
12a10467 AN |
87 | # generate preview images |
88 | greatest = [model.width, model.height, model.depth] | |
89 | greatest.sort() | |
90 | greatest = greatest[-1] | |
91 | ||
92 | def snap(name, camera, width=640, height=640, project="ORTHO"): | |
93 | path = create_pub_filepath(entry, name_builder.fill(name)) | |
94 | render_file = mgg.public_store.get_file(path, "wb") | |
95 | shot = { | |
96 | "model_path" : queued_filename, | |
97 | "model_ext" : ext, | |
98 | "camera_coord" : camera, | |
99 | "camera_focus" : model.average, | |
100 | "camera_clip" : greatest*10, | |
101 | "greatest" : greatest, | |
102 | "projection" : project, | |
103 | "width" : width, | |
104 | "height" : height, | |
105 | "out_file" : render_file.name, | |
106 | } | |
107 | render_file.close() | |
108 | blender_render(shot) | |
109 | return path | |
110 | ||
111 | thumb_path = snap( | |
112 | "{basename}.thumb.jpg", | |
113 | [0, greatest*-1.5, greatest], | |
114 | mgg.global_config['media:thumb']['max_width'], | |
115 | mgg.global_config['media:thumb']['max_height'], | |
116 | project="PERSP") | |
117 | ||
118 | perspective_path = snap( | |
119 | "{basename}.perspective.jpg", | |
120 | [0, greatest*-1.5, greatest], project="PERSP") | |
121 | ||
122 | topview_path = snap( | |
123 | "{basename}.top.jpg", | |
124 | [model.average[0], model.average[1], greatest*2]) | |
125 | ||
126 | frontview_path = snap( | |
127 | "{basename}.front.jpg", | |
128 | [model.average[0], greatest*-2, model.average[2]]) | |
129 | ||
130 | sideview_path = snap( | |
131 | "{basename}.side.jpg", | |
132 | [greatest*-2, model.average[1], model.average[2]]) | |
133 | ||
134 | ||
135 | ||
76918e52 AN |
136 | |
137 | # Save the public file stuffs | |
138 | model_filepath = create_pub_filepath( | |
139 | entry, name_builder.fill('{basename}{ext}')) | |
140 | ||
141 | with mgg.public_store.get_file(model_filepath, 'wb') as model_file: | |
142 | with open(queued_filename, 'rb') as queued_file: | |
143 | model_file.write(queued_file.read()) | |
144 | ||
145 | ||
146 | # Remove queued media file from storage and database | |
147 | mgg.queue_store.delete_file(queued_filepath) | |
148 | entry.queued_media_file = [] | |
149 | ||
150 | # Insert media file information into database | |
151 | media_files_dict = entry.setdefault('media_files', {}) | |
152 | media_files_dict[u'original'] = model_filepath | |
12a10467 AN |
153 | media_files_dict[u'thumb'] = thumb_path |
154 | media_files_dict[u'perspective'] = perspective_path | |
155 | media_files_dict[u'top'] = topview_path | |
156 | media_files_dict[u'side'] = sideview_path | |
157 | media_files_dict[u'front'] = frontview_path | |
76918e52 AN |
158 | |
159 | # Put model dimensions into the database | |
160 | dimensions = { | |
161 | "center_x" : model.average[0], | |
162 | "center_y" : model.average[1], | |
163 | "center_z" : model.average[2], | |
164 | "width" : model.width, | |
165 | "height" : model.height, | |
166 | "depth" : model.depth, | |
167 | } | |
168 | entry.media_data_init(**dimensions) | |
169 | ||
170 | # clean up workbench | |
171 | workbench.destroy_self() |