5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rust で AVIF を生成してみる(Windows 編)

Posted at

Firefox も version 92.0 で AVIF をサポートするということで Windows 環境の Rust で AVIF を生成してみたいと思います。

image crate

image crate が AVIF をサポートしているので使ってみます。↓こんな感じで書いてみました。JPEG -> AVIF 変換しています。

Cargo.toml
[package]
name = "avif_test"
version = "0.1.0"
authors = ["benki"]
edition = "2018"

[dependencies]
anyhow = "1.0"

[dependencies.image]
version = "0.23"
default-features = false
features = [
    "jpeg",
    "avif-encoder"
]
main.rs
use anyhow::Result;

fn main() -> Result<()> {
    let img = image::open(r"C:\Users\benki\Desktop\test.jpg")?;
    img.save_with_format(
        r"C:\Users\benki\Desktop\test.avif",
        image::ImageFormat::Avif,
    )?;
    Ok(())
}

cargo run --releaseすると…

error: failed to run custom build command for `rav1e v0.4.1`

Caused by:
  process didn't exit successfully: `C:\Users\benki\Documents\rust_projects\avif_test\target\release\build\rav1e-595ba7b94a49d3bb\build-script-build` (exit code: 101)
  --- stdout
  cargo:rustc-cfg=nasm_x86_64

  --- stderr
  thread 'main' panicked at 'This version of NASM is too old: 指定されたファイルが見つかりません。 (os error 2)', C:\Users\benki\.cargo\registry\src\github.com-1ecc6299db9ec823\rav1e-0.4.1\build.rs:251:7
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
warning: build failed, waiting for other jobs to finish...
error: build failed

エラーが出ました。NASM が必要らしいのでインストールします。

NASM インストール(不要)

インストール手順は zip をダウンロードして解凍してパスを通して再起動です。これでビルドできるでしょう。cargo run --releaseすると…

error: failed to run custom build command for `rav1e v0.4.1`

Caused by:
  process didn't exit successfully: `C:\Users\benki\Documents\rust_projects\avif_test\target\release\build\rav1e-595ba7b94a49d3bb\build-script-build` (exit code: 101)
  --- stdout
  cargo:rustc-cfg=nasm_x86_64
  running: "nasm" "-fwin64" "-IC:\\Users\\benki\\Documents\\rust_projects\\avif_test\\target\\release\\build\\rav1e-24085274cf597553\\out/" "-Isrc/" "C:\\Users\\benki\\.cargo\\registry\\src\\github.com-1ecc6299db9ec823\\rav1e-0.4.1\\src/x86/mc_sse.asm" "-o" "C:\\Users\\benki\\Documents\\rust_projects\\avif_test\\target\\release\\build\\rav1e-24085274cf597553\\out\\src/x86/mc_sse.o"

(中略)

  --- stderr
  Some((2, 14, 0)) "NASM version 2.15.05 compiled on Aug 28 2020\r\n" (2, 15, 5)
  C:\Users\benki\.cargo\registry\src\github.com-1ecc6299db9ec823\rav1e-0.4.1\src/x86/sse.asm:446: warning: dropping trailing empty parameter in call to multi-line macro `LOAD_SCALES_8X4' [-w+macro-params-legacy]

(中略)

  C:\Users\benki\.cargo\registry\src\github.com-1ecc6299db9ec823\rav1e-0.4.1\src/x86/tables.asm:534: warning: dropping trailing empty parameter in call to multi-line macro `const' [-w+macro-params-legacy]
  thread 'main' panicked at 'NASM build failed. Make sure you have nasm installed. https://nasm.us: "failed to spawn process: 指定されたフ 
ァイルが見つかりません。 (os error 2)"', C:\Users\benki\.cargo\registry\src\github.com-1ecc6299db9ec823\rav1e-0.4.1\build.rs:116:6
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

だめだー!:sob:
パス文字列がダメなのかと思って、rav1e の build.rs を弄ってみましたがやっぱりビルドできないので、asm feature を使わないことにします。

