はじめに
下記で作成した「RustとWebAssembly使ってAsciiアート」に引き続き同じ構成で
なんとなくですが、学習用にRustとWebAssembly使ってFaviconGenerator的なのを作成しようと思います。
faviconについて
プロジェクトの作成
wasm-packのテンプレートを作成。
今回は、wasmでimageのdataを受け取り、画像加工しFavicon作成して出力する関数を作成する。
画面のRadioButtonで背景の指定があった場合は、その背景色に合わせて背景を加工する。
背景の判定ロジックは処理を簡単にするため左上Pixelを背景色とした。(どんなアプローチがあるのか勉強したい🐬)
背景色と同じなら指定色にPixelを入替する。
// 省略
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に入れて
マルチアイコン化する。
// 省略
// 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クレートで行うと下記のようになる。
// 省略
// 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
デモ画像
・元画像
※icoはUpload出来なかったため代替でJpgをUploadしています。
左から順に
1.通常 2.透過 3.不透過(背景白) 4.不透過(背景黒)
ソース
まとめ
背景透過のアルゴリズムが思いつかなかったので今回は左上Pixelを参照するロジックにしたが、
画像系のアルゴリズムなども学習していきたいと思う。📚
次回はFaviconのマルチアイコンのCheckerを作成して何サイズが含まれるか確認できるツールを作りたいと思います。💪
※間違い等ありましたら、ご指摘いただけると助かります。