跳转至

图像与 SVG

影片代码
import manimgx as m
import numpy as np


class ImagesAndSvgHero(m.Scene):
    def construct(self) -> None:
        x = np.linspace(-1, 1, 64)
        pixels = np.zeros((64, 64, 3), dtype=np.uint8)
        pixels[..., 0] = 255 * (x[None, :] + 1) / 2
        pixels[..., 2] = 255 * (x[:, None] + 1) / 2
        image = m.ImageMobject(pixels).scale_to_fit_height(4)
        image.set_resampling_algorithm(m.RESAMPLING_ALGORITHMS["nearest"])
        self.play(m.FadeIn(image))
        self.play(image.animate.rotate(m.PI / 8).scale(0.8))
        self.wait()

图像是位于矩形上的图片:从文件(PNG、JPEG 等)读取,或由像素数组生成。它像任何 mobject 一样移动、缩放、旋转和淡入淡出;其像素保持自身不变。SVG 绘图则不同:其 形状变为路径,每条路径都是一个可着色、移动和绘制的部分,作为 ManimGX 自身的 形状。

ImageMobject

代码
import numpy as np

import manimgx as m


class ImageMobjectExample(m.Scene):
    def construct(self) -> None:
        ramp = np.linspace(0, 255, 256)
        pixels = np.zeros((256, 256, 3), dtype=np.uint8)
        pixels[..., 0] = ramp  # red grows to the right
        pixels[..., 2] = ramp[:, np.newaxis]  # blue grows downward
        image = m.ImageMobject(pixels, scale_to_resolution=400)
        self.play(m.FadeIn(image))
ImageMobjectResamplingExample
代码
import numpy as np

import manimgx as m


class ImageMobjectResamplingExample(m.Scene):
    def construct(self) -> None:
        pixels = np.full((3, 3), 60, dtype=np.uint8)
        pixels[1, 1] = 255  # one white pixel, amid gray ones
        images = m.Group()
        for name in ("nearest", "linear", "cubic"):
            image = m.ImageMobject(
                pixels,
                scale_to_resolution=6,
                resampling_algorithm=m.RESAMPLING_ALGORITHMS[name],
            )
            images.add(m.Group(image, m.Text(name).next_to(image, m.DOWN)))
        self.add(images.arrange(buff=0.5))

一幅图片:一个图像文件或一个像素数组,置于一个与其像素高度相当的矩形上。

一幅 scale_to_resolution 像素高(未指定时为 1080)的图像与画框短边 (默认为 8 个场景单位)等高,其他图像按比例缩放。当显示尺寸大于其像素时, 图片由 resampling_algorithm 从像素重建:默认为穿过每个像素的平滑三次曲线; linear 混合相邻像素;nearest 将每个像素显示为其颜色的小方块。当显示尺寸 小于其像素时,图片被采样而非平均。该 mobject 的不透明度与其像素自身的相乘。

m.ImageMobject(filename_or_array, scale_to_resolution=1080, invert=False, image_mode='RGBA', resampling_algorithm=3, stroke_width=0, stroke_color=WHITE, **kwargs)
filename_or_array

图片内容:图像文件的路径、文件内容 (字节串),或取值 0 到 255 的像素值数组:(h, w) 灰度、(h, w, 3) RGB 或 (h, w, 4) RGBA。

scale_to_resolution

与画框短边等高的图像有多少像素高; 0 表示图像高 3 个单位,与其尺寸无关。

invert

是否反转其颜色(不反转其透明度)。

image_mode

文件被读入的模式,以 Pillow 库的命名方式表示: "RGBA",或 "L" 表示灰度。

resampling_algorithm

图片如何从其像素重建,以 Pillow 库的编号表示: 0,nearest;2,linear;3,cubic(Keys 的三次卷积,Pillow 的 bicubic); RESAMPLING_ALGORITHMS 按名称给出这些值。

stroke_width

图片周围边框的宽度,以百分之一场景单位为单位; 0 表示无边框。

stroke_color

边框的颜色。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobjects\images.py

def __init__(
    self,
    filename_or_array: str | Path | bytes | np.ndarray,
    scale_to_resolution: int = 1080,
    invert: bool = False,
    image_mode: str = "RGBA",
    resampling_algorithm: Resampling = 3,
    stroke_width: float = 0,  # a border's (the picture is the texture)
    stroke_color: ParsableManimColor = WHITE,
    **kwargs: Unpack[Look],
) -> None:
    import io

    from PIL import Image

    if isinstance(filename_or_array, (str, Path, bytes)):
        source = (
            io.BytesIO(filename_or_array)
            if isinstance(filename_or_array, bytes)
            else filename_or_array
        )
        pixels = np.array(Image.open(source).convert(image_mode))
    else:
        pixels = np.array(filename_or_array)
    pixels = _to_rgba(pixels)
    if invert:
        pixels[:, :, :3] = 255 - pixels[:, :, :3]
    pixels.flags.writeable = False
    self.scale_to_resolution = scale_to_resolution
    self.resampling_algorithm = resampling_algorithm
    super().__init__(
        np.array([UP + LEFT, UP + RIGHT, DOWN + LEFT, DOWN + RIGHT], dtype=float),
        np.array([[0, 1, 2], [1, 3, 2]]),
        uvs=np.array([[0, 0], [1, 0], [0, 1], [1, 1]], dtype=float),
        texture=pixels,
        **kwargs,
    )
    if (
        stroke_width > 0
    ):  # a border is just a rectangle child that follows every transform
        from manimgx.mobjects.shapes import Polygon

        self.add(
            Polygon(
                *self.points[[0, 1, 3, 2]],
                stroke_width=stroke_width,
                stroke_color=stroke_color,
            )
        )

pixel_array

当前图片的 (h, w, 4) RGBA 像素,取值 0 到 255。

由该图像解码或着色的图片是只读的。当变为另一个带纹理网格时, 会采用其纹理,包括其是否可写。

image_mobject.pixel_array
源码

manimgx\mobjects\images.py

def pixel_array(self) -> np.ndarray:
    """当前图片的 (h, w, 4) RGBA 像素,取值 0 到 255。

    由该图像解码或着色的图片是只读的。当变为另一个带纹理网格时,
    会采用其纹理,包括其是否可写。
    """
    texture = self.paint.texture
    assert isinstance(texture, np.ndarray)
    return texture

set_color

将每个像素着为 color,保留其不透明度:图片变为该颜色的剪影。

image_mobject.set_color(color=YELLOW_C, alpha=None, family=True)
alpha

同时设置每个像素的不透明度,取值 0 到 1;None 保留各自的原值。

family

仅为 Manim 兼容性而接受;被忽略:仅对图片本身着色。

源码

manimgx\mobjects\images.py

def set_color(  # pyright: ignore[reportIncompatibleMethodOverride]  # ty: ignore[invalid-method-override]  # CE's: an image's tint, then its alpha
    self,
    color: ParsableManimColor = YELLOW_C,
    alpha: float | None = None,
    family: bool = True,
) -> Self:
    """将每个像素着为 `color`,保留其不透明度:图片变为该颜色的剪影。

    Args:
        alpha: 同时设置每个像素的不透明度,取值 0 到 1;None 保留各自的原值。
        family: 仅为 Manim 兼容性而接受;被忽略:仅对图片本身着色。
    """
    pixels = self.pixel_array.copy()
    pixels[:, :, :3] = (ManimColor(color).to_rgb() * 255).astype(np.uint8)
    if alpha is not None:
        pixels[:, :, 3] = int(255 * alpha)
    pixels.flags.writeable = False
    self.paint = self.paint.but(texture=pixels)
    return self

set_opacity

设置图片的不透明度,该值与其像素自身的相乘。

image_mobject.set_opacity(opacity=1.0, family=True, *, alpha=None)
opacity

不透明度,取值 0 到 1。

family

是否设置其整个族(包括边框),还是仅设置图片本身。

alpha

不透明度,使用 Manim 图像所用的名称;若给定,则优先于 opacity。

源码

manimgx\mobjects\images.py

def set_opacity(
    self, opacity: float = 1.0, family: bool = True, *, alpha: float | None = None
) -> Self:
    """设置图片的不透明度,该值与其像素自身的相乘。

    Args:
        opacity: 不透明度,取值 0 到 1。
        family: 是否设置其整个族(包括边框),还是仅设置图片本身。
        alpha: 不透明度,使用 Manim 图像所用的名称;若给定,则优先于
            `opacity`。
    """
    return super().set_opacity(opacity if alpha is None else alpha, family)

set_resampling_algorithm

设置在显示尺寸大于像素时,图片如何从其像素重建。

image_mobject.set_resampling_algorithm(resampling_algorithm)
resampling_algorithm

滤波器,以 Pillow 库的编号表示:0,nearest (每个像素为其颜色的小方块);2,linear;3,cubic(平滑,且 穿过每个像素); RESAMPLING_ALGORITHMS 按名称给出 这些值。

源码

manimgx\mobjects\images.py

def set_resampling_algorithm(self, resampling_algorithm: Resampling) -> Self:
    """设置在显示尺寸大于像素时,图片如何从其像素重建。

    Args:
        resampling_algorithm: 滤波器,以 Pillow 库的编号表示:0,nearest
            (每个像素为其颜色的小方块);2,linear;3,cubic(平滑,且
            穿过每个像素);
            [RESAMPLING_ALGORITHMS][manimgx.RESAMPLING_ALGORITHMS] 按名称给出
            这些值。
    """
    self.resampling_algorithm = resampling_algorithm
    return self

m.RESAMPLING_ALGORITHMS

图像重建可用的滤镜,按名称排列,各附其编号(参见 Resampling):"nearest" 或 "none"、"bilinear" 或 "linear"、"bicubic" 或 "cubic"。

Resampling

Resampling = Literal[0, 2, 3]

图像在绘制尺寸大于像素尺寸时从像素重建的方式,编号与 Pillow 库的滤镜编号一致: 0,最近邻(每个像素为一个其颜色的方块);2,线性;3,三次(Keys 的三次卷积, a = −½,即 Pillow 的 BICUBIC:平滑且经过每个像素)。

