libvips/
image.rs

1// (c) Copyright 2019-2025 OLX
2use crate::bindings;
3use crate::error::Error;
4use crate::ops::*;
5use crate::utils;
6use crate::Result;
7
8use num_traits::{FromPrimitive, ToPrimitive};
9use std::borrow::Cow;
10use std::convert::TryInto;
11use std::ffi::*;
12use std::ptr::null_mut;
13
14const NULL: *const c_void = null_mut();
15
16#[derive(Debug, Clone)]
17pub struct VipsImage {
18    pub(crate) ctx: *mut bindings::VipsImage,
19}
20
21#[derive(Debug, Clone)]
22pub struct VipsInterpolate {
23    pub(crate) ctx: *mut bindings::VipsInterpolate,
24}
25
26#[derive(Debug, Clone)]
27pub struct VipsBlob {
28    pub(crate) ctx: *mut bindings::VipsBlob,
29}
30
31#[derive(Debug, Clone)]
32pub struct VipsConnection {
33    pub(crate) ctx: *mut bindings::VipsConnection,
34}
35
36#[derive(Debug, Clone)]
37pub struct VipsSource {
38    pub(crate) ctx: *mut bindings::VipsSource,
39}
40
41#[derive(Debug, Clone)]
42pub struct VipsTarget {
43    pub(crate) ctx: *mut bindings::VipsTarget,
44}
45
46/// This is the main type of vips. It represents an image and most operations will take one as input and output a new one.
47/// In the moment this type is not thread safe. Be careful working within thread environments.
48impl VipsImage {
49    pub fn new() -> VipsImage {
50        VipsImage {
51            ctx: unsafe { bindings::vips_image_new() },
52        }
53    }
54
55    pub fn new_memory() -> Result<VipsImage> {
56        unsafe {
57            let res = bindings::vips_image_new_memory();
58            vips_image_result(res, Error::InitializationError("Could not generate object"))
59        }
60    }
61
62    pub fn new_from_file(filename: &str) -> Result<VipsImage> {
63        unsafe {
64            let f = utils::new_c_string(filename)?;
65            let res = bindings::vips_image_new_from_file(f.as_ptr(), NULL);
66            vips_image_result(
67                res,
68                Error::InitializationError("Could not initialise VipsImage from file"),
69            )
70        }
71    }
72
73    pub fn new_from_file_rw(filename: &str) -> Result<VipsImage> {
74        unsafe {
75            let f = utils::new_c_string(filename)?;
76            let res = bindings::vips_image_new_from_file_RW(f.as_ptr());
77            vips_image_result(
78                res,
79                Error::InitializationError("Could not initialise VipsImage from file"),
80            )
81        }
82    }
83
84    pub fn new_from_file_raw(
85        filename: &str,
86        x_size: i32,
87        y_size: i32,
88        bands: i32,
89        offset: u64,
90    ) -> Result<VipsImage> {
91        unsafe {
92            let f = utils::new_c_string(filename)?;
93            let res =
94                bindings::vips_image_new_from_file_raw(f.as_ptr(), x_size, y_size, bands, offset);
95            vips_image_result(
96                res,
97                Error::InitializationError("Could not initialise VipsImage from file"),
98            )
99        }
100    }
101
102    pub fn new_from_file_access(filename: &str, access: Access, memory: bool) -> Result<VipsImage> {
103        unsafe {
104            let access_str = utils::new_c_string("access")?;
105            let memory_str = utils::new_c_string("memory")?;
106            let f = utils::new_c_string(filename)?;
107            let res = bindings::vips_image_new_from_file(
108                f.as_ptr(),
109                access_str.as_ptr(),
110                access as i32,
111                memory_str.as_ptr(),
112                if memory { 1 } else { 0 },
113                NULL,
114            );
115            vips_image_result(
116                res,
117                Error::InitializationError("Could not initialise VipsImage from file"),
118            )
119        }
120    }
121
122    pub fn new_from_buffer(buffer: &[u8], option_str: &str) -> Result<VipsImage> {
123        unsafe {
124            let options = utils::new_c_string(option_str)?;
125            let res = bindings::vips_image_new_from_buffer(
126                buffer.as_ptr() as *const c_void,
127                buffer.len() as u64,
128                options.as_ptr(),
129                NULL,
130            );
131            vips_image_result(
132                res,
133                Error::InitializationError("Could not initialise VipsImage from file"),
134            )
135        }
136    }
137
138    pub fn new_from_memory(
139        buffer: &[u8],
140        width: i32,
141        height: i32,
142        bands: i32,
143        format: BandFormat,
144    ) -> Result<VipsImage> {
145        unsafe {
146            if let Some(format) = format.to_i32() {
147                let res = bindings::vips_image_new_from_memory(
148                    buffer.as_ptr() as *const c_void,
149                    buffer.len() as u64,
150                    width,
151                    height,
152                    bands,
153                    format,
154                );
155                vips_image_result(
156                    res,
157                    Error::InitializationError("Could not initialise VipsImage from memory"),
158                )
159            } else {
160                Err(Error::InitializationError(
161                    "Invalid BandFormat. Please file a bug report, as this should never happen.",
162                ))
163            }
164        }
165    }
166
167    pub fn image_new_matrix(width: i32, height: i32) -> Result<VipsImage> {
168        unsafe {
169            let res = bindings::vips_image_new_matrix(width, height);
170            vips_image_result(
171                res,
172                Error::InitializationError("Could not initialise VipsImage from file"),
173            )
174        }
175    }
176
177    pub fn image_new_matrix_from_array(
178        width: i32,
179        height: i32,
180        array: &[f64],
181    ) -> Result<VipsImage> {
182        unsafe {
183            let res = bindings::vips_image_new_matrix_from_array(
184                width,
185                height,
186                array.as_ptr(),
187                array.len() as i32,
188            );
189            vips_image_result(
190                res,
191                Error::InitializationError("Could not initialise VipsImage from file"),
192            )
193        }
194    }
195
196    pub fn new_from_image(image: &VipsImage, array: &[f64]) -> Result<VipsImage> {
197        unsafe {
198            let res =
199                bindings::vips_image_new_from_image(image.ctx, array.as_ptr(), array.len() as i32);
200            vips_image_result(
201                res,
202                Error::InitializationError("Could not initialise VipsImage from Object"),
203            )
204        }
205    }
206
207    pub fn new_from_image1(image: &VipsImage, c: f64) -> Result<VipsImage> {
208        unsafe {
209            let res = bindings::vips_image_new_from_image1(image.ctx, c);
210            vips_image_result(
211                res,
212                Error::InitializationError("Could not initialise VipsImage from Object"),
213            )
214        }
215    }
216
217    pub fn image_new_temp_file(format: &str) -> Result<VipsImage> {
218        unsafe {
219            let format_c_str = utils::new_c_string(format)?;
220            let res = bindings::vips_image_new_temp_file(format_c_str.as_ptr());
221            vips_image_result(
222                res,
223                Error::InitializationError("Could not initialise VipsImage from format"),
224            )
225        }
226    }
227
228    pub fn image_copy_memory(image: VipsImage) -> Result<VipsImage> {
229        unsafe {
230            let result = bindings::vips_image_copy_memory(image.ctx);
231            vips_image_result(result, Error::OperationError("Could not copy memory"))
232        }
233    }
234
235    pub fn image_wio_input(&mut self) -> Result<()> {
236        unsafe {
237            let result = bindings::vips_image_wio_input(self.ctx);
238            utils::result(
239                result,
240                (),
241                Error::OperationError("Error on vips image_wio_input"),
242            )
243        }
244    }
245
246    pub fn get_filename(&self) -> std::result::Result<&str, std::str::Utf8Error> {
247        unsafe {
248            let filename = bindings::vips_image_get_filename(self.ctx);
249            let res = CStr::from_ptr(filename);
250            res.to_str()
251        }
252    }
253
254    pub fn get_width(&self) -> i32 {
255        unsafe { bindings::vips_image_get_width(self.ctx) }
256    }
257
258    pub fn get_height(&self) -> i32 {
259        unsafe { bindings::vips_image_get_height(self.ctx) }
260    }
261
262    pub fn get_xoffset(&self) -> i32 {
263        unsafe { bindings::vips_image_get_xoffset(self.ctx) }
264    }
265
266    pub fn get_yoffset(&self) -> i32 {
267        unsafe { bindings::vips_image_get_yoffset(self.ctx) }
268    }
269
270    pub fn get_scale(&self) -> f64 {
271        unsafe { bindings::vips_image_get_scale(self.ctx) }
272    }
273
274    pub fn get_offset(&self) -> f64 {
275        unsafe { bindings::vips_image_get_offset(self.ctx) }
276    }
277
278    pub fn get_xres(&self) -> f64 {
279        unsafe { bindings::vips_image_get_xres(self.ctx) }
280    }
281
282    pub fn get_yres(&self) -> f64 {
283        unsafe { bindings::vips_image_get_yres(self.ctx) }
284    }
285
286    pub fn get_bands(&self) -> i32 {
287        unsafe { bindings::vips_image_get_bands(self.ctx) }
288    }
289
290    pub fn get_page_height(&self) -> i32 {
291        unsafe { bindings::vips_image_get_page_height(self.ctx) }
292    }
293
294    pub fn get_n_pages(&self) -> i32 {
295        unsafe { bindings::vips_image_get_n_pages(self.ctx) }
296    }
297
298    pub fn get_coding(&self) -> Result<Coding> {
299        unsafe {
300            let res = bindings::vips_image_get_format(self.ctx);
301            let format_enum = FromPrimitive::from_i32(res);
302            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
303        }
304    }
305
306    pub fn get_format(&self) -> Result<BandFormat> {
307        unsafe {
308            let res = bindings::vips_image_get_format(self.ctx);
309            let format_enum = FromPrimitive::from_i32(res);
310            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
311        }
312    }
313
314    pub fn guess_format(&self) -> Result<BandFormat> {
315        unsafe {
316            let res = bindings::vips_image_guess_format(self.ctx);
317            let format_enum = FromPrimitive::from_i32(res);
318            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
319        }
320    }
321
322    pub fn get_orientation(&self) -> i32 {
323        unsafe { bindings::vips_image_get_orientation(self.ctx) }
324    }
325
326    pub fn get_interpretation(&self) -> Result<Interpretation> {
327        unsafe {
328            let res = bindings::vips_image_get_interpretation(self.ctx);
329            let format_enum = FromPrimitive::from_i32(res);
330            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
331        }
332    }
333
334    pub fn guess_interpretation(&self) -> Result<Interpretation> {
335        unsafe {
336            let res = bindings::vips_image_guess_interpretation(self.ctx);
337            let format_enum = FromPrimitive::from_i32(res);
338            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
339        }
340    }
341
342    pub fn image_set_delete_on_close(&mut self, flag: bool) {
343        unsafe {
344            bindings::vips_image_set_delete_on_close(self.ctx, if flag { 1 } else { 0 });
345        }
346    }
347
348    pub fn image_invalidate_all(&self) {
349        unsafe {
350            bindings::vips_image_invalidate_all(self.ctx);
351        }
352    }
353
354    pub fn image_minimise_all(&self) {
355        unsafe {
356            bindings::vips_image_minimise_all(self.ctx);
357        }
358    }
359
360    pub fn image_iskilled(&self) -> bool {
361        unsafe { bindings::vips_image_iskilled(self.ctx) == 1 }
362    }
363
364    pub fn image_isMSBfirst(&self) -> bool {
365        unsafe { bindings::vips_image_isMSBfirst(self.ctx) == 1 }
366    }
367
368    pub fn image_isfile(&self) -> bool {
369        unsafe { bindings::vips_image_isfile(self.ctx) == 1 }
370    }
371
372    pub fn image_ispartial(&self) -> bool {
373        unsafe { bindings::vips_image_ispartial(self.ctx) == 1 }
374    }
375
376    pub fn image_hasalpha(&self) -> bool {
377        unsafe { bindings::vips_image_hasalpha(self.ctx) == 1 }
378    }
379
380    pub fn image_set_kill(&self, flag: bool) {
381        unsafe {
382            bindings::vips_image_set_kill(self.ctx, if flag { 1 } else { 0 });
383        }
384    }
385
386    pub fn image_set_progress(&self, flag: bool) {
387        unsafe {
388            bindings::vips_image_set_progress(self.ctx, if flag { 1 } else { 0 });
389        }
390    }
391
392    pub fn image_write(&self) -> Result<VipsImage> {
393        unsafe {
394            let out: *mut bindings::VipsImage = null_mut();
395            let res = bindings::vips_image_write(self.ctx, out);
396            utils::result(
397                res,
398                VipsImage { ctx: out },
399                Error::IOError("Cannot write input to output"),
400            )
401        }
402    }
403
404    pub fn image_pio_input(&mut self) -> Result<()> {
405        unsafe {
406            let res = bindings::vips_image_pio_input(self.ctx);
407            utils::result(res, (), Error::IOError("Cannot read image"))
408        }
409    }
410
411    pub fn image_pio_output(&mut self) -> Result<()> {
412        unsafe {
413            let res = bindings::vips_image_pio_output(self.ctx);
414            utils::result(res, (), Error::IOError("Cannot write image"))
415        }
416    }
417
418    pub fn image_inplace(&self) -> Result<()> {
419        unsafe {
420            let res = bindings::vips_image_inplace(self.ctx);
421            utils::result(res, (), Error::IOError("Cannot cannot be modified inplace"))
422        }
423    }
424
425    pub fn image_write_to_file(&self, filename: &str) -> Result<()> {
426        unsafe {
427            let file_c_str = utils::new_c_string(filename)?;
428            let res = bindings::vips_image_write_to_file(self.ctx, file_c_str.as_ptr(), NULL);
429            utils::result(res, (), Error::IOError("Cannot write to file"))
430        }
431    }
432
433    pub fn image_write_prepare(&self) -> Result<()> {
434        unsafe {
435            let res = bindings::vips_image_write_prepare(self.ctx);
436            utils::result(res, (), Error::IOError("Cannot prepare file to write"))
437        }
438    }
439
440    pub fn image_write_to_buffer(&self, suffix: &str) -> Result<Vec<u8>> {
441        unsafe {
442            let mut buffer_buf_size: u64 = 0;
443            let mut buffer_out: *mut c_void = null_mut();
444            let suffix_c_str = utils::new_c_string(suffix)?;
445            let res = bindings::vips_image_write_to_buffer(
446                self.ctx,
447                suffix_c_str.as_ptr(),
448                &mut buffer_out,
449                &mut buffer_buf_size,
450                NULL,
451            );
452            utils::result(
453                res,
454                utils::new_byte_array(buffer_out, buffer_buf_size),
455                Error::IOError("Cannot write content to buffer"),
456            )
457        }
458    }
459
460    pub fn image_write_to_memory(&self) -> Vec<u8> {
461        unsafe {
462            let mut buffer_buf_size: u64 = 0;
463            let buffer_out = bindings::vips_image_write_to_memory(self.ctx, &mut buffer_buf_size);
464            let buf = std::slice::from_raw_parts(buffer_out as *mut u8, buffer_buf_size as usize).to_vec();
465            bindings::g_free(buffer_out);
466            buf
467        }
468    }
469
470    pub fn image_decode_predict(&self) -> Result<(i32, BandFormat)> {
471        unsafe {
472            let mut out_bands = 0;
473            let mut out_format = 0;
474            let res =
475                bindings::vips_image_decode_predict(self.ctx, &mut out_bands, &mut out_format);
476            let format_enum = FromPrimitive::from_i32(out_format);
477            if format_enum.is_some() {
478                utils::result(
479                    res,
480                    (out_bands, format_enum.unwrap()),
481                    Error::IOError("Could not predict image format"),
482                )
483            } else {
484                Err(Error::IOError("Could not predict image format"))
485            }
486        }
487    }
488
489    pub fn image_decode(&self) -> Result<VipsImage> {
490        unsafe {
491            let mut out: *mut bindings::VipsImage = null_mut();
492            let res = bindings::vips_image_decode(self.ctx, &mut out);
493            utils::result(
494                res,
495                VipsImage { ctx: out },
496                Error::IOError("Cannot decode image"),
497            )
498        }
499    }
500
501    pub fn image_encode(&self, coding: Coding) -> Result<VipsImage> {
502        unsafe {
503            let mut out: *mut bindings::VipsImage = null_mut();
504            let res = bindings::vips_image_encode(self.ctx, &mut out, coding as i32);
505            utils::result(
506                res,
507                VipsImage { ctx: out },
508                Error::IOError("Cannot encode image"),
509            )
510        }
511    }
512}
513
514impl VipsConnection {
515    pub fn connection_filename(&self) -> Option<String> {
516        unsafe {
517            let result = bindings::vips_connection_filename(self.ctx);
518            if result.is_null() {
519                None
520            } else {
521                let cstr = CStr::from_ptr(result);
522                match cstr.to_string_lossy() {
523                    Cow::Borrowed(slice) => Some(slice.to_string()),
524                    Cow::Owned(string) => Some(string),
525                }
526            }
527        }
528    }
529
530    pub fn connection_nick(&self) -> Option<String> {
531        unsafe {
532            let result = bindings::vips_connection_nick(self.ctx);
533            if result.is_null() {
534                None
535            } else {
536                let cstr = CStr::from_ptr(result);
537                match cstr.to_string_lossy() {
538                    Cow::Borrowed(slice) => Some(slice.to_string()),
539                    Cow::Owned(string) => Some(string),
540                }
541            }
542        }
543    }
544}
545
546impl VipsSource {
547    pub fn new_from_descriptor(descriptor: i32) -> Result<Self> {
548        unsafe {
549            let res = bindings::vips_source_new_from_descriptor(descriptor);
550            vips_source_result(
551                res,
552                Error::InitializationError("Could not initialise VipsSource from descriptor"),
553            )
554        }
555    }
556
557    pub fn new_from_file(filename: &str) -> Result<Self> {
558        unsafe {
559            let f = utils::new_c_string(filename)?;
560            let res = bindings::vips_source_new_from_file(f.as_ptr());
561            vips_source_result(
562                res,
563                Error::InitializationError("Could not initialise VipsSource from file"),
564            )
565        }
566    }
567
568    // not sure if it this is safe
569    // should test before making it public
570    fn new_from_blob(blob: VipsBlob) -> Result<Self> {
571        unsafe {
572            let res = bindings::vips_source_new_from_blob(blob.ctx);
573            vips_source_result(
574                res,
575                Error::InitializationError("Could not initialise VipsSource from blob"),
576            )
577        }
578    }
579
580    pub fn new_from_memory(buffer: &[u8]) -> Result<Self> {
581        unsafe {
582            let res = bindings::vips_source_new_from_memory(
583                buffer.as_ptr() as *const c_void,
584                buffer.len() as u64,
585            );
586            vips_source_result(
587                res,
588                Error::InitializationError("Could not initialise VipsSource from memory"),
589            )
590        }
591    }
592
593    pub fn new_from_options(option_str: &str) -> Result<Self> {
594        unsafe {
595            let options = utils::new_c_string(option_str)?;
596            let res = bindings::vips_source_new_from_options(options.as_ptr());
597            vips_source_result(
598                res,
599                Error::InitializationError("Could not initialise VipsSource from options"),
600            )
601        }
602    }
603
604    pub fn minimise(&mut self) {
605        unsafe {
606            bindings::vips_source_minimise(self.ctx);
607        }
608    }
609
610    pub fn unminimise(&mut self) -> Result<()> {
611        unsafe {
612            let result = bindings::vips_source_unminimise(self.ctx);
613            utils::result(
614                result,
615                (),
616                Error::OperationError("Error on vips unminimise"),
617            )
618        }
619    }
620
621    pub fn decode(&mut self) -> Result<()> {
622        unsafe {
623            let result = bindings::vips_source_decode(self.ctx);
624            utils::result(
625                result,
626                (),
627                Error::OperationError("Error on vips decode"),
628            )
629        }
630    }
631
632    pub fn read(&mut self, length: u64) -> Result<Vec<u8>> {
633        unsafe {
634            let bytes: *mut c_void = null_mut();
635            let result = bindings::vips_source_read(self.ctx, bytes, length);
636            if result != -1 {
637                let buffer =
638                    Vec::from_raw_parts(bytes as *mut u8, result as usize, result as usize);
639                Ok(buffer)
640            } else {
641                Err(Error::OperationError("Error on vips read"))
642            }
643        }
644    }
645
646    pub fn is_mappable(&self) -> bool {
647        unsafe { bindings::vips_source_is_mappable(self.ctx) == 1 }
648    }
649
650    pub fn seek(&mut self, offset: i64, whence: i32) -> Result<i64> {
651        unsafe {
652            let result = bindings::vips_source_seek(self.ctx, offset, whence);
653            if result == -1 {
654                Err(Error::OperationError("Error on vips seek"))
655            } else {
656                Ok(result)
657            }
658        }
659    }
660
661    pub fn rewind(&mut self) -> Result<()> {
662        unsafe {
663            let result = bindings::vips_source_rewind(self.ctx);
664            if result == -1 {
665                Err(Error::OperationError("Error on vips rewind"))
666            } else {
667                Ok(())
668            }
669        }
670    }
671
672    pub fn length(&self) -> Result<i64> {
673        unsafe {
674            let result = bindings::vips_source_length(self.ctx);
675            if result == -1 {
676                Err(Error::OperationError("Error on vips length"))
677            } else {
678                Ok(result)
679            }
680        }
681    }
682}
683
684impl<'a> VipsSource {
685    pub fn map(&'a self) -> Result<&'a [u8]> {
686        unsafe {
687            let length: *mut u64 = null_mut();
688            let result = bindings::vips_source_map(self.ctx, length);
689            if length.is_null() {
690                Err(Error::OperationError("Error on vips map"))
691            } else {
692                let size = (*length)
693                    .try_into()
694                    .map_err(|_| Error::OperationError("Can't get size of array"))?;
695                Ok(std::slice::from_raw_parts(result as *mut u8, size))
696            }
697        }
698    }
699
700    // pub fn map_blob(&'a self) -> Result<&'a VipsBlob> {
701    //     unsafe {
702    //         let result = bindings::vips_source_map_blob(self.ctx);
703    //         if result.is_null() {
704    //             Err(Error::OperationError("Error on vips map blob"))
705    //         } else {
706    //             Ok(&VipsBlob { ctx: result })
707    //         }
708    //     }
709    // }
710}
711
712impl VipsTarget {
713    pub fn new_to_descriptor(descriptor: i32) -> Result<Self> {
714        unsafe {
715            let res = bindings::vips_target_new_to_descriptor(descriptor);
716            vips_target_result(
717                res,
718                Error::InitializationError("Could not initialise VipsTarget from descriptor"),
719            )
720        }
721    }
722
723    pub fn new_to_file(filename: &str) -> Result<Self> {
724        unsafe {
725            let f = utils::new_c_string(filename)?;
726            let res = bindings::vips_target_new_to_file(f.as_ptr());
727            vips_target_result(
728                res,
729                Error::InitializationError("Could not initialise VipsTarget from file"),
730            )
731        }
732    }
733
734    pub fn new_to_memory() -> Result<Self> {
735        unsafe {
736            let res = bindings::vips_target_new_to_memory();
737            vips_target_result(
738                res,
739                Error::InitializationError("Could not initialise VipsTarget from memory"),
740            )
741        }
742    }
743
744    pub fn write(&mut self, buffer: &[u8]) -> Result<()> {
745        unsafe {
746            let res = bindings::vips_target_write(
747                self.ctx,
748                buffer.as_ptr() as *const c_void,
749                buffer.len() as u64,
750            );
751            if res == -1 {
752                Err(Error::OperationError("Could not write to buffer"))
753            } else {
754                Ok(())
755            }
756        }
757    }
758
759    pub fn finish(self) {
760        unsafe {
761            bindings::vips_target_finish(self.ctx);
762        }
763    }
764
765    pub fn putc(&mut self, ch: char) -> Result<()> {
766        unsafe {
767            let res = bindings::vips_target_putc(self.ctx, ch as i32);
768            if res == -1 {
769                Err(Error::OperationError("Could not write to buffer"))
770            } else {
771                Ok(())
772            }
773        }
774    }
775
776    pub fn writes(&mut self, text: &str) -> Result<()> {
777        unsafe {
778            let cstr = CString::new(text).map_err(|_| Error::OperationError("Cannot initialize C string"))?;
779            let res = bindings::vips_target_writes(self.ctx, cstr.as_ptr());
780            if res == -1 {
781                Err(Error::OperationError("Could not write to buffer"))
782            } else {
783                Ok(())
784            }
785        }
786    }
787
788    pub fn write_amp(&mut self, text: &str) -> Result<()> {
789        unsafe {
790            let cstr = CString::new(text).map_err(|_| Error::OperationError("Cannot initialize C string"))?;
791            let res = bindings::vips_target_write_amp(self.ctx, cstr.as_ptr());
792            if res == -1 {
793                Err(Error::OperationError("Could not write to buffer"))
794            } else {
795                Ok(())
796            }
797        }
798    }
799}
800
801unsafe fn vips_image_result(res: *mut bindings::VipsImage, err: Error) -> Result<VipsImage> {
802    if res.is_null() {
803        Err(err)
804    } else {
805        Ok(VipsImage { ctx: res })
806    }
807}
808
809unsafe fn vips_source_result(res: *mut bindings::VipsSource, err: Error) -> Result<VipsSource> {
810    if res.is_null() {
811        Err(err)
812    } else {
813        Ok(VipsSource { ctx: res })
814    }
815}
816
817unsafe fn vips_target_result(res: *mut bindings::VipsTarget, err: Error) -> Result<VipsTarget> {
818    if res.is_null() {
819        Err(err)
820    } else {
821        Ok(VipsTarget { ctx: res })
822    }
823}
824
825impl VipsInterpolate {
826    /// defaults to vips_interpolate_nearest_static
827    pub fn new() -> VipsInterpolate {
828        unsafe {
829            VipsInterpolate {
830                ctx: bindings::vips_interpolate_nearest_static(),
831            }
832        }
833    }
834
835    pub fn new_from_neasest_static() -> VipsInterpolate {
836        unsafe {
837            VipsInterpolate {
838                ctx: bindings::vips_interpolate_nearest_static(),
839            }
840        }
841    }
842
843    pub fn new_from_bilinear_static() -> VipsInterpolate {
844        unsafe {
845            VipsInterpolate {
846                ctx: bindings::vips_interpolate_bilinear_static(),
847            }
848        }
849    }
850
851    pub fn new_from_name(name: &str) -> Result<VipsInterpolate> {
852        unsafe {
853            let nickname = utils::new_c_string(name)?;
854            let res = bindings::vips_interpolate_new(nickname.as_ptr());
855            if res.is_null() {
856                Err(Error::InitializationError(
857                    "Cannot initialize interpolator with provided nickname",
858                ))
859            } else {
860                Ok(VipsInterpolate { ctx: res })
861            }
862        }
863    }
864
865    pub fn get_window_size(&self) -> i32 {
866        unsafe { bindings::vips_interpolate_get_window_size(self.ctx) }
867    }
868
869    pub fn get_windows_offset(&self) -> i32 {
870        unsafe { bindings::vips_interpolate_get_window_offset(self.ctx) }
871    }
872}
873
874impl Drop for VipsImage {
875    fn drop(&mut self) {
876        unsafe {
877            if !self.ctx.is_null() {
878                bindings::g_object_unref(self.ctx as *mut c_void);
879            }
880        }
881    }
882}
883
884impl Drop for VipsInterpolate {
885    fn drop(&mut self) {
886        unsafe {
887            if !self.ctx.is_null() {
888                bindings::g_object_unref(self.ctx as *mut c_void);
889            }
890        }
891    }
892}
893
894impl Drop for VipsBlob {
895    fn drop(&mut self) {
896        unsafe {
897            if !self.ctx.is_null() {
898                bindings::g_object_unref(self.ctx as *mut c_void);
899            }
900        }
901    }
902}
903
904impl Drop for VipsConnection {
905    fn drop(&mut self) {
906        unsafe {
907            if !self.ctx.is_null() {
908                bindings::g_object_unref(self.ctx as *mut c_void);
909            }
910        }
911    }
912}
913
914impl Drop for VipsSource {
915    fn drop(&mut self) {
916        unsafe {
917            if !self.ctx.is_null() {
918                bindings::g_object_unref(self.ctx as *mut c_void);
919            }
920        }
921    }
922}
923
924impl Drop for VipsTarget {
925    fn drop(&mut self) {
926        unsafe {
927            if !self.ctx.is_null() {
928                bindings::g_object_unref(self.ctx as *mut c_void);
929            }
930        }
931    }
932}
933
934impl Into<Vec<u8>> for VipsBlob {
935    fn into(self) -> Vec<u8> {
936        unsafe {
937            let mut size: u64 = 0;
938            let bytes = bindings::vips_blob_get(self.ctx, &mut size);
939            Vec::from_raw_parts(bytes as *mut u8, size as usize, size as usize)
940        }
941    }
942}