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