「TAURI」にも必要な「Rust」の「クレート」を使う

2023年11月16日(木)
大西 武 (オオニシ タケシ)
第5回の今回は、「TAURI」にも必要な「Rust」の追加機能である「クレート」の使い方やプログラミング方法について解説します。

はじめに

次回から本格的に「TAURI」を使っていきますが、今回はTAURIにも必要な「Rust」の「クレート」のインストール方法やプログラミング方法について解説していきます。

クレートとは、Rustでプログラミングする際に基本機能だけではできない画像を扱ったり、サウンドを扱ったりといった様々な機能を追加するためのプログラムです。クレートは通常のrsファイルでRustプログラミングしたものと同じもので、バイナリやライブラリで提供されます。クレートは誰でも公開できたりダウンロードできたりします。

今回は、パソコンのすぐわかる主な機能と言えば画面と音なので、画像とサウンドを扱うクレートを紹介したいと思います。

サンプルプロジェクトのzipファイル(TauriSample05.zip)はこちらからダウンロードできます。画像を扱う「img」プロジェクトと、サウンドを扱う「sound」プロジェクトが入っています。

画像を扱う「image」クレート

それでは、最初に画像を生成したり読み書きできる「image」クレートの使い方から解説していきます。クレートを使うと、自分で作ればとても手間のかかる機能の実装を、例えばここでは画像を扱うためにずっと少ないコードで構造体や関数を呼び出すだけで楽に画像を扱えるようになります。

プロジェクトの作成

まず、Rustプロジェクトの作成からです。Tauriプロジェクトではありません。「Rust」などのフォルダをカレントフォルダにして、ターミナルで次のコマンドを実行して「img」プロジェクトを作成します。プロジェクト名は任意の名前で構いません。それからカレントフォルダを作成されたimgフォルダに変更します。

・imgプロジェクトの作成
$ cargo new img

「Cargo.toml」ファイルにクレートを追記

画像を扱うimageクレートをimgプロジェクトに加え、imageクレートを使う設定を次のように「Cargo.toml」ファイルに追記します。さらに名前を付けて保存するダイアログを扱う「native-dialog」クレートの設定も追加します。これで2つのクレートをrsファイル内で使えるようになり、ビルド時にまだダウンロードされていなければダウンロードされ、プロジェクトとともにコンパイルされます。

・「Cargo.toml」ファイルに追記
[package]
name = "img"
version = "0.1.0"
edition = "2021"

[dependencies]
image = "0.24.7" # 画像のクレート
native-dialog = "0.6.4" # ファイルダイアログのクレート

「src」→「main.rs」ファイルで画像生成

次のサンプルコードのように「src」→「main.rs」ファイルでimageクレートを使って画像を生成してみましょう。「cargo run」すれば下図のようにグレースケールでグラデーションした画像が生成されます。本来なら何行もコードを書かなければならないところを、imageクレートを使えば10行にも満たないコードで画像を生成してファイルに保存できるようになりました。

図1:グレースケールでグラデーションした生成画像

rsファイルではコードの最初に「use」文を使ってクレートの関数や構造体などにアクセスできるようになります。さらに本文のコードの中で、より短くクレート名を省略するなどして関数名や構造体名などのコードが書けます。

・「main.rs」ファイルで画像の生成のサンプルコード
//画像を扱うクレート
use image::{Rgba,ImageBuffer};
//最初に呼ばれるメイン関数
fn main() {
  //色を返すクロージャ
  let draw = |x, _y| {
    //u8の灰色
    let gray = x as u8;
    //赤緑青アルファからなる色
    Rgba::<u8>([gray,gray,gray,255])
  };
  //256x256の画像を生成
  let img = ImageBuffer::from_fn(256, 256, draw);
  //画像を「gray_img.png」ファイルに保存
  img.save("gray_img.png").unwrap();
}

【サンプルコードの解説】
use文でimageクレートの「Rgba」構造体と「ImageBuffer」構造体を使えるようにします。
main関数がこのアプリで最初に呼ばれる関数です。
「draw」クロージャは画像のデータを返します。「クロージャ」はプログラミング言語「Java」でいう「ラムダ式」に似たもので、変数にできる「無名関数」のことです。「ImageBuffer::from_fn」メソッドの3つ目の引数からdrawクロージャが呼ばれ、ここではx座標の0~255を灰色とします。「gray」変数に「u32」型のx引数を「u8」型にキャストしたものを代入します。
生成されて「img」変数に代入されたグレースケールのグラデーションした画像を「gray_img.png」ファイルに保存します。「unwrap()」は失敗した場合を考慮しないように手間を省きますが、失敗した場合にエラーが出ます。

ファイルダイアログで画像を保存

「src」→「main.rs」ファイルでnative-dialogクレートを使って画像をファイルダイアログで保存してみましょう。ファイルダイアログで保存と言っても、ファイルダイアログはパス名を取得するだけで、ファイルに保存するのはimageクレートの役割です。

ファイルを名前を付けて保存するダイアログ(図2)は既存のファイルを選択した場合、上書きしても良いかを確認するメッセージが表示されます。これがファイルを開くダイアログ(後述)との大きな違いです。

図2:名前を付けて保存ダイアログ

今回はファイルダイアログにnative-dialogクレートを使いましたが、TAURIを使う場合にはそのクレートとは別にフロントエンドでJavaScriptによるファイルダイアログを扱う関数を使います。

ここで「match」文が出てきて「Some」の場合と「None」の場合に分かれていますが、これは「FileDialog::new()」の戻り値が以前なら存在するか「NULL」かを場合分けしていました。プログラミング言語Rustでは動作に問題が起きやすいNULLは使わず、存在する場合のSomeとしない場合のNoneを使うことで、確実に場合分けできるようにしています。

・「main.rs」ファイルで画像を生成し、ファイルダイアログで保存するサンプルコード
use image::{Rgba,ImageBuffer};
//ファイルダイアログを扱うクレート
use native_dialog::FileDialog;

fn main() {
  let draw = |x, _y| {
    let gray = x as u8;
    Rgba::<u8>([gray,gray,gray,255])
  };
  let img = ImageBuffer::from_fn(256, 256, draw);
  //ファイルダイアログ
  let path = FileDialog::new()
  //最初にデスクトップを開く
  .set_location("~/Desktop")
  //ファイルの種類をPNGだけに
  .add_filter("PNG Image", &["png"])
  //名前を付けて保存ダイアログ
  .show_save_single_file()
  //失敗した場合を無視
  .unwrap();
  //パスの場合分け
  match path {
    //パス名が存在した場合
    Some(path) => {
      //画像をパス名でファイルに保存
      img.save(path).unwrap();
    },
    //パス名がない場合
    None => return,
  };
}

【サンプルコードの解説】
use文で「native_dialog」クレートの「FileDialog」構造体を使えるようにします。クレート名は「native-dialog」でしたが、Rustの文法上rsファイル内では「-(ハイフン)」から「_(アンダーバー)」に代わるようです。
FileDialog構造体のコンストラクタ(newメソッド)でインスタンスを生成し「path」変数に代入します。「set_location("~/Desktop")」メソッドで最初に開くフォルダをデスクトップにします。「add_filter("PNG Image", &["png"])」メソッドでファイルの種類を「png」拡張子だけにします。「show_save_single_file()」メソッドでファイルダイアログの種類を1ファイルだけに名前を付けて保存するダイアログにセットします。
path変数にパス名が存在する場合はパス名でグレースケールグラデーション画像を保存します。パス名が存在しない場合はreturnでmain関数を抜け出します。

著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。

連載バックナンバー

開発言語技術解説
第13回

「TAURI」で「簡易RSSリーダー」を開発してみよう

2024/4/16
第13回の今回は「TAURI」で「RSSフィード」を読み込んでWebページに一覧表示し、リンクのページを開くための新規ウィンドウを作成するところまでを解説します。
開発言語技術解説
第12回

「TAURI」でExcelのデータを読み書きしてWebページに表示してみよう

2024/4/2
第12回の今回は「TAURI」で「Rust」の「umya-spreadsheet」クレートを使って「Excel」の「xlsx」ファイルを読み書きし、Webページに表示するところまでを解説します。
開発言語技術解説
第11回

「TAURI」と「Rust」の「テスト」機能を試してみよう

2024/3/12
第11回の今回は「Rust」で値が正しいか「テスト」する「assert_eq!」マクロなどを解説します。また「TAURI」でもプログラムが正しく動作するかの「テスト」についても解説します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています