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