Update scripts to account for removal of the context override to bpy.ops
[blender-addons.git] / object_print3d_utils / export.py
blob9fda6b24d6944065472a4c3d3d6a3fc4e19c3712
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Export wrappers and integration with external tools.
6 import bpy
8 from bpy.app.translations import (
9 pgettext_tip as tip_,
10 pgettext_data as data_,
14 def image_get(mat):
15 from bpy_extras import node_shader_utils
17 if mat.use_nodes:
18 mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat)
19 base_color_tex = mat_wrap.base_color_texture
20 if base_color_tex and base_color_tex.image:
21 return base_color_tex.image
24 def image_copy_guess(filepath, objects):
25 # 'filepath' is the path we are writing to.
26 image = None
27 mats = set()
29 for obj in objects:
30 for slot in obj.material_slots:
31 if slot.material:
32 mats.add(slot.material)
34 for mat in mats:
35 image = image_get(mat)
36 if image is not None:
37 break
39 if image is not None:
40 import os
41 import shutil
43 imagepath = bpy.path.abspath(image.filepath, library=image.library)
44 if os.path.exists(imagepath):
45 filepath_noext = os.path.splitext(filepath)[0]
46 ext = os.path.splitext(imagepath)[1]
48 imagepath_dst = filepath_noext + ext
49 print(f"copying texture: {imagepath!r} -> {imagepath_dst!r}")
51 try:
52 shutil.copy(imagepath, imagepath_dst)
53 except:
54 import traceback
55 traceback.print_exc()
58 def write_mesh(context, report_cb):
59 import os
61 scene = context.scene
62 layer = context.view_layer
63 unit = scene.unit_settings
64 print_3d = scene.print_3d
66 export_format = print_3d.export_format
67 global_scale = unit.scale_length if (unit.system != 'NONE' and print_3d.use_apply_scale) else 1.0
68 path_mode = 'COPY' if print_3d.use_export_texture else 'AUTO'
69 export_path = bpy.path.abspath(print_3d.export_path)
70 obj = layer.objects.active
71 export_data_layers = print_3d.use_data_layers
73 # Create name 'export_path/blendname-objname'
74 # add the filename component
75 if bpy.data.is_saved:
76 name = os.path.basename(bpy.data.filepath)
77 name = os.path.splitext(name)[0]
78 else:
79 name = data_("untitled")
81 # add object name
82 import re
83 name += "-" + re.sub(r'[\\/:*?"<>|]', "", obj.name)
85 # first ensure the path is created
86 if export_path:
87 # this can fail with strange errors,
88 # if the dir can't be made then we get an error later.
89 try:
90 os.makedirs(export_path, exist_ok=True)
91 except:
92 import traceback
93 traceback.print_exc()
95 filepath = os.path.join(export_path, name)
97 # ensure addon is enabled
98 import addon_utils
100 def addon_ensure(addon_id):
101 # Enable the addon, dont change preferences.
102 _default_state, loaded_state = addon_utils.check(addon_id)
103 if not loaded_state:
104 addon_utils.enable(addon_id, default_set=False)
106 if export_format == 'STL':
107 addon_ensure("io_mesh_stl")
108 filepath = bpy.path.ensure_ext(filepath, ".stl")
109 ret = bpy.ops.export_mesh.stl(
110 filepath=filepath,
111 ascii=False,
112 use_mesh_modifiers=True,
113 use_selection=True,
114 global_scale=global_scale,
116 elif export_format == 'PLY':
117 filepath = bpy.path.ensure_ext(filepath, ".ply")
118 ret = bpy.ops.wm.ply_export(
119 filepath=filepath,
120 ascii_format=False,
121 apply_modifiers=True,
122 export_selected_objects=True,
123 global_scale=global_scale,
124 export_normals=export_data_layers,
125 export_uv=export_data_layers,
126 export_colors="SRGB" if export_data_layers else "NONE",
128 elif export_format == 'X3D':
129 addon_ensure("io_scene_x3d")
130 filepath = bpy.path.ensure_ext(filepath, ".x3d")
131 ret = bpy.ops.export_scene.x3d(
132 filepath=filepath,
133 use_mesh_modifiers=True,
134 use_selection=True,
135 global_scale=global_scale,
136 path_mode=path_mode,
137 use_normals=export_data_layers,
139 elif export_format == 'OBJ':
140 filepath = bpy.path.ensure_ext(filepath, ".obj")
141 ret = bpy.ops.wm.obj_export(
142 filepath=filepath,
143 apply_modifiers=True,
144 export_selected_objects=True,
145 scaling_factor=global_scale,
146 path_mode=path_mode,
147 export_normals=export_data_layers,
148 export_uv=export_data_layers,
149 export_materials=export_data_layers,
150 export_colors=export_data_layers,
152 else:
153 assert 0
155 # for formats that don't support images
156 if path_mode == 'COPY' and export_format in {'STL', 'PLY'}:
157 image_copy_guess(filepath, context.selected_objects)
159 if 'FINISHED' in ret:
160 if report_cb is not None:
161 report_cb({'INFO'}, tip_("Exported: {!r}").format(filepath))
163 return True
165 if report_cb is not None:
166 report_cb({'ERROR'}, "Export failed")
168 return False