SVGMobject

从 SVG 文件中读取的绘图:其每个形状为一个部件,按文件绘制它的方式上色,高度为 2 个单位, 除非另行指定尺寸。

路径、直线、矩形(含圆角)、圆、椭圆、多边形和折线按文件中的顺序成为部件, 带有文件的填充、描边和变换;组与 <use> 会被跟随,文本会被跳过并发出警告。 文件未指定如何绘制的部分采用 SVG 的默认值,即黑色填充且无描边, 除非 svg_default 另有指定。文件的组按其 id 保留在 id_to_vgroup_dict 中。

m.SVGMobject(file_name=None, should_center=True, height=2, width=None, color=None, opacity=None, fill_color=None, fill_opacity=None, stroke_color=None, stroke_opacity=None, stroke_width=None, svg_default=None, path_string_config=None, use_svg_cache=True, **kwargs)
file_name

SVG 文件。

should_center

绘图是否居中于原点。

height

将绘图缩放至的高度,以场景单位表示;None 保留 文件的尺寸,即每个 SVG 单位对应一个场景单位。

width

将绘图缩放至的宽度,以场景单位表示,在 height 之后应用(因此 它优先);None:与 height 的结果一致。

color

为兼容 Manim 而接受;无效果:各部件保留文件的 颜色(用 fill_color 和 stroke_color 覆盖它们,或通过 svg_default 为文件未指定如何绘制的部分上色)。

opacity

为兼容 Manim 而接受;被忽略。

fill_color

每个部件的填充颜色;None 保留文件的值。

fill_opacity

每个部件的填充不透明度,取值 0 到 1;None 保留文件的值。

stroke_color

每个部件的描边颜色;None 保留文件的值。

stroke_opacity

每个部件的描边不透明度,取值 0 到 1;None 保留 文件的值。

stroke_width

每个部件的描边宽度,以场景单位的百分之一表示; None 保留文件的值。

svg_default

为文件未指定如何绘制的部分提供的绘制关键字; None 表示 {"stroke_width": 0}:无描边。

path_string_config

每条路径的SVG 路径 关键字。

use_svg_cache

是否对相同的 SVG 内容和路径设置保留并复制已解析的绘图。 文件始终会被读取以检测更改。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobjects\svg.py

def __init__(
    self,
    file_name: str | os.PathLike[str] | None = None,
    should_center: bool = True,
    height: float | None = 2,
    width: float | None = None,
    color: Colors | None = None,
    opacity: float | None = None,
    fill_color: Colors | None = None,
    fill_opacity: float | Sequence[float] | None = None,
    stroke_color: Colors | None = None,
    stroke_opacity: float | Sequence[float] | None = None,
    stroke_width: float | None = None,
    svg_default: Repaint | None = None,
    path_string_config: PathOptions | None = None,
    use_svg_cache: bool = True,
    **kwargs: Unpack[Look],
):
    super().__init__(stroke_color=None, fill_color=None, **kwargs)
    self.file_name = Path(file_name) if file_name is not None else None
    self.should_center = should_center
    self.svg_height = height
    self.svg_width = width
    self.set_color(BLACK if color is None else color)
    self.opacity = opacity
    self.fill_color = fill_color
    self.fill_opacity = fill_opacity
    self.stroke_color = stroke_color
    self.stroke_opacity = stroke_opacity
    self.stroke_width = 0 if stroke_width is None else stroke_width
    self.id_to_vgroup_dict: dict[str, VGroup] = {}
    """绘图的各个组,按其 id 索引:每个 `<g>` 元素的 id 命名其内部
    形状构成的组,"root" 命名全部形状;没有 id 的元素以
    "numbered_group_" 加一个数字命名。"""
    self.svg_default: Repaint = (
        {"stroke_width": 0} if svg_default is None else svg_default
    )
    self.path_string_config: PathOptions = (
        {} if path_string_config is None else path_string_config
    )
    self.init_svg_mobject(use_svg_cache=use_svg_cache)
    self.set_style(
        fill_color=fill_color,
        fill_opacity=fill_opacity,
        stroke_color=stroke_color,
        stroke_opacity=stroke_opacity,
        stroke_width=stroke_width,
    )
    self.move_into_position()

id_to_vgroup_dict

绘图的各个组,按其 id 索引:每个 <g> 元素的 id 命名其内部 形状构成的组,"root" 命名全部形状;没有 id 的元素以 "numbered_group_" 加一个数字命名。

PathOptions

SVG 路径如何变为曲线:SVGMobject 的 path_string_config,即它读取的每条路径的关键字。

除此之外,它们还接受样式关键字。

long_lines

为兼容 Manim 而接受;被忽略(默认为 False)。

should_subdivide_sharp_curves

为兼容 Manim 而接受;被忽略(默认为 False)。

should_remove_null_curves

为兼容 Manim 而接受;被忽略(默认为 False)。

color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

long_lines

为兼容 Manim 而接受;被忽略(默认为 False)。

should_subdivide_sharp_curves

为兼容 Manim 而接受;被忽略(默认为 False)。

should_remove_null_curves

为兼容 Manim 而接受;被忽略(默认为 False)。