Skip to main content

deepmap2/
lib.rs

1//! Decoder for Apple's Deepmap2 image payloads.
2//!
3//! Use [`decode`] for standalone `dmp2` payloads and [`decode_kcbc`] for tiled
4//! `KCBC` sequences. The stable root exposes decode entry points plus a small
5//! enum surface, while [`raw`] contains the parsed binary header structs.
6
7mod apple_compression;
8pub mod codec;
9mod color;
10mod model;
11mod predictor;
12pub mod raw;
13pub mod tile;
14
15pub use crate::model::{DecodeType, PixelFormat, Predictor};
16
17use thiserror::Error;
18
19#[derive(Error, Debug)]
20pub enum Deepmap2Error {
21    #[error("invalid magic bytes")]
22    InvalidMagic,
23    #[error("truncated data")]
24    Truncated,
25    #[error("unsupported decode type: {0}")]
26    UnsupportedDecodeType(u8),
27    #[error("unsupported pixel format: {0}")]
28    UnsupportedPixelFormat(u8),
29    #[error("invalid palette size: {0}")]
30    InvalidPaletteSize(u16),
31    #[error("invalid palette type: {0}")]
32    InvalidPaletteType(u16),
33    #[error("invalid data: {0}")]
34    InvalidData(String),
35    #[error("lzfse decompression failed")]
36    LzfseDecompress,
37    #[error("native fallback unavailable: {0}")]
38    NativeFallbackUnavailable(&'static str),
39    #[error("lzvn decompression failed")]
40    LzvnDecompress,
41    #[error("deku parse error: {0}")]
42    DekuParse(#[from] deku::DekuError),
43}
44
45pub type Deepmap2Result<T> = Result<T, Deepmap2Error>;
46
47pub struct DecodedImage {
48    pub source_header: raw::Deepmap2Header,
49    pub width: u16,
50    pub height: u16,
51    pub pixel_format: PixelFormat,
52    pub rgba: Vec<u8>,
53}
54
55pub fn decode(data: &[u8]) -> Deepmap2Result<DecodedImage> {
56    decode_with_options(data, None, None, None)
57}
58
59pub fn decode_with_options(
60    data: &[u8],
61    output_width: Option<u16>,
62    output_height: Option<u16>,
63    pixel_format_override: Option<PixelFormat>,
64) -> Deepmap2Result<DecodedImage> {
65    use deku::prelude::*;
66
67    let mut cursor = std::io::Cursor::new(data);
68    let mut reader = Reader::new(&mut cursor);
69    let header = raw::Deepmap2Header::from_reader_with_ctx(&mut reader, ())?;
70    let header_size = header.header_size();
71    let payload = data.get(header_size..).ok_or(Deepmap2Error::Truncated)?;
72
73    let width = output_width.unwrap_or(header.width);
74    let height = output_height.unwrap_or(header.height);
75    let rgba = codec::decode_raw_with_options(
76        &header,
77        payload,
78        Some(width),
79        Some(height),
80        pixel_format_override,
81    )?;
82    let pixel_format = pixel_format_override.unwrap_or(header.pixel_format);
83
84    Ok(DecodedImage {
85        source_header: header,
86        width,
87        height,
88        pixel_format,
89        rgba,
90    })
91}
92
93pub fn decode_kcbc(data: &[u8]) -> Deepmap2Result<DecodedImage> {
94    decode_kcbc_with_options(data, None, None, None)
95}
96
97pub fn decode_kcbc_with_options(
98    data: &[u8],
99    expected_width: Option<u16>,
100    expected_height: Option<u16>,
101    pixel_format_override: Option<PixelFormat>,
102) -> Deepmap2Result<DecodedImage> {
103    tile::decode_kcbc_sequence_with_options(
104        data,
105        expected_width,
106        expected_height,
107        pixel_format_override,
108    )
109}