use std::ptr::NonNull;
use llama_crab_sys as sys;
use crate::error::{LlamaError, Result};
#[derive(Debug)]
pub struct MtmdBitmap {
handle: NonNull<sys::mtmd_bitmap>,
}
impl MtmdBitmap {
pub fn from_image_data(nx: u32, ny: u32, data: &[u8]) -> Result<Self> {
if data.len() < (nx as usize) * (ny as usize) * 3 {
return Err(LlamaError::Batch("bitmap data too small".into()));
}
let handle = unsafe { sys::mtmd_bitmap_init(nx, ny, data.as_ptr()) };
NonNull::new(handle)
.map(|handle| Self { handle })
.ok_or(LlamaError::Batch("mtmd_bitmap_init returned null".into()))
}
pub fn from_audio_data(data: &[f32]) -> Result<Self> {
let handle = unsafe { sys::mtmd_bitmap_init_from_audio(data.len(), data.as_ptr()) };
NonNull::new(handle)
.map(|handle| Self { handle })
.ok_or(LlamaError::Batch(
"mtmd_bitmap_init_from_audio returned null".into(),
))
}
pub fn from_file(path: impl AsRef<std::path::Path>) -> Result<Self> {
let img = image::open(path.as_ref())
.map_err(|e| LlamaError::Batch(format!("image decode: {e}")))?;
let rgb8 = img.to_rgb8();
let (nx, ny) = (rgb8.width(), rgb8.height());
let bytes = rgb8.into_raw();
let handle = unsafe { sys::mtmd_bitmap_init(nx, ny, bytes.as_ptr()) };
NonNull::new(handle)
.map(|handle| Self { handle })
.ok_or(LlamaError::Batch("mtmd_bitmap_init returned null".into()))
}
#[must_use]
pub fn nx(&self) -> u32 {
unsafe { sys::mtmd_bitmap_get_nx(self.handle.as_ptr()) }
}
#[must_use]
pub fn ny(&self) -> u32 {
unsafe { sys::mtmd_bitmap_get_ny(self.handle.as_ptr()) }
}
#[must_use]
pub fn n_bytes(&self) -> usize {
unsafe { sys::mtmd_bitmap_get_n_bytes(self.handle.as_ptr()) }
}
#[must_use]
pub fn is_audio(&self) -> bool {
unsafe { sys::mtmd_bitmap_is_audio(self.handle.as_ptr()) }
}
pub(crate) fn as_ptr_const(&self) -> *const sys::mtmd_bitmap {
self.handle.as_ptr().cast_const()
}
}
impl Drop for MtmdBitmap {
fn drop(&mut self) {
unsafe { sys::mtmd_bitmap_free(self.handle.as_ptr()) };
}
}
#[derive(Debug, Clone)]
pub struct MtmdInputText<'a> {
pub text: &'a str,
pub add_special: bool,
pub parse_special: bool,
}
impl<'a> MtmdInputText<'a> {
#[must_use]
pub fn new(text: &'a str) -> Self {
Self {
text,
add_special: true,
parse_special: true,
}
}
pub(crate) fn into_c(self) -> sys::mtmd_input_text {
let cstr = std::ffi::CString::new(self.text).expect("text with no nul bytes");
sys::mtmd_input_text {
text: cstr.into_raw().cast_const(),
add_special: self.add_special,
parse_special: self.parse_special,
}
}
}