[patch]

image crate は AVIF エンコーダとして、ravif を使用しています。ravif は rav1e に依存しています。ravif が rav1e の asm feature を使用しているので、これを無効にします。

sub dependencies のfeaturesをどうやって設定するのか悩んだのですが、Cargo.toml の[patch]を使って ravif の Cargo.toml を書き換えることにしました。

まず ravif-0.6.4 のソースコードを丸ごと src フォルダにコピー。src/ravif-0.6.4/Cargo.toml の 56~57 行目をコメントアウトします。

src/ravif-0.6.4/Cargo.toml
[features]
# asm = ["rav1e/asm"]
# default = ["asm"]

そして、avif_test の Cargo.toml に以下を追加。

Cargo.toml
[patch.crates-io]
ravif = { path = "src/ravif-0.6.4" }

これで crates.io リポジトリの ravif ではなく、ローカルのものが使用されます。便利。cargo run --releaseすると…

   Compiling avif_test v0.1.0 (C:\Users\benki\Documents\rust_projects\avif_test)
    Finished release [optimized] target(s) in 2.56s
     Running `target\release\avif_test.exe`

NASM なしでビルドできました。無事 test.avif も生成されました。やったぜ。
でも何やら様子がおかしい…

test.jpg test.avif
204 KB 566 KB

元の JPEG よりファイルサイズ大きくなってるんですが?:thinking:
どうやら image crate のsave_with_format(path, image::ImageFormat::Avif)は最高品質で AVIF を生成するようです。

もっと圧縮

ということで、もっとファイルサイズを圧縮するコードを書きました。全部まとめてどうぞ。

Cargo.toml
[package]
name = "avif_test"
version = "0.1.0"
authors = ["benki"]
edition = "2018"

[dependencies]
anyhow = "1.0"

[dependencies.image]
version = "0.23"
default-features = false
features = [
    "jpeg",
    "avif-encoder"
]

[patch.crates-io]
ravif = { path = "src/ravif-0.6.4" }
src/ravif-0.6.4/Cargo.tomlの55~57行目
[features]
# asm = ["rav1e/asm"]
# default = ["asm"]
main.rs
use anyhow::{Context, Result};
use image::{avif::AvifEncoder, ColorType::Rgb8, GenericImageView};
use std::fs::File;
use std::io::BufWriter;

fn main() -> Result<()> {
    let img = image::open(r"C:\Users\benki\Desktop\test.JPG")?;
    let data = img.as_rgb8().context("no rgb8")?.to_vec();
    let fout = &mut BufWriter::new(File::create(r"C:\Users\benki\Desktop\test.avif")?);

    // Create a new encoder with specified speed and quality, that writes its output to `w`.
    // `speed` accepts a value in the range 0-10, where 0 is the slowest and 10 is the fastest.
    // `quality` accepts a value in the range 0-100, where 0 is the worst and 100 is the best.
    // pub fn new_with_speed_quality(w: W, speed: u8, quality: u8) -> Self
    AvifEncoder::new_with_speed_quality(fout, 5, 60).write_image(
        &data,
        img.width(),
        img.height(),
        Rgb8,
    )?;
    Ok(())
}

cargo run --releaseすると…

test.jpg test.avif
204 KB 126 KB

けっこう小さくなりました。new_with_speed_qualityspeedqualityの値を変えて画質とファイルサイズのバランスを調整すると良いでしょう。speedを小さくすると画質はよくなりますが、画像の生成に現実的でないくらいの時間が掛かります。何事もバランスが大事です。

さて肝心の Firefox でのサポート状況なんですが、生成した test.avif を Firefox で開いても「データが壊れている」とエラーが出て表示できませんでした…:sob:。VSCode だとちゃんと表示されるんですけどねぇ。

Netflix の AVIF サンプルも Firefox ではエラーで表示できないので、Firefox のデコーダがおかしいのかもしれません…。おわり。

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?