Skip to content

Clip class

Clip object class module.

Clip(clip_id: int, project: Project | None = None)

Bases: pytvpaint.utils.Removable, pytvpaint.utils.Renderable

A Clip is a container for layers and is part of a Scene.

Constructs a Clip from an existing TVPaint clip (giving its id).

Note

You should use Clip.new to create a new clip

Parameters:

Name Type Description Default
clip_id int

an existing clip id

required
project pytvpaint.project.Project | None

the project or the current one if None

None
Source code in pytvpaint/clip.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def __init__(
    self,
    clip_id: int,
    project: Project | None = None,
) -> None:
    """Constructs a Clip from an existing TVPaint clip (giving its id).

    Note:
        You should use `Clip.new` to create a new clip

    Args:
        clip_id: an existing clip id
        project: the project or the current one if None
    """
    from pytvpaint.project import Project

    super().__init__()
    self._id = clip_id
    self._project = project or Project.current_project()
    self._data = george.tv_clip_info(self.id)

id: int property

The clip id.

project: Project property

The clip's project.

scene: Scene property writable

The clip's scene.

Raises:

Type Description
ValueError

if no current scene in the project

camera: Camera property

The clip camera.

position: int property writable

The position of the clip in the scene.

Raises:

Type Description
ValueError

if clip cannot be found in the project

name: str property writable

The clip name.

duration: int property

The duration of the clip in frames. Takes into account the mark in/out of the clip.

is_selected: bool property writable

Returns True if the clip is selected.

is_visible: bool property writable

Returns True if the clip is visible.

color_index: int property writable

Get the clip color index.

action_text: str property writable

Get the action text of the clip.

dialog_text: str property writable

Get the dialog text of the clip.

note_text: str property writable

Get the note text of the clip.

current_frame: int property writable

Returns the current frame in the clip (timeline) relative to the project start frame.

layer_ids: Iterator[int] property

Returns an iterator over the layer ids.

layers: Iterator[Layer] property

Returns an iterator over the clip's animation layers, excluding all Folder, Camera and CTG layers.

Warning

DEPRECATED: use Clip.get_layers() instead.

anim_layers: Iterator[Layer] property

Returns an iterator over the clip's animation layers, excluding all Folder, Camera and CTG layers.

ctg_layers: Iterator[CTGLayer] property

Returns an iterator over the clip's CTG layers.

Note

This function is only available in TVPaint version 12 and above.

Raises:

Type Description
NotImplemented

if used in tvpaint version inferior to 12

folders: Iterator[LayerFolder] property

Returns an iterator over the clip's Folder layers.

Note

This function is only available in TVPaint version 12 and above.

Raises:

Type Description
NotImplemented

if used in tvpaint version inferior to 12

camera_layer: CameraLayer | None property

Returns the clip's Camera layer.

Note

This function is only available in TVPaint version 12 and above.

Raises:

Type Description
NotImplemented

if used in tvpaint version inferior to 12

layer_names: Iterator[str] property

Returns an iterator over the clip's layer names.

current_layer: Layer property

Get the current layer in the clip.

Raises:

Type Description
ValueError

if no current layer in clip

selected_layers: Iterator[Layer] property

Returns an iterator over the selected layers.

visible_layers: Iterator[Layer] property

Returns an iterator over the visible layers.

mark_in: int | None property writable

Get the mark in of the clip.

mark_out: int | None property writable

Get the mark out of the clip.

layer_colors: Iterator[LayerColor] property

Returns an iterator over the layer colors.

bookmarks: Iterator[int] property

Returns an iterator over the clip bookmarks.

sounds: Iterator[ClipSound] property

Iterates through the clip's soundtracks.

refresh_on_call = True instance-attribute

is_removed: bool property

Checks if the object is removed by trying to refresh its data.

Returns:

Name Type Description
bool bool

whether if it was removed or not

new(name: str, scene: Scene | None = None, project: Project | None = None) -> Clip classmethod

Creates a new clip.

Parameters:

Name Type Description Default
name str

the new clip name

required
scene pytvpaint.scene.Scene | None

the scene or the current one if None. Defaults to None.

None
project pytvpaint.project.Project | None

the project or the current one if None. Defaults to None.

None

Returns:

Name Type Description
Clip pytvpaint.clip.Clip

the newly created clip

Source code in pytvpaint/clip.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@classmethod
def new(
    cls,
    name: str,
    scene: Scene | None = None,
    project: Project | None = None,
) -> Clip:
    """Creates a new clip.

    Args:
        name: the new clip name
        scene: the scene or the current one if None. Defaults to None.
        project: the project or the current one if None. Defaults to None.

    Returns:
        Clip: the newly created clip
    """
    from pytvpaint.project import Project

    project = project or Project.current_project()
    project.make_current()

    scene = scene or project.current_scene
    scene.make_current()

    name = utils.get_unique_name(project.clip_names, name)
    george.tv_clip_new(name)

    return Clip.current_clip()

refresh() -> None

Refreshes the clip data.

Source code in pytvpaint/clip.py
94
95
96
97
98
99
def refresh(self) -> None:
    """Refreshes the clip data."""
    super().refresh()
    if not self.refresh_on_call and self._data:
        return
    self._data = george.tv_clip_info(self._id)

make_current() -> None

Make the clip the current one.

Source code in pytvpaint/clip.py
101
102
103
104
105
106
def make_current(self) -> None:
    """Make the clip the current one."""
    self.project.make_current()
    if george.tv_clip_current_id() == self.id:
        return
    george.tv_clip_select(self.id)

start() -> int

The start frame of the clip.

Source code in pytvpaint/clip.py
176
177
178
179
@refreshed_property
def start(self) -> int:
    """The start frame of the clip."""
    return self._data.first_frame + self.project.start_frame

end() -> int

The end frame of the clip.

Source code in pytvpaint/clip.py
181
182
183
184
@refreshed_property
def end(self) -> int:
    """The end frame of the clip."""
    return self._data.last_frame + self.project.start_frame

timeline_start() -> int

The start frame of the clip relative to the project's timeline.

Source code in pytvpaint/clip.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
@refreshed_property
def timeline_start(self) -> int:
    """The start frame of the clip relative to the project's timeline."""
    # get clip real start in project timeline
    clip_real_start = 0
    for clip in self.project.clips:
        if clip == self:
            break
        clip_start = clip.mark_in or clip.start
        clip_end = clip.mark_out or clip.end
        clip_duration = (clip_end - clip_start) + 1
        clip_real_start += clip_duration

    return clip_real_start + self.project.start_frame

timeline_end() -> int

The end frame of the clip relative to the project's timeline.

Source code in pytvpaint/clip.py
206
207
208
209
210
211
212
@refreshed_property
def timeline_end(self) -> int:
    """The end frame of the clip relative to the project's timeline."""
    clip_start = self.mark_in or self.start
    clip_end = self.mark_out or self.end
    clip_duration = clip_end - clip_start
    return self.timeline_start + clip_duration

frame_count() -> int

The clip's frame count.

Source code in pytvpaint/clip.py
214
215
216
217
@refreshed_property
def frame_count(self) -> int:
    """The clip's frame count."""
    return self._data.frame_count

is_current() -> bool

Returns True if the clip is the current one.

Source code in pytvpaint/clip.py
279
280
281
282
@refreshed_property
def is_current(self) -> bool:
    """Returns True if the clip is the current one."""
    return Clip.current_clip_id() == self.id

current_clip_id() -> int staticmethod

Returns the id of the current clip.

Source code in pytvpaint/clip.py
284
285
286
287
@staticmethod
def current_clip_id() -> int:
    """Returns the id of the current clip."""
    return george.tv_clip_current_id()

current_clip() -> Clip staticmethod

Returns the current clip object.

Source code in pytvpaint/clip.py
289
290
291
292
293
294
@staticmethod
def current_clip() -> Clip:
    """Returns the current clip object."""
    from pytvpaint.project import Project

    return Clip(Clip.current_clip_id(), Project.current_project())

duplicate() -> Clip

Duplicates the clip.

Note

a new unique name is choosen for the duplicated clip with get_unique_name.

Source code in pytvpaint/clip.py
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
@set_as_current
def duplicate(self) -> Clip:
    """Duplicates the clip.

    Note:
        a new unique name is choosen for the duplicated clip with `get_unique_name`.
    """
    current_clips = list(self.project.clips)
    george.tv_clip_duplicate(self.id)
    new_clip = [clip for clip in self.project.clips if clip not in current_clips][0]  # noqa: RUF015

    clip_names = [clip.name for clip in current_clips]
    new_name = utils.get_unique_name(clip_names, self.name)
    new_clip.name = new_name

    return new_clip

remove() -> None

Removes the clip.

Warning

the instance is not usable after that call because it's marked as removed.

Source code in pytvpaint/clip.py
325
326
327
328
329
330
331
332
def remove(self) -> None:
    """Removes the clip.

    Warning:
        the instance is not usable after that call because it's marked as removed.
    """
    george.tv_clip_close(self.id)
    self.mark_removed()

get_layers(filter_types: tuple[type, ...] | None = None, ignore_types: tuple[type, ...] | None = None) -> Iterator[Layer]

Returns an iterator over the clip's layers.

Parameters:

Name Type Description Default
filter_types tuple[type, ...] | None

list of layer types to return, default is None, meaning all.

None
ignore_types tuple[type, ...] | None

list of layer types to ignore, default is None, meaning all.

None
Note

Since TVP12 have introduced multiple layer types, this function will replace Clip.layers.

Source code in pytvpaint/clip.py
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
def get_layers(
    self,
    filter_types: tuple[type, ...] | None = None,
    ignore_types: tuple[type, ...] | None = None,
) -> Iterator[Layer]:
    """Returns an iterator over the clip's layers.

    Args:
        filter_types: list of layer types to return, default is None, meaning all.
        ignore_types: list of layer types to ignore, default is None, meaning all.

    Note:
        Since TVP12 have introduced multiple layer types, this function will replace Clip.layers.
    """
    for layer_id in self.layer_ids:
        layer_data = george.tv_layer_info(layer_id)

        layer_class = Layer
        if layer_data.type == george.LayerType.FOLDER:
            layer_class = LayerFolder
        elif layer_data.type == george.LayerType.CAMERA:
            layer_class = CameraLayer
        # handle CTG layers like regular layers in TVP versions < 12
        elif not george.is_tvp_version_below_12() and layer_data.type is george.LayerType.SCRIBBLES:
            layer_class = CTGLayer

        if filter_types and layer_class not in filter_types:
            continue
        if ignore_types and layer_class in ignore_types:
            continue

        yield layer_class(layer_id, clip=self, data=layer_data)

get_layer(by_id: int | None = None, by_name: str | None = None, by_regex: re.Pattern[str] | None = None) -> Layer | None

Get a specific layer by id or name.

Parameters:

Name Type Description Default
by_id int | None

search by id. Defaults to None.

None
by_name str | None

search by name, search is case-insensitive. Defaults to None.

None
by_regex re.Pattern[str] | None

search by name using a compiled regex, case-sensitivity is left to the regex. Defaults to None.

None

Raises:

Type Description
ValueError

if none of the search arguments where provided

Returns:

Type Description
pytvpaint.layer.Layer | None

Layer | None: the searched element or None if search was unsuccessful

Source code in pytvpaint/clip.py
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
def get_layer(
    self,
    by_id: int | None = None,
    by_name: str | None = None,
    by_regex: re.Pattern[str] | None = None,
) -> Layer | None:
    """Get a specific layer by id or name.

    Args:
        by_id: search by id. Defaults to None.
        by_name: search by name, search is case-insensitive. Defaults to None.
        by_regex: search by name using a compiled regex, case-sensitivity is left to the regex. Defaults to None.

    Raises:
        ValueError: if none of the search arguments where provided

    Returns:
        Layer | None: the searched element or None if search was unsuccessful
    """
    return utils.get_tvp_element(self.get_layers(), by_id=by_id, by_name=by_name, by_regex=by_regex)

add_layer(layer_name: str) -> Layer

Add a new layer in the layer stack.

Source code in pytvpaint/clip.py
475
476
477
478
@set_as_current
def add_layer(self, layer_name: str) -> Layer:
    """Add a new layer in the layer stack."""
    return Layer.new(name=layer_name, clip=self)

add_layer_folder(folder_name: str) -> LayerFolder

Add a new layer in the layer stack.

Note

This function is only available in TVPaint version 12 and above.

Raises:

Type Description
NotImplemented

if used in tvpaint version inferior to 12

Source code in pytvpaint/clip.py
480
481
482
483
484
485
486
487
488
489
490
491
@george.min_version_compatible(min_version="12")
@set_as_current
def add_layer_folder(self, folder_name: str) -> LayerFolder:
    """Add a new layer in the layer stack.

    Note:
        This function is only available in TVPaint version 12 and above.

    Raises:
        NotImplemented: if used in tvpaint version inferior to 12
    """
    return cast(LayerFolder, LayerFolder.new(name=folder_name, clip=self))

load_media(media_path: Path, start_count: tuple[int, int] | None = None, stretch: bool = False, time_stretch: bool = False, preload: bool = False, with_name: str = '', field_order: george.FieldOrder = george.FieldOrder.LOWER) -> Layer

Loads a media (single frame, video, ...) into a new Layer in the clip.

Parameters:

Name Type Description Default
media_path pathlib.Path

the path of the media. If it's a file sequence, give the path of the first image.

required
start_count tuple[int, int] | None

the start and number of image of sequence to load. Defaults to None.

None
stretch bool

Stretch each image to the size of the layer. Defaults to None.

False
time_stretch bool

Once loaded, the layer will have a new number of image corresponding to the project framerate. Defaults to None.

False
preload bool

Load all the images in memory, no more reference on the files. Defaults to None.

False
with_name str

the name of the new layer

''
field_order pytvpaint.george.FieldOrder

the field order. Defaults to None.

pytvpaint.george.FieldOrder.LOWER

Returns:

Name Type Description
Layer pytvpaint.layer.Layer

the new layer created

