rs_vips/
utils.rs

1// (c) Copyright 2019-2025 OLX
2// (c) Copyright 2025 mrdkprj
3use crate::bindings::{self, g_type_from_name};
4use crate::bindings::{VipsArrayDouble, VipsArrayImage, VipsArrayInt};
5use crate::error::Error;
6use crate::VipsImage;
7use crate::{
8    connection::{VipsSource, VipsTarget},
9    Result,
10};
11use std::ffi::c_void;
12use std::ffi::CString;
13
14pub(crate) struct VipsArrayIntWrapper {
15    pub ctx: *mut VipsArrayInt,
16}
17pub(crate) struct VipsArrayDoubleWrapper {
18    pub ctx: *mut VipsArrayDouble,
19}
20pub(crate) struct VipsArrayImageWrapper {
21    pub ctx: *mut VipsArrayImage,
22}
23
24impl Drop for VipsArrayIntWrapper {
25    fn drop(&mut self) {
26        unsafe {
27            bindings::vips_area_unref(self.ctx as *mut bindings::VipsArea);
28        }
29    }
30}
31
32impl Drop for VipsArrayDoubleWrapper {
33    fn drop(&mut self) {
34        unsafe {
35            bindings::vips_area_unref(self.ctx as *mut bindings::VipsArea);
36        }
37    }
38}
39
40impl Drop for VipsArrayImageWrapper {
41    fn drop(&mut self) {
42        unsafe {
43            bindings::vips_area_unref(self.ctx as *mut bindings::VipsArea);
44        }
45    }
46}
47
48impl From<&[i32]> for VipsArrayIntWrapper {
49    #[inline]
50    fn from(array: &[i32]) -> Self {
51        VipsArrayIntWrapper {
52            ctx: unsafe {
53                bindings::vips_array_int_new(
54                    array.as_ptr(),
55                    array.len() as i32,
56                )
57            },
58        }
59    }
60}
61
62impl From<&[f64]> for VipsArrayDoubleWrapper {
63    #[inline]
64    fn from(array: &[f64]) -> Self {
65        VipsArrayDoubleWrapper {
66            ctx: unsafe {
67                bindings::vips_array_double_new(
68                    array.as_ptr(),
69                    array.len() as i32,
70                )
71            },
72        }
73    }
74}
75
76impl From<&[VipsImage]> for VipsArrayImageWrapper {
77    #[inline]
78    fn from(array: &[VipsImage]) -> Self {
79        let len = array.len() as i32;
80        let as_vips = array
81            .iter()
82            .map(|v| v.ctx)
83            .collect::<Vec<_>>()
84            .as_mut_ptr();
85        VipsArrayImageWrapper {
86            ctx: unsafe {
87                bindings::vips_array_image_new(
88                    as_vips,
89                    len,
90                )
91            },
92        }
93    }
94}
95
96pub(crate) fn vips_image_result(res: *mut bindings::VipsImage, err: Error) -> Result<VipsImage> {
97    if res.is_null() {
98        Err(err.extend())
99    } else {
100        Ok(
101            VipsImage {
102                ctx: res,
103            },
104        )
105    }
106}
107
108pub(crate) fn vips_image_result_ext(res: VipsImage, err: Error) -> Result<VipsImage> {
109    if res
110        .ctx
111        .is_null()
112    {
113        Err(err.extend())
114    } else {
115        Ok(res)
116    }
117}
118
119pub(crate) fn vips_source_result(res: *mut bindings::VipsSource, err: Error) -> Result<VipsSource> {
120    if res.is_null() {
121        Err(err.extend())
122    } else {
123        Ok(
124            VipsSource {
125                ctx: res,
126            },
127        )
128    }
129}
130
131pub(crate) fn vips_target_result(res: *mut bindings::VipsTarget, err: Error) -> Result<VipsTarget> {
132    if res.is_null() {
133        Err(err.extend())
134    } else {
135        Ok(
136            VipsTarget {
137                ctx: res,
138            },
139        )
140    }
141}
142
143#[inline]
144pub fn result<T>(res: i32, output: T, error: Error) -> Result<T> {
145    if res == 0 {
146        Ok(output)
147    } else {
148        Err(error.extend())
149    }
150}
151
152#[inline]
153pub(crate) fn safe_result<F, O, R>(res: i32, output: O, func: F, error: Error) -> Result<R>
154where
155    F: Fn(O) -> R,
156{
157    if res == 0 {
158        Ok(func(
159            output,
160        ))
161    } else {
162        Err(error.extend())
163    }
164}
165
166#[inline]
167pub(crate) fn new_c_string(string: impl Into<Vec<u8>>) -> Result<CString> {
168    CString::new(string)
169        .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
170}
171
172#[inline]
173pub(crate) fn ensure_null_terminated(input: impl AsRef<[u8]>) -> crate::Result<CString> {
174    let bytes = input.as_ref();
175
176    // Check if already null-terminated
177    if bytes.last() == Some(&0) {
178        CString::new(&bytes[..bytes.len() - 1])
179            .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
180    } else {
181        // Not null-terminated, append 0 and create CString
182        CString::new(bytes)
183            .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
184    }
185}
186
187#[inline]
188pub(crate) unsafe fn new_byte_array(buf: *mut c_void, size: u64) -> Vec<u8> {
189    Vec::from_raw_parts(
190        buf as *mut u8,
191        size as usize,
192        size as usize,
193    )
194}
195
196#[inline]
197pub(crate) unsafe fn new_int_array(array: *mut i32, size: u64) -> Vec<i32> {
198    Vec::from(
199        std::slice::from_raw_parts(
200            array,
201            size as usize,
202        ),
203    )
204}
205
206#[inline]
207pub(crate) unsafe fn new_double_array(array: *mut f64, size: u64) -> Vec<f64> {
208    Vec::from(
209        std::slice::from_raw_parts(
210            array,
211            size as usize,
212        ),
213    )
214}
215
216fn vips_image_sizeof_element(image: &bindings::VipsImage) -> usize {
217    unsafe { bindings::vips_format_sizeof_unsafe(image.BandFmt) as usize }
218}
219
220fn vips_image_sizeof_pel(image: &bindings::VipsImage) -> usize {
221    vips_image_sizeof_element(image) * image.Bands as usize
222}
223
224fn vips_image_sizeof_line(image: &bindings::VipsImage) -> usize {
225    vips_image_sizeof_pel(image) * image.Xsize as usize
226}
227
228unsafe fn vips_image_addr(image: &bindings::VipsImage, x: i32, y: i32) -> *mut u8 {
229    let offset =
230        y as usize * vips_image_sizeof_line(image) + x as usize * vips_image_sizeof_pel(image);
231    image
232        .data
233        .add(offset)
234}
235
236pub(crate) unsafe fn vips_matrix(image: &bindings::VipsImage, x: i32, y: i32) -> *mut f64 {
237    vips_image_addr(
238        image, x, y,
239    ) as *mut f64
240}
241
242pub(crate) const G_TYPE_BOOLEAN: &str = "gboolean";
243pub(crate) const G_TYPE_INT: &str = "gint";
244pub(crate) const G_TYPE_UINT64: &str = "guint64";
245pub(crate) const G_TYPE_DOUBLE: &str = "gdouble";
246pub(crate) const G_TYPE_STRING: &str = "gchararray";
247
248pub(crate) fn get_g_type(name: &str) -> u64 {
249    let type_name = new_c_string(name).unwrap();
250    unsafe { g_type_from_name(type_name.as_ptr()) }
251}