I need to import a bunch of models which use .dds textures, which are not supported by Cycles, but they are supported by Blender. I can open such a .dds in the image editor, and press F3(Save image as) to save it as a perfectly functional .png file.

However when I try to do this through Python, it fails without a useful error message, and no new file gets created.

Here is my code:

# Set current panel to Image/UV Editor
area = bpy.context.area
area.type = 'IMAGE_EDITOR'

for i in bpy.data.images:
    area.spaces.active.image = i
    newPath = i.filepath.replace("dds", "png")
    bpy.ops.image.save_as(save_as_render=False, filepath=newPath, relative_path=True)

Which will throw this useless error:

Couldn't save picture.
D:\Path\FileName.png: No error
Error: Could not write image: No error
Traceback (most recent call last):
  File "D:\ProjectPath\TexConvertTest.blend\Text", line 19, in <module>
  File "C:\3D\Blender\blender-2.79-windows64\2.79\scripts\modules\bpy\ops.py", line 189, in __call__
    ret = op_call(self.idname_py(), None, kw)
RuntimeError: Error: Could not write image: No error

I tried running it with admin priviliges, but no difference. Any other suggestions would be appreciated!

  • $\begingroup$ Have you checked if i.filepath contains something useful? RenderResult and other internal images do not have any filepath, which has to be filtered out. Otherwise add a print statement to identify what image it fails on. $\endgroup$ – J. Bakker Jan 15 '18 at 7:40

Don't use operators unless there is no other way. In this case you're making your life overly complicated with them. This is my proposed approach:

for i in bpy.data.images:
    new_path = i.filepath.replace(".dds", ".png")
    if new_path == i.filepath:
        print('Refusing to overwrite %s (name=%r)' % (i.filepath, i.name))

I've also taken the liberty to change a bit more:

  • Replacing .dds instead of just dds. You don't want to change adds-liquid.dds into apng-liquid.png. For more reliable manipulating of file paths I would recommend pathlib rather than string manipulation.
  • Using bpy.path.abspath() to convert any blendfile-relative file path to an absolute path. Without this, saving the file won't work reliably.
  • Added a check to prevent overwriting a non-DDS file.
  • Applied PEP 8 -- Style Guide for Python Code to your variable names.
  • 1
    $\begingroup$ Works like a charm, thank you so much! Both for the solution and the great advice. $\endgroup$ – Mets Jan 15 '18 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.