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 mut images = array
81            .iter()
82            .map(|v| v.ctx)
83            .collect::<Vec<_>>();
84        VipsArrayImageWrapper {
85            ctx: unsafe {
86                bindings::vips_array_image_new(
87                    images.as_mut_ptr(),
88                    len,
89                )
90            },
91        }
92    }
93}
94
95pub(crate) fn vips_image_result(res: *mut bindings::VipsImage, err: Error) -> Result<VipsImage> {
96    if res.is_null() {
97        Err(err.extend())
98    } else {
99        Ok(
100            VipsImage {
101                ctx: res,
102            },
103        )
104    }
105}
106
107pub(crate) fn vips_image_result_ext(res: VipsImage, err: Error) -> Result<VipsImage> {
108    if res
109        .ctx
110        .is_null()
111    {
112        Err(err.extend())
113    } else {
114        Ok(res)
115    }
116}
117
118pub(crate) fn vips_source_result(res: *mut bindings::VipsSource, err: Error) -> Result<VipsSource> {
119    if res.is_null() {
120        Err(err.extend())
121    } else {
122        Ok(
123            VipsSource {
124                ctx: res,
125            },
126        )
127    }
128}
129
130pub(crate) fn vips_target_result(res: *mut bindings::VipsTarget, err: Error) -> Result<VipsTarget> {
131    if res.is_null() {
132        Err(err.extend())
133    } else {
134        Ok(
135            VipsTarget {
136                ctx: res,
137            },
138        )
139    }
140}
141
142#[inline]
143pub fn result<T>(res: i32, output: T, error: Error) -> Result<T> {
144    if res == 0 {
145        Ok(output)
146    } else {
147        Err(error.extend())
148    }
149}
150
151#[inline]
152pub(crate) fn safe_result<F, O, R>(res: i32, output: O, func: F, error: Error) -> Result<R>
153where
154    F: Fn(O) -> R,
155{
156    if res == 0 {
157        Ok(func(
158            output,
159        ))
160    } else {
161        Err(error.extend())
162    }
163}
164
165#[inline]
166pub(crate) fn new_c_string(string: impl Into<Vec<u8>>) -> Result<CString> {
167    CString::new(string)
168        .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
169}
170
171#[inline]
172pub(crate) fn ensure_null_terminated(input: impl AsRef<[u8]>) -> crate::Result<CString> {
173    let bytes = input.as_ref();
174
175    // Check if already null-terminated
176    if bytes.last() == Some(&0) {
177        CString::new(&bytes[..bytes.len() - 1])
178            .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
179    } else {
180        // Not null-terminated, append 0 and create CString
181        CString::new(bytes)
182            .map_err(|_| Error::InitializationError("Error initializing C string.".to_string()))
183    }
184}
185
186#[inline]
187pub(crate) unsafe fn new_byte_array(buf: *mut c_void, size: u64) -> Vec<u8> {
188    Vec::from_raw_parts(
189        buf as *mut u8,
190        size as usize,
191        size as usize,
192    )
193}
194
195#[inline]
196pub(crate) unsafe fn new_int_array(array: *mut i32, size: u64) -> Vec<i32> {
197    Vec::from(
198        std::slice::from_raw_parts(
199            array,
200            size as usize,
201        ),
202    )
203}
204
205#[inline]
206pub(crate) unsafe fn new_double_array(array: *mut f64, size: u64) -> Vec<f64> {
207    Vec::from(
208        std::slice::from_raw_parts(
209            array,
210            size as usize,
211        ),
212    )
213}
214
215fn vips_image_sizeof_element(image: &bindings::VipsImage) -> usize {
216    unsafe { bindings::vips_format_sizeof_unsafe(image.BandFmt) as usize }
217}
218
219fn vips_image_sizeof_pel(image: &bindings::VipsImage) -> usize {
220    vips_image_sizeof_element(image) * image.Bands as usize
221}
222
223fn vips_image_sizeof_line(image: &bindings::VipsImage) -> usize {
224    vips_image_sizeof_pel(image) * image.Xsize as usize
225}
226
227unsafe fn vips_image_addr(image: &bindings::VipsImage, x: i32, y: i32) -> *mut u8 {
228    let offset =
229        y as usize * vips_image_sizeof_line(image) + x as usize * vips_image_sizeof_pel(image);
230    image
231        .data
232        .add(offset)
233}
234
235pub(crate) unsafe fn vips_matrix(image: &bindings::VipsImage, x: i32, y: i32) -> *mut f64 {
236    vips_image_addr(
237        image, x, y,
238    ) as *mut f64
239}
240
241pub(crate) const G_TYPE_BOOLEAN: &str = "gboolean";
242pub(crate) const G_TYPE_INT: &str = "gint";
243pub(crate) const G_TYPE_UINT64: &str = "guint64";
244pub(crate) const G_TYPE_DOUBLE: &str = "gdouble";
245pub(crate) const G_TYPE_STRING: &str = "gchararray";
246
247pub(crate) fn get_g_type(name: &str) -> u64 {
248    let type_name = new_c_string(name).unwrap();
249    unsafe { g_type_from_name(type_name.as_ptr()) }
250}