Skip to content

capture

Maya Capture

Playblasting with independent viewport, camera and display options

apply_scene(**options)

Apply options from scene

Example

apply_scene({"start_frame": 1009})

Parameters:

Name Type Description Default
options dict

Scene options

{}
Source code in client/ayon_maya/vendor/python/capture.py
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
def apply_scene(**options):
    """Apply options from scene

    Example:
        >>> apply_scene({"start_frame": 1009})

    Arguments:
        options (dict): Scene options

    """

    if "start_frame" in options:
        cmds.playbackOptions(minTime=options["start_frame"])

    if "end_frame" in options:
        cmds.playbackOptions(maxTime=options["end_frame"])

    if "width" in options:
        _safe_setAttr("defaultResolution.width", options["width"])

    if "height" in options:
        _safe_setAttr("defaultResolution.height", options["height"])

    if "compression" in options:
        cmds.optionVar(
            stringValue=["playblastCompression", options["compression"]])

    if "filename" in options:
        cmds.optionVar(
            stringValue=["playblastFile", options["filename"]])

    if "format" in options:
        cmds.optionVar(
            stringValue=["playblastFormat", options["format"]])

    if "off_screen" in options:
        cmds.optionVar(
            intValue=["playblastFormat", options["off_screen"]])

    if "show_ornaments" in options:
        cmds.optionVar(
            intValue=["show_ornaments", options["show_ornaments"]])

    if "quality" in options:
        cmds.optionVar(
            floatValue=["playblastQuality", options["quality"]])

apply_view(panel, **options)

Apply options to panel

Source code in client/ayon_maya/vendor/python/capture.py
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def apply_view(panel, **options):
    """Apply options to panel"""

    camera = cmds.modelPanel(panel, camera=True, query=True)

    # Display options
    display_options = options.get("display_options", {})
    _iteritems = getattr(display_options, "iteritems", display_options.items)
    for key, value in _iteritems():
        if key in _DisplayOptionsRGB:
            cmds.displayRGBColor(key, *value)
        else:
            cmds.displayPref(**{key: value})

    # Camera options
    camera_options = options.get("camera_options", {})
    _iteritems = getattr(camera_options, "iteritems", camera_options.items)
    for key, value in _iteritems:
        _safe_setAttr("{0}.{1}".format(camera, key), value)

    # Viewport options
    viewport_options = options.get("viewport_options", {})
    _iteritems = getattr(viewport_options, "iteritems", viewport_options.items)
    for key, value in _iteritems():
        cmds.modelEditor(panel, edit=True, **{key: value})

    viewport2_options = options.get("viewport2_options", {})
    _iteritems = getattr(
        viewport2_options, "iteritems", viewport2_options.items
    )
    for key, value in _iteritems():
        attr = "hardwareRenderingGlobals.{0}".format(key)
        _safe_setAttr(attr, value)

capture(camera=None, width=None, height=None, filename=None, start_frame=None, end_frame=None, frame=None, format='qt', compression='H.264', quality=100, off_screen=False, viewer=True, show_ornaments=True, sound=None, isolate=None, maintain_aspect_ratio=True, overwrite=False, frame_padding=4, raw_frame_numbers=False, camera_options=None, display_options=None, viewport_options=None, viewport2_options=None, complete_filename=None, log=None)

Playblast in an independent panel

Parameters:

Name Type Description Default
camera str

Name of camera, defaults to "persp"

None
width int

Width of output in pixels

None
height int

Height of output in pixels

None
filename str

Name of output file. If none is specified, no files are saved.

None
start_frame float

Defaults to current start frame.

None
end_frame float

Defaults to current end frame.

None
frame float or tuple

A single frame or list of frames. Use this to capture a single frame or an arbitrary sequence of frames.

None
format str

Name of format, defaults to "qt".

'qt'
compression str

Name of compression, defaults to "H.264"

'H.264'
quality int

The quality of the output, defaults to 100

100
off_screen bool

Whether or not to playblast off screen

False
viewer bool

Display results in native player

True
show_ornaments bool

Whether or not model view ornaments (e.g. axis icon, grid and HUD) should be displayed.

True
sound str

Specify the sound node to be used during playblast. When None (default) no sound will be used.

None
isolate list

List of nodes to isolate upon capturing

None
maintain_aspect_ratio bool

Modify height in order to maintain aspect ratio.

True
overwrite bool

Whether or not to overwrite if file already exists. If disabled and file exists and error will be raised.

False
frame_padding bool

Number of zeros used to pad file name for image sequences.

4
raw_frame_numbers bool

Whether or not to use the exact frame numbers from the scene or capture to a sequence starting at zero. Defaults to False. When set to True viewer can't be used and will be forced to False.

False
camera_options dict

Supplied camera options, using CameraOptions

None
display_options dict

Supplied display options, using DisplayOptions

None
viewport_options dict

Supplied viewport options, using ViewportOptions

None
viewport2_options dict

Supplied display options, using Viewport2Options

None
complete_filename str

Exact name of output file. Use this to override the output of filename so it excludes frame padding.

None
log logger

pass logger for logging messages.

None
Example

Launch default capture

capture()

Launch capture with custom viewport settings

capture('persp', 800, 600, ... viewport_options={ ... "displayAppearance": "wireframe", ... "grid": False, ... "polymeshes": True, ... }, ... camera_options={ ... "displayResolution": True ... } ... )

Source code in client/ayon_maya/vendor/python/capture.py
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
def capture(camera=None,
            width=None,
            height=None,
            filename=None,
            start_frame=None,
            end_frame=None,
            frame=None,
            format='qt',
            compression='H.264',
            quality=100,
            off_screen=False,
            viewer=True,
            show_ornaments=True,
            sound=None,
            isolate=None,
            maintain_aspect_ratio=True,
            overwrite=False,
            frame_padding=4,
            raw_frame_numbers=False,
            camera_options=None,
            display_options=None,
            viewport_options=None,
            viewport2_options=None,
            complete_filename=None,
            log=None):
    """Playblast in an independent panel

    Arguments:
        camera (str, optional): Name of camera, defaults to "persp"
        width (int, optional): Width of output in pixels
        height (int, optional): Height of output in pixels
        filename (str, optional): Name of output file. If
            none is specified, no files are saved.
        start_frame (float, optional): Defaults to current start frame.
        end_frame (float, optional): Defaults to current end frame.
        frame (float or tuple, optional): A single frame or list of frames.
            Use this to capture a single frame or an arbitrary sequence of
            frames.
        format (str, optional): Name of format, defaults to "qt".
        compression (str, optional): Name of compression, defaults to "H.264"
        quality (int, optional): The quality of the output, defaults to 100
        off_screen (bool, optional): Whether or not to playblast off screen
        viewer (bool, optional): Display results in native player
        show_ornaments (bool, optional): Whether or not model view ornaments
            (e.g. axis icon, grid and HUD) should be displayed.
        sound (str, optional):  Specify the sound node to be used during
            playblast. When None (default) no sound will be used.
        isolate (list): List of nodes to isolate upon capturing
        maintain_aspect_ratio (bool, optional): Modify height in order to
            maintain aspect ratio.
        overwrite (bool, optional): Whether or not to overwrite if file
            already exists. If disabled and file exists and error will be
            raised.
        frame_padding (bool, optional): Number of zeros used to pad file name
            for image sequences.
        raw_frame_numbers (bool, optional): Whether or not to use the exact
            frame numbers from the scene or capture to a sequence starting at
            zero. Defaults to False. When set to True `viewer` can't be used
            and will be forced to False.
        camera_options (dict, optional): Supplied camera options,
            using `CameraOptions`
        display_options (dict, optional): Supplied display
            options, using `DisplayOptions`
        viewport_options (dict, optional): Supplied viewport
            options, using `ViewportOptions`
        viewport2_options (dict, optional): Supplied display
            options, using `Viewport2Options`
        complete_filename (str, optional): Exact name of output file. Use this
            to override the output of `filename` so it excludes frame padding.
        log (logger, optional): pass logger for logging messages.

    Example:
        >>> # Launch default capture
        >>> capture()
        >>> # Launch capture with custom viewport settings
        >>> capture('persp', 800, 600,
        ...         viewport_options={
        ...             "displayAppearance": "wireframe",
        ...             "grid": False,
        ...             "polymeshes": True,
        ...         },
        ...         camera_options={
        ...             "displayResolution": True
        ...         }
        ... )


    """
    global logger
    if log:
        logger = log
    camera = camera or "persp"

    # Ensure camera exists
    if not cmds.objExists(camera):
        raise RuntimeError("Camera does not exist: {0}".format(camera))

    if width and height :
        maintain_aspect_ratio = False
    width = width or cmds.getAttr("defaultResolution.width")
    height = height or cmds.getAttr("defaultResolution.height")
    if maintain_aspect_ratio:
        ratio = cmds.getAttr("defaultResolution.deviceAspectRatio")
        height = round(width / ratio)

    if start_frame is None:
        start_frame = cmds.playbackOptions(minTime=True, query=True)
    if end_frame is None:
        end_frame = cmds.playbackOptions(maxTime=True, query=True)

    # (#74) Bugfix: `maya.cmds.playblast` will raise an error when playblasting
    # with `rawFrameNumbers` set to True but no explicit `frames` provided.
    # Since we always know what frames will be included we can provide it
    # explicitly
    if raw_frame_numbers and frame is None:
        frame = range(int(start_frame), int(end_frame) + 1)

    # We need to wrap `completeFilename`, otherwise even when None is provided
    # it will use filename as the exact name. Only when lacking as argument
    # does it function correctly.
    playblast_kwargs = dict()
    if complete_filename:
        playblast_kwargs['completeFilename'] = complete_filename
    if frame is not None:
        playblast_kwargs['frame'] = frame
    if sound is not None:
        playblast_kwargs['sound'] = sound

    # We need to raise an error when the user gives a custom frame range with
    # negative frames in combination with raw frame numbers. This will result
    # in a minimal integer frame number : filename.-2147483648.png for any
    # negative rendered frame
    if frame and raw_frame_numbers:
        check = frame if isinstance(frame, (list, tuple)) else [frame]
        if any(f < 0 for f in check):
            raise RuntimeError("Negative frames are not supported with "
                               "raw frame numbers and explicit frame numbers")

    # (#21) Bugfix: `maya.cmds.playblast` suffers from undo bug where it
    # always sets the currentTime to frame 1. By setting currentTime before
    # the playblast call it'll undo correctly.
    cmds.currentTime(cmds.currentTime(query=True))

    padding = 10  # Extend panel to accommodate for OS window manager

    with _independent_panel(width=width + padding,
                            height=height + padding,
                            off_screen=off_screen) as panel:
        cmds.setFocus(panel)

        all_playblast_kwargs = {
            "compression": compression,
            "format": format,
            "percent": 100,
            "quality": quality,
            "viewer": viewer,
            "startTime": start_frame,
            "endTime": end_frame,
            "offScreen": off_screen,
            "showOrnaments": show_ornaments,
            "forceOverwrite": overwrite,
            "filename": filename,
            "widthHeight": [width, height],
            "rawFrameNumbers": raw_frame_numbers,
            "framePadding": frame_padding
        }
        all_playblast_kwargs.update(playblast_kwargs)

        if getattr(contextlib, "nested", None):
            with contextlib.nested(
                _disabled_inview_messages(),
                _maintain_camera(panel, camera),
                _applied_viewport_options(viewport_options, panel),
                _applied_camera_options(camera_options, panel),
                _applied_display_options(display_options),
                _applied_viewport2_options(viewport2_options),
                _isolated_nodes(isolate, panel),
                _maintained_time()
            ):
                output = cmds.playblast(**all_playblast_kwargs)
        else:
            with contextlib.ExitStack() as stack:
                stack.enter_context(_disabled_inview_messages())
                stack.enter_context(_maintain_camera(panel, camera))
                stack.enter_context(
                    _applied_viewport_options(viewport_options, panel)
                )
                stack.enter_context(
                    _applied_camera_options(camera_options, panel)
                )
                stack.enter_context(
                    _applied_display_options(display_options)
                )
                stack.enter_context(
                    _applied_viewport2_options(viewport2_options)
                )
                stack.enter_context(_isolated_nodes(isolate, panel))
                stack.enter_context(_maintained_time())

                output = cmds.playblast(**all_playblast_kwargs)

        return output

