LoginSignup
0
0

はじめに

下記で作成した「RustとWebAssembly使ってAsciiアート」に引き続き同じ構成で

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

faviconについて

プロジェクトの作成

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

今回は、wasmでimageのdataを受け取り、画像加工しFavicon作成して出力する関数を作成する。

画面のRadioButtonで背景の指定があった場合は、その背景色に合わせて背景を加工する。

背景の判定ロジックは処理を簡単にするため左上Pixelを背景色とした。(どんなアプローチがあるのか勉強したい🐬)

背景色と同じなら指定色にPixelを入替する。

lib.rs
// 省略

 if input_color == "transparent" || input_color == "black" || input_color == "white"{
        let rgb_img = img.to_rgb8();
        // 左上Pixelを背景色とする
        let background_color = rgb_img.get_pixel(0, 0);
        let mut output_img = ImageBuffer::new(rgb_img.width(), rgb_img.height());
        for (y, row) in rgb_img.rows().enumerate() {
            for (x, pixel) in row.enumerate() {
                if pixel == background_color {
                    if input_color == "transparent"{
                        output_img.put_pixel(x as u32, y as u32, Rgba([0, 0, 0, 0]));
                    }
                    if input_color == "black" {
                        output_img.put_pixel(x as u32, y as u32, Rgba([0, 0, 0, 255]));
                    }
                    if input_color == "white"{
                        output_img.put_pixel(x as u32, y as u32, Rgba([255, 255, 255, 255]));
                    }
                } else {
                    output_img.put_pixel(x as u32, y as u32, Rgba([pixel[0], pixel[1], pixel[2], 255]));
                }
            }
        }
        img = DynamicImage::ImageRgba8(output_img);
    }


// 省略

各アイコンサイズをループ中にリサイズする。

icoクレートを使い、そのリサイズした画像をIconDirに入れて

マルチアイコン化する。

lib.rs
// 省略

  // ICOエンコーダーを作成
    let mut icon_dir = ico::IconDir::new(ico::ResourceType::Icon);
    // 各アイコンサイズに対してループ処理
    let icon_sizes = vec![16,32,48,96,144,192,240,288];
    for size in icon_sizes {
        let resized_img = img.resize(size, size, FilterType::Lanczos3);
        let rgba = resized_img.to_rgba8().to_vec();
        let icon_img = ico::IconImage::from_rgba_data(size, size, rgba);

        // エンコードした画像をICOディレクトリに追加
        let icon = ico::IconDirEntry::encode(&icon_img).unwrap();
        icon_dir.add_entry(icon);
    }

// 省略

正直、下記ダウンロード処理についてはJavascript側で処理しても良いが、、、

せっかくならWasmでWeb-sysクレートを使用してJavascriptAPIを操作してみる。💪

よくJavascriptで行う a要素 を使用してダウンロードする処理を

RustとWeb-sysクレートで行うと下記のようになる。

lib.rs
// 省略

    // Blobを作成
    let blob = Blob::new_with_u8_array_sequence_and_options(&parts,BlobPropertyBag::new().type_("image/vnd.microsoft.icon")).unwrap();
    // BlobのURLを取得
    let url = Url::create_object_url_with_blob(&blob).unwrap();
    // a要素を作成
    let link = window.document().unwrap().create_element("a").unwrap().dyn_into::<web_sys::HtmlAnchorElement>().unwrap();
    link.set_href(&url);
    link.set_download("favicon.ico");
    link.click();

// 省略

今回の成果物

デモURL

デモ画像

・元画像

RustとWebAssemblyでFaviconGenerator作ってみた_001.jpg

RustとWebAssemblyでFaviconGenerator作ってみた_002.jpg

※icoはUpload出来なかったため代替でJpgをUploadしています。

左から順に

1.通常 2.透過 3.不透過(背景白) 4.不透過(背景黒)

RustとWebAssemblyでFaviconGenerator作ってみた_007.jpg

ソース

まとめ

背景透過のアルゴリズムが思いつかなかったので今回は左上Pixelを参照するロジックにしたが、

画像系のアルゴリズムなども学習していきたいと思う。📚

次回はFaviconのマルチアイコンのCheckerを作成して何サイズが含まれるか確認できるツールを作りたいと思います。💪

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

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