io_scene_gltf2: delay 'datetime' import
[blender-addons.git] / io_import_gimp_image_to_scene.py
blob94d496e33f25491d3d30e4196114354e53d0d409
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 #####
19 bl_info = {
20 "name": "Import GIMP Image to Scene (.xcf/.xjt)",
21 "author": "Daniel Salazar (ZanQdo)",
22 "version": (2, 0, 1),
23 "blender": (2, 73, 0),
24 "location": "File > Import > GIMP Image to Scene(.xcf/.xjt)",
25 "description": "Imports GIMP multilayer image files as a series of multiple planes",
26 "warning": "XCF import requires xcftools installed",
27 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Import-Export/GIMPImageToScene",
29 "category": "Import-Export",
32 """
33 This script imports GIMP layered image files into 3D Scenes (.xcf, .xjt)
34 """
36 def main(report, File, Path, LayerViewers, MixerViewers, LayerOffset,
37 LayerScale, OpacityMode, AlphaMode, ShadelessMats,
38 SetCamera, SetupCompo, GroupUntagged, Ext):
40 #-------------------------------------------------
42 #Folder = '['+File.rstrip(Ext)+']'+'_images/'
43 Folder = 'images_'+'['+File.rstrip(Ext)+']/'
45 if not bpy.data.is_saved:
46 PathSaveRaw = Path+Folder
47 PathSave = PathSaveRaw.replace(' ', '\ ')
48 try: os.mkdir(PathSaveRaw)
49 except: pass
50 else:
51 PathSave = bpy.data.filepath
52 RSlash = PathSave.rfind('/')
53 PathSaveRaw = PathSave[:RSlash+1]+Folder
54 PathSave = PathSaveRaw.replace(' ', '\ ')
55 try: os.mkdir(PathSaveRaw)
56 except: pass
57 PathSaveRaw = bpy.path.relpath(PathSaveRaw)+'/'
59 PathRaw = Path
60 Path = Path.replace(' ', '\ ')
61 if Ext == '.xjt':
62 ExtSave = '.jpg'
63 #-------------------------------------------------
64 # EXTRACT XJT
65 import tarfile
67 IMG = tarfile.open ('%s%s' % (PathRaw, File))
68 PRP = IMG.extractfile('PRP')
70 Members = IMG.getmembers()
72 for Member in Members:
73 Name = Member.name
74 if Name.startswith('l') and Name.endswith('.jpg'):
75 IMG.extract(Name, path=PathSaveRaw)
77 #-------------------------------------------------
78 # INFO XJT
79 IMGs = []
80 for Line in PRP.readlines():
81 Line = str(Line)
83 if Line.startswith("b'GIMP_XJ_IMAGE"):
84 for Segment in Line.split():
85 if Segment.startswith('w/h:'):
86 ResX, ResY = map (int, Segment[4:].split(','))
87 if Line.startswith(("b'L", "b'l")):
89 """The "nice" method to check if layer has alpha channel
90 sadly GIMP sometimes decides not to export an alpha channel
91 if it's pure white so we are not completely sure here yet"""
92 if Line.startswith("b'L"): HasAlpha = True
93 else: HasAlpha = False
95 md = None
96 op = 1
97 ox, oy = 0,0
99 for Segment in Line.split():
101 if Segment.startswith("b'"):
102 imageFile = 'l' + Segment[3:] + '.jpg'
103 imageFileAlpha ='la'+Segment[3:]+'.jpg'
105 """Phisically double checking if alpha image exists
106 now we can be sure! (damn GIMP)"""
107 if HasAlpha:
108 if not os.path.isfile(PathSaveRaw+imageFileAlpha): HasAlpha = False
110 # Get Width and Height from images
111 data = open(PathSaveRaw+imageFile, "rb").read()
113 hexList = []
114 for ch in data:
115 byt = "%02X" % ch
116 hexList.append(byt)
118 for k in range(len(hexList)-1):
119 if hexList[k] == 'FF' and (hexList[k+1] == 'C0' or hexList[k+1] == 'C2'):
120 ow = int(hexList[k+7],16)*256 + int(hexList[k+8],16)
121 oh = int(hexList[k+5],16)*256 + int(hexList[k+6],16)
123 elif Segment.startswith('md:'): # mode
124 md = Segment[3:]
126 elif Segment.startswith('op:'): # opacity
127 op = float(Segment[3:])*.01
129 elif Segment.startswith('o:'): # origin
130 ox, oy = map(int, Segment[2:].split(','))
132 elif Segment.startswith('n:'): # name
133 n = Segment[3:-4]
134 OpenBracket = n.find ('[')
135 CloseBracket = n.find (']')
137 if OpenBracket != -1 and CloseBracket != -1:
138 RenderLayer = n[OpenBracket+1:CloseBracket]
139 NameShort = n[:OpenBracket]
141 else:
142 RenderLayer = n
143 NameShort = n
145 os.rename(PathSaveRaw+imageFile, PathSaveRaw+NameShort+'.jpg')
146 if HasAlpha: os.rename(PathSaveRaw+imageFileAlpha, PathSaveRaw+NameShort+'_A'+'.jpg')
148 IMGs.append({'LayerMode':md, 'LayerOpacity':op,
149 'LayerName':n, 'LayerNameShort':NameShort,
150 'RenderLayer':RenderLayer, 'LayerCoords':[ow, oh, ox, oy], 'HasAlpha':HasAlpha})
152 else: # Ext == '.xcf':
153 ExtSave = '.png'
154 #-------------------------------------------------
155 # CONFIG
156 XCFInfo = 'xcfinfo'
157 XCF2PNG = 'xcf2png'
158 #-------------------------------------------------
159 # INFO XCF
161 try:
162 Info = subprocess.check_output((XCFInfo, Path+File))
163 except FileNotFoundError as e:
164 if XCFInfo in str(e):
165 report({'ERROR'}, "Please install xcftools, xcfinfo seems to be missing (%s)" % str(e))
166 return False
167 else:
168 raise e
170 Info = Info.decode()
171 IMGs = []
172 for Line in Info.split('\n'):
173 if Line.startswith ('+'):
175 Line = Line.split(' ', 4)
177 RenderLayer = Line[4]
179 OpenBracket = RenderLayer.find ('[')
180 CloseBracket = RenderLayer.find (']')
182 if OpenBracket != -1 and CloseBracket != -1:
183 RenderLayer = RenderLayer[OpenBracket+1:CloseBracket]
184 NameShort = Line[4][:OpenBracket]
185 else:
186 NameShort = Line[4].rstrip()
187 if GroupUntagged:
188 RenderLayer = '__Undefined__'
189 else:
190 RenderLayer = NameShort
192 LineThree = Line[3]
193 Slash = LineThree.find('/')
194 if Slash == -1:
195 Mode = LineThree
196 Opacity = 1
197 else:
198 Mode = LineThree[:Slash]
199 Opacity = float(LineThree[Slash+1:LineThree.find('%')])*.01
201 IMGs.append ({
202 'LayerMode': Mode,
203 'LayerOpacity': Opacity,
204 'LayerName': Line[4].rstrip(),
205 'LayerNameShort': NameShort,
206 'LayerCoords': list(map(int, Line[1].replace('x', ' ').replace('+', ' +').replace('-', ' -').split())),
207 'RenderLayer': RenderLayer,
208 'HasAlpha': True,
210 elif Line.startswith('Version'):
211 ResX, ResY = map (int, Line.split()[2].split('x'))
213 #-------------------------------------------------
214 # EXTRACT XCF
215 if OpacityMode == 'BAKE':
216 Opacity = ()
217 else:
218 Opacity = ("--percent", "100")
219 xcf_path = Path + File
220 for Layer in IMGs:
221 png_path = "%s%s.png" % (PathSave, Layer['LayerName'].replace(' ', '_'))
222 subprocess.call((XCF2PNG, "-C", xcf_path, "-o", png_path, Layer['LayerName']) + Opacity)
224 #-------------------------------------------------
225 Scene = bpy.context.scene
226 #-------------------------------------------------
227 # CAMERA
229 if SetCamera:
230 bpy.ops.object.camera_add(location=(0, 0, 10))
232 Camera = bpy.context.active_object.data
234 Camera.type = 'ORTHO'
235 Camera.ortho_scale = ResX * .01
237 #-------------------------------------------------
238 # RENDER SETTINGS
240 Render = Scene.render
242 if SetCamera:
243 Render.resolution_x = ResX
244 Render.resolution_y = ResY
245 Render.resolution_percentage = 100
246 Render.alpha_mode = 'TRANSPARENT'
248 #-------------------------------------------------
249 # 3D VIEW SETTINGS
251 Scene.game_settings.material_mode = 'GLSL'
253 Areas = bpy.context.screen.areas
255 for Area in Areas:
256 if Area.type == 'VIEW_3D':
257 Area.spaces.active.viewport_shade = 'TEXTURED'
258 Area.spaces.active.show_textured_solid = True
259 Area.spaces.active.show_floor = False
261 #-------------------------------------------------
262 # 3D LAYERS
264 def Make3DLayer (Name, NameShort, Z, Coords, RenderLayer, LayerMode, LayerOpacity, HasAlpha):
266 # RenderLayer
268 if SetupCompo:
269 if not bpy.context.scene.render.layers.get(RenderLayer):
271 bpy.ops.scene.render_layer_add()
273 LayerActive = bpy.context.scene.render.layers.active
274 LayerActive.name = RenderLayer
275 LayerActive.use_pass_vector = True
276 LayerActive.use_sky = False
277 LayerActive.use_edge_enhance = False
278 LayerActive.use_strand = False
279 LayerActive.use_halo = False
281 global LayerNum
282 for i in range (0,20):
283 if not i == LayerNum:
284 LayerActive.layers[i] = False
286 bpy.context.scene.layers[LayerNum] = True
288 LayerFlags[RenderLayer] = bpy.context.scene.render.layers.active.layers
290 LayerList.append([RenderLayer, LayerMode, LayerOpacity])
292 LayerNum += 1
294 # Object
295 bpy.ops.mesh.primitive_plane_add(view_align=False,
296 enter_editmode=False,
297 rotation=(0, 0, 0))
299 bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
302 Active = bpy.context.active_object
304 if SetupCompo:
305 Active.layers = LayerFlags[RenderLayer]
307 Active.location = (
308 (float(Coords[2])-(ResX*0.5))*LayerScale,
309 (-float(Coords[3])+(ResY*0.5))*LayerScale, Z)
311 for Vert in Active.data.vertices:
312 Vert.co[0] += 1
313 Vert.co[1] += -1
315 Active.dimensions = float(Coords[0])*LayerScale, float(Coords[1])*LayerScale, 0
317 bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
319 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
321 Active.show_wire = True
323 Active.name = NameShort
324 bpy.ops.mesh.uv_texture_add()
326 # Material
328 '''if bpy.data.materials.get(NameShort):
329 Mat = bpy.data.materials[NameShort]
330 if not Active.material_slots:
331 bpy.ops.object.material_slot_add()
332 Active.material_slots[0].material = Mat
333 else:'''
335 Mat = bpy.data.materials.new(NameShort)
336 Mat.diffuse_color = (1,1,1)
337 Mat.use_raytrace = False
338 Mat.use_shadows = False
339 Mat.use_cast_buffer_shadows = False
340 Mat.use_cast_approximate = False
341 if HasAlpha:
342 Mat.use_transparency = True
343 if OpacityMode == 'MAT': Mat.alpha = LayerOpacity
344 else: Mat.alpha = 0
345 if ShadelessMats: Mat.use_shadeless = True
347 if Ext == '.xcf':
348 # Color & Alpha PNG
349 Tex = bpy.data.textures.new(NameShort, 'IMAGE')
350 Tex.extension = 'CLIP'
351 Tex.use_preview_alpha = True
353 Img = bpy.data.images.new(NameShort, 128, 128)
354 Img.source = 'FILE'
355 Img.alpha_mode = AlphaMode
356 Img.filepath = '%s%s%s' % (PathSaveRaw, Name, ExtSave)
358 UVFace = Active.data.uv_textures[0].data[0]
359 UVFace.image = Img
361 Tex.image = Img
363 Mat.texture_slots.add()
364 TexSlot = Mat.texture_slots[0]
365 TexSlot.texture = Tex
366 TexSlot.use_map_alpha = True
367 TexSlot.texture_coords = 'UV'
368 if OpacityMode == 'TEX': TexSlot.alpha_factor = LayerOpacity
369 elif OpacityMode == 'MAT': TexSlot.blend_type = 'MULTIPLY'
371 else: # Ext == '.xjt'
372 # Color JPG
373 Tex = bpy.data.textures.new(NameShort, 'IMAGE')
374 Tex.extension = 'CLIP'
376 Img = bpy.data.images.new(NameShort, 128, 128)
377 Img.source = 'FILE'
378 Img.filepath = '%s%s%s' % (PathSaveRaw, Name, ExtSave)
380 UVFace = Active.data.uv_textures[0].data[0]
381 UVFace.image = Img
383 Tex.image = Img
385 Mat.texture_slots.add()
386 TexSlot = Mat.texture_slots[0]
387 TexSlot.texture = Tex
388 TexSlot.texture_coords = 'UV'
390 if HasAlpha:
391 # Alpha JPG
392 Tex = bpy.data.textures.new(NameShort+'_A', 'IMAGE')
393 Tex.extension = 'CLIP'
394 Tex.use_preview_alpha = True
396 Img = bpy.data.images.new(NameShort+'_A', 128, 128)
397 Img.source = 'FILE'
398 Img.alpha_mode = AlphaMode
399 Img.filepath = '%s%s_A%s' % (PathSaveRaw, Name, ExtSave)
400 Img.use_alpha = False
402 Tex.image = Img
404 Mat.texture_slots.add()
405 TexSlot = Mat.texture_slots[1]
406 TexSlot.texture = Tex
407 TexSlot.use_map_alpha = True
408 TexSlot.use_map_color_diffuse = False
409 TexSlot.texture_coords = 'UV'
410 if OpacityMode == 'TEX': TexSlot.alpha_factor = LayerOpacity
411 elif OpacityMode == 'MAT': TexSlot.blend_type = 'MULTIPLY'
413 if not Active.material_slots:
414 bpy.ops.object.material_slot_add()
416 Active.material_slots[0].material = Mat
419 Z = 0
420 global LayerNum
421 LayerNum = 0
422 LayerFlags = {}
423 LayerList = []
425 for Layer in IMGs:
426 Make3DLayer(Layer['LayerName'].replace(' ', '_'),
427 Layer['LayerNameShort'].replace(' ', '_'),
429 Layer['LayerCoords'],
430 Layer['RenderLayer'],
431 Layer['LayerMode'],
432 Layer['LayerOpacity'],
433 Layer['HasAlpha'],
436 Z -= LayerOffset
438 if SetupCompo:
439 #-------------------------------------------------
440 # COMPO NODES
442 Scene.use_nodes = True
444 Tree = Scene.node_tree
446 for i in Tree.nodes:
447 Tree.nodes.remove(i)
449 LayerList.reverse()
451 Offset = 0
452 LayerLen = len(LayerList)
454 for Layer in LayerList:
456 Offset += 1
458 X_Offset = (500*Offset)
459 Y_Offset = (-300*Offset)
461 Node = Tree.nodes.new('CompositorNodeRLayers')
462 Node.location = (-500+X_Offset, 300+Y_Offset)
463 Node.name = 'R_'+ str(Offset)
464 Node.scene = Scene
465 Node.layer = Layer[0]
467 if LayerViewers:
468 Node_V = Tree.nodes.new('CompositorNodeViewer')
469 Node_V.name = Layer[0]
470 Node_V.location = (-200+X_Offset, 200+Y_Offset)
472 Tree.links.new(Node.outputs[0], Node_V.inputs[0])
474 if LayerLen > Offset:
476 Mode = LayerList[Offset][1] # has to go one step further
477 LayerOpacity = LayerList[Offset][2]
479 if not Mode in {'Normal', '-1'}:
481 Node = Tree.nodes.new('CompositorNodeMixRGB')
482 if OpacityMode == 'COMPO': Node.inputs['Fac'].default_value = LayerOpacity
483 else: Node.inputs['Fac'].default_value = 1
484 Node.use_alpha = True
486 if Mode in {'Addition', '7'}: Node.blend_type = 'ADD'
487 elif Mode in {'Subtract', '8'}: Node.blend_type = 'SUBTRACT'
488 elif Mode in {'Multiply', '3'}: Node.blend_type = 'MULTIPLY'
489 elif Mode in {'DarkenOnly', '9'}: Node.blend_type = 'DARKEN'
490 elif Mode in {'Dodge', '16'}: Node.blend_type = 'DODGE'
491 elif Mode in {'LightenOnly', '10'}: Node.blend_type = 'LIGHTEN'
492 elif Mode in {'Difference', '6'}: Node.blend_type = 'DIFFERENCE'
493 elif Mode in {'Divide', '15'}: Node.blend_type = 'DIVIDE'
494 elif Mode in {'Overlay', '5'}: Node.blend_type = 'OVERLAY'
495 elif Mode in {'Screen', '4'}: Node.blend_type = 'SCREEN'
496 elif Mode in {'Burn', '17'}: Node.blend_type = 'BURN'
497 elif Mode in {'Color', '13'}: Node.blend_type = 'COLOR'
498 elif Mode in {'Value', '14'}: Node.blend_type = 'VALUE'
499 elif Mode in {'Saturation', '12'}: Node.blend_type = 'SATURATION'
500 elif Mode in {'Hue', '11'}: Node.blend_type = 'HUE'
501 elif Mode in {'Softlight', '19'}: Node.blend_type = 'SOFT_LIGHT'
502 else: pass
504 else:
505 Node = Tree.nodes.new('CompositorNodeAlphaOver')
506 if OpacityMode == 'COMPO': Node.inputs['Fac'].default_value = LayerOpacity
507 Node.name = 'M_' + str(Offset)
508 Node.location = (300+X_Offset, 250+Y_Offset)
510 if MixerViewers:
511 Node_V = Tree.nodes.new('CompositorNodeViewer')
512 Node_V.name = Layer[0]
513 Node_V.location = (500+X_Offset, 350+Y_Offset)
515 Tree.links.new(Node.outputs[0], Node_V.inputs[0])
517 else:
518 Node = Tree.nodes.new('CompositorNodeComposite')
519 Node.name = 'Composite'
520 Node.location = (400+X_Offset, 350+Y_Offset)
522 Nodes = bpy.context.scene.node_tree.nodes
524 if LayerLen > 1:
525 for i in range (1, LayerLen + 1):
526 if i == 1:
527 Tree.links.new(Nodes['R_'+str(i)].outputs[0], Nodes['M_'+str(i)].inputs[1])
528 if 1 < i < LayerLen:
529 Tree.links.new(Nodes['M_'+str(i-1)].outputs[0], Nodes['M_'+str(i)].inputs[1])
530 if 1 < i < LayerLen+1:
531 Tree.links.new(Nodes['R_'+str(i)].outputs[0], Nodes['M_'+str(i-1)].inputs[2])
532 if i == LayerLen:
533 Tree.links.new(Nodes['M_'+str(i-1)].outputs[0], Nodes['Composite'].inputs[0])
534 else:
535 Tree.links.new(Nodes['R_1'].outputs[0], Nodes['Composite'].inputs[0])
537 for i in Tree.nodes:
538 i.location[0] += -250*Offset
539 i.location[1] += 150*Offset
541 return True
543 #------------------------------------------------------------------------
544 import os, subprocess
545 import bpy
546 from bpy.props import *
547 from math import pi
549 # Operator
550 class GIMPImageToScene(bpy.types.Operator):
551 """"""
552 bl_idname = "import.gimp_image_to_scene"
553 bl_label = "GIMP Image to Scene"
554 bl_description = "Imports GIMP multilayer image files into 3D Scenes"
555 bl_options = {'REGISTER', 'UNDO'}
557 filename = StringProperty(name="File Name",
558 description="Name of the file")
559 directory = StringProperty(name="Directory",
560 description="Directory of the file")
562 LayerViewers = BoolProperty(name="Layer Viewers",
563 description="Add Viewer nodes to each Render Layer node",
564 default=True)
566 MixerViewers = BoolProperty(name="Mixer Viewers",
567 description="Add Viewer nodes to each Mix node",
568 default=True)
570 AlphaMode = EnumProperty(name="Alpha Mode",
571 description="Representation of alpha information in the RGBA pixels",
572 items=(
573 ('STRAIGHT', 'Texture Alpha Factor', 'Transparent RGB and alpha pixels are unmodified'),
574 ('PREMUL', 'Material Alpha Value', 'Transparent RGB pixels are multiplied by the alpha channel')),
575 default='STRAIGHT')
577 ShadelessMats = BoolProperty(name="Shadeless Material",
578 description="Set Materials as Shadeless",
579 default=True)
581 OpacityMode = EnumProperty(name="Opacity Mode",
582 description="Layer Opacity management",
583 items=(
584 ('TEX', 'Texture Alpha Factor', ''),
585 ('MAT', 'Material Alpha Value', ''),
586 ('COMPO', 'Mixer Node Factor', ''),
587 ('BAKE', 'Baked in Image Alpha', '')),
588 default='TEX')
590 SetCamera = BoolProperty(name="Set Camera",
591 description="Create an Ortho Camera matching image resolution",
592 default=True)
594 SetupCompo = BoolProperty(name="Setup Node Compositing",
595 description="Create a compositing node setup (will delete existing nodes)",
596 default=False)
598 GroupUntagged = BoolProperty(name="Group Untagged",
599 description="Layers with no tag go to a single Render Layer",
600 default=False)
602 LayerOffset = FloatProperty(name="Layer Separation",
603 description="Distance between each 3D Layer in the Z axis",
604 min=0,
605 default=0.50)
607 LayerScale = FloatProperty(name="Layer Scale",
608 description="Scale pixel resolution by Blender units",
609 min=0,
610 default=0.01)
612 def draw(self, context):
613 layout = self.layout
615 box = layout.box()
616 box.label('3D Layers:', icon='SORTSIZE')
617 box.prop(self, 'SetCamera', icon='OUTLINER_DATA_CAMERA')
618 box.prop(self, 'OpacityMode', icon='GHOST')
619 if self.OpacityMode == 'COMPO' and self.SetupCompo == False:
620 box.label('Tip: Enable Node Compositing', icon='INFO')
621 box.prop(self, 'AlphaMode', icon='IMAGE_RGB_ALPHA')
622 box.prop(self, 'ShadelessMats', icon='SHADING_SOLID')
623 box.prop(self, 'LayerOffset')
624 box.prop(self, 'LayerScale')
626 box = layout.box()
627 box.label('Compositing:', icon='RENDERLAYERS')
628 box.prop(self, 'SetupCompo', icon='NODETREE')
629 if self.SetupCompo:
630 box.prop(self, 'GroupUntagged', icon='IMAGE_ZDEPTH')
631 box.prop(self, 'LayerViewers', icon='NODE')
632 box.prop(self, 'MixerViewers', icon='NODE')
634 def execute(self, context):
635 # File Path
636 filename = self.filename
637 directory = self.directory
639 # Settings
640 LayerViewers = self.LayerViewers
641 MixerViewers = self.MixerViewers
642 OpacityMode = self.OpacityMode
643 AlphaMode = self.AlphaMode
644 ShadelessMats = self.ShadelessMats
645 SetCamera = self.SetCamera
646 SetupCompo = self.SetupCompo
647 GroupUntagged = self.GroupUntagged
648 LayerOffset = self.LayerOffset
649 LayerScale = self.LayerScale
651 Ext = None
652 if filename.endswith('.xcf'): Ext = '.xcf'
653 elif filename.endswith('.xjt'): Ext = '.xjt'
655 # Call Main Function
656 if Ext:
657 ret = main(self.report, filename, directory, LayerViewers, MixerViewers, LayerOffset,
658 LayerScale, OpacityMode, AlphaMode, ShadelessMats,
659 SetCamera, SetupCompo, GroupUntagged, Ext)
660 if not ret:
661 return {'CANCELLED'}
662 else:
663 self.report({'ERROR'},"Selected file wasn't valid, try .xcf or .xjt")
664 return {'CANCELLED'}
666 return {'FINISHED'}
668 def invoke(self, context, event):
669 wm = bpy.context.window_manager
670 wm.fileselect_add(self)
672 return {'RUNNING_MODAL'}
675 # Registering / Unregister
676 def menu_func(self, context):
677 self.layout.operator(GIMPImageToScene.bl_idname, text="GIMP Image to Scene (.xcf, .xjt)", icon='PLUGIN')
680 def register():
681 bpy.utils.register_module(__name__)
683 bpy.types.TOPBAR_MT_file_import.append(menu_func)
686 def unregister():
687 bpy.utils.unregister_module(__name__)
689 bpy.types.TOPBAR_MT_file_import.remove(menu_func)
692 if __name__ == "__main__":
693 register()