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;
14#[cfg(feature = "v1_20")]
15use crate::Track;
16use crate::{
17 Encoder, EncodingOptions, HeifError, HeifErrorCode, HeifErrorSubCode, Image, ImageHandle,
18 ItemId, Result,
19};
20
21#[allow(dead_code)]
22enum Source<'a> {
23 None,
24 File,
25 Memory(&'a [u8]),
26 Reader(Box<Box<dyn Reader + 'a>>),
27}
28
29pub struct HeifContext<'a> {
30 pub(crate) inner: *mut lh::heif_context,
31 source: Source<'a>,
32}
33
34impl HeifContext<'static> {
35 pub fn new() -> Result<HeifContext<'static>> {
37 let ctx = unsafe { lh::heif_context_alloc() };
38 if ctx.is_null() {
39 Err(HeifError {
40 code: HeifErrorCode::ContextCreateFailed,
41 sub_code: HeifErrorSubCode::Unspecified,
42 message: String::from(""),
43 })
44 } else {
45 Ok(HeifContext {
46 inner: ctx,
47 source: Source::None,
48 })
49 }
50 }
51
52 pub fn read_from_file(name: &str) -> Result<HeifContext<'static>> {
54 let mut context = HeifContext::new()?;
55 context.read_file(name)?;
56 Ok(context)
57 }
58
59 #[cfg(feature = "v1_18")]
63 pub(crate) unsafe fn from_ptr(ctx: *mut lh::heif_context) -> HeifContext<'static> {
64 HeifContext {
65 inner: ctx,
66 source: Source::None,
67 }
68 }
69}
70
71impl<'a> HeifContext<'a> {
72 pub fn read_file(&mut self, name: &str) -> Result<()> {
74 self.source = Source::File;
75 let c_name = ffi::CString::new(name).unwrap();
76 let err =
77 unsafe { lh::heif_context_read_from_file(self.inner, c_name.as_ptr(), ptr::null()) };
78 HeifError::from_heif_error(err)?;
79 Ok(())
80 }
81
82 pub fn read_reader(&mut self, reader: Box<dyn Reader + 'a>) -> Result<()> {
84 let mut reader_box = Box::new(reader);
85 let user_data = reader_box.as_mut() as *mut _ as *mut c_void;
86 let err = unsafe {
87 lh::heif_context_read_from_reader(self.inner, &HEIF_READER, user_data, ptr::null())
88 };
89 HeifError::from_heif_error(err)?;
90 self.source = Source::Reader(reader_box);
91 Ok(())
92 }
93
94 pub fn read_from_reader(reader: Box<dyn Reader + 'a>) -> Result<HeifContext<'a>> {
96 let mut context = HeifContext::new()?;
97 context.read_reader(reader)?;
98 Ok(context)
99 }
100
101 pub fn read_from_bytes(bytes: &[u8]) -> Result<HeifContext<'_>> {
107 let mut context = HeifContext::new()?;
108 context.read_bytes(bytes)?;
109 Ok(context)
110 }
111
112 pub fn read_bytes<'b: 'a>(&mut self, bytes: &'b [u8]) -> Result<()> {
118 self.source = Source::Memory(bytes);
119 let err = unsafe {
120 lh::heif_context_read_from_memory_without_copy(
121 self.inner,
122 bytes.as_ptr() as _,
123 bytes.len(),
124 ptr::null(),
125 )
126 };
127 HeifError::from_heif_error(err)?;
128 Ok(())
129 }
130
131 unsafe extern "C" fn vector_writer(
132 _ctx: *mut lh::heif_context,
133 data: *const c_void,
134 size: usize,
135 user_data: *mut c_void,
136 ) -> lh::heif_error {
137 let vec: &mut Vec<u8> = &mut *(user_data as *mut Vec<u8>);
138 vec.reserve(size);
139 ptr::copy_nonoverlapping::<u8>(data as _, vec.as_mut_ptr(), size);
140 vec.set_len(size);
141
142 lh::heif_error {
143 code: lh::heif_error_code_heif_error_Ok,
144 subcode: lh::heif_suberror_code_heif_suberror_Unspecified,
145 message: b"\0".as_ptr() as _,
146 }
147 }
148
149 pub fn write_to_bytes(&self) -> Result<Vec<u8>> {
150 let mut res = Vec::<u8>::new();
151 let pointer_to_res = &mut res as *mut _ as *mut c_void;
152
153 let mut writer = lh::heif_writer {
154 writer_api_version: 1,
155 write: Some(Self::vector_writer),
156 };
157
158 let err = unsafe { lh::heif_context_write(self.inner, &mut writer, pointer_to_res) };
159 HeifError::from_heif_error(err)?;
160 Ok(res)
161 }
162
163 pub fn write_to_file(&self, name: &str) -> Result<()> {
164 let c_name = ffi::CString::new(name).unwrap();
165 let err = unsafe { lh::heif_context_write_to_file(self.inner, c_name.as_ptr()) };
166 HeifError::from_heif_error(err)
167 }
168
169 #[deprecated(since = "2.7.0", note = "use 'image_ids' method instead.")]
175 pub fn number_of_top_level_images(&self) -> usize {
176 unsafe { lh::heif_context_get_number_of_top_level_images(self.inner) as _ }
177 }
178
179 #[deprecated(since = "2.7.0", note = "use 'image_ids' method instead.")]
183 pub fn top_level_image_ids(&self, item_ids: &mut [ItemId]) -> usize {
184 if item_ids.is_empty() {
185 0
186 } else {
187 unsafe {
188 lh::heif_context_get_list_of_top_level_image_IDs(
189 self.inner,
190 item_ids.as_mut_ptr(),
191 item_ids.len() as _,
192 ) as usize
193 }
194 }
195 }
196
197 pub fn image_ids(&self) -> Vec<ItemId> {
199 let count = unsafe { lh::heif_context_get_number_of_top_level_images(self.inner) as usize };
200 let mut item_ids = vec![0; count];
201 let real_count = unsafe {
202 lh::heif_context_get_list_of_top_level_image_IDs(
203 self.inner,
204 item_ids.as_mut_ptr(),
205 count as _,
206 ) as usize
207 };
208 item_ids.truncate(real_count);
209 item_ids
210 }
211
212 pub fn image_handle(&self, item_id: ItemId) -> Result<ImageHandle> {
214 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
215 let err = unsafe { lh::heif_context_get_image_handle(self.inner, item_id, &mut handle) };
216 HeifError::from_heif_error(err)?;
217 Ok(ImageHandle::new(handle))
218 }
219
220 pub fn primary_image_handle(&self) -> Result<ImageHandle> {
225 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
226 let err = unsafe { lh::heif_context_get_primary_image_handle(self.inner, &mut handle) };
227 HeifError::from_heif_error(err)?;
228 Ok(ImageHandle::new(handle))
229 }
230
231 pub fn top_level_image_handles(&self) -> Vec<ImageHandle> {
233 let item_ids = self.image_ids();
234 let mut handles = Vec::with_capacity(item_ids.len());
235 for item_id in item_ids {
236 if let Ok(handle) = self.image_handle(item_id) {
237 handles.push(handle);
238 }
239 }
240 handles
241 }
242
243 pub fn encode_image(
248 &mut self,
249 image: &Image,
250 encoder: &mut Encoder,
251 encoding_options: Option<EncodingOptions>,
252 ) -> Result<ImageHandle> {
253 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
254 unsafe {
255 let err = lh::heif_context_encode_image(
256 self.inner,
257 image.inner,
258 encoder.inner,
259 get_encoding_options_ptr(&encoding_options),
260 &mut handle,
261 );
262 HeifError::from_heif_error(err)?;
263 }
264 Ok(ImageHandle::new(handle))
265 }
266
267 pub fn encode_thumbnail(
278 &mut self,
279 image: &Image,
280 master_image_handle: &ImageHandle,
281 bbox_size: u32,
282 encoder: &mut Encoder,
283 encoding_options: Option<EncodingOptions>,
284 ) -> Result<Option<ImageHandle>> {
285 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
286 unsafe {
287 let err = lh::heif_context_encode_thumbnail(
288 self.inner,
289 image.inner,
290 master_image_handle.inner,
291 encoder.inner,
292 get_encoding_options_ptr(&encoding_options),
293 bbox_size.min(i32::MAX as _) as _,
294 &mut handle,
295 );
296 HeifError::from_heif_error(err)?;
297 }
298 Ok(Some(ImageHandle::new(handle)))
299 }
300
301 #[cfg(feature = "v1_18")]
314 pub fn encode_grid(
315 &mut self,
316 tiles: &[Image],
317 rows: NonZeroU16,
318 encoder: &mut Encoder,
319 encoding_options: Option<EncodingOptions>,
320 ) -> Result<Option<ImageHandle>> {
321 let mut handle: *mut lh::heif_image_handle = ptr::null_mut();
322 let mut tiles_inners: Vec<*mut lh::heif_image> =
323 tiles.iter().map(|img| img.inner).collect();
324 let rows = rows.get();
325 let columns = (tiles_inners.len() as u32 / rows as u32).min(u16::MAX as _) as u16;
326 unsafe {
327 let err = lh::heif_context_encode_grid(
328 self.inner,
329 tiles_inners.as_mut_ptr(),
330 rows,
331 columns,
332 encoder.inner,
333 get_encoding_options_ptr(&encoding_options),
334 &mut handle,
335 );
336 HeifError::from_heif_error(err)?;
337 }
338 Ok(Some(ImageHandle::new(handle)))
339 }
340
341 pub fn assign_thumbnail(
343 &mut self,
344 master_image_handle: &ImageHandle,
345 thumbnail_image_handle: &ImageHandle,
346 ) -> Result<()> {
347 unsafe {
348 let err = lh::heif_context_assign_thumbnail(
349 self.inner,
350 master_image_handle.inner,
351 thumbnail_image_handle.inner,
352 );
353 HeifError::from_heif_error(err)
354 }
355 }
356
357 pub fn set_primary_image(&mut self, image_handle: &mut ImageHandle) -> Result<()> {
358 unsafe {
359 let err = lh::heif_context_set_primary_image(self.inner, image_handle.inner);
360 HeifError::from_heif_error(err)
361 }
362 }
363
364 pub fn add_generic_metadata<T>(
373 &mut self,
374 image_handle: &ImageHandle,
375 data: &[u8],
376 item_type: T,
377 content_type: Option<&str>,
378 ) -> Result<()>
379 where
380 T: Into<FourCC>,
381 {
382 let c_item_type = str_to_cstring(&item_type.into().to_string(), "item_type")?;
383 let c_content_type = match content_type {
384 Some(s) => Some(str_to_cstring(s, "content_type")?),
385 None => None,
386 };
387 let c_content_type_ptr = c_content_type.map(|s| s.as_ptr()).unwrap_or(ptr::null());
388 let error = unsafe {
389 lh::heif_context_add_generic_metadata(
390 self.inner,
391 image_handle.inner,
392 data.as_ptr() as _,
393 data.len() as _,
394 c_item_type.as_ptr(),
395 c_content_type_ptr,
396 )
397 };
398 HeifError::from_heif_error(error)
399 }
400
401 pub fn add_exif_metadata(&mut self, master_image: &ImageHandle, data: &[u8]) -> Result<()> {
403 let error = unsafe {
404 lh::heif_context_add_exif_metadata(
405 self.inner,
406 master_image.inner,
407 data.as_ptr() as _,
408 data.len() as _,
409 )
410 };
411 HeifError::from_heif_error(error)
412 }
413
414 pub fn add_xmp_metadata(&mut self, master_image: &ImageHandle, data: &[u8]) -> Result<()> {
416 let error = unsafe {
417 lh::heif_context_add_XMP_metadata(
418 self.inner,
419 master_image.inner,
420 data.as_ptr() as _,
421 data.len() as _,
422 )
423 };
424 HeifError::from_heif_error(error)
425 }
426
427 pub fn set_max_decoding_threads(&mut self, max_threads: u32) {
436 let max_threads = max_threads.min(libc::c_int::MAX as u32) as libc::c_int;
437 unsafe { lh::heif_context_set_max_decoding_threads(self.inner, max_threads) };
438 }
439
440 #[cfg(feature = "v1_19")]
445 pub fn security_limits(&self) -> SecurityLimits {
446 let inner_ptr = unsafe { lh::heif_context_get_security_limits(self.inner) };
447 let inner = ptr::NonNull::new(inner_ptr).unwrap();
448 SecurityLimits::from_inner(inner)
449 }
450
451 #[cfg(feature = "v1_19")]
453 pub fn set_security_limits(&mut self, limits: &SecurityLimits) -> Result<()> {
454 let err = unsafe { lh::heif_context_set_security_limits(self.inner, limits.as_inner()) };
455 HeifError::from_heif_error(err)
456 }
457
458 #[cfg(feature = "v1_20")]
460 pub fn has_sequence(&self) -> bool {
461 unsafe { lh::heif_context_has_sequence(self.inner) != 0 }
462 }
463
464 #[cfg(feature = "v1_20")]
470 pub fn sequence_timescale(&self) -> u32 {
471 unsafe { lh::heif_context_get_sequence_timescale(self.inner) }
472 }
473
474 #[cfg(feature = "v1_20")]
480 pub fn sequence_duration(&self) -> u64 {
481 unsafe { lh::heif_context_get_sequence_duration(self.inner) }
482 }
483
484 #[cfg(feature = "v1_20")]
486 pub fn track_ids(&self) -> Vec<u32> {
487 let num_tracks = unsafe { lh::heif_context_number_of_sequence_tracks(self.inner) as usize };
488 let mut track_ids = vec![0u32; num_tracks];
489
490 unsafe {
491 lh::heif_context_get_track_ids(self.inner, track_ids.as_mut_ptr() as *mut [u32; 0]);
492 }
493
494 track_ids
495 }
496
497 #[cfg(feature = "v1_20")]
506 pub fn track(&self, id: u32) -> Option<Track> {
507 unsafe {
508 let heif_track = lh::heif_context_get_track(self.inner, id);
509 if heif_track.is_null() {
510 None
511 } else {
512 Some(Track::from_heif_track(heif_track))
513 }
514 }
515 }
516}
517
518impl Drop for HeifContext<'_> {
519 fn drop(&mut self) {
520 unsafe { lh::heif_context_free(self.inner) };
521 }
522}
523
524unsafe impl Send for HeifContext<'_> {}