parse_active_panel()

Parse the active modelPanel.

Raises RuntimeError: When no active modelPanel an error is raised.

Returns:

Name Type Description
str

Name of modelPanel

Source code in client/ayon_maya/vendor/python/capture.py
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
def parse_active_panel():
    """Parse the active modelPanel.

    Raises
        RuntimeError: When no active modelPanel an error is raised.

    Returns:
        str: Name of modelPanel

    """

    panel = cmds.getPanel(withFocus=True)

    # This happens when last focus was on panel
    # that got deleted (e.g. `capture()` then `parse_active_view()`)
    if not panel or "modelPanel" not in panel:
        raise RuntimeError("No active model panel found")

    return panel

parse_active_scene()

Parse active scene for arguments for capture()

*Resolution taken from render settings.

Source code in client/ayon_maya/vendor/python/capture.py
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
def parse_active_scene():
    """Parse active scene for arguments for capture()

    *Resolution taken from render settings.

    """

    time_control = mel.eval("$gPlayBackSlider = $gPlayBackSlider")

    return {
        "start_frame": cmds.playbackOptions(minTime=True, query=True),
        "end_frame": cmds.playbackOptions(maxTime=True, query=True),
        "width": cmds.getAttr("defaultResolution.width"),
        "height": cmds.getAttr("defaultResolution.height"),
        "compression": cmds.optionVar(query="playblastCompression"),
        "filename": (cmds.optionVar(query="playblastFile")
                     if cmds.optionVar(query="playblastSaveToFile") else None),
        "format": cmds.optionVar(query="playblastFormat"),
        "off_screen": (True if cmds.optionVar(query="playblastOffscreen")
                       else False),
        "show_ornaments": (True if cmds.optionVar(query="playblastShowOrnaments")
                       else False),
        "quality": cmds.optionVar(query="playblastQuality"),
        "sound": cmds.timeControl(time_control, q=True, sound=True) or None
    }

parse_active_view()

Parse the current settings from the active view

Source code in client/ayon_maya/vendor/python/capture.py
446
447
448
449
def parse_active_view():
    """Parse the current settings from the active view"""
    panel = parse_active_panel()
    return parse_view(panel)

parse_view(panel)

Parse the scene, panel and camera for their current settings

Example

parse_view("modelPanel1")

Parameters:

Name Type Description Default
panel str

Name of modelPanel

required
Source code in client/ayon_maya/vendor/python/capture.py
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
def parse_view(panel):
    """Parse the scene, panel and camera for their current settings

    Example:
        >>> parse_view("modelPanel1")

    Arguments:
        panel (str): Name of modelPanel

    """

    camera = cmds.modelPanel(panel, query=True, camera=True)

    # Display options
    display_options = {}
    for key in DisplayOptions:
        if key in _DisplayOptionsRGB:
            display_options[key] = cmds.displayRGBColor(key, query=True)
        else:
            display_options[key] = cmds.displayPref(query=True, **{key: True})

    # Camera options
    camera_options = {}
    for key in CameraOptions:
        camera_options[key] = cmds.getAttr("{0}.{1}".format(camera, key))

    # Viewport options
    viewport_options = {}

    # capture plugin display filters first to ensure we never override
    # built-in arguments if ever possible a plugin has similarly named
    # plugin display filters (which it shouldn't!)
    plugins = cmds.pluginDisplayFilter(query=True, listFilters=True)
    for plugin in plugins:
        plugin = str(plugin)  # unicode->str for simplicity of the dict
        state = cmds.modelEditor(panel, query=True, queryPluginObjects=plugin)
        viewport_options[plugin] = state

    for key in ViewportOptions:
        viewport_options[key] = cmds.modelEditor(
            panel, query=True, **{key: True})

    viewport2_options = {}
    for key in Viewport2Options.keys():
        attr = "hardwareRenderingGlobals.{0}".format(key)
        try:
            viewport2_options[key] = cmds.getAttr(attr)
        except ValueError:
            continue

    return {
        "camera": camera,
        "display_options": display_options,
        "camera_options": camera_options,
        "viewport_options": viewport_options,
        "viewport2_options": viewport2_options
    }

snap(*args, **kwargs)

Single frame playblast in an independent panel.

The arguments of capture are all valid here as well, except for start_frame and end_frame.

Parameters:

Name Type Description Default
frame float

The frame to snap. If not provided current frame is used.

required
clipboard bool

Whether to add the output image to the global clipboard. This allows to easily paste the snapped image into another application, eg. into Photoshop.

required
Keywords

See capture.

Source code in client/ayon_maya/vendor/python/capture.py
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
def snap(*args, **kwargs):
    """Single frame playblast in an independent panel.

    The arguments of `capture` are all valid here as well, except for
    `start_frame` and `end_frame`.

    Arguments:
        frame (float, optional): The frame to snap. If not provided current
            frame is used.
        clipboard (bool, optional): Whether to add the output image to the
            global clipboard. This allows to easily paste the snapped image
            into another application, eg. into Photoshop.

    Keywords:
        See `capture`.

    """

    # capture single frame
    frame = kwargs.pop('frame', cmds.currentTime(q=1))
    kwargs['start_frame'] = frame
    kwargs['end_frame'] = frame
    kwargs['frame'] = frame

    if not isinstance(frame, (int, float)):
        raise TypeError("frame must be a single frame (integer or float). "
                        "Use `capture()` for sequences.")

    # override capture defaults
    format = kwargs.pop('format', "image")
    compression = kwargs.pop('compression', "png")
    viewer = kwargs.pop('viewer', False)
    raw_frame_numbers = kwargs.pop('raw_frame_numbers', True)
    kwargs['compression'] = compression
    kwargs['format'] = format
    kwargs['viewer'] = viewer
    kwargs['raw_frame_numbers'] = raw_frame_numbers

    # pop snap only keyword arguments
    clipboard = kwargs.pop('clipboard', False)

    # perform capture
    output = capture(*args, **kwargs)

    def replace(m):
        """Substitute # with frame number"""
        return str(int(frame)).zfill(len(m.group()))

    output = re.sub("#+", replace, output)

    # add image to clipboard
    if clipboard:
        _image_to_clipboard(output)

    return output