Source code in pytvpaint/clip.py
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
@set_as_current
@george.undoable
def load_media(
    self,
    media_path: Path,
    start_count: tuple[int, int] | None = None,
    stretch: bool = False,
    time_stretch: bool = False,
    preload: bool = False,
    with_name: str = "",
    field_order: george.FieldOrder = george.FieldOrder.LOWER,
) -> Layer:
    """Loads a media (single frame, video, ...) into a new Layer in the clip.

    Args:
        media_path: the path of the media. If it's a file sequence, give the path of the first image.
        start_count: the start and number of image of sequence to load. Defaults to None.
        stretch: Stretch each image to the size of the layer. Defaults to None.
        time_stretch: Once loaded, the layer will have a new number of image corresponding to the project framerate. Defaults to None.
        preload: Load all the images in memory, no more reference on the files. Defaults to None.
        with_name: the name of the new layer
        field_order: the field order. Defaults to None.

    Returns:
        Layer: the new layer created
    """
    media_path = Path(media_path)

    george.tv_load_sequence(
        media_path,
        start_count,
        field_order,
        stretch,
        time_stretch,
        preload,
    )

    new_layer = Layer.current_layer()
    new_layer.name = with_name or media_path.stem

    return new_layer

render(output_path: Path | str | FileSequence, start: int | None = None, end: int | None = None, frame_set: FrameSet | None = None, use_camera: bool = False, layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None) -> Path | FileSequence

Render the clip to a single frame or frame sequence or movie.

Parameters:

Name Type Description Default
output_path pathlib.Path | str | fileseq.filesequence.FileSequence

a single file or file sequence pattern

required
start int | None

the start frame to render or the mark in or the clip's start if None. Defaults to None.

None
end int | None

the end frame to render or the mark out or the clip's end if None. Defaults to None.

None
frame_set fileseq.frameset.FrameSet | None

a FrameSet with the frames/range to render. Defaults to None.

None
use_camera bool

use the camera for rendering, otherwise render the whole canvas. Defaults to False.

False
layer_selection list[pytvpaint.layer.Layer] | None

list of layers to render, if None render all of them. Defaults to None.

None
alpha_mode pytvpaint.george.AlphaSaveMode

the alpha mode for rendering. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the background mode for rendering. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None

Raises:

Type Description
ValueError

if requested range (start-end) not in clip range/bounds

ValueError

if output is a movie, and it's duration is equal to 1 frame

FileNotFoundError

if the render failed and no files were found on disk or missing frames

Note

This function uses the clip's range as a basis (start-end). This is different from the project range, which uses the project timeline. For more details on the differences in frame ranges and the timeline in TVPaint, please check the Usage/Rendering section of the documentation.

Warning

Even though pytvpaint does a pretty good job of correcting the frame ranges for rendering, we're still encountering some weird edge cases where TVPaint will consider the range invalid for seemingly no reason.

Returns:

Type Description
pathlib.Path | fileseq.filesequence.FileSequence

the output file path or sequence

Source code in pytvpaint/clip.py
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
@set_as_current
def render(
    self,
    output_path: Path | str | FileSequence,
    start: int | None = None,
    end: int | None = None,
    frame_set: FrameSet | None = None,
    use_camera: bool = False,
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
) -> Path | FileSequence:
    """Render the clip to a single frame or frame sequence or movie.

    Args:
        output_path: a single file or file sequence pattern
        start: the start frame to render or the mark in or the clip's start if None. Defaults to None.
        end: the end frame to render or the mark out or the clip's end if None. Defaults to None.
        frame_set: a FrameSet with the frames/range to render. Defaults to None.
        use_camera: use the camera for rendering, otherwise render the whole canvas. Defaults to False.
        layer_selection: list of layers to render, if None render all of them. Defaults to None.
        alpha_mode: the alpha mode for rendering. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the background mode for rendering. Defaults to None.
        format_opts: custom format options. Defaults to None.

    Raises:
        ValueError: if requested range (start-end) not in clip range/bounds
        ValueError: if output is a movie, and it's duration is equal to 1 frame
        FileNotFoundError: if the render failed and no files were found on disk or missing frames

    Note:
        This function uses the clip's range as a basis (start-end). This  is different from the project range, which
        uses the project timeline. For more details on the differences in frame ranges and the timeline in TVPaint,
        please check the `Usage/Rendering` section of the documentation.

    Warning:
        Even though pytvpaint does a pretty good job of correcting the frame ranges for rendering, we're still
        encountering some weird edge cases where TVPaint will consider the range invalid for seemingly no reason.

    Returns:
        the output file path or sequence
    """
    default_start = self.mark_in or self.start
    default_end = self.mark_out or self.end

    return self._render(
        output_path=output_path,
        default_start=default_start,
        default_end=default_end,
        start=start,
        end=end,
        frame_set=frame_set,
        use_camera=use_camera,
        layer_selection=layer_selection,
        alpha_mode=alpha_mode,
        background_mode=background_mode,
        format_opts=format_opts,
    )

