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