[Bf-extensions-cvs] [8e725721] master: glTF exporter: fix / enhancement of texture images export
Julien Duroure
noreply at git.blender.org
Tue Apr 9 18:49:34 CEST 2019
Commit: 8e72572153ed7166c284598c53af1e0ab4937263
Author: Julien Duroure
Date: Tue Apr 9 18:48:14 2019 +0200
Branches: master
https://developer.blender.org/rBA8e72572153ed7166c284598c53af1e0ab4937263
glTF exporter: fix / enhancement of texture images export
===================================================================
M io_scene_gltf2/__init__.py
M io_scene_gltf2/blender/exp/gltf2_blender_gather_image.py
M io_scene_gltf2/blender/exp/gltf2_blender_gltf2_exporter.py
A io_scene_gltf2/blender/exp/gltf2_blender_image.py
M io_scene_gltf2/io/exp/gltf2_io_image_data.py
===================================================================
diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 8c4d8db4..7b639bf5 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -107,6 +107,22 @@ class ExportGLTF2_Base:
default=''
)
+ export_image_format: EnumProperty(
+ name='Image Format',
+ items=(('NAME', 'from image name',
+ 'Determine the output format from the blender image name'),
+ ('JPEG', 'jpeg image format (.jpg)',
+ 'encode and save textures as .jpeg files. Be aware of a possible loss in quality.'),
+ ('PNG', 'png image format (.png)',
+ 'encode and save textures as .png files.')
+ ),
+ description=(
+ 'Output format for images. PNG is lossless and generally preferred, but JPEG might be preferable for web '
+ 'applications due to the smaller file size'
+ ),
+ default='NAME'
+ )
+
export_texcoords: BoolProperty(
name='UVs',
description='Export UVs (texture coordinates) with meshes',
@@ -348,6 +364,7 @@ class ExportGLTF2_Base:
export_settings['gltf_filedirectory'] = os.path.dirname(export_settings['gltf_filepath']) + '/'
export_settings['gltf_format'] = self.export_format
+ export_settings['gltf_image_format'] = self.export_image_format
export_settings['gltf_copyright'] = self.export_copyright
export_settings['gltf_texcoords'] = self.export_texcoords
export_settings['gltf_normals'] = self.export_normals
@@ -428,6 +445,7 @@ class ExportGLTF2_Base:
col.prop(self, 'export_extras')
col.prop(self, 'will_save_settings')
col.prop(self, 'export_copyright')
+ col.prop(self, 'export_image_format')
def draw_mesh_settings(self):
col = self.layout.box().column()
diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_image.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_image.py
index b570e616..71913034 100755
--- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_image.py
+++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_image.py
@@ -24,8 +24,11 @@ from io_scene_gltf2.blender.exp import gltf2_blender_search_node_tree
from io_scene_gltf2.io.exp import gltf2_io_binary_data
from io_scene_gltf2.io.exp import gltf2_io_image_data
from io_scene_gltf2.io.com import gltf2_io_debug
+from io_scene_gltf2.blender.exp import gltf2_blender_image
+from io_scene_gltf2.blender.exp.gltf2_blender_gather_cache import cached
+ at cached
def gather_image(
blender_shader_sockets_or_texture_slots: typing.Union[typing.Tuple[bpy.types.NodeSocket],
typing.Tuple[bpy.types.Texture]],
@@ -39,13 +42,11 @@ def gather_image(
# The blender image has no data
return None
- mime_type = __gather_mime_type(uri.filepath if uri is not None else "")
-
image = gltf2_io.Image(
buffer_view=buffer_view,
extensions=__gather_extensions(blender_shader_sockets_or_texture_slots, export_settings),
extras=__gather_extras(blender_shader_sockets_or_texture_slots, export_settings),
- mime_type=mime_type,
+ mime_type=__gather_mime_type(blender_shader_sockets_or_texture_slots, export_settings),
name=__gather_name(blender_shader_sockets_or_texture_slots, export_settings),
uri=uri
)
@@ -64,7 +65,7 @@ def __gather_buffer_view(sockets_or_slots, export_settings):
if image is None:
return None
return gltf2_io_binary_data.BinaryData(
- data=image.to_image_data(__gather_mime_type()))
+ data=image.encode(__gather_mime_type(sockets_or_slots, export_settings)))
return None
@@ -76,29 +77,43 @@ def __gather_extras(sockets_or_slots, export_settings):
return None
-def __gather_mime_type(filepath=""):
- extension_types = {'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg'}
- default_extension = extension_types['.png']
-
- matches = re.findall(r'\.\w+$', filepath)
- extension = matches[0] if len(matches) > 0 else default_extension
- return extension_types[extension] if extension.lower() in extension_types.keys() else default_extension
+def __gather_mime_type(sockets_or_slots, export_settings):
+ if export_settings["gltf_image_format"] == "NAME":
+ image_name = __get_texname_from_slot(sockets_or_slots, export_settings)
+ _, extension = os.path.splitext(image_name)
+ if extension in [".jpeg", ".jpg", ".png"]:
+ return {
+ ".jpeg": "image/jpeg",
+ ".jpg": "image/jpeg",
+ ".png": "image/png",
+ }[extension]
+ return "image/png"
+
+ elif export_settings["gltf_image_format"] == "JPEG":
+ return "image/jpeg"
+ else:
+ return "image/png"
def __gather_name(sockets_or_slots, export_settings):
- if __is_socket(sockets_or_slots):
- node = __get_tex_from_socket(sockets_or_slots[0])
- if node is not None:
- return node.shader_node.image.name
- elif isinstance(sockets_or_slots[0], bpy.types.MaterialTextureSlot):
- return sockets_or_slots[0].name
- return None
+ image_name = __get_texname_from_slot(sockets_or_slots, export_settings)
+
+ name, extension = os.path.splitext(image_name)
+ if extension in [".jpeg", ".jpg", ".png"]:
+ return name
+ return image_name
def __gather_uri(sockets_or_slots, export_settings):
if export_settings[gltf2_blender_export_keys.FORMAT] == 'GLTF_SEPARATE':
# as usual we just store the data in place instead of already resolving the references
- return __get_image_data(sockets_or_slots, export_settings)
+ mime_type = __gather_mime_type(sockets_or_slots, export_settings)
+ return gltf2_io_image_data.ImageData(
+ data=__get_image_data(sockets_or_slots, export_settings).encode(mime_type=mime_type),
+ mime_type=mime_type,
+ name=__gather_name(sockets_or_slots, export_settings)
+ )
+
return None
@@ -110,7 +125,7 @@ def __is_slot(sockets_or_slots):
return isinstance(sockets_or_slots[0], bpy.types.MaterialTextureSlot)
-def __get_image_data(sockets_or_slots, export_settings):
+def __get_image_data(sockets_or_slots, export_settings) -> gltf2_blender_image.ExportImage:
# For shared ressources, such as images, we just store the portion of data that is needed in the glTF property
# in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary
# ressources.
@@ -128,8 +143,8 @@ def __get_image_data(sockets_or_slots, export_settings):
return channels
if __is_socket(sockets_or_slots):
- results = [__get_tex_from_socket(socket) for socket in sockets_or_slots]
- image = None
+ results = [__get_tex_from_socket(socket, export_settings) for socket in sockets_or_slots]
+ composed_image = None
for result, socket in zip(results, sockets_or_slots):
if result.shader_node.image.channels == 0:
gltf2_io_debug.print_console("WARNING",
@@ -138,9 +153,7 @@ def __get_image_data(sockets_or_slots, export_settings):
continue
# rudimentarily try follow the node tree to find the correct image data.
- source_channel = None
- target_channel = None
- source_channels_length = None
+ source_channel = 0
for elem in result.path:
if isinstance(elem.from_node, bpy.types.ShaderNodeSeparateRGB):
source_channel = {
@@ -149,68 +162,30 @@ def __get_image_data(sockets_or_slots, export_settings):
'B': 2
}[elem.from_socket.name]
- if source_channel is not None:
- pixels = [split_pixels_by_channels(result.shader_node.image, export_settings)[source_channel]]
- target_channel = source_channel
- source_channel = 0
- source_channels_length = 1
- else:
- pixels = split_pixels_by_channels(result.shader_node.image, export_settings)
- target_channel = 0
- source_channel = 0
- source_channels_length = len(pixels)
+ image = gltf2_blender_image.ExportImage.from_blender_image(result.shader_node.image)
+
+ if composed_image is None:
+ composed_image = gltf2_blender_image.ExportImage.white_image(image.width, image.height)
# Change target channel for metallic and roughness.
if elem.to_socket.name == 'Metallic':
- target_channel = 2
- source_channels_length = 1
+ composed_image[2] = image[source_channel]
elif elem.to_socket.name == 'Roughness':
- target_channel = 1
- source_channels_length = 1
-
- file_name = os.path.splitext(result.shader_node.image.name)[0]
- if result.shader_node.image.packed_file is None:
- file_path = result.shader_node.image.filepath
+ composed_image[1] = image[source_channel]
else:
- # empty path for packed textures, because they are converted to png anyway
- file_path = ""
-
- image_data = gltf2_io_image_data.ImageData(
- file_name,
- file_path,
- result.shader_node.image.size[0],
- result.shader_node.image.size[1],
- source_channel,
- target_channel,
- source_channels_length,
- pixels)
-
- if image is None:
- image = image_data
- else:
- image.add_to_image(target_channel, image_data)
+ composed_image.update(image)
+
+ return composed_image
- return image
elif __is_slot(sockets_or_slots):
texture = __get_tex_from_slot(sockets_or_slots[0])
- pixels = split_pixels_by_channels(texture.image, export_
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list