Skip to main content

atmos/os_lib/webp/
mod.rs

1//! WebP 画像デコーダ(vendoring 版)。
2//!
3//! 上流: [`image-webp`](https://crates.io/crates/image-webp) (MIT/Apache-2.0) を
4//! `no_std` 向けに vendoring。`std::io`/`byteorder_lite`/`quick_error` への依存を
5//! 自前 io シム・手書き enum に置換し、エンコーダ(`encoder.rs`)は除外。
6//! アルゴリズム本体([`vp8`]/[`lossless`] 等)は無改変。
7//!
8//! エントリポイントは [`decode_webp`](先頭フレームを RGBA8888 にデコード)。
9// webp - image-webp 0.2.4 を no_std 向けに vendoring したデコーダ
10//
11// 上流: https://crates.io/crates/image-webp (MIT/Apache-2.0)
12// 改変点: std::io / byteorder_lite / quick_error への依存を自前 io シム・手書き enum に置換し、
13//         エンコーダ(encoder.rs)は除外。アルゴリズム本体(vp8/lossless 等)は無改変。
14#![allow(dead_code)]
15#![allow(clippy::all)]
16// ベンダリングした上流デコーダはカーネルの panic 禁止ポリシー (unwrap_used/expect_used deny)
17// の対象外とする。restriction 系 lint は clippy::all に含まれないため個別に allow する。
18// デコードは画像ローダ (非クリティカルな background スレッド) で実行されるため、
19// 万一の panic も当該スレッド終了で隔離され、カーネルには波及しない。
20#![allow(clippy::unwrap_used)]
21#![allow(clippy::expect_used)]
22
23pub mod io;
24
25mod alpha_blending;
26mod decoder;
27mod extended;
28mod huffman;
29mod loop_filter;
30mod lossless;
31mod lossless_transform;
32mod transform;
33pub mod vp8;
34mod vp8_arithmetic_decoder;
35pub mod yuv;
36
37pub use decoder::{DecodingError, WebPDecoder};
38
39use alloc::vec;
40use alloc::vec::Vec;
41
42/// WebP バイト列を RGBA8888 にデコードする(先頭フレーム)。
43/// 返り値: (width, height, rgba)
44pub fn decode_webp(data: &[u8]) -> Option<(u32, u32, Vec<u8>)> {
45    let cursor = io::Cursor::new(data);
46    let mut decoder = WebPDecoder::new(cursor).ok()?;
47    let (w, h) = decoder.dimensions();
48    if w == 0 || h == 0 || w > 8192 || h > 8192 {
49        return None;
50    }
51    let has_alpha = decoder.has_alpha();
52    let buf_size = decoder.output_buffer_size()?;
53    let mut buf = vec![0u8; buf_size];
54    decoder.read_image(&mut buf).ok()?;
55
56    // RGB(3ch) なら RGBA に展開、RGBA(4ch) ならそのまま
57    let total = (w * h) as usize;
58    if has_alpha {
59        // すでに RGBA
60        if buf.len() == total * 4 {
61            return Some((w, h, buf));
62        }
63    } else {
64        // RGB → RGBA
65        if buf.len() == total * 3 {
66            let mut rgba = vec![0u8; total * 4];
67            for i in 0..total {
68                rgba[i * 4] = buf[i * 3];
69                rgba[i * 4 + 1] = buf[i * 3 + 1];
70                rgba[i * 4 + 2] = buf[i * 3 + 2];
71                rgba[i * 4 + 3] = 255;
72            }
73            return Some((w, h, rgba));
74        }
75    }
76    None
77}