1use crate::{
4 bindings::{self, vips_blob_new},
5 connection::{VipsSource, VipsTarget},
6 error::Error,
7 ops::*,
8 region::VipsBlob,
9 utils::{self, ensure_null_terminated, vips_image_result, vips_image_result_ext},
10 voption::{call, call_option_string_, Setter, VOption},
11 Result,
12};
13use num_traits::{FromPrimitive, ToPrimitive};
14use std::ptr::null_mut;
15use std::{ffi::*, path::Path};
16
17const NULL: *const c_void = null_mut();
18
19#[derive(Debug, Clone)]
20pub struct VipsImage {
21 pub(crate) ctx: *mut bindings::VipsImage,
22}
23
24impl Default for VipsImage {
25 fn default() -> VipsImage {
26 VipsImage {
27 ctx: unsafe { bindings::vips_image_new() },
28 }
29 }
30}
31
32impl VipsImage {
35 pub fn new() -> VipsImage {
36 VipsImage {
37 ctx: unsafe { bindings::vips_image_new() },
38 }
39 }
40
41 pub fn new_memory() -> Result<VipsImage> {
42 unsafe {
43 let res = bindings::vips_image_new_memory();
44 vips_image_result(
45 res,
46 Error::InitializationError("Could not generate object".to_string()),
47 )
48 }
49 }
50
51 pub fn new_from_file<P: AsRef<Path>>(filename: P) -> Result<VipsImage> {
52 Self::new_from_file_with_opts(
53 filename,
54 VOption::new(),
55 )
56 }
57
58 pub fn new_from_file_with_opts<P: AsRef<Path>>(
59 filename: P,
60 option: VOption,
61 ) -> Result<VipsImage> {
62 unsafe {
63 let f = utils::new_c_string(
64 filename
65 .as_ref()
66 .to_string_lossy()
67 .to_string(),
68 )?;
69 let filename_ = bindings::vips_filename_get_filename(f.as_ptr());
70 let string_options = bindings::vips_filename_get_options(f.as_ptr());
71
72 let operation = bindings::vips_foreign_find_load(filename_);
73 if operation.is_null() {
74 return vips_image_result(
75 NULL as _,
76 Error::InitializationError("Could not find operation".to_string()),
77 );
78 }
79
80 let mut out_out = VipsImage::from(null_mut());
81 call_option_string_(
82 operation,
83 string_options,
84 option
85 .set(
86 "filename",
87 CStr::from_ptr(filename_)
88 .to_str()
89 .unwrap(),
90 )
91 .set(
92 "out",
93 &mut out_out,
94 ),
95 );
96 vips_image_result_ext(
97 out_out,
98 Error::InitializationError("Could not initialise VipsImage from file".to_string()),
99 )
100 }
101 }
102
103 pub fn new_from_file_rw<P: AsRef<Path>>(filename: P) -> Result<VipsImage> {
104 unsafe {
105 let f = utils::new_c_string(
106 filename
107 .as_ref()
108 .to_string_lossy()
109 .to_string(),
110 )?;
111 let res = bindings::vips_image_new_from_file_RW(f.as_ptr());
112 vips_image_result(
113 res,
114 Error::InitializationError("Could not initialise VipsImage from file".to_string()),
115 )
116 }
117 }
118
119 pub fn new_from_file_raw<P: AsRef<Path>>(
120 filename: P,
121 x_size: i32,
122 y_size: i32,
123 bands: i32,
124 offset: u64,
125 ) -> Result<VipsImage> {
126 unsafe {
127 let f = utils::new_c_string(
128 filename
129 .as_ref()
130 .to_string_lossy()
131 .to_string(),
132 )?;
133 let res = bindings::vips_image_new_from_file_raw(
134 f.as_ptr(),
135 x_size,
136 y_size,
137 bands,
138 offset,
139 );
140 vips_image_result(
141 res,
142 Error::InitializationError("Could not initialise VipsImage from file".to_string()),
143 )
144 }
145 }
146
147 pub fn new_from_file_access<P: AsRef<Path>>(
148 filename: P,
149 access: Access,
150 memory: bool,
151 ) -> Result<VipsImage> {
152 unsafe {
153 let access_str = utils::new_c_string("access")?;
154 let memory_str = utils::new_c_string("memory")?;
155 let f = utils::new_c_string(
156 filename
157 .as_ref()
158 .to_string_lossy()
159 .to_string(),
160 )?;
161 let res = bindings::vips_image_new_from_file(
162 f.as_ptr(),
163 access_str.as_ptr(),
164 access as i32,
165 memory_str.as_ptr(),
166 if memory { 1 } else { 0 },
167 NULL,
168 );
169 vips_image_result(
170 res,
171 Error::InitializationError("Could not initialise VipsImage from file".to_string()),
172 )
173 }
174 }
175
176 pub fn new_from_buffer(buffer: &[u8], option_str: &str) -> Result<VipsImage> {
177 Self::new_from_buffer_with_opts(
178 buffer,
179 option_str,
180 VOption::new(),
181 )
182 }
183
184 pub fn new_from_buffer_with_opts(
185 buffer: &[u8],
186 option_str: &str,
187 option: VOption,
188 ) -> Result<VipsImage> {
189 unsafe {
190 let operation = bindings::vips_foreign_find_load_buffer(
191 buffer.as_ptr() as *const c_void,
192 buffer.len() as u64,
193 );
194 if operation.is_null() {
195 return vips_image_result(
196 NULL as _,
197 Error::InitializationError(
198 "Could not initialise VipsImage from buffer".to_string(),
199 ),
200 );
201 }
202
203 let vips_blob = vips_blob_new(
204 None,
205 buffer.as_ptr() as _,
206 buffer.len() as _,
207 );
208 let mut out_out = VipsImage::from(null_mut());
209 let blob = VipsBlob::from(vips_blob);
210 call_option_string_(
211 operation,
212 utils::new_c_string(option_str)?.as_ptr() as _,
213 option
214 .set(
215 "buffer",
216 &blob,
217 )
218 .set(
219 "out",
220 &mut out_out,
221 ),
222 );
223 blob.area_unref();
224 vips_image_result_ext(
225 out_out,
226 Error::InitializationError(
227 "Could not initialise VipsImage from buffer".to_string(),
228 ),
229 )
230 }
231 }
232
233 pub fn new_from_source(source: &VipsSource, option_str: &str) -> Result<VipsImage> {
234 Self::new_from_source_with_opts(
235 source,
236 option_str,
237 VOption::new(),
238 )
239 }
240
241 pub fn new_from_source_with_opts(
242 source: &VipsSource,
243 option_str: &str,
244 option: VOption,
245 ) -> Result<VipsImage> {
246 unsafe {
247 let operation = bindings::vips_foreign_find_load_source(source.ctx);
248 if operation.is_null() {
249 return vips_image_result(
250 NULL as _,
251 Error::InitializationError(
252 "Could not initialise VipsImage from source".to_string(),
253 ),
254 );
255 }
256
257 let mut out_out = VipsImage::from(null_mut());
258 call_option_string_(
259 operation,
260 utils::new_c_string(option_str)?.as_ptr() as _,
261 option
262 .set(
263 "source",
264 source,
265 )
266 .set(
267 "out",
268 &mut out_out,
269 ),
270 );
271 vips_image_result_ext(
272 out_out,
273 Error::InitializationError(
274 "Could not initialise VipsImage from buffer".to_string(),
275 ),
276 )
277 }
278 }
279
280 pub fn new_from_memory(
281 buffer: &[u8],
282 width: i32,
283 height: i32,
284 bands: i32,
285 format: BandFormat,
286 ) -> Result<VipsImage> {
287 unsafe {
288 if let Some(format) = format.to_i32() {
289 let res = bindings::vips_image_new_from_memory(
290 buffer.as_ptr() as *const c_void,
291 buffer.len() as u64,
292 width,
293 height,
294 bands,
295 format,
296 );
297 vips_image_result(
298 res,
299 Error::InitializationError(
300 "Could not initialise VipsImage from memory".to_string(),
301 ),
302 )
303 } else {
304 Err(Error::InitializationError(
305 "Invalid BandFormat. Please file a bug report, as this should never happen.".to_string(),
306 ))
307 }
308 }
309 }
310
311 pub fn new_matrix(width: i32, height: i32) -> Result<VipsImage> {
312 unsafe {
313 let res = bindings::vips_image_new_matrix(
314 width,
315 height,
316 );
317 vips_image_result(
318 res,
319 Error::InitializationError(
320 "Could not initialise VipsImage from matrix".to_string(),
321 ),
322 )
323 }
324 }
325
326 pub fn new_matrixv(width: i32, height: i32, array: &[f64]) -> Result<VipsImage> {
327 unsafe {
328 let matrix = bindings::vips_image_new_matrix(
329 width,
330 height,
331 );
332
333 let mut i = 0;
334 for y in 0..height {
335 for x in 0..width {
336 *utils::vips_matrix(
337 &*matrix,
338 x,
339 y,
340 ) = array[i];
341 i += 1;
342 }
343 }
344 vips_image_result(
345 matrix,
346 Error::InitializationError(
347 "Could not initialise VipsImage from matrix".to_string(),
348 ),
349 )
350 }
351 }
352
353 pub fn new_matrix_from_array(width: i32, height: i32, array: &[f64]) -> Result<VipsImage> {
354 unsafe {
355 let res = bindings::vips_image_new_matrix_from_array(
356 width,
357 height,
358 array.as_ptr(),
359 array.len() as i32,
360 );
361 vips_image_result(
362 res,
363 Error::InitializationError(
364 "Could not initialise VipsImage from matrix".to_string(),
365 ),
366 )
367 }
368 }
369
370 pub fn new_from_image(image: &VipsImage, array: &[f64]) -> Result<VipsImage> {
371 unsafe {
372 let res = bindings::vips_image_new_from_image(
373 image.ctx,
374 array.as_ptr(),
375 array.len() as i32,
376 );
377 vips_image_result(
378 res,
379 Error::InitializationError(
380 "Could not initialise VipsImage from Object".to_string(),
381 ),
382 )
383 }
384 }
385
386 pub fn new_from_image1(image: &VipsImage, c: f64) -> Result<VipsImage> {
387 unsafe {
388 let res = bindings::vips_image_new_from_image1(
389 image.ctx,
390 c,
391 );
392 vips_image_result(
393 res,
394 Error::InitializationError(
395 "Could not initialise VipsImage from Object".to_string(),
396 ),
397 )
398 }
399 }
400
401 pub fn new_temp_file(format: &str) -> Result<VipsImage> {
402 unsafe {
403 let format_c_str = utils::new_c_string(format)?;
404 let res = bindings::vips_image_new_temp_file(format_c_str.as_ptr());
405 vips_image_result(
406 res,
407 Error::InitializationError(
408 "Could not initialise VipsImage from format".to_string(),
409 ),
410 )
411 }
412 }
413
414 pub fn copy_memory(image: VipsImage) -> Result<VipsImage> {
415 unsafe {
416 let result = bindings::vips_image_copy_memory(image.ctx);
417 vips_image_result(
418 result,
419 Error::OperationError("Could not copy memory".to_string()),
420 )
421 }
422 }
423
424 pub fn wio_input(&mut self) -> Result<()> {
425 unsafe {
426 let result = bindings::vips_image_wio_input(self.ctx);
427 utils::result(
428 result,
429 (),
430 Error::OperationError("Error on vips image_wio_input".to_string()),
431 )
432 }
433 }
434
435 pub fn get_filename(&self) -> std::result::Result<&str, std::str::Utf8Error> {
436 unsafe {
437 let filename = bindings::vips_image_get_filename(self.ctx);
438 let res = CStr::from_ptr(filename);
439 res.to_str()
440 }
441 }
442
443 pub fn get_width(&self) -> i32 {
444 unsafe { bindings::vips_image_get_width(self.ctx) }
445 }
446
447 pub fn get_height(&self) -> i32 {
448 unsafe { bindings::vips_image_get_height(self.ctx) }
449 }
450
451 pub fn get_xoffset(&self) -> i32 {
452 unsafe { bindings::vips_image_get_xoffset(self.ctx) }
453 }
454
455 pub fn get_yoffset(&self) -> i32 {
456 unsafe { bindings::vips_image_get_yoffset(self.ctx) }
457 }
458
459 pub fn get_scale(&self) -> f64 {
460 unsafe { bindings::vips_image_get_scale(self.ctx) }
461 }
462
463 pub fn get_offset(&self) -> f64 {
464 unsafe { bindings::vips_image_get_offset(self.ctx) }
465 }
466
467 pub fn get_xres(&self) -> f64 {
468 unsafe { bindings::vips_image_get_xres(self.ctx) }
469 }
470
471 pub fn get_yres(&self) -> f64 {
472 unsafe { bindings::vips_image_get_yres(self.ctx) }
473 }
474
475 pub fn get_bands(&self) -> i32 {
476 unsafe { bindings::vips_image_get_bands(self.ctx) }
477 }
478
479 pub fn get_page_height(&self) -> i32 {
480 unsafe { bindings::vips_image_get_page_height(self.ctx) }
481 }
482
483 pub fn get_n_pages(&self) -> i32 {
484 unsafe { bindings::vips_image_get_n_pages(self.ctx) }
485 }
486
487 pub fn get_coding(&self) -> Result<Coding> {
488 unsafe {
489 let res = bindings::vips_image_get_format(self.ctx);
490 let format_enum = FromPrimitive::from_i32(res);
491 format_enum.ok_or(Error::IOError("Could get format from image".to_string()))
492 }
493 }
494
495 pub fn get_format(&self) -> Result<BandFormat> {
496 unsafe {
497 let res = bindings::vips_image_get_format(self.ctx);
498 let format_enum = FromPrimitive::from_i32(res);
499 format_enum.ok_or(Error::IOError("Could get format from image".to_string()))
500 }
501 }
502
503 pub fn guess_format(&self) -> Result<BandFormat> {
504 unsafe {
505 let res = bindings::vips_image_guess_format(self.ctx);
506 let format_enum = FromPrimitive::from_i32(res);
507 format_enum.ok_or(Error::IOError("Could get format from image".to_string()))
508 }
509 }
510
511 pub fn get_orientation(&self) -> i32 {
512 unsafe { bindings::vips_image_get_orientation(self.ctx) }
513 }
514
515 pub fn get_interpretation(&self) -> Result<Interpretation> {
516 unsafe {
517 let res = bindings::vips_image_get_interpretation(self.ctx);
518 let format_enum = FromPrimitive::from_i32(res);
519 format_enum.ok_or(Error::IOError("Could get format from image".to_string()))
520 }
521 }
522
523 pub fn guess_interpretation(&self) -> Result<Interpretation> {
524 unsafe {
525 let res = bindings::vips_image_guess_interpretation(self.ctx);
526 let format_enum = FromPrimitive::from_i32(res);
527 format_enum.ok_or(Error::IOError("Could get format from image".to_string()))
528 }
529 }
530
531 pub fn set_delete_on_close(&mut self, flag: bool) {
532 unsafe {
533 bindings::vips_image_set_delete_on_close(
534 self.ctx,
535 if flag { 1 } else { 0 },
536 );
537 }
538 }
539
540 pub fn invalidate_all(&self) {
541 unsafe {
542 bindings::vips_image_invalidate_all(self.ctx);
543 }
544 }
545
546 pub fn minimise_all(&self) {
547 unsafe {
548 bindings::vips_image_minimise_all(self.ctx);
549 }
550 }
551
552 pub fn iskilled(&self) -> bool {
553 unsafe { bindings::vips_image_iskilled(self.ctx) == 1 }
554 }
555
556 pub fn isMSBfirst(&self) -> bool {
557 unsafe { bindings::vips_image_isMSBfirst(self.ctx) == 1 }
558 }
559
560 pub fn isfile(&self) -> bool {
561 unsafe { bindings::vips_image_isfile(self.ctx) == 1 }
562 }
563
564 pub fn ispartial(&self) -> bool {
565 unsafe { bindings::vips_image_ispartial(self.ctx) == 1 }
566 }
567
568 pub fn hasalpha(&self) -> bool {
569 unsafe { bindings::vips_image_hasalpha(self.ctx) == 1 }
570 }
571
572 pub fn pio_input(&mut self) -> Result<()> {
573 unsafe {
574 let res = bindings::vips_image_pio_input(self.ctx);
575 utils::result(
576 res,
577 (),
578 Error::IOError("Cannot read image".to_string()),
579 )
580 }
581 }
582
583 pub fn pio_output(&mut self) -> Result<()> {
584 unsafe {
585 let res = bindings::vips_image_pio_output(self.ctx);
586 utils::result(
587 res,
588 (),
589 Error::IOError("Cannot write image".to_string()),
590 )
591 }
592 }
593
594 pub fn inplace(&self) -> Result<()> {
595 unsafe {
596 let res = bindings::vips_image_inplace(self.ctx);
597 utils::result(
598 res,
599 (),
600 Error::IOError("Cannot cannot be modified inplace".to_string()),
601 )
602 }
603 }
604
605 pub fn set_kill(&self, flag: bool) {
606 unsafe {
607 bindings::vips_image_set_kill(
608 self.ctx,
609 if flag { 1 } else { 0 },
610 );
611 }
612 }
613
614 pub fn set_progress(&self, flag: bool) {
615 unsafe {
616 bindings::vips_image_set_progress(
617 self.ctx,
618 if flag { 1 } else { 0 },
619 );
620 }
621 }
622
623 pub fn write(&self) -> Result<VipsImage> {
624 unsafe {
625 let out: *mut bindings::VipsImage = null_mut();
626 let res = bindings::vips_image_write(
627 self.ctx,
628 out,
629 );
630 utils::result(
631 res,
632 VipsImage {
633 ctx: out,
634 },
635 Error::IOError("Cannot write input to output".to_string()),
636 )
637 }
638 }
639
640 pub fn write_to_file<P: AsRef<Path>>(&self, filename: P) -> Result<()> {
641 self.write_to_file_with_opts(
642 filename,
643 VOption::new(),
644 )
645 }
646
647 pub fn write_to_file_with_opts<P: AsRef<Path>>(
648 &self,
649 filename: P,
650 option: VOption,
651 ) -> Result<()> {
652 unsafe {
653 let f = utils::new_c_string(
654 filename
655 .as_ref()
656 .to_string_lossy()
657 .to_string(),
658 )?;
659 let filename_ = bindings::vips_filename_get_filename(f.as_ptr());
660 let string_options = bindings::vips_filename_get_options(f.as_ptr());
661
662 let operation = bindings::vips_foreign_find_save(filename_);
663 if operation.is_null() {
664 return utils::result(
665 -1,
666 (),
667 Error::IOError("Cannot write to file".to_string()),
668 );
669 }
670
671 let res = call_option_string_(
672 operation,
673 string_options,
674 option
675 .set("in", self)
676 .set(
677 "filename",
678 CStr::from_ptr(filename_)
679 .to_str()
680 .unwrap(),
681 ),
682 );
683 utils::result(
684 res,
685 (),
686 Error::IOError("Cannot write to file".to_string()),
687 )
688 }
689 }
690
691 pub fn write_prepare(&self) -> Result<()> {
692 unsafe {
693 let res = bindings::vips_image_write_prepare(self.ctx);
694 utils::result(
695 res,
696 (),
697 Error::IOError("Cannot prepare file to write".to_string()),
698 )
699 }
700 }
701
702 pub fn write_to_buffer(&self, suffix: &str) -> Result<Vec<u8>> {
703 self.write_to_buffer_with_opts(
704 suffix,
705 VOption::new(),
706 )
707 }
708
709 pub fn write_to_buffer_with_opts(&self, suffix: &str, option: VOption) -> Result<Vec<u8>> {
710 unsafe {
711 let f = utils::new_c_string(suffix)?;
712 let filename = bindings::vips_filename_get_filename(f.as_ptr());
713 let string_options = bindings::vips_filename_get_options(f.as_ptr());
714
715 bindings::vips_error_freeze();
721 let operation = bindings::vips_foreign_find_save_target(filename);
722 bindings::vips_error_thaw();
723
724 if !operation.is_null() {
725 let target = VipsTarget::new_to_memory()?;
726 let res = call_option_string_(
727 operation,
728 string_options,
729 option
730 .set("in", self)
731 .set(
732 "target",
733 &target,
734 ),
735 );
736 return utils::safe_result(
737 res,
738 target,
739 move |target| {
740 target
741 .get_blob()
742 .into()
743 },
744 Error::IOError("Cannot write to buffer".to_string()),
745 );
746 }
747
748 let operation = bindings::vips_foreign_find_save_buffer(filename);
749 if operation.is_null() {
750 return utils::result(
751 -1,
752 Vec::new(),
753 Error::IOError("Cannot write to buffer".to_string()),
754 );
755 }
756
757 let mut buffer_out = VipsBlob::from(null_mut());
758 let res = call_option_string_(
759 operation,
760 string_options,
761 option
762 .set("in", self)
763 .set(
764 "buffer",
765 &mut buffer_out,
766 ),
767 );
768 utils::result(
769 res,
770 buffer_out.into(),
771 Error::IOError("Cannot write to buffer".to_string()),
772 )
773 }
774 }
775
776 pub fn write_to_target(&self, suffix: &str, target: &VipsTarget) -> Result<()> {
777 self.write_to_target_with_opts(
778 suffix,
779 target,
780 VOption::new(),
781 )
782 }
783
784 pub fn write_to_target_with_opts(
785 &self,
786 suffix: &str,
787 target: &VipsTarget,
788 option: VOption,
789 ) -> Result<()> {
790 unsafe {
791 let f = utils::new_c_string(suffix)?;
792 let filename = bindings::vips_filename_get_filename(f.as_ptr());
793 let string_options = bindings::vips_filename_get_options(f.as_ptr());
794
795 let operation = bindings::vips_foreign_find_save_target(filename);
796
797 if operation.is_null() {
798 return utils::result(
799 -1,
800 (),
801 Error::IOError("Cannot write to target".to_string()),
802 );
803 }
804
805 let res = call_option_string_(
806 operation,
807 string_options,
808 option
809 .set("in", self)
810 .set(
811 "target",
812 target,
813 ),
814 );
815 utils::result(
816 res,
817 (),
818 Error::IOError("Cannot write to target".to_string()),
819 )
820 }
821 }
822
823 pub fn write_to_memory(&self) -> Vec<u8> {
824 unsafe {
825 let mut buffer_buf_size: u64 = 0;
826 let buffer_out = bindings::vips_image_write_to_memory(
827 self.ctx,
828 &mut buffer_buf_size,
829 );
830 let buf = std::slice::from_raw_parts(
831 buffer_out as *mut u8,
832 buffer_buf_size as usize,
833 )
834 .to_vec();
835 bindings::g_free(buffer_out);
836 buf
837 }
838 }
839
840 pub fn decode_predict(
841 &self,
842 ) -> Result<(
843 i32,
844 BandFormat,
845 )> {
846 unsafe {
847 let mut out_bands = 0;
848 let mut out_format = 0;
849 let res = bindings::vips_image_decode_predict(
850 self.ctx,
851 &mut out_bands,
852 &mut out_format,
853 );
854 let format_enum = FromPrimitive::from_i32(out_format);
855 if let Some(format_enum) = format_enum {
856 utils::result(
857 res,
858 (
859 out_bands,
860 format_enum,
861 ),
862 Error::IOError("Could not predict image format".to_string()),
863 )
864 } else {
865 Err(Error::IOError("Could not predict image format".to_string()))
866 }
867 }
868 }
869
870 pub fn decode(&self) -> Result<VipsImage> {
871 unsafe {
872 let mut out: *mut bindings::VipsImage = null_mut();
873 let res = bindings::vips_image_decode(
874 self.ctx,
875 &mut out,
876 );
877 utils::result(
878 res,
879 VipsImage {
880 ctx: out,
881 },
882 Error::IOError("Cannot decode image".to_string()),
883 )
884 }
885 }
886
887 pub fn encode(&self, coding: Coding) -> Result<VipsImage> {
888 unsafe {
889 let mut out: *mut bindings::VipsImage = null_mut();
890 let res = bindings::vips_image_encode(
891 self.ctx,
892 &mut out,
893 coding as i32,
894 );
895 utils::result(
896 res,
897 VipsImage {
898 ctx: out,
899 },
900 Error::IOError("Cannot encode image".to_string()),
901 )
902 }
903 }
904
905 pub fn as_mut_ptr(&self) -> *mut bindings::VipsImage {
906 self.ctx
907 }
908
909 pub fn get_typeof(&self, type_: impl AsRef<[u8]>) -> Result<u64> {
911 unsafe {
912 let type_name = ensure_null_terminated(type_)?;
913 let gtype = bindings::vips_image_get_typeof(
914 self.ctx,
915 type_name.as_ptr(),
916 );
917 utils::result(
918 0,
919 gtype,
920 Error::IOError("Cannot get type".to_string()),
921 )
922 }
923 }
924
925 pub fn get_int(&self, name: impl AsRef<[u8]>) -> Result<i32> {
927 unsafe {
928 let mut out = 0;
929 let name = ensure_null_terminated(name)?;
930 let res = bindings::vips_image_get_int(
931 self.ctx,
932 name.as_ptr(),
933 &mut out,
934 );
935 utils::result(
936 res,
937 out,
938 Error::IOError("Cannot get int".to_string()),
939 )
940 }
941 }
942
943 pub fn set_int(&self, name: impl AsRef<[u8]>, value: i32) -> Result<()> {
945 unsafe {
946 let name = ensure_null_terminated(name)?;
947 bindings::vips_image_set_int(
948 self.ctx,
949 name.as_ptr(),
950 value,
951 );
952 Ok(())
953 }
954 }
955
956 pub fn get_double(&self, name: impl AsRef<[u8]>) -> Result<f64> {
958 unsafe {
959 let mut out = 0.0;
960 let name = ensure_null_terminated(name)?;
961 let res = bindings::vips_image_get_double(
962 self.ctx,
963 name.as_ptr(),
964 &mut out,
965 );
966 utils::result(
967 res,
968 out,
969 Error::IOError("Cannot get int".to_string()),
970 )
971 }
972 }
973
974 pub fn set_double(&self, name: impl AsRef<[u8]>, value: f64) -> Result<()> {
976 unsafe {
977 let name = ensure_null_terminated(name)?;
978 bindings::vips_image_set_double(
979 self.ctx,
980 name.as_ptr(),
981 value,
982 );
983 Ok(())
984 }
985 }
986
987 pub fn get_string(&self, name: impl AsRef<[u8]>) -> Result<String> {
989 unsafe {
990 let mut out: *const c_char = std::ptr::null();
991 let name = ensure_null_terminated(name)?;
992 let res = bindings::vips_image_get_string(
993 self.ctx,
994 name.as_ptr(),
995 &mut out,
996 );
997 utils::safe_result(
998 res,
999 out,
1000 move |out| {
1001 if let Ok(cstr) = CStr::from_ptr(out).to_str() {
1002 cstr.to_string()
1003 } else {
1004 String::new()
1005 }
1006 },
1007 Error::IOError("Cannot get string".to_string()),
1008 )
1009 }
1010 }
1011
1012 pub fn set_string(&self, name: impl AsRef<[u8]>, value: &str) -> Result<()> {
1014 unsafe {
1015 let name = ensure_null_terminated(name)?;
1016 let value = ensure_null_terminated(value)?;
1017
1018 bindings::vips_image_set_string(
1019 self.ctx,
1020 name.as_ptr(),
1021 value.as_ptr(),
1022 );
1023 Ok(())
1024 }
1025 }
1026
1027 pub fn get_blob(&self, name: impl AsRef<[u8]>) -> Result<Vec<u8>> {
1029 unsafe {
1030 let mut out: *const c_void = std::ptr::null();
1031 let mut length = 0;
1032 let name = ensure_null_terminated(name)?;
1033 let res = bindings::vips_image_get_blob(
1034 self.ctx,
1035 name.as_ptr(),
1036 &mut out,
1037 &mut length,
1038 );
1039 utils::safe_result(
1040 res,
1041 out,
1042 move |out| {
1043 std::slice::from_raw_parts(
1044 out as *const u8,
1045 length as _,
1046 )
1047 .to_vec()
1048 },
1049 Error::IOError("Cannot get blob".to_string()),
1050 )
1051 }
1052 }
1053
1054 pub fn set_blob(&self, name: impl AsRef<[u8]>, blob: &[u8]) -> Result<()> {
1056 unsafe {
1057 let name = ensure_null_terminated(name)?;
1058 bindings::vips_image_set_blob(
1059 self.ctx,
1060 name.as_ptr(),
1061 None,
1062 blob.as_ptr() as _,
1063 blob.len() as _,
1064 );
1065 Ok(())
1066 }
1067 }
1068
1069 pub fn get_array_int(&self, name: impl AsRef<[u8]>) -> Result<Vec<i32>> {
1071 unsafe {
1072 let mut out: *mut i32 = std::ptr::null_mut();
1073 let mut size = 0;
1074 let name = ensure_null_terminated(name)?;
1075 let res = bindings::vips_image_get_array_int(
1076 self.ctx,
1077 name.as_ptr(),
1078 &mut out,
1079 &mut size,
1080 );
1081 utils::safe_result(
1082 res,
1083 out,
1084 move |out| {
1085 utils::new_int_array(
1086 out,
1087 size as _,
1088 )
1089 },
1090 Error::IOError("Cannot get array int".to_string()),
1091 )
1092 }
1093 }
1094
1095 pub fn set_array_int(&self, name: impl AsRef<[u8]>, value: &[i32]) -> Result<()> {
1097 unsafe {
1098 let name = ensure_null_terminated(name)?;
1099 bindings::vips_image_set_array_int(
1100 self.ctx,
1101 name.as_ptr(),
1102 value.as_ptr(),
1103 value.len() as _,
1104 );
1105 Ok(())
1106 }
1107 }
1108
1109 pub fn get_array_double(&self, name: impl AsRef<[u8]>) -> Result<Vec<f64>> {
1111 unsafe {
1112 let mut out: *mut f64 = std::ptr::null_mut();
1113 let mut size = 0;
1114 let name = ensure_null_terminated(name)?;
1115 let res = bindings::vips_image_get_array_double(
1116 self.ctx,
1117 name.as_ptr(),
1118 &mut out,
1119 &mut size,
1120 );
1121 utils::safe_result(
1122 res,
1123 out,
1124 move |out| {
1125 utils::new_double_array(
1126 out,
1127 size as _,
1128 )
1129 },
1130 Error::IOError("Cannot get array double".to_string()),
1131 )
1132 }
1133 }
1134
1135 pub fn set_array_double(&self, name: impl AsRef<[u8]>, value: &[f64]) -> Result<()> {
1137 unsafe {
1138 let name = ensure_null_terminated(name)?;
1139 bindings::vips_image_set_array_double(
1140 self.ctx,
1141 name.as_ptr(),
1142 value.as_ptr(),
1143 value.len() as _,
1144 );
1145 Ok(())
1146 }
1147 }
1148
1149 pub fn remove(&self, name: impl AsRef<[u8]>) -> Result<bool> {
1151 unsafe {
1152 let name = ensure_null_terminated(name)?;
1153 Ok(
1154 bindings::vips_image_remove(
1155 self.ctx,
1156 name.as_ptr(),
1157 ) == 1,
1158 )
1159 }
1160 }
1161
1162 pub fn minpos(&self) -> Result<(f64, f64)> {
1163 let mut x: f64 = 0.0;
1164 let mut y: f64 = 0.0;
1165
1166 let vips_op_response = call(
1167 "min",
1168 VOption::new()
1169 .set("in", self)
1170 .set(
1171 "x",
1172 &mut x,
1173 )
1174 .set(
1175 "y",
1176 &mut y,
1177 ),
1178 );
1179 utils::result(
1180 vips_op_response,
1181 (x, y),
1182 Error::OperationError("minpos failed".to_string()),
1183 )
1184 }
1185
1186 pub fn maxpos(&self) -> Result<(f64, f64)> {
1187 let mut x: f64 = 0.0;
1188 let mut y: f64 = 0.0;
1189
1190 let vips_op_response = call(
1191 "max",
1192 VOption::new()
1193 .set("in", self)
1194 .set(
1195 "x",
1196 &mut x,
1197 )
1198 .set(
1199 "y",
1200 &mut y,
1201 ),
1202 );
1203 utils::result(
1204 vips_op_response,
1205 (x, y),
1206 Error::OperationError("maxpos failed".to_string()),
1207 )
1208 }
1209}
1210
1211impl Drop for VipsImage {
1212 fn drop(&mut self) {
1213 unsafe {
1214 if !self
1215 .ctx
1216 .is_null()
1217 {
1218 bindings::g_object_unref(self.ctx as *mut c_void);
1219 }
1220 }
1221 }
1222}
1223
1224impl From<*mut bindings::VipsImage> for VipsImage {
1225 fn from(value: *mut bindings::VipsImage) -> Self {
1226 Self {
1227 ctx: value,
1228 }
1229 }
1230}