Export Layer Anim - To export layers in distinct files with anim support

Hello

This plugin was created to export layers in distinct files with one file created for each animation’s frame.
It also supports files or layers that aren’t animated.

Please let me know if you have any comments or recommendations.

Link: GitHub - Grimo0/kritaExportLayerAnim: A plugin for [Krita](https://krita.org/) that exports layers in separate files.

Preview:
screen

4 Likes

Also, if anyone knows how to get the list of layers stocked in the Compositions tool, i have been looking hopelessly.

Maybe this helps…

from krita import (
        Krita,)

from PyQt5.QtCore import (
        Qt,
        QObject)

from PyQt5.QtWidgets import (
        QListView,)


def walk(q_object, filter=QObject):
    stack = [(q_object, 0)]
    while stack:
        cursor, depth = stack.pop(-1)
        if isinstance(cursor, filter):
            yield cursor, depth
        stack.extend((c, depth + 1) for c in reversed(cursor.children()))


def dump(start_q_obj):
    for q_obj, depth in walk(start_q_obj):
        indent = '  ' * depth
        obj_type = type(q_obj).__qualname__
        meta_cls_name = q_obj.metaObject().className()
        obj_name = q_obj.objectName()
        try:
            text = q_obj.text()
        except AttributeError:
            text = None
        print(f'{indent}{obj_type=} {meta_cls_name=} {obj_name=} {text=}')


def dump_model_info(model):
    print('some info from CompositionDocker/compositionView.model():\n'
            '(hint this most likely the thing you need)')
    for row in range(model.rowCount()):
        index = model.index(row, 0)
        checked_state = index.data(role=Qt.CheckStateRole)
        text = index.data(role=Qt.DisplayRole)
        print(f'  {row=} {checked_state=} {text=}')


def dump_selection_model_info(s_model):
    print('some info from CompositionDocker/compositionView.selectionModel():')
    for index in s_model.selectedIndexes():
        row = index.row()
        checked_state = index.data(role=Qt.CheckStateRole)
        text = index.data(role=Qt.DisplayRole)
        print(f'  {row=} {checked_state=} {text=}')


app = Krita.instance()
composition_docker = next(d for d in app.dockers() if d.objectName() == 'CompositionDocker')
composition_view = composition_docker.findChild(QListView, 'compositionView')

dump(composition_docker)
print()

dump_model_info(composition_view.model())
print()

dump_selection_model_info(composition_view.selectionModel())
print()

and here is way to temporarily activate composition context.
selection is based on name of compositon → ‘name_of_my_special_composition’

from contextlib import (
        contextmanager,)

from krita import (
        Krita,)

from PyQt5.QtCore import (
        Qt,
        QObject,
        QItemSelectionModel)

from PyQt5.QtWidgets import (
        QListView,)


@contextmanager
def composition(composition_name):
    app = Krita.instance()
    composition_docker = next(d for d in app.dockers() if d.objectName() == 'CompositionDocker')
    composition_view = composition_docker.findChild(QListView, 'compositionView')
    meta = composition_docker.metaObject()
    activateCurrentIndex = meta.method(meta.indexOfSlot(b'activateCurrentIndex()'))

    model = composition_view.model()
    s_model = composition_view.selectionModel()

    old_index = s_model.currentIndex()
    new_index = None
    for row in range(model.rowCount()):
        index = model.index(row, 0)
        checked_state = index.data(role=Qt.CheckStateRole)
        text = index.data(role=Qt.DisplayRole)
        if text == composition_name:
            new_index = index
            break
    else:
        raise RuntimeError(f'Unknown composition. (did get: {composition_name=})')

    try:
        s_model.setCurrentIndex(new_index, QItemSelectionModel.Current)
        activateCurrentIndex.invoke(composition_docker)
        yield
    finally:
        s_model.setCurrentIndex(old_index, QItemSelectionModel.Current)
        activateCurrentIndex.invoke(composition_docker)
        

def dump_top_layer_visibility(doc):
    for node in doc.topLevelNodes():
        name = node.name()
        is_visible = node.visible()
        print(f'{name=} {is_visible=}')


app = Krita.instance()
doc = app.activeDocument()

# dump current state
dump_top_layer_visibility(doc)

# dump state in composition context
with composition('name_of_my_special_composition'):
    dump_top_layer_visibility(doc)

# dump restored state (should be same as before)
dump_top_layer_visibility(doc)

/AkiR

Wow, this was way more than i hoped ! Thank you so much.

I have been tinkering with this for some time today. I’ll add some features to the plugin later with that.

So, thanks to your help i was able to update the plugin. There is now an option to export layers of each checked composition.

Something like this should be native! be able to export animation respecting the layer structure.

on tvpaint you have “export layer structure” and export a PSD sec, in each PSD you have the layer structure. so you can import that PSD sec on after effects and you have the same layer structure there!