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