4
$\begingroup$

I load an image texture (of 3 frames) as a material node. I draw on all (3) frames in texture paint mode.

save

I want to save all modified images at once, preferably with python. How can I save all images of the image sequence at once?

$\endgroup$
0

1 Answer 1

4
$\begingroup$

You can just call bpy.ops.image.save_sequence() within the Image Editor.

Override the context

If you would like to call the operator from another area, you can override the context:

Blender 3.2+

import bpy
from bpy import context

for area in context.screen.areas:
    if area.type == 'IMAGE_EDITOR':
        with context.temp_override(area=area):
            bpy.ops.image.save_sequence()
        break

Blender 2.8+

import bpy

C = bpy.context

for area in C.screen.areas:
    if area.type == 'IMAGE_EDITOR':
        override = C.copy()
        override['area'] = area
        bpy.ops.image.save_sequence(override)
        break

Console output:

Info: 3 image(s) will be saved in /tmp/
Info: Saved /tmp/untitled_0003.exr
Info: Saved /tmp/untitled_0002.exr
Info: Saved /tmp/untitled_0001.exr

Switch the area

If there is no Image Editor available, you can also switch the current area to the Image Editor, assign the sequence, call the operator and reset the area to its old type:

import bpy

C = bpy.context
img_seq = bpy.data.images['untitled_0001.exr']

# Store current area
area = C.area
old_type = area.type

# Set the area type and assign the sequence
area.type = 'IMAGE_EDITOR'
area.spaces.active.image = img_seq

# Call the operator and reset the area
bpy.ops.image.save_sequence()
area.type = old_type

Console output:

Info: 3 image(s) will be saved in /tmp/
Info: Saved /tmp/untitled_0003.exr
Info: Saved /tmp/untitled_0002.exr
Info: Saved /tmp/untitled_0001.exr

Custom operator

Operator demo based on the operator_node.py template that comes with Blender in order to save the image sequence of the selected Image node in the Node Editor:

import bpy

class NodeOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "node.simple_operator"
    bl_label = "Simple Node Operator"

    @classmethod
    def poll(cls, context):
        space = context.space_data
        return space.type == 'NODE_EDITOR' and \
            context.active_node.type=='TEX_IMAGE'

    def execute(self, context):
        image_sequence = context.active_node.image
        if image_sequence.source == 'SEQUENCE':
            # Store current area
            area = context.area
            old_type = area.type
            # Set the area type and assign the sequence
            area.type = 'IMAGE_EDITOR'
            area.spaces.active.image = image_sequence
            # Call the operator and reset the area
            bpy.ops.image.save_sequence()
            area.type = old_type
        return {'FINISHED'}

def register():
    bpy.utils.register_class(NodeOperator)
def unregister():
    bpy.utils.unregister_class(NodeOperator)
if __name__ == "__main__":
    register()
$\endgroup$
5
  • $\begingroup$ 1. What if there is no Image Editor, just a node graph? 2. Can we call the function from the ui? $\endgroup$
    – Leander
    Commented Sep 5, 2021 at 16:23
  • $\begingroup$ re 1: you'd have to switch the area temporarily see the link. re 2: Sure, layout.operator("image.save_sequence") (already part of the header menu, Image Editor > Image > Save Sequence) Does this answer your question(s)? @Leander $\endgroup$
    – brockmann
    Commented Sep 5, 2021 at 16:28
  • $\begingroup$ Actually quite so. It seems I just completely overlooked that operator/button. Obligatory, but futile follow up: Can we access that functionality without ops? $\endgroup$
    – Leander
    Commented Sep 5, 2021 at 21:58
  • $\begingroup$ Not sure, need to investigate. AFAICT there is no way to access each image (buffer) individually so I don't see any potential improvements of a low-level solution. We would have to change the frame using frame_set() and save the result which is quite expensive and slow, I guess. The operator on the other hand just saves the image buffer already in memory: github.com/blender/blender/blob/master/source/blender/editors/… @Leander $\endgroup$
    – brockmann
    Commented Sep 6, 2021 at 8:52
  • $\begingroup$ I had tried your suggestion, but the image buffer was not replaced after frame_set(). Your argument about performance makes a lot of sense though. $\endgroup$
    – Leander
    Commented Sep 6, 2021 at 9:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .