🧬
Dioxus で QR code を生成する Web サイトを作ってみた
概要
Dioxus で QR code を生成する Web サイト ZEQRA を作ってみたので、雑な内容ですが記事にしました。
環境
- dioxus: 0.5.1
- bulma: 1.0.0
- qrcode-rust: 0.14.0
関連記事
実装
結構雑に書いてるので GitHub のコードも併せて参照して下さい。
-
Dioxus のプロジェクトを作成します。
次のコマンドでプロジェクトの作成を開始します。
dx new
プロジェクトの設定は次の通りです。
✔ 🤷 Which sub-template should be expanded? · Web 🤷 Project Name: zeqra ✔ 🤷 How do you want to create CSS? · Vanilla ✔ 🤷 Should the application use the Dioxus router? · false
-
Cargo.toml マニフェストファイルに依存関係を追加します。
cargo add qrcode base64 anyhow serde cargo add dioxus-free-icons --features=ionicons
-
bulma の CSS ファイルを
zeqra/assets/bulma.min.css
に保存します。 -
bulma の CSS ファイルを読み込みます。
zeqra/Dioxus.tomlstyle = ["./bulma.min.css"]
-
依存関係を追加します。
zeqra/src/main.rsuse dioxus_free_icons::{icons::io_icons::{IoCloudDownload, IoLogoGithub, IoLogoTwitter, IoOpen}, Icon}; use serde::{Deserialize, Serialize}; use qrcode::render::svg; use qrcode::QrCode; use base64::{engine::general_purpose, Engine as _}; use anyhow::Result;
-
State を実装します。
zeqra/src/main.rs#[derive(Debug, Serialize, Deserialize)] pub struct AppState { isError: bool, dataUrl: Option<String>, topNavbarBurgerActive: bool, topNavbarBurgerClass: String, topNavbarMenuClass: String, termsOfUseModalActive: bool, termsOfUseModalClass: String, privacyPolicyModalActive: bool, privacyPolicyModalClass: String, } impl AppState { fn new() -> Self { Self { isError: false, dataUrl: None, topNavbarBurgerActive: false, topNavbarBurgerClass: "navbar-burger".to_string(), topNavbarMenuClass: "navbar-menu".to_string(), termsOfUseModalActive: false, termsOfUseModalClass: "modal".to_string(), privacyPolicyModalActive: false, privacyPolicyModalClass: "modal".to_string(), } } }
-
QR code を作成する関数を実装します。
zeqra/src/main.rs#[derive(PartialEq, Props, Clone)] struct MakeQrCodeProps { text: String, width: u32, height: u32, dark_color: String, light_color: String, } impl Default for MakeQrCodeProps { fn default() -> Self { Self { text: "".to_string(), width: 200, height: 200, dark_color: "#000000".to_string(), light_color: "#ffffff".to_string(), } } } fn makeQrCode(props: MakeQrCodeProps) -> Result<String> { let code: QrCode = QrCode::new(props.text.as_bytes())?; let image = code.render() .min_dimensions(props.width, props.height) .dark_color(svg::Color(&props.dark_color)) .light_color(svg::Color(&props.light_color)) .build(); let data_url = format!("data:image/svg+xml;base64,{}", general_purpose::STANDARD.encode(&image)); Ok(data_url) }
-
QR code を表示する QrCode コンポーネントを実装します。AppState.dataUrl の値を img タグの src 属性 に設定しています。
zeqra/src/main.rs#[component] fn QrCode() -> Element { let app_state = consume_context::<Signal<AppState>>(); let data_url = app_state.read().dataUrl.clone(); match data_url { Some(data_url) => { rsx! { div { class: "container pt-5 has-text-centered", div { img { src: "{data_url}", width: "150", height: "150" } } div { class: "pt-3", a { class: "button is-medium is-success", href: "{data_url}", download: "QR-code.svg", span { class: "icon is-small mr-2", Icon { width: 24, height: 24, icon: IoCloudDownload } }, "Download" } } } } } None => None } }
-
QR コードを生成
ボタンを押下すると makeQrCode 関数を実行して戻り値を AppState.dataUrl に設定するように App コンポーネントを実装します。また、生成した QR code を表示するために QrCode コンポーネントも追加します。zeqra/src/main.rs#[component] fn App() -> Element { use_context_provider(|| Signal::new(AppState::new())); let mut app_state = consume_context::<Signal<AppState>>(); rsx! { link { rel: "stylesheet", href: "main.css" } div { class: "container px-3 py-3", form { class: "box", onsubmit: move |ev| { let qrCode = makeQrCode(MakeQrCodeProps { text: ev.values().get("text").unwrap().as_value(), ..Default::default() }); match qrCode { Ok(data_url) => { app_state.write().isError = false; app_state.write().dataUrl = Some(data_url); } Err(_) => { app_state.write().isError = true; app_state.write().dataUrl = None; } } }, div { class: "field", div { class: "control", input { id: "text", name: "text", class: "input", r#type: "text", required: true, placeholder: "テキストを入力してください", } } } div { class: "field is-grouped is-justify-content-center", div { class: "control", button { class: "button is-medium is-fullwidth is-link", r#type: "submit", "QR コードを生成" } } } } } QrCode {} } }
Discussion