#braille #terminal #animation #tui #cli

rsille

一个功能齐全的盲文代码艺术库

12 个稳定版本

2.3.1 2024 年 6 月 27 日
2.3.0 2024 年 4 月 19 日
2.1.3 2024 年 2 月 27 日
1.2.0 2024 年 2 月 19 日

#56 in 图形 API

每月 39 次下载

MIT 许可证

94KB
2K SLoC

Rsille 🎨

GitHub License Crates.io Version Crates.io Total Downloads docs.rs

英文中文

anime 3d object life game mandelbrot set lena turtle

📚 目录


👀 尝试它

README 中使用的所有图像都可以在 examples 文件夹中找到,无需编程即可运行!

git clone https://github.com/nidhoggfgg/rsille.git
cd rsille
cargo run --example cube

这将生成一个旋转的立方体。

要获取更多示例或尝试生成有趣的图案,您可以使用 cargo run --example,您将找到所有无需编程即可运行的示例。

当然,还有更多示例,例如 bad-apple 等。您可以通过查看用法来了解如何使用此库。

🔧 安装

这是一个 Rust 库,所以您只需要将以下代码添加到您的 Cargo.toml 中即可使用它

[dependencies]
rsille = "2.1.0"

🚀 使用

由于空间限制,这里只提供了常用 API 和通用使用方法。

有关详细 API,请访问 doc.rs

基础

最基本的函数是 set

use rsille::Canvas;
fn main() {
    let mut c = Canvas::new();
    for x in -360..360 {
        let x = x as f64;
        c.set(x / 10.0, x.to_radians().sin() * 10.0);
    }
    c.print();
}

basic-sin

为什么是 (x / 10.0, x.to_radians().sin() * 10.0) 而不是 (x, x.sin())?您可以尝试添加、减去、乘以和除以来改变绘制的坐标。一个小提示: 包含 8 个点。如果您真的不理解或想知道为什么,可以直接在您的算法中使用 (x, y)。我可能以后会写一篇文章关于盲文代码。


set 的相反操作是 unset,它会擦除已设置的点。


另一个有用的方法是 toggle,它会擦除已设置的点并设置尚未设置的点。

use rsille::Canvas;
fn main() {
    let mut c = Canvas::new();
    for x in (0..360).step_by(4) {
        let x = x as f64;
        c.set(x / 4.0, x.to_radians().sin() * 30.0);
    }

    for x in 0..=30 {
        for y in 0..=30 {
            c.toggle(x, y);
            c.toggle(x + 30, y - 30);
            c.toggle(x + 60, y);
        }
    }
    c.print();
}

toggle-sin

这个例子稍微长一点,让我们来解释一下。

  • (0..360).step_by(4)遍历区间[0, π)内的x,并且使用step_by(4)进行下采样以使线条更细(值太低可能会导致不精确)。
  • 第一个for循环用于绘制f(x) = sin(x)的图形。为了使其看起来更好,对xy都应用了某种缩放。
  • 第二个for循环用于创建那些toggle块,每个块的大小为31x31。

toggle中,没有使用f64,因为所有方法都支持泛型,可以接受各种数字类型!然而,仍然强烈建议使用f64以获得更高的精度。

龟形图

在Python中,有一个有趣的库叫做turtle。它允许初学者在开始使用Python时体验编程的乐趣。这个库也实现了turtle中的大多数方法。

use rsille::{extra::Turtle, Canvas};
fn main() {
    let mut canvas = Canvas::new();
    let mut t = Turtle::new();
    for _ in 0..5 {
        t.forward(50);
        t.right(144);
    }
    canvas.paint(&t, 0, 0).unwrap();
    canvas.print();
}

turtle-star

paint方法中的两个0不是固定的;它们将绘制对象放置在(0, 0)。这是任意的,但始终在(0, 0)处绘制单个对象是个好主意。

不再介绍turtle;您可以直接复制Python代码并稍作修改后使用。

3D 对象

这个库还支持3D对象,并提供方便的方法来轻松构建对象。

use rsille::{extra::Object3D, Animation};

fn main() {
    let mut anime = Animation::new();
    let cube = Object3D::cube(30);
    anime.push(
        cube,
        |cube| {
            cube.rotate((1.0, 2.0, 3.0));
            false
        },
        (0, 0),
    );
    anime.run();
}

cube

在这里,使用Animation创建动画,这些动画也是内部支持的。您可以查看动画以获取更多信息。

Object3D主要有两个有用的方法:rotate用于旋转对象,zoom用于缩放对象。

康威的生命游戏

康威的生命游戏非常有趣,因此它也是库的一部分。

use rsille::{extra::LifeGame, Animation};

fn main() {
    let mut anime = Animation::new();
    let lg = LifeGame::from(r#"x = 47, y = 47, rule = B3/S23
18bo$18b3o$21bo$20b2o$$32b2o$32b2o$26bobo$28bo$$22b3o$15b2o5bo2bo$15b2o
2o5bo3bo$5b2o19bo$5b2o15bo3bo$22bo2bo8b2o$22b3o9b2o$$7b2o36b2o$45bo$7b
o4b3o28bobo$11bo3bo27b2o$10bo5bo13b3ob3o$10bo5bo13bo5bo$10b3ob3o13bo5b
o$2b2o27bo3bo$bobo28b3o4bo$bo$2o36b2o$$11b2o9b3o$11b2o8bo2bo$20bo3bo
15b2o$20bo19b2o$20bo3bo5b2o$21bo2bo5b2o$22b3o$$18bo$18bobo$13b2o$13b2o
$$25b2o$25bo$26b3o$28bo!"#).unwrap();
    anime.push(
        lg,
        |lg| lg.update(),
        (0, 0),
    );
    anime.run();
}

lifegame

在这里,仍然使用Animation,并解析康威的生命游戏的rle文件。解析rle文件所需的一切都已经写入Lifegame内部,没有任何额外的依赖项,并且解析代码非常轻量。

图像

使用盲文代码绘制图像也是一个不错的选择。然而,用于解析images的图像库有点大,因此默认不启用。要使用它,请在您的Cargo.toml中添加以下内容

[dependencies]
rsille = { version = "2.1.0", features = ["img"] }

这里是一个使用示例。注意:请填写图像文件路径!

use rsille::{extra::Imgille, Canvas};

fn main() {
    let mut canvas = Canvas::new();
    let img = Imgille::new("path/to/img").unwrap();
    canvas.paint(&img, 0, 0).unwrap();
    canvas.print();
}

lena xkcd xkcd-invert

默认情况下,它使用颜色,这对灰度图像或黑白图像(如xkcd中的图像)不是很友好,并且可能会降低清晰度!

因此,对于它们,您必须肯定调用color(false)

它还支持反转,例如上面两个xkcd图像,以黑色为主色的那个没有反转,以白色为主色的那个反转了。调用invert(true)来反转颜色。对于彩色图像,不使用颜色也是一个好选择,例如

lena-gray

此外,图像大小将自动与终端缩放,无论是长终端还是宽终端,都始终正确缩放!

动画

生成一些对象,然后在 Canvas 上绘制它们,然后更新对象,并重新绘制。您还需要设置帧率,处理用户输入等。使用基本 Canvas 创建动画的代码总是非常麻烦!更不用说适当的屏幕清除和防止闪烁等。

因此,这个库封装了所有这些麻烦的事情。只需用 3 行代码就可以使用它创建动画!

  1. 创建一个新的动画 let mut anime = Animation::new()
  2. 加载一个可绘制对象和一个更新函数 anime.push()
  3. 运行 anime.run()

这非常简单!

use rsille::{extra::Object3D , Animation};

fn main() {
    let cube = Object3D::cube(30);
    let mut anime = Animation::new();
    anime.push(cube, |cube| { cube.rotate((1.0, 2.0, 3.0)); false }, (0, 0));
    anime.run();
}

push 方法的参数如下

  1. 对象,直接传递即可。
  2. 一个返回布尔值的闭包,作为更新函数。这个闭包会每帧运行一次。当闭包返回 true 时,对象停止更新,将不再执行更新函数,但它仍然会在画布上绘制。当所有对象完成更新后,动画停止。
  3. (x, y),对象放置的位置,通常只在有多个对象时使用。

对于用户输入处理,目前,只有 ctrl+c 和 esc 可以用来退出。将来可能会支持自定义处理。

📌 TODO

  • 优化 Animation 的多线程。
  • Animation 添加更多功能。
  • 添加更多可绘制对象。
  • Lifegame 添加有界版本。
  • 更多示例。

📝 许可证

MIT

依赖项

~0.8–6.5MB
~31K SLoC