4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめての記事投稿
Qiita Engineer Festa20242024年7月17日まで開催中!

RustとWebAssemblyでAsciiアート生成ツール作ってみた

Last updated at Posted at 2024-06-27

はじめに

無料個人非商用版があるRustIDE「RustRover」が正式リリースされたついでに、以前から触ってみたかったRustを学習していきたいと思います。

なんとなくですが、学習用にRustとWebAssembly使ってAsciiアートGenerator的なのを作成しようと思います。

RustRoverについて

プロジェクトの作成

wasm-packのテンプレートを作成。

RustとWebAssemblyでAsciiアート生成ツール作ってみた_001.jpg

buildのtargetをwebにする。

RustとWebAssemblyでAsciiアート生成ツール作ってみた_002.jpg

wasm-packのbuildのtargetをwebにする理由(Gemini1.5proに聞いてみた)

target web を指定すると、以下の様な Web ブラウザ向けの最適化が行われます。
・JavaScript のモジュール形式: Web ブラウザで読み込めるように、ES Modules 形式の JavaScript ファイルが出力されます。
・Web API との連携: web-sys クレートなどを利用して、DOM 操作や fetch API などの Web API を利用するためのコードを含めることができます。
・サイズ最適化: Web ブラウザでのダウンロードを高速化するために、コードサイズが小さく保たれます。

wasmでimageのdataを受け取り、解析して、文字列を返すような関数を作成。

lib.rs
// 省略

#[wasm_bindgen]
pub fn process_image(image_data: &[u8]) -> String {
    // 画像データからImageBufferを作成
    let mut img = ImageReader::new(std::io::Cursor::new(image_data))
        .with_guessed_format()
        .unwrap()
        .decode()
        .unwrap()
        .to_rgba8();

    // セルのサイズ
    let cell_size = 16;
    let mut result = String::new();

    // セルごとに処理
    for y in 0..img.height() / cell_size {
        for x in 0..img.width() / cell_size {
            // セルを切り出す
            let cell = img.sub_image(
                x * cell_size,
                y * cell_size,
                cell_size,
                cell_size,
            );

            // セルを解析
            let recognized_char = analyze_cell(cell.to_image());
            result.push(recognized_char);
            result.push(recognized_char);
        }
        result.push('\n');
    }
    result
}
fn analyze_cell(cell: ImageBuffer<Rgba<u8>, Vec<u8>>) -> char {
    // 黒ピクセルの数をカウント
    let black_pixels = cell.pixels().filter(|p| p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] != 0).count();

    // 黒ピクセル数に応じて文字を判定
    match black_pixels {
        0..=50 => '-',
        _ => '@',
    }
}

//略

要所のコード説明(Gemini1.5proに聞いてみた)

・ wasm_bindgen は、RustのコードをWebAssemblyにコンパイルし、JavaScriptから呼び出すことを可能にするためのツールです。
・ std::io::Cursor を使用することで、バイト列を ImageReader が読み込める形式に変換しています。
・ .with_guessed_format() 画像のフォーマットを自動判別します。
・ sub_image メソッドを使って、現在のセルに対応する部分画像を切り出します。
・ p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] != 0 赤、緑、青成分がすべて0(黒)で、アルファ成分が0以外(透明ではない)のピクセル数をカウントします。
・ 0..=50 => '-', 黒ピクセル数が50以下の場合は、 - を返します。
・ _ => '@', それ以外の場合は、 @ を返します。

生成された成果物のwasmを使い、

キャンバスに書いた絵や文字が出力されるような処理を実装

(お絵描き処理はFabric.jsで実装)

asciiart.js

import init, { process_image } from './rust_asciiart.js';

//略

async function run() {
    await init();

    document.getElementById("GeneBtn").addEventListener("click", (event) => {  
        canvasToUint8Array()
        .then((uint8Array) => {
            console.log(uint8Array);
            const result = process_image(uint8Array);
            document.getElementById("AsciiArea").innerText = result;
        })
        .catch((error) => {
            console.error('Error converting canvas to Uint8Array:', error);
        });
    });       

}
run();

//略

今回の成果物

デモURL

デモ画像

RustとWebAssemblyでAsciiアート生成ツール作ってみた_003.jpg

RustとWebAssemblyでAsciiアート生成ツール作ってみた_004.jpg

ソース

まとめ

Rust自体触ったことがなかったがこれを機に学習していきたい。📚

RustRoverははじめてでも使いやすかったので今後も使い倒していきます。💪

今回、Gemini1.5proを利用しながらプログラミングしましたが、改めてAI強いなと思いました。🤖

※間違い等ありましたら、ご指摘いただけると助かります。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?