export_tvp(export_path: Path | str) -> None

Exports the clip in .tvp format which can be imported as a project in TVPaint.

Raises:

Type Description
ValueError

if output extension is not (.tvp)

FileNotFoundError

if the render failed and no files were found on disk

Source code in pytvpaint/clip.py
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
@set_as_current
def export_tvp(self, export_path: Path | str) -> None:
    """Exports the clip in .tvp format which can be imported as a project in TVPaint.

    Raises:
        ValueError: if output extension is not (.tvp)
        FileNotFoundError: if the render failed and no files were found on disk
    """
    export_path = Path(export_path)

    if export_path.suffix != ".tvp":
        raise ValueError("The file extension must be .tvp")

    export_path.parent.mkdir(exist_ok=True, parents=True)
    george.tv_save_clip(export_path)

    if not export_path.exists():
        raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

export_json(export_path: Path | str, save_format: george.SaveFormat, folder_pattern: str = '[%3li] %ln', file_pattern: str = '[%3ii] %ln', layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None, all_images: bool = False, ignore_duplicates: bool = False) -> None

Exports the instances (or all the images) of layers in the clip and a JSON file describing the structure of that clip.

Parameters:

Name Type Description Default
export_path pathlib.Path | str

the JSON export path

required
save_format pytvpaint.george.SaveFormat

file format to use for rendering

required
folder_pattern str

the folder name pattern (%li: layer index, %ln: layer name, %fi: file index (added in 11.0.8)). Defaults to None.

'[%3li] %ln'
file_pattern str

the file name pattern (%li: layer index, %ln: layer name, %ii: image index, %in: image name, %fi: file index (added in 11.0.8)). Defaults to None.

'[%3ii] %ln'
layer_selection list[pytvpaint.layer.Layer] | None

list of layers to render or all if None. Defaults to None.

None
alpha_mode pytvpaint.george.AlphaSaveMode

the export alpha mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the export background mode. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None
all_images bool

export all images (not only the instances). Defaults to False.

False
ignore_duplicates bool

Ignore duplicates images. Defaults to None.

False

Raises:

Type Description
FileNotFoundError

if the export failed and no files were found on disk

Source code in pytvpaint/clip.py
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
@set_as_current
def export_json(
    self,
    export_path: Path | str,
    save_format: george.SaveFormat,
    folder_pattern: str = r"[%3li] %ln",
    file_pattern: str = r"[%3ii] %ln",
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
    all_images: bool = False,
    ignore_duplicates: bool = False,
) -> None:
    """Exports the instances (or all the images) of layers in the clip and a JSON file describing the structure of that clip.

    Args:
        export_path: the JSON export path
        save_format: file format to use for rendering
        folder_pattern: the folder name pattern (%li: layer index, %ln: layer name, %fi: file index (added in 11.0.8)). Defaults to None.
        file_pattern: the file name pattern (%li: layer index, %ln: layer name, %ii: image index, %in: image name, %fi: file index (added in 11.0.8)). Defaults to None.
        layer_selection: list of layers to render or all if None. Defaults to None.
        alpha_mode: the export alpha mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the export background mode. Defaults to None.
        format_opts: custom format options. Defaults to None.
        all_images: export all images (not only the instances). Defaults to False.
        ignore_duplicates: Ignore duplicates images. Defaults to None.

    Raises:
        FileNotFoundError: if the export failed and no files were found on disk
    """
    export_path = Path(export_path)
    export_path.parent.mkdir(exist_ok=True, parents=True)

    fill_background = bool(background_mode not in [None, george.BackgroundMode.NONE])

    with utils.render_context(alpha_mode, background_mode, save_format, format_opts, layer_selection):
        george.tv_clip_save_structure_json(
            export_path,
            save_format,
            fill_background=fill_background,
            folder_pattern=folder_pattern,
            file_pattern=file_pattern,
            visible_layers_only=True,
            all_images=all_images,
            ignore_duplicates=ignore_duplicates,
        )

    if not export_path.exists():
        raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

export_psd(export_path: Path | str, mode: george.PSDSaveMode, start: int | None = None, end: int | None = None, layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None) -> None

Save the current clip as a PSD.

Parameters:

Name Type Description Default
export_path pathlib.Path | str

the PSD save path

required
mode pytvpaint.george.PSDSaveMode

whether to save all the images, only the instances or inside the markin

required
start int | None

the start frame. Defaults to None.

None
end int | None

the end frame. Defaults to None.

None
layer_selection list[pytvpaint.layer.Layer] | None

layers to render. Defaults to None (render all the layers).

None
alpha_mode pytvpaint.george.AlphaSaveMode

the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the export background mode. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None

Raises:

Type Description
FileNotFoundError

if the export failed and no files were found on disk

Source code in pytvpaint/clip.py
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
@set_as_current
def export_psd(
    self,
    export_path: Path | str,
    mode: george.PSDSaveMode,
    start: int | None = None,
    end: int | None = None,
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
) -> None:
    """Save the current clip as a PSD.

    Args:
        export_path: the PSD save path
        mode: whether to save all the images, only the instances or inside the markin
        start: the start frame. Defaults to None.
        end: the end frame. Defaults to None.
        layer_selection: layers to render. Defaults to None (render all the layers).
        alpha_mode: the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the export background mode. Defaults to None.
        format_opts: custom format options. Defaults to None.

    Raises:
        FileNotFoundError: if the export failed and no files were found on disk
    """
    start = start or self.mark_in or self.start
    end = end or self.mark_out or self.end

    export_path = Path(export_path)
    image = start if mode == george.PSDSaveMode.IMAGE else None

    with utils.render_context(
        alpha_mode,
        background_mode,
        george.SaveFormat.PSD,
        format_opts,
        layer_selection,
    ):
        george.tv_clip_save_structure_psd(
            export_path,
            mode,
            image=image,
            mark_in=start,
            mark_out=end,
        )

    if mode == george.PSDSaveMode.MARKIN:
        # raises error if sequence not found
        check_path = export_path.with_suffix(f".#{export_path.suffix}").as_posix()
        assert FileSequence.findSequenceOnDisk(check_path)
    else:
        if not export_path.exists():
            raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

export_csv(export_path: Path | str, save_format: george.SaveFormat, all_images: bool = False, exposure_label: str = '', layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None) -> None

Save the current clip as a CSV.

Parameters:

Name Type Description Default
export_path pathlib.Path | str

the .csv export path

required
save_format pytvpaint.george.SaveFormat

file format to use for rendering

required
all_images bool

export all images or only instances. Defaults to None.

False
exposure_label str

give a label when the image is an exposure. Defaults to None.

''
layer_selection list[pytvpaint.layer.Layer] | None

layers to render. Defaults to None (render all the layers).

None
alpha_mode pytvpaint.george.AlphaSaveMode

the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the export background mode. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None

Raises:

Type Description
ValueError

if the extension is not .csv

FileNotFoundError

if the render failed and no files were found on disk

Source code in pytvpaint/clip.py
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
@set_as_current
def export_csv(
    self,
    export_path: Path | str,
    save_format: george.SaveFormat,
    all_images: bool = False,
    exposure_label: str = "",
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
) -> None:
    """Save the current clip as a CSV.

    Args:
        export_path: the .csv export path
        save_format: file format to use for rendering
        all_images: export all images or only instances. Defaults to None.
        exposure_label: give a label when the image is an exposure. Defaults to None.
        layer_selection: layers to render. Defaults to None (render all the layers).
        alpha_mode: the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the export background mode. Defaults to None.
        format_opts: custom format options. Defaults to None.

    Raises:
        ValueError: if the extension is not .csv
        FileNotFoundError: if the render failed and no files were found on disk
    """
    export_path = Path(export_path)

    if export_path.suffix != ".csv":
        raise ValueError("Export path must have .csv extension")

    with utils.render_context(alpha_mode, background_mode, save_format, format_opts, layer_selection):
        george.tv_clip_save_structure_csv(export_path, all_images, exposure_label)

    if not export_path.exists():
        raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

export_sprites(export_path: Path | str, layout: george.SpriteLayout | None = None, space: int = 0, layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None) -> None

Save the current clip as sprites in one image.

Parameters:

Name Type Description Default
export_path pathlib.Path | str

description

required
layout pytvpaint.george.SpriteLayout | None

the sprite layout. Defaults to None.

None
space int

the space between each sprite in the image. Defaults to None.

0
layer_selection list[pytvpaint.layer.Layer] | None

layers to render. Defaults to None (render all the layers).

None
alpha_mode pytvpaint.george.AlphaSaveMode

the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the export background mode. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None

Raises:

Type Description
FileNotFoundError

if the export failed and no files were found on disk

Source code in pytvpaint/clip.py
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
@set_as_current
def export_sprites(
    self,
    export_path: Path | str,
    layout: george.SpriteLayout | None = None,
    space: int = 0,
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
) -> None:
    """Save the current clip as sprites in one image.

    Args:
        export_path (Path | str): _description_
        layout: the sprite layout. Defaults to None.
        space: the space between each sprite in the image. Defaults to None.
        layer_selection: layers to render. Defaults to None (render all the layers).
        alpha_mode: the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the export background mode. Defaults to None.
        format_opts: custom format options. Defaults to None.

    Raises:
        FileNotFoundError: if the export failed and no files were found on disk
    """
    export_path = Path(export_path)
    save_format = george.SaveFormat.from_extension(export_path.suffix)

    with utils.render_context(alpha_mode, background_mode, save_format, format_opts, layer_selection):
        george.tv_clip_save_structure_sprite(export_path, layout, space)

    if not export_path.exists():
        raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

export_flix(export_path: Path | str, start: int | None = None, end: int | None = None, import_parameters: str = '', file_parameters: str = '', send: bool = False, layer_selection: list[Layer] | None = None, alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY, background_mode: george.BackgroundMode | None = None, format_opts: list[str] | None = None) -> None

Save the current clip for Flix.

Parameters:

Name Type Description Default
export_path pathlib.Path | str

the .xml export path

required
start int | None

the start frame. Defaults to None.

None
end int | None

the end frame. Defaults to None.

None
import_parameters str

the attribute(s) of the global tag (waitForSource/...). Defaults to None.

''
file_parameters str

the attribute(s) of each (file) tag (dialogue/...). Defaults to None.

''
send bool

open a browser with the prefilled url. Defaults to None.

False
layer_selection list[pytvpaint.layer.Layer] | None

layers to render. Defaults to None (render all the layers).

None
alpha_mode pytvpaint.george.AlphaSaveMode

the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.

pytvpaint.george.AlphaSaveMode.PREMULTIPLY
background_mode pytvpaint.george.BackgroundMode | None

the export background mode. Defaults to None.

None
format_opts list[str] | None

custom format options. Defaults to None.

None

Raises:

Type Description
ValueError

if the extension is not .xml

FileNotFoundError

if the export failed and no files were found on disk

Source code in pytvpaint/clip.py
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
@set_as_current
def export_flix(
    self,
    export_path: Path | str,
    start: int | None = None,
    end: int | None = None,
    import_parameters: str = "",
    file_parameters: str = "",
    send: bool = False,
    layer_selection: list[Layer] | None = None,
    alpha_mode: george.AlphaSaveMode = george.AlphaSaveMode.PREMULTIPLY,
    background_mode: george.BackgroundMode | None = None,
    format_opts: list[str] | None = None,
) -> None:
    """Save the current clip for Flix.

    Args:
        export_path: the .xml export path
        start: the start frame. Defaults to None.
        end: the end frame. Defaults to None.
        import_parameters: the attribute(s) of the global <flixImport> tag (waitForSource/...). Defaults to None.
        file_parameters: the attribute(s) of each <image> (file) tag (dialogue/...). Defaults to None.
        send: open a browser with the prefilled url. Defaults to None.
        layer_selection: layers to render. Defaults to None (render all the layers).
        alpha_mode: the alpha save mode. Defaults to george.AlphaSaveMode.PREMULTIPLY.
        background_mode: the export background mode. Defaults to None.
        format_opts: custom format options. Defaults to None.

    Raises:
        ValueError: if the extension is not .xml
        FileNotFoundError: if the export failed and no files were found on disk
    """
    export_path = Path(export_path)

    if export_path.suffix != ".xml":
        raise ValueError("Export path must have .xml extension")

    original_file = self.project.path
    import_parameters = import_parameters or 'waitForSource="1" multipleSetups="1" replaceSelection="0"'

    # The project needs to be saved
    self.project.save()

    # save alpha mode and save format values
    with utils.render_context(alpha_mode, background_mode, None, format_opts, layer_selection):
        george.tv_clip_save_structure_flix(
            export_path,
            start,
            end,
            import_parameters,
            file_parameters,
            send,
            original_file,
        )

    if not export_path.exists():
        raise FileNotFoundError(f"Could not find output at : {export_path.as_posix()}")

set_layer_color(layer_color: LayerColor) -> None

Set the layer color at the provided index.

Parameters:

Name Type Description Default
layer_color pytvpaint.layer.LayerColor

the layer color instance.

required
Source code in pytvpaint/clip.py
963
964
965
966
967
968
969
970
971
def set_layer_color(self, layer_color: LayerColor) -> None:
    """Set the layer color at the provided index.

    Args:
        layer_color: the layer color instance.
    """
    if not george.is_tvp_version_below_12():
        log.warning("this function currently does not work properly in tvpaint 12")
    george.tv_layer_color_set_color(self.id, layer_color.index, layer_color.color, layer_color.name)

get_layer_color(by_index: int | None = None, by_name: str | None = None, by_regex: re.Pattern[str] | None = None) -> LayerColor | None

Get a layer color by index or name.

Parameters:

Name Type Description Default
by_index int | None

search by color index. Defaults to None.

None
by_name str | None

search by name, search is case-insensitive. Defaults to None.

None
by_regex re.Pattern[str] | None

search by name using a compiled regex, case-sensitivity is left to the regex. Defaults to None.

None

Raises:

Type Description
ValueError

if none of the search arguments where provided

Source code in pytvpaint/clip.py
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
def get_layer_color(
    self,
    by_index: int | None = None,
    by_name: str | None = None,
    by_regex: re.Pattern[str] | None = None,
) -> LayerColor | None:
    """Get a layer color by index or name.

    Args:
        by_index: search by color index. Defaults to None.
        by_name: search by name, search is case-insensitive. Defaults to None.
        by_regex: search by name using a compiled regex, case-sensitivity is left to the regex. Defaults to None.

    Raises:
        ValueError: if none of the search arguments where provided
    """
    values = (by_index, by_name, by_regex)
    if not any(v is not None for v in values):
        raise ValueError(f"At least one value ({' or '.join(str(v) for v in values)} must be provided")

    if by_index is not None:
        return next(c for i, c in enumerate(self.layer_colors) if i == by_index)

    if by_name is not None:
        try:
            return next(c for c in self.layer_colors if c.name.lower() == by_name.lower())
        except StopIteration:
            return None

    if by_regex is not None:
        try:
            return next(c for c in self.layer_colors if by_regex.search(c.name))
        except StopIteration:
            return None

    return None

add_bookmark(frame: int) -> None

Add a bookmark at that frame.

Source code in pytvpaint/clip.py
1017
1018
1019
def add_bookmark(self, frame: int) -> None:
    """Add a bookmark at that frame."""
    george.tv_bookmark_set(frame - self.project.start_frame)

remove_bookmark(frame: int) -> None

Remove a bookmark at that frame.

Source code in pytvpaint/clip.py
1021
1022
1023
def remove_bookmark(self, frame: int) -> None:
    """Remove a bookmark at that frame."""
    george.tv_bookmark_clear(frame - self.project.start_frame)

clear_bookmarks() -> None

Remove all the bookmarks.

Source code in pytvpaint/clip.py
1025
1026
1027
1028
1029
def clear_bookmarks(self) -> None:
    """Remove all the bookmarks."""
    bookmarks = list(self.bookmarks)
    for frame in bookmarks:
        self.remove_bookmark(frame)

go_to_previous_bookmark() -> None

Go to the previous bookmarks frame.

Source code in pytvpaint/clip.py
1031
1032
1033
1034
@set_as_current
def go_to_previous_bookmark(self) -> None:
    """Go to the previous bookmarks frame."""
    george.tv_bookmark_prev()

go_to_next_bookmark() -> None

Go to the next bookmarks frame.

Source code in pytvpaint/clip.py
1036
1037
1038
1039
@set_as_current
def go_to_next_bookmark(self) -> None:
    """Go to the next bookmarks frame."""
    george.tv_bookmark_next()

get_sound(by_track_index: int | None = None, by_path: Path | str | None = None) -> ClipSound | None

Get a clip sound by track index or path.

Parameters:

Name Type Description Default
by_track_index int | None

search by track index. Defaults to None.

None
by_path pathlib.Path | str | None

search by path. Defaults to None.

None

Raises:

Type Description
ValueError

if none of the search arguments where provided

Returns:

Type Description
pytvpaint.sound.ClipSound | None

ClipSound | None: the searched element or None if search was unsuccessful

Source code in pytvpaint/clip.py
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
def get_sound(
    self,
    by_track_index: int | None = None,
    by_path: Path | str | None = None,
) -> ClipSound | None:
    """Get a clip sound by track index or path.

    Args:
        by_track_index: search by track index. Defaults to None.
        by_path: search by path. Defaults to None.

    Raises:
        ValueError: if none of the search arguments where provided

    Returns:
        ClipSound | None: the searched element or None if search was unsuccessful
    """
    values = (by_track_index, by_path)
    if not any(v is not None for v in values):
        raise ValueError(f"At least one value ({' or '.join(str(v) for v in values)} must be provided")

    for sound in self.sounds:
        if by_track_index is not None and sound.by_track_index != by_track_index:
            continue
        if by_path is not None and sound.path != Path(by_path):
            continue
        return sound

    return None

add_sound(sound_path: Path | str) -> ClipSound

Adds a new clip soundtrack.

Source code in pytvpaint/clip.py
1079
1080
1081
def add_sound(self, sound_path: Path | str) -> ClipSound:
    """Adds a new clip soundtrack."""
    return ClipSound.new(sound_path, parent=self)

mark_removed() -> None

Marks the object as removed and is therefor not usable.

Source code in pytvpaint/utils.py
 98
 99
100
def mark_removed(self) -> None:
    """Marks the object as removed and is therefor not usable."""
    self._is_removed = True