1use std::ffi::CString;
2use std::path::Path;
3use std::ptr;
4
5use libheif_sys as lh;
6
7use crate::decoder::get_decoding_options_ptr;
8use crate::utils::path_to_cstring;
9use crate::{
10 ColorSpace, CompressionFormat, DecoderDescriptor, DecodingOptions, Encoder, EncoderDescriptor,
11 HeifError, Image, ImageHandle, Result,
12};
13
14pub struct LibHeif(());
25
26impl LibHeif {
27 pub fn new() -> Self {
28 let mut init_params = lh::heif_init_params { version: 0 };
29 unsafe {
30 lh::heif_init(&mut init_params as _);
31 }
32 Self(())
33 }
34
35 pub fn new_checked() -> Result<Self> {
41 let mut init_params = lh::heif_init_params { version: 0 };
42 let error = unsafe { lh::heif_init(&mut init_params as _) };
43 HeifError::from_heif_error(error)?;
44 Ok(Self(()))
45 }
46}
47
48impl Drop for LibHeif {
49 fn drop(&mut self) {
50 unsafe {
51 lh::heif_deinit();
52 }
53 }
54}
55
56impl Default for LibHeif {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl LibHeif {
63 pub fn version(&self) -> [u8; 3] {
67 let version: u32 = unsafe { lh::heif_get_version_number() };
69 let parts = version.to_be_bytes();
70 [parts[0], parts[1], parts[2]]
71 }
72
73 pub fn load_plugins(&self, dir_path: impl AsRef<Path>) -> Result<usize> {
77 self._load_plugins(dir_path.as_ref())
78 }
79
80 fn _load_plugins(&self, dir_path: &Path) -> Result<usize> {
82 let dir_path = path_to_cstring(dir_path);
83 let mut plugins_loaded: libc::c_int = 0;
84 let err = unsafe {
85 lh::heif_load_plugins(
86 dir_path.as_ptr(),
87 ptr::null_mut() as _,
88 &mut plugins_loaded as _,
89 0,
90 )
91 };
92 HeifError::from_heif_error(err)?;
93 Ok(plugins_loaded as usize)
94 }
95
96 pub fn decode(
102 &self,
103 image_handle: &ImageHandle,
104 color_space: ColorSpace,
105 decoding_options: Option<DecodingOptions>,
106 ) -> Result<Image> {
107 let mut c_image: *mut lh::heif_image = ptr::null_mut();
108 let err = unsafe {
109 lh::heif_decode_image(
110 image_handle.inner,
111 &mut c_image,
112 color_space.heif_color_space(),
113 color_space.heif_chroma(),
114 get_decoding_options_ptr(&decoding_options),
115 )
116 };
117 HeifError::from_heif_error(err)?;
118 Ok(Image::from_heif_image(c_image))
119 }
120
121 pub fn decoder_descriptors(
127 &self,
128 max_count: usize,
129 format_filter: Option<CompressionFormat>,
130 ) -> Vec<DecoderDescriptor<'_>> {
131 let format_filter = format_filter.unwrap_or(CompressionFormat::Undefined);
132 let max_count = max_count.min(libc::c_int::MAX as usize);
133
134 let mut descriptors_ptr = Vec::with_capacity(max_count);
135 unsafe {
136 let count = lh::heif_get_decoder_descriptors(
137 format_filter as _,
138 descriptors_ptr.as_mut_ptr(),
139 max_count as _,
140 );
141 descriptors_ptr.set_len(count as usize);
142 }
143
144 descriptors_ptr
145 .into_iter()
146 .filter_map(|d_ptr| unsafe { d_ptr.as_ref().map(DecoderDescriptor::new) })
147 .collect()
148 }
149
150 pub fn encoder_descriptors(
159 &self,
160 max_count: usize,
161 format_filter: Option<CompressionFormat>,
162 name_filter: Option<&str>,
163 ) -> Vec<EncoderDescriptor<'_>> {
164 let format_filter = format_filter.unwrap_or(CompressionFormat::Undefined);
165 let max_count = max_count.min(libc::c_int::MAX as usize);
166 let name_filter = name_filter
167 .map(|s| CString::new(s).ok())
168 .unwrap_or_default();
169 let name_filter_ptr = name_filter.map(|s| s.as_ptr()).unwrap_or(ptr::null());
170
171 let mut descriptors_ptr = Vec::with_capacity(max_count);
172 unsafe {
173 let count = lh::heif_get_encoder_descriptors(
174 format_filter as _,
175 name_filter_ptr,
176 descriptors_ptr.as_mut_ptr(),
177 max_count as _,
178 );
179 descriptors_ptr.set_len(count as usize);
180 }
181
182 descriptors_ptr
183 .into_iter()
184 .filter_map(|d_ptr| unsafe { d_ptr.as_ref().map(EncoderDescriptor::new) })
185 .collect()
186 }
187
188 pub fn encoder(&self, descriptor: EncoderDescriptor) -> Result<Encoder<'_>> {
191 let mut c_encoder: *mut lh::heif_encoder = ptr::null_mut();
192 let err = unsafe {
193 lh::heif_context_get_encoder(ptr::null_mut(), descriptor.inner, &mut c_encoder)
194 };
195 HeifError::from_heif_error(err)?;
196 let encoder = Encoder::new(unsafe { &mut *c_encoder })?;
197 Ok(encoder)
198 }
199
200 pub fn encoder_for_format(&self, format: CompressionFormat) -> Result<Encoder<'_>> {
204 let mut c_encoder: *mut lh::heif_encoder = ptr::null_mut();
205 let err = unsafe {
206 lh::heif_context_get_encoder_for_format(
207 ptr::null_mut() as _,
208 format as _,
209 &mut c_encoder,
210 )
211 };
212 HeifError::from_heif_error(err)?;
213 let encoder = Encoder::new(unsafe { &mut *c_encoder })?;
214 Ok(encoder)
215 }
216}