1use crate::utils::{cstr_to_str, str_to_cstring};
2use crate::{ChromaDownsamplingAlgorithm, ChromaUpsamplingAlgorithm, HeifError};
3use libheif_sys as lh;
4use std::ffi::CString;
5use std::fmt::{Debug, Formatter};
6use std::ptr;
7use std::sync::Mutex;
8
9static DECODER_MUTEX: Mutex<()> = Mutex::new(());
10
11#[derive(Debug)]
12pub struct DecodingOptions {
13 inner: ptr::NonNull<lh::heif_decoding_options>,
14 decoder_id: Option<CString>,
15}
16
17impl DecodingOptions {
18 pub fn new() -> Option<Self> {
19 let inner_ptr = unsafe { lh::heif_decoding_options_alloc() };
20 ptr::NonNull::new(inner_ptr).map(|inner| Self {
21 inner,
22 decoder_id: None,
23 })
24 }
25}
26
27impl Drop for DecodingOptions {
28 fn drop(&mut self) {
29 unsafe {
30 lh::heif_decoding_options_free(self.inner.as_ptr());
31 }
32 }
33}
34
35impl DecodingOptions {
36 #[inline(always)]
37 fn inner_ref(&self) -> &lh::heif_decoding_options {
38 unsafe { self.inner.as_ref() }
39 }
40
41 #[inline(always)]
42 pub(crate) fn inner_mut(&mut self) -> &mut lh::heif_decoding_options {
43 unsafe { self.inner.as_mut() }
44 }
45
46 #[inline]
47 pub fn version(&self) -> u8 {
48 self.inner_ref().version
49 }
50
51 #[inline]
54 pub fn ignore_transformations(&self) -> bool {
55 self.inner_ref().ignore_transformations != 0
56 }
57
58 #[inline]
59 pub fn set_ignore_transformations(&mut self, enable: bool) {
60 self.inner_mut().ignore_transformations = if enable { 1 } else { 0 }
61 }
62
63 #[inline]
64 pub fn convert_hdr_to_8bit(&self) -> bool {
65 self.inner_ref().convert_hdr_to_8bit != 0
66 }
67
68 #[inline]
69 pub fn set_convert_hdr_to_8bit(&mut self, enable: bool) {
70 self.inner_mut().convert_hdr_to_8bit = if enable { 1 } else { 0 }
71 }
72
73 pub fn strict_decoding(&self) -> bool {
77 self.inner_ref().strict_decoding != 0
78 }
79
80 pub fn set_strict_decoding(&mut self, enable: bool) {
81 self.inner_mut().strict_decoding = if enable { 1 } else { 0 }
82 }
83
84 pub fn decoder_id(&self) -> Option<&str> {
88 cstr_to_str(self.inner_ref().decoder_id)
89 }
90
91 pub fn set_decoder_id(&mut self, decoder_id: Option<&str>) -> Result<(), HeifError> {
92 if let Some(decoder_id) = decoder_id {
93 let c_decoder_id = str_to_cstring(decoder_id, "decoder_id")?;
94 self.inner_mut().decoder_id = c_decoder_id.as_ptr();
95 self.decoder_id = Some(c_decoder_id);
96 } else {
97 self.inner_mut().decoder_id = ptr::null() as _;
98 self.decoder_id = None;
99 }
100 Ok(())
101 }
102
103 pub fn color_conversion_options(&self) -> ColorConversionOptions {
104 let lh_options = self.inner_ref().color_conversion_options;
105 ColorConversionOptions {
106 preferred_chroma_downsampling_algorithm: ChromaDownsamplingAlgorithm::n(
107 lh_options.preferred_chroma_downsampling_algorithm,
108 )
109 .unwrap_or(ChromaDownsamplingAlgorithm::Average),
110 preferred_chroma_upsampling_algorithm: ChromaUpsamplingAlgorithm::n(
111 lh_options.preferred_chroma_upsampling_algorithm,
112 )
113 .unwrap_or(ChromaUpsamplingAlgorithm::Bilinear),
114 only_use_preferred_chroma_algorithm: lh_options.only_use_preferred_chroma_algorithm
115 != 0,
116 }
117 }
118
119 pub fn set_color_conversion_options(&mut self, options: ColorConversionOptions) {
120 let lh_options = &mut self.inner_mut().color_conversion_options;
121 lh_options.preferred_chroma_downsampling_algorithm =
122 options.preferred_chroma_downsampling_algorithm as _;
123 lh_options.preferred_chroma_upsampling_algorithm =
124 options.preferred_chroma_upsampling_algorithm as _;
125 lh_options.only_use_preferred_chroma_algorithm =
126 options.only_use_preferred_chroma_algorithm as _;
127 }
128}
129
130pub(crate) fn get_decoding_options_ptr(
133 options: &Option<DecodingOptions>,
134) -> *mut lh::heif_decoding_options {
135 options
136 .as_ref()
137 .map(|o| o.inner.as_ptr())
138 .unwrap_or_else(ptr::null_mut)
139}
140
141#[repr(C)]
142#[derive(Debug, Copy, Clone)]
143pub struct ColorConversionOptions {
144 pub preferred_chroma_downsampling_algorithm: ChromaDownsamplingAlgorithm,
145 pub preferred_chroma_upsampling_algorithm: ChromaUpsamplingAlgorithm,
146 pub only_use_preferred_chroma_algorithm: bool,
149}
150
151#[derive(Copy, Clone)]
152pub struct DecoderDescriptor<'a> {
153 inner: &'a lh::heif_decoder_descriptor,
154}
155
156impl<'a> DecoderDescriptor<'a> {
157 pub(crate) fn new(inner: &'a lh::heif_decoder_descriptor) -> Self {
158 Self { inner }
159 }
160
161 pub fn id(&self) -> &str {
164 let name = unsafe { lh::heif_decoder_descriptor_get_id_name(self.inner) };
165 cstr_to_str(name).unwrap_or_default()
166 }
167
168 pub fn name(&self) -> String {
171 let _lock = DECODER_MUTEX.lock();
174 let name = unsafe { lh::heif_decoder_descriptor_get_name(self.inner) };
175 cstr_to_str(name).unwrap_or_default().to_owned()
176 }
177}
178
179impl<'a> Debug for DecoderDescriptor<'a> {
180 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
181 f.debug_struct("DecoderDescriptor")
182 .field("id", &self.id())
183 .field("name", &self.name())
184 .finish()
185 }
186}