0
0

はじめに

下記でAsciiアート生成ツールを作成した際は、Fabric.jsを利用してCanvas操作していたが、

今回はweb-sysというRustからJavaScriptのWeb APIにアクセスするクレートを利用して

Canvas操作しつつ写真ペイントツールを作成してみようと思う。🧑‍🎨

(Wasmから直接DOM操作はできないため、

JavaScriptのWeb APIで仲介しているだけなのでRustでやる意味はないかもしれません。🤔)

web-sysについて

プロジェクトの作成

下記に既にCanvasのペイント処理のExampleがあったのでこれを参考にしながら

スマホのTouch操作の処理を実装と、写真のCanvas表示を実装してみる。

取り込んだ写真をCanvasに表示するように実装、

web-sysを使ってstyleの設定とかもできた。

lib.rs
// 省略

 let document = web_sys::window().unwrap().document().unwrap();
    let canvas = document.create_element("canvas").unwrap()
        .dyn_into::<web_sys::HtmlCanvasElement>().unwrap();
    canvas.set_id("myCanvas");
    document.body().unwrap().append_child(&canvas).unwrap();
    canvas.set_width(img.width());
    canvas.set_height(img.height());
    canvas.style().set_property("border", "solid").unwrap();
    let context =
        canvas.get_context("2d").unwrap().unwrap()
            .dyn_into::<web_sys::CanvasRenderingContext2d>().unwrap();
    let context = Rc::new(context);

    // image crate の画像データを RGBA のベクタに変換
    let raw_pixels: Vec<u8> = match img {
        DynamicImage::ImageRgba8(ref img_buffer) => img_buffer.clone().into_raw(),
        _ => {
            img.to_rgba8().into_raw()
        }
    };
    let image_data = ImageData::new_with_u8_clamped_array_and_sh(
        wasm_bindgen::Clamped(&mut raw_pixels.clone()),
        img.width(),
        img.height(),
    ).unwrap();
    context.put_image_data(&image_data, 0.0, 0.0).unwrap();

// 省略

次にスマホのTouch操作の処理を実装する。

雑だが、touchmove中の座標をtouchend時に繋げるような感じで実装

lib.rs
// 省略
        let closure = Closure::<dyn FnMut(_)>::new(move |event: web_sys::TouchEvent| {
            // Canvas要素の位置を取得
            let rect = canvas_clone.get_bounding_client_rect();
            // タッチ座標をCanvas座標系に変換
            let canvas_x = event.touches().get(0).unwrap().client_x() as f64 - rect.left();
            let canvas_y = event.touches().get(0).unwrap().client_y() as f64 - rect.top();
            // 現在の位置に矩形を描画
            context.fill_rect(canvas_x, canvas_y, 1f64, 1f64);
            my_xy_clone.borrow_mut().push(Point{x:canvas_x, y:canvas_y});
        });
        canvas.add_event_listener_with_callback("touchmove", closure.as_ref().unchecked_ref()).unwrap();
        closure.forget();

// 省略

        let closure = Closure::<dyn FnMut(_)>::new(move |_event: web_sys::TouchEvent| {
            for i in 0..my_xy_clone.borrow().len(){
                if i > 0 && i < my_xy_clone.borrow().len() - 1 {
                    context.begin_path();
                    context.move_to(my_xy_clone.borrow().get(i-1).unwrap().x,my_xy_clone.borrow().get(i-1).unwrap().y);
                    context.line_to(my_xy_clone.borrow().get(i).unwrap().x,my_xy_clone.borrow().get(i).unwrap().y);
                    context.stroke();
                }
            }
            my_xy_clone.borrow_mut().clear();
        });
        canvas.add_event_listener_with_callback("touchend", closure.as_ref().unchecked_ref()).unwrap();
        closure.forget();

// 省略

今回の成果物

デモURL

デモ画像

元画像

web-sys使って写真ペイントツール作ってみた_001.jpg

お絵描き後の画像

web-sys使って写真ペイントツール作ってみた_002.jpg

ソース

まとめ

Javascriptで直接操作したほうが、楽なような気がするが、

Rust初学者なため、こういったクレートを使うことも学習促進になるような気がした💪

まだまだ、理解できていないところも多いがコツコツと勉強していたい。

上記、画像が大きい場合に、Windowサイズを大きくはみ出てる課題があったため、

下記で修正版の記事を書きました。💪

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

0
0
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
0
0