libvips_rs/
image.rs

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