1#[cfg(feature = "v1_18")]
2use std::num::NonZeroU16;
3use std::os::raw::c_void;
4use std::{ffi, ptr};
5
6use four_cc::FourCC;
7use libheif_sys as lh;
8
9use crate::encoder::get_encoding_options_ptr;
10use crate::reader::{Reader, HEIF_READER};
11use crate::utils::str_to_cstring;
12#[cfg(feature = "v1_19")]
13use crate::SecurityLimits;
14use crate::{
15 Encoder, EncodingOptions, HeifError, HeifErrorCode, HeifErrorSubCode, Image, ImageHandle,
16 ItemId, Result,
17};
18
19#[allow(dead_code)]
20enum Source<'a> {
21 None,
22 File,
23 Memory(&'a [u8]),
24 Reader(Box<Box<dyn Reader>>),
25}
26
27pub struct HeifContext<'a> {
28 pub(crate) inner: *mut lh::heif_context,
29 source: Source<'a>,
30}
31
32impl HeifContext<'static> {
33 pub fn new() -> Result<HeifContext<'static>> {
35 let ctx = unsafe { lh::heif_context_alloc() };
36 if ctx.is_null() {
37 Err(HeifError {
38 code: HeifErrorCode::ContextCreateFailed,
39 sub_code: HeifErrorSubCode::Unspecified,
40 message: String::from(""),
41 })
42 } else {
43 Ok(HeifContext {
44 inner: ctx,
45 source: Source::None,
46 })
47 }
48 }
49
50 pub fn read_from_file(name: &str) -> Result<HeifContext<'static>> {
52 let mut context = HeifContext::new()?;
53 context.read_file(name)?;
54 Ok(context)
55 }
56
57 pub fn read_file(&mut self, name: &str) -> Result<()> {
59 self.source = Source::File;
60 let c_name = ffi::CString::new(name).unwrap();
61 let err =
62 unsafe { lh::heif_context_read_from_file(self.inner, c_name.as_ptr(), ptr::null()) };
63 HeifError::from_heif_error(err)?;
64 Ok(())
65 }
66
67 pub fn read_from_reader(reader: Box<dyn Reader>) -> Result<HeifContext<'static>> {
69 let mut context = HeifContext::new()?;
70 context.read_reader(reader)?;
71 Ok(context)
72 }
73
74 pub fn read_reader(&mut self, reader: Box<dyn Reader>) -> Result<()> {
76 let mut reader_box = Box::new(reader);
77 let user_data = reader_box.as_mut() as *mut _ as *mut c_void;
78 let err = unsafe {
79 lh::heif_context_read_from_reader(self.inner, &HEIF_READER, user_data, ptr::null())
80 };
81 HeifError::from_heif_error(err)?;
82 self.source = Source::Reader(reader_box);
83 Ok(())
84 }
85
86 #[cfg(feature = "v1_18")]
90 pub(crate) unsafe fn from_ptr(ctx: *mut lh::heif_context) -> HeifContext<'static> {
91 HeifContext {
92 inner: ctx,
93 source: Source::None,
94 }
95 }
96}
97
98impl<'a> HeifContext<'a> {
99 pub fn read_from_bytes(bytes: &[u8]) -> Result<HeifContext> {
105 let mut context = HeifContext::new()?;
106 context.read_bytes(bytes)?;
107 Ok(context)
108 }
109
110 pub fn read_bytes<'b: 'a>(&mut self, bytes: &'b [u8]) -> Result<()> {
116 self.source = Source::Memory(bytes);
117 let err = unsafe {
118 lh::heif_context_read_from_memory_without_copy(
119 self.inner,
120 bytes.as_ptr() as _,
121 bytes.len(),
122 ptr::null(),
123 )
124 };
125 HeifError::from_heif_error(err)?;
126 Ok(())
127 }
128
129 unsafe extern "C" fn vector_writer(
130 _ctx: *mut lh::heif_context,
131 data: *const c_void,
132 size: usize,
133 user_data: *mut c_void,
134 ) -> lh::heif_error {
135 let vec: &mut Vec<u8> = &mut *(user_data as *mut Vec<u8>);
136 vec.reserve(size);
137 ptr::copy_nonoverlapping::<u8>(data as _, vec.as_mut_ptr(), size);
138 vec.set_len(size);
139
140 lh::heif_error {
141 code: lh::heif_error_code_heif_error_Ok,
142 subcode: lh::heif_suberror_code_heif_suberror_Unspecified,
143 message: b"\0".as_ptr() as _,
144 }
145 }
146
147 pub fn write_to_bytes(&self) -> Result<Vec<u8>> {
148 let mut res = Vec::<u8>::new();
149 let pointer_to_res = &mut res as *mut _ as *mut c_void;
150
151 let mut writer = lh::heif_writer {
152 writer_api_version: 1,
153 write: Some(Self::vector_writer),
154 };
155
156 let err = unsafe { lh::heif_context_write(self.inner, &mut writer, pointer_to_res) };
157 HeifError::from_heif_error(err)?;
158 Ok(res)
159 }
160
161 pub fn write_to_file(&self, name: &str) -> Result<()> {
162 let c_name = ffi::CString::new(name).unwrap();
163 let err = unsafe { lh::heif_context_write_to_file(self.inner, c_name.as_ptr()) };
164 HeifError::from_heif_error(err)
165 }
166
167 pub fn number_of_top_level_images(&self) -> usize {
168 unsafe { lh::heif_context_get_number_of_top_level_images(self.inner) as _ }
169 }
170
171 pub fn top_level_image_ids(&self, item_ids: &mut [ItemId]) -> usize {
172 if item_ids.is_empty() {
173 0
174 } else {
175 unsafe {
176 lh::heif_context_get_list_of_top_level_image_IDs(
177 self.inner,
178 item_ids.as_mut_ptr(),
179 item_ids.len() as _,
180 ) as usize
181 }
182 }
183 }
184
185 pub fn image_handle(&self, item_id: ItemId) -> Result<ImageHandle> {
186 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
187 let err = unsafe { lh::heif_context_get_image_handle(self.inner, item_id, &mut handle) };
188 HeifError::from_heif_error(err)?;
189 Ok(ImageHandle::new(handle))
190 }
191
192 pub fn primary_image_handle(&self) -> Result<ImageHandle> {
193 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
194 let err = unsafe { lh::heif_context_get_primary_image_handle(self.inner, &mut handle) };
195 HeifError::from_heif_error(err)?;
196 Ok(ImageHandle::new(handle))
197 }
198
199 pub fn top_level_image_handles(&self) -> Vec<ImageHandle> {
200 let max_count = self.number_of_top_level_images();
201 let mut item_ids = Vec::with_capacity(max_count);
202 unsafe {
203 let count = lh::heif_context_get_list_of_top_level_image_IDs(
204 self.inner,
205 item_ids.as_mut_ptr(),
206 max_count as _,
207 ) as usize;
208 item_ids.set_len(count);
209 }
210 let mut handles = Vec::with_capacity(item_ids.len());
211 for item_id in item_ids {
212 if let Ok(handle) = self.image_handle(item_id) {
213 handles.push(handle);
214 }
215 }
216 handles
217 }
218
219 pub fn encode_image(
223 &mut self,
224 image: &Image,
225 encoder: &mut Encoder,
226 encoding_options: Option<EncodingOptions>,
227 ) -> Result<ImageHandle> {
228 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
229 unsafe {
230 let err = lh::heif_context_encode_image(
231 self.inner,
232 image.inner,
233 encoder.inner,
234 get_encoding_options_ptr(&encoding_options),
235 &mut handle,
236 );
237 HeifError::from_heif_error(err)?;
238 }
239 Ok(ImageHandle::new(handle))
240 }
241
242 pub fn encode_thumbnail(
252 &mut self,
253 image: &Image,
254 master_image_handle: &ImageHandle,
255 bbox_size: u32,
256 encoder: &mut Encoder,
257 encoding_options: Option<EncodingOptions>,
258 ) -> Result<Option<ImageHandle>> {
259 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
260 unsafe {
261 let err = lh::heif_context_encode_thumbnail(
262 self.inner,
263 image.inner,
264 master_image_handle.inner,
265 encoder.inner,
266 get_encoding_options_ptr(&encoding_options),
267 bbox_size.min(i32::MAX as _) as _,
268 &mut handle,
269 );
270 HeifError::from_heif_error(err)?;
271 }
272 Ok(Some(ImageHandle::new(handle)))
273 }
274
275 #[cfg(feature = "v1_18")]
288 pub fn encode_grid(
289 &mut self,
290 tiles: &[Image],
291 rows: NonZeroU16,
292 encoder: &mut Encoder,
293 encoding_options: Option<EncodingOptions>,
294 ) -> Result<Option<ImageHandle>> {
295 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
296 let mut tiles_inners: Vec<*mut lh::heif_image> =
297 tiles.iter().map(|img| img.inner).collect();
298 let rows = rows.get();
299 let columns = (tiles_inners.len() as u32 / rows as u32).min(u16::MAX as _) as u16;
300 unsafe {
301 let err = lh::heif_context_encode_grid(
302 self.inner,
303 tiles_inners.as_mut_ptr(),
304 rows,
305 columns,
306 encoder.inner,
307 get_encoding_options_ptr(&encoding_options),
308 &mut handle,
309 );
310 HeifError::from_heif_error(err)?;
311 }
312 Ok(Some(ImageHandle::new(handle)))
313 }
314
315 pub fn assign_thumbnail(
317 &mut self,
318 master_image_handle: &ImageHandle,
319 thumbnail_image_handle: &ImageHandle,
320 ) -> Result<()> {
321 unsafe {
322 let err = lh::heif_context_assign_thumbnail(
323 self.inner,
324 master_image_handle.inner,
325 thumbnail_image_handle.inner,
326 );
327 HeifError::from_heif_error(err)
328 }
329 }
330
331 pub fn set_primary_image(&mut self, image_handle: &mut ImageHandle) -> Result<()> {
332 unsafe {
333 let err = lh::heif_context_set_primary_image(self.inner, image_handle.inner);
334 HeifError::from_heif_error(err)
335 }
336 }
337
338 pub fn add_generic_metadata<T>(
346 &mut self,
347 image_handle: &ImageHandle,
348 data: &[u8],
349 item_type: T,
350 content_type: Option<&str>,
351 ) -> Result<()>
352 where
353 T: Into<FourCC>,
354 {
355 let c_item_type = str_to_cstring(&item_type.into().to_string(), "item_type")?;
356 let c_content_type = match content_type {
357 Some(s) => Some(str_to_cstring(s, "content_type")?),
358 None => None,
359 };
360 let c_content_type_ptr = c_content_type.map(|s| s.as_ptr()).unwrap_or(ptr::null());
361 let error = unsafe {
362 lh::heif_context_add_generic_metadata(
363 self.inner,
364 image_handle.inner,
365 data.as_ptr() as _,
366 data.len() as _,
367 c_item_type.as_ptr(),
368 c_content_type_ptr,
369 )
370 };
371 HeifError::from_heif_error(error)
372 }
373
374 pub fn add_exif_metadata(&mut self, master_image: &ImageHandle, data: &[u8]) -> Result<()> {
376 let error = unsafe {
377 lh::heif_context_add_exif_metadata(
378 self.inner,
379 master_image.inner,
380 data.as_ptr() as _,
381 data.len() as _,
382 )
383 };
384 HeifError::from_heif_error(error)
385 }
386
387 pub fn add_xmp_metadata(&mut self, master_image: &ImageHandle, data: &[u8]) -> Result<()> {
389 let error = unsafe {
390 lh::heif_context_add_XMP_metadata(
391 self.inner,
392 master_image.inner,
393 data.as_ptr() as _,
394 data.len() as _,
395 )
396 };
397 HeifError::from_heif_error(error)
398 }
399
400 pub fn set_max_decoding_threads(&mut self, max_threads: u32) {
409 let max_threads = max_threads.min(libc::c_int::MAX as u32) as libc::c_int;
410 unsafe { lh::heif_context_set_max_decoding_threads(self.inner, max_threads) };
411 }
412
413 #[cfg(feature = "v1_19")]
418 pub fn security_limits(&self) -> SecurityLimits {
419 let inner_ptr = unsafe { lh::heif_context_get_security_limits(self.inner) };
420 let inner = ptr::NonNull::new(inner_ptr).unwrap();
421 SecurityLimits::from_inner(inner)
422 }
423
424 #[cfg(feature = "v1_19")]
426 pub fn set_security_limits(&mut self, limits: &SecurityLimits) -> Result<()> {
427 let err = unsafe { lh::heif_context_set_security_limits(self.inner, limits.as_inner()) };
428 HeifError::from_heif_error(err)
429 }
430}
431
432impl Drop for HeifContext<'_> {
433 fn drop(&mut self) {
434 unsafe { lh::heif_context_free(self.inner) };
435 }
436}
437
438unsafe impl Send for HeifContext<'_> {}