1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 "name": "Adobe Illustrator / PDF / SVG",
21 "author": "Howard Trickey",
23 "blender": (2, 80, 0),
24 "location": "File > Import-Export > Vector files (.ai, .pdf, .svg)",
25 "description": "Import Adobe Illustrator, PDF, and SVG",
27 "doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Import-Export/AI_PDF_SVG",
29 "category": "Import-Export"}
34 importlib
.reload(geom
)
35 importlib
.reload(model
)
36 importlib
.reload(vecfile
)
37 importlib
.reload(import_vecfile
)
38 importlib
.reload(offset
)
41 importlib
.reload(triquad
)
42 importlib
.reload(art2polyarea
)
58 import bpy_extras
.io_utils
59 from bpy
.props
import (BoolProperty
,
65 from bpy_extras
.io_utils
import ImportHelper
68 class VectorImporter(bpy
.types
.Operator
, ImportHelper
):
69 """Load an AI or PDF or SVG file"""
70 bl_idname
= "import_vec.aipdfsvg"
71 bl_label
= "Import AI/PDF/SVG"
74 filter_glob
: StringProperty(default
="*.ai;*.pdf;*.svg", options
={"HIDDEN"})
75 smoothness
: IntProperty(name
="Smoothness",
76 description
="How closely to approximate curves",
80 scale
: FloatProperty(name
="Scale",
81 description
="Scale longer bounding box side to this size",
86 subdiv_kind
: EnumProperty(name
="Subdivision Method",
87 description
="Method for approximating curves with lines",
89 ('UNIFORM', "Uniform",
90 "All curves bisected 'smoothness' times"),
91 ('ADAPTIVE', "Adaptive",
92 "Curves subdivided until flat enough, as" \
93 " determined by 'smoothness'"),
95 "Curves subdivided until segments have a common length," \
96 " determined by 'smoothness'"),
99 filled_only
: BoolProperty(name
="Filled paths only",
100 description
="Only import filled paths",
102 ignore_white
: BoolProperty(name
="Ignore white-filled",
103 description
="Do not import white-filled paths",
105 combine_paths
: BoolProperty(name
="Combine paths",
106 description
="Use all paths when looking for holes",
108 use_colors
: BoolProperty(name
="Use colors",
109 description
="Use colors from vector file as materials",
111 extrude_depth
: FloatProperty(name
="Extrude depth",
112 description
="Depth of extrusion, if > 0",
117 bevel_amount
: FloatProperty(name
="Bevel amount",
118 description
="Amount of inward bevel, if > 0",
123 bevel_pitch
: FloatProperty(name
="Bevel pitch",
124 description
="Angle of bevel from horizontal",
125 default
=45 * math
.pi
/ 180.0,
127 max=89.0 * math
.pi
/ 180.0,
129 cap_back
: BoolProperty(name
="Cap back",
130 description
="Cap the back if extruding",
132 true_scale
: BoolProperty(name
="True Scale",
133 description
="Use true scale, with 1 meter = 1 blender unit",
135 # some info display properties
136 num_verts
: IntProperty(name
="Number of vertices",
138 num_faces
: IntProperty(name
="Number of faces",
141 def draw(self
, context
):
144 box
.label(text
="Import Options")
145 box
.prop(self
, "smoothness")
146 box
.prop(self
, "scale")
147 box
.prop(self
, "true_scale")
148 box
.prop(self
, "subdiv_kind")
149 box
.prop(self
, "filled_only")
150 box
.prop(self
, "ignore_white")
151 box
.prop(self
, "combine_paths")
152 box
.prop(self
, "use_colors")
153 box
.prop(self
, "extrude_depth")
154 box
.prop(self
, "bevel_amount")
155 box
.prop(self
, "bevel_pitch")
156 box
.prop(self
, "cap_back")
157 if self
.num_verts
> 0:
158 layout
.label(text
="Ve:" + str(self
.num_verts
) + \
159 " | Fa:" + str(self
.num_faces
))
161 def action(self
, context
):
162 #convert the filename to an object name
163 if not self
.filepath
:
165 objname
= self
.filepath
.split("\\")[-1].split("/")[-1]
166 if objname
.find(".") > 0:
167 objname
= objname
.split(".")[0]
168 options
= import_vecfile
.ImportOptions()
170 options
.scaled_side_target
= 0.0
172 options
.scaled_side_target
= self
.scale
173 options
.quadrangulate
= True
174 options
.extrude_depth
= self
.extrude_depth
175 options
.bevel_amount
= self
.bevel_amount
176 options
.bevel_pitch
= self
.bevel_pitch
177 options
.cap_back
= self
.cap_back
178 options
.convert_options
.subdiv_kind
= self
.subdiv_kind
179 options
.convert_options
.smoothness
= self
.smoothness
180 options
.convert_options
.filled_only
= self
.filled_only
181 options
.convert_options
.ignore_white
= self
.ignore_white
182 options
.convert_options
.combine_paths
= self
.combine_paths
183 (mdl
, msg
) = import_vecfile
.ReadVecFileToModel(self
.filepath
, options
)
185 self
.report({'ERROR'},
186 "Problem reading file " + self
.filepath
+ ": " + msg
)
188 verts
= mdl
.points
.pos
190 # assume model units are 90 dpi, if svg file
192 # convert to meters (1 inch = 0.0254 meters)
193 if self
.filepath
[-4:] in (".svg", ".SVG"):
198 verts
= [(s
* v
[0], s
* v
[1], s
* v
[2]) for v
in verts
]
199 faces
= [f
for f
in mdl
.faces
if 3 <= len(f
) <= 4]
200 mesh
= bpy
.data
.meshes
.new(objname
)
201 mesh
.from_pydata(verts
, [], faces
)
203 add_colors(mesh
, mdl
.face_data
)
205 self
.num_verts
= len(verts
)
206 self
.num_faces
= len(faces
)
207 obj
= bpy
.data
.objects
.new(objname
, mesh
)
208 context
.scene
.collection
.objects
.link(obj
)
209 bpy
.ops
.object.select_all(action
='DESELECT')
211 context
.view_layer
.objects
.active
= obj
213 def execute(self
, context
):
218 def add_colors(mesh
, colors
):
219 # assume colors are parallel to faces in mesh
220 if len(colors
) < len(mesh
.polygons
):
223 # use rgbtoindex to keep track of colors already
224 # seen and map them to indices into mesh.materials
226 matnameprefix
= "VImat." + mesh
.name
+ "."
227 for i
, c
in enumerate(colors
):
228 print("color for face", i
)
229 if c
not in rgbtoindex
:
230 matname
= matnameprefix
+ str(len(bpy
.data
.materials
))
231 mat
= bpy
.data
.materials
.new(matname
)
232 mat
.diffuse_color
= c
233 mesh
.materials
.append(mat
)
234 cindex
= len(mesh
.materials
) - 1
235 rgbtoindex
[c
] = cindex
237 cindex
= rgbtoindex
[c
]
238 mesh
.polygons
[i
].material_index
= cindex
241 def menu_import(self
, context
):
242 self
.layout
.operator(VectorImporter
.bl_idname
,
243 text
="Vector files (.ai, .pdf, .svg)")
247 bpy
.utils
.register_class(VectorImporter
)
249 bpy
.types
.TOPBAR_MT_file_import
.append(menu_import
)
253 bpy
.utils
.unregister_class(VectorImporter
)
255 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_import
)
258 if __name__
== "__main__":