libvips_rs/
image.rs

1// (c) Copyright 2019-2023 MIT
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_interpretation(&self) -> Result<Interpretation> {
323        unsafe {
324            let res = bindings::vips_image_get_interpretation(self.ctx);
325            let format_enum = FromPrimitive::from_i32(res);
326            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
327        }
328    }
329
330    pub fn guess_interpretation(&self) -> Result<Interpretation> {
331        unsafe {
332            let res = bindings::vips_image_guess_interpretation(self.ctx);
333            let format_enum = FromPrimitive::from_i32(res);
334            format_enum.ok_or_else(|| Error::IOError("Could get format from image"))
335        }
336    }
337
338    pub fn image_set_delete_on_close(&mut self, flag: bool) {
339        unsafe {
340            bindings::vips_image_set_delete_on_close(self.ctx, if flag { 1 } else { 0 });
341        }
342    }
343
344    pub fn image_invalidate_all(&self) {
345        unsafe {
346            bindings::vips_image_invalidate_all(self.ctx);
347        }
348    }
349
350    pub fn image_minimise_all(&self) {
351        unsafe {
352            bindings::vips_image_minimise_all(self.ctx);
353        }
354    }
355
356    pub fn image_iskilled(&self) -> bool {
357        unsafe { bindings::vips_image_iskilled(self.ctx) == 1 }
358    }
359
360    pub fn image_isMSBfirst(&self) -> bool {
361        unsafe { bindings::vips_image_isMSBfirst(self.ctx) == 1 }
362    }
363
364    pub fn image_isfile(&self) -> bool {
365        unsafe { bindings::vips_image_isfile(self.ctx) == 1 }
366    }
367
368    pub fn image_ispartial(&self) -> bool {
369        unsafe { bindings::vips_image_ispartial(self.ctx) == 1 }
370    }
371
372    pub fn image_hasalpha(&self) -> bool {
373        unsafe { bindings::vips_image_hasalpha(self.ctx) == 1 }
374    }
375
376    pub fn image_set_kill(&self, flag: bool) {
377        unsafe {
378            bindings::vips_image_set_kill(self.ctx, if flag { 1 } else { 0 });
379        }
380    }
381
382    pub fn image_set_progress(&self, flag: bool) {
383        unsafe {
384            bindings::vips_image_set_progress(self.ctx, if flag { 1 } else { 0 });
385        }
386    }
387
388    pub fn image_write(&self) -> Result<VipsImage> {
389        unsafe {
390            let out: *mut bindings::VipsImage = null_mut();
391            let res = bindings::vips_image_write(self.ctx, out);
392            utils::result(
393                res,
394                VipsImage { ctx: out },
395                Error::IOError("Cannot write input to output"),
396            )
397        }
398    }
399
400    pub fn image_pio_input(&mut self) -> Result<()> {
401        unsafe {
402            let res = bindings::vips_image_pio_input(self.ctx);
403            utils::result(res, (), Error::IOError("Cannot read image"))
404        }
405    }
406
407    pub fn image_pio_output(&mut self) -> Result<()> {
408        unsafe {
409            let res = bindings::vips_image_pio_output(self.ctx);
410            utils::result(res, (), Error::IOError("Cannot write image"))
411        }
412    }
413
414    pub fn image_inplace(&self) -> Result<()> {
415        unsafe {
416            let res = bindings::vips_image_inplace(self.ctx);
417            utils::result(res, (), Error::IOError("Cannot cannot be modified inplace"))
418        }
419    }
420
421    pub fn image_write_to_file(&self, filename: &str) -> Result<()> {
422        unsafe {
423            let file_c_str = utils::new_c_string(filename)?;
424            let res = bindings::vips_image_write_to_file(self.ctx, file_c_str.as_ptr(), NULL);
425            utils::result(res, (), Error::IOError("Cannot write to file"))
426        }
427    }
428
429    pub fn image_write_prepare(&self) -> Result<()> {
430        unsafe {
431            let res = bindings::vips_image_write_prepare(self.ctx);
432            utils::result(res, (), Error::IOError("Cannot prepare file to write"))
433        }
434    }
435
436    pub fn image_write_to_buffer(&self, suffix: &str) -> Result<Vec<u8>> {
437        unsafe {
438            let mut buffer_buf_size: u64 = 0;
439            let mut buffer_out: *mut c_void = null_mut();
440            let suffix_c_str = utils::new_c_string(suffix)?;
441            let res = bindings::vips_image_write_to_buffer(
442                self.ctx,
443                suffix_c_str.as_ptr(),
444                &mut buffer_out,
445                &mut buffer_buf_size,
446                NULL,
447            );
448            utils::result(
449                res,
450                utils::new_byte_array(buffer_out, buffer_buf_size),
451                Error::IOError("Cannot write content to buffer"),
452            )
453        }
454    }
455
456    pub fn image_write_to_memory(&self) -> Vec<u8> {
457        unsafe {
458            let mut buffer_buf_size: u64 = 0;
459            let buffer_out = bindings::vips_image_write_to_memory(self.ctx, &mut buffer_buf_size);
460            let buf = std::slice::from_raw_parts(buffer_out as *mut u8, buffer_buf_size as usize).to_vec();
461            bindings::g_free(buffer_out);
462            buf
463        }
464    }
465
466    pub fn image_decode_predict(&self) -> Result<(i32, BandFormat)> {
467        unsafe {
468            let mut out_bands = 0;
469            let mut out_format = 0;
470            let res =
471                bindings::vips_image_decode_predict(self.ctx, &mut out_bands, &mut out_format);
472            let format_enum = FromPrimitive::from_i32(out_format);
473            if format_enum.is_some() {
474                utils::result(
475                    res,
476                    (out_bands, format_enum.unwrap()),
477                    Error::IOError("Could not predict image format"),
478                )
479            } else {
480                Err(Error::IOError("Could not predict image format"))
481            }
482        }
483    }
484
485    pub fn image_decode(&self) -> Result<VipsImage> {
486        unsafe {
487            let mut out: *mut bindings::VipsImage = null_mut();
488            let res = bindings::vips_image_decode(self.ctx, &mut out);
489            utils::result(
490                res,
491                VipsImage { ctx: out },
492                Error::IOError("Cannot decode image"),
493            )
494        }
495    }
496
497    pub fn image_encode(&self, coding: Coding) -> Result<VipsImage> {
498        unsafe {
499            let mut out: *mut bindings::VipsImage = null_mut();
500            let res = bindings::vips_image_encode(self.ctx, &mut out, coding as i32);
501            utils::result(
502                res,
503                VipsImage { ctx: out },
504                Error::IOError("Cannot encode image"),
505            )
506        }
507    }
508}
509
510impl VipsConnection {
511    pub fn connection_filename(&self) -> Option<String> {
512        unsafe {
513            let result = bindings::vips_connection_filename(self.ctx);
514            if result.is_null() {
515                None
516            } else {
517                let cstr = CStr::from_ptr(result);
518                match cstr.to_string_lossy() {
519                    Cow::Borrowed(slice) => Some(slice.to_string()),
520                    Cow::Owned(string) => Some(string),
521                }
522            }
523        }
524    }
525
526    pub fn connection_nick(&self) -> Option<String> {
527        unsafe {
528            let result = bindings::vips_connection_nick(self.ctx);
529            if result.is_null() {
530                None
531            } else {
532                let cstr = CStr::from_ptr(result);
533                match cstr.to_string_lossy() {
534                    Cow::Borrowed(slice) => Some(slice.to_string()),
535                    Cow::Owned(string) => Some(string),
536                }
537            }
538        }
539    }
540}
541
542impl VipsSource {
543    pub fn new_from_descriptor(descriptor: i32) -> Result<Self> {
544        unsafe {
545            let res = bindings::vips_source_new_from_descriptor(descriptor);
546            vips_source_result(
547                res,
548                Error::InitializationError("Could not initialise VipsSource from descriptor"),
549            )
550        }
551    }
552
553    pub fn new_from_file(filename: &str) -> Result<Self> {
554        unsafe {
555            let f = utils::new_c_string(filename)?;
556            let res = bindings::vips_source_new_from_file(f.as_ptr());
557            vips_source_result(
558                res,
559                Error::InitializationError("Could not initialise VipsSource from file"),
560            )
561        }
562    }
563
564    // not sure if it this is safe
565    // should test before making it public
566    fn new_from_blob(blob: VipsBlob) -> Result<Self> {
567        unsafe {
568            let res = bindings::vips_source_new_from_blob(blob.ctx);
569            vips_source_result(
570                res,
571                Error::InitializationError("Could not initialise VipsSource from blob"),
572            )
573        }
574    }
575
576    pub fn new_from_memory(buffer: &[u8]) -> Result<Self> {
577        unsafe {
578            let res = bindings::vips_source_new_from_memory(
579                buffer.as_ptr() as *const c_void,
580                buffer.len() as u64,
581            );
582            vips_source_result(
583                res,
584                Error::InitializationError("Could not initialise VipsSource from memory"),
585            )
586        }
587    }
588
589    pub fn new_from_options(option_str: &str) -> Result<Self> {
590        unsafe {
591            let options = utils::new_c_string(option_str)?;
592            let res = bindings::vips_source_new_from_options(options.as_ptr());
593            vips_source_result(
594                res,
595                Error::InitializationError("Could not initialise VipsSource from options"),
596            )
597        }
598    }
599
600    pub fn minimise(&mut self) {
601        unsafe {
602            bindings::vips_source_minimise(self.ctx);
603        }
604    }
605
606    pub fn unminimise(&mut self) -> Result<()> {
607        unsafe {
608            let result = bindings::vips_source_unminimise(self.ctx);
609            utils::result(
610                result,
611                (),
612                Error::OperationError("Error on vips unminimise"),
613            )
614        }
615    }
616
617    pub fn decode(&mut self) -> Result<()> {
618        unsafe {
619            let result = bindings::vips_source_decode(self.ctx);
620            utils::result(
621                result,
622                (),
623                Error::OperationError("Error on vips decode"),
624            )
625        }
626    }
627
628    pub fn read(&mut self, length: u64) -> Result<Vec<u8>> {
629        unsafe {
630            let bytes: *mut c_void = null_mut();
631            let result = bindings::vips_source_read(self.ctx, bytes, length);
632            if result != -1 {
633                let buffer =
634                    Vec::from_raw_parts(bytes as *mut u8, result as usize, result as usize);
635                Ok(buffer)
636            } else {
637                Err(Error::OperationError("Error on vips read"))
638            }
639        }
640    }
641
642    pub fn is_mappable(&self) -> bool {
643        unsafe { bindings::vips_source_is_mappable(self.ctx) == 1 }
644    }
645
646    pub fn seek(&mut self, offset: i64, whence: i32) -> Result<i64> {
647        unsafe {
648            let result = bindings::vips_source_seek(self.ctx, offset, whence);
649            if result == -1 {
650                Err(Error::OperationError("Error on vips seek"))
651            } else {
652                Ok(result)
653            }
654        }
655    }
656
657    pub fn rewind(&mut self) -> Result<()> {
658        unsafe {
659            let result = bindings::vips_source_rewind(self.ctx);
660            if result == -1 {
661                Err(Error::OperationError("Error on vips rewind"))
662            } else {
663                Ok(())
664            }
665        }
666    }
667
668    pub fn length(&self) -> Result<i64> {
669        unsafe {
670            let result = bindings::vips_source_length(self.ctx);
671            if result == -1 {
672                Err(Error::OperationError("Error on vips length"))
673            } else {
674                Ok(result)
675            }
676        }
677    }
678}
679
680impl<'a> VipsSource {
681    pub fn map(&'a self) -> Result<&'a [u8]> {
682        unsafe {
683            let length: *mut u64 = null_mut();
684            let result = bindings::vips_source_map(self.ctx, length);
685            if length.is_null() {
686                Err(Error::OperationError("Error on vips map"))
687            } else {
688                let size = (*length)
689                    .try_into()
690                    .map_err(|_| Error::OperationError("Can't get size of array"))?;
691                Ok(std::slice::from_raw_parts(result as *mut u8, size))
692            }
693        }
694    }
695
696    // pub fn map_blob(&'a self) -> Result<&'a VipsBlob> {
697    //     unsafe {
698    //         let result = bindings::vips_source_map_blob(self.ctx);
699    //         if result.is_null() {
700    //             Err(Error::OperationError("Error on vips map blob"))
701    //         } else {
702    //             Ok(&VipsBlob { ctx: result })
703    //         }
704    //     }
705    // }
706}
707
708impl VipsTarget {
709    pub fn new_to_descriptor(descriptor: i32) -> Result<Self> {
710        unsafe {
711            let res = bindings::vips_target_new_to_descriptor(descriptor);
712            vips_target_result(
713                res,
714                Error::InitializationError("Could not initialise VipsTarget from descriptor"),
715            )
716        }
717    }
718
719    pub fn new_to_file(filename: &str) -> Result<Self> {
720        unsafe {
721            let f = utils::new_c_string(filename)?;
722            let res = bindings::vips_target_new_to_file(f.as_ptr());
723            vips_target_result(
724                res,
725                Error::InitializationError("Could not initialise VipsTarget from file"),
726            )
727        }
728    }
729
730    pub fn new_to_memory() -> Result<Self> {
731        unsafe {
732            let res = bindings::vips_target_new_to_memory();
733            vips_target_result(
734                res,
735                Error::InitializationError("Could not initialise VipsTarget from memory"),
736            )
737        }
738    }
739
740    pub fn write(&mut self, buffer: &[u8]) -> Result<()> {
741        unsafe {
742            let res = bindings::vips_target_write(
743                self.ctx,
744                buffer.as_ptr() as *const c_void,
745                buffer.len() as u64,
746            );
747            if res == -1 {
748                Err(Error::OperationError("Could not write to buffer"))
749            } else {
750                Ok(())
751            }
752        }
753    }
754
755    pub fn finish(self) {
756        unsafe {
757            bindings::vips_target_finish(self.ctx);
758        }
759    }
760
761    pub fn putc(&mut self, ch: char) -> Result<()> {
762        unsafe {
763            let res = bindings::vips_target_putc(self.ctx, ch as i32);
764            if res == -1 {
765                Err(Error::OperationError("Could not write to buffer"))
766            } else {
767                Ok(())
768            }
769        }
770    }
771
772    pub fn writes(&mut self, text: &str) -> Result<()> {
773        unsafe {
774            let cstr = CString::new(text).map_err(|_| Error::OperationError("Cannot initialize C string"))?;
775            let res = bindings::vips_target_writes(self.ctx, cstr.as_ptr());
776            if res == -1 {
777                Err(Error::OperationError("Could not write to buffer"))
778            } else {
779                Ok(())
780            }
781        }
782    }
783
784    pub fn write_amp(&mut self, text: &str) -> Result<()> {
785        unsafe {
786            let cstr = CString::new(text).map_err(|_| Error::OperationError("Cannot initialize C string"))?;
787            let res = bindings::vips_target_write_amp(self.ctx, cstr.as_ptr());
788            if res == -1 {
789                Err(Error::OperationError("Could not write to buffer"))
790            } else {
791                Ok(())
792            }
793        }
794    }
795}
796
797unsafe fn vips_image_result(res: *mut bindings::VipsImage, err: Error) -> Result<VipsImage> {
798    if res.is_null() {
799        Err(err)
800    } else {
801        Ok(VipsImage { ctx: res })
802    }
803}
804
805unsafe fn vips_source_result(res: *mut bindings::VipsSource, err: Error) -> Result<VipsSource> {
806    if res.is_null() {
807        Err(err)
808    } else {
809        Ok(VipsSource { ctx: res })
810    }
811}
812
813unsafe fn vips_target_result(res: *mut bindings::VipsTarget, err: Error) -> Result<VipsTarget> {
814    if res.is_null() {
815        Err(err)
816    } else {
817        Ok(VipsTarget { ctx: res })
818    }
819}
820
821impl VipsInterpolate {
822    /// defaults to vips_interpolate_nearest_static
823    pub fn new() -> VipsInterpolate {
824        unsafe {
825            VipsInterpolate {
826                ctx: bindings::vips_interpolate_nearest_static(),
827            }
828        }
829    }
830
831    pub fn new_from_neasest_static() -> VipsInterpolate {
832        unsafe {
833            VipsInterpolate {
834                ctx: bindings::vips_interpolate_nearest_static(),
835            }
836        }
837    }
838
839    pub fn new_from_bilinear_static() -> VipsInterpolate {
840        unsafe {
841            VipsInterpolate {
842                ctx: bindings::vips_interpolate_bilinear_static(),
843            }
844        }
845    }
846
847    pub fn new_from_name(name: &str) -> Result<VipsInterpolate> {
848        unsafe {
849            let nickname = utils::new_c_string(name)?;
850            let res = bindings::vips_interpolate_new(nickname.as_ptr());
851            if res.is_null() {
852                Err(Error::InitializationError(
853                    "Cannot initialize interpolator with provided nickname",
854                ))
855            } else {
856                Ok(VipsInterpolate { ctx: res })
857            }
858        }
859    }
860
861    pub fn get_window_size(&self) -> i32 {
862        unsafe { bindings::vips_interpolate_get_window_size(self.ctx) }
863    }
864
865    pub fn get_windows_offset(&self) -> i32 {
866        unsafe { bindings::vips_interpolate_get_window_offset(self.ctx) }
867    }
868}
869
870impl Drop for VipsImage {
871    fn drop(&mut self) {
872        unsafe {
873            if !self.ctx.is_null() {
874                bindings::g_object_unref(self.ctx as *mut c_void);
875            }
876        }
877    }
878}
879
880impl Drop for VipsInterpolate {
881    fn drop(&mut self) {
882        unsafe {
883            if !self.ctx.is_null() {
884                bindings::g_object_unref(self.ctx as *mut c_void);
885            }
886        }
887    }
888}
889
890impl Drop for VipsBlob {
891    fn drop(&mut self) {
892        unsafe {
893            if !self.ctx.is_null() {
894                bindings::g_object_unref(self.ctx as *mut c_void);
895            }
896        }
897    }
898}
899
900impl Drop for VipsConnection {
901    fn drop(&mut self) {
902        unsafe {
903            if !self.ctx.is_null() {
904                bindings::g_object_unref(self.ctx as *mut c_void);
905            }
906        }
907    }
908}
909
910impl Drop for VipsSource {
911    fn drop(&mut self) {
912        unsafe {
913            if !self.ctx.is_null() {
914                bindings::g_object_unref(self.ctx as *mut c_void);
915            }
916        }
917    }
918}
919
920impl Drop for VipsTarget {
921    fn drop(&mut self) {
922        unsafe {
923            if !self.ctx.is_null() {
924                bindings::g_object_unref(self.ctx as *mut c_void);
925            }
926        }
927    }
928}
929
930impl Into<Vec<u8>> for VipsBlob {
931    fn into(self) -> Vec<u8> {
932        unsafe {
933            let mut size: u64 = 0;
934            let bytes = bindings::vips_blob_get(self.ctx, &mut size);
935            Vec::from_raw_parts(bytes as *mut u8, size as usize, size as usize)
936        }
937    }
938}