1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 use glib::object::IsA; 4 use glib::translate::*; 5 use glib::Error; 6 use libc::{c_uchar, c_void}; 7 use std::io::Read; 8 use std::mem; 9 use std::path::Path; 10 use std::pin::Pin; 11 use std::ptr; 12 use std::slice; 13 14 use std::future::Future; 15 16 use crate::{Colorspace, Pixbuf, PixbufFormat}; 17 18 impl Pixbuf { 19 #[doc(alias = "gdk_pixbuf_new_from_data")] from_mut_slice<T: AsMut<[u8]>>( data: T, colorspace: Colorspace, has_alpha: bool, bits_per_sample: i32, width: i32, height: i32, row_stride: i32, ) -> Pixbuf20 pub fn from_mut_slice<T: AsMut<[u8]>>( 21 data: T, 22 colorspace: Colorspace, 23 has_alpha: bool, 24 bits_per_sample: i32, 25 width: i32, 26 height: i32, 27 row_stride: i32, 28 ) -> Pixbuf { 29 unsafe extern "C" fn destroy<T: AsMut<[u8]>>(_: *mut c_uchar, data: *mut c_void) { 30 let _data: Box<T> = Box::from_raw(data as *mut T); // the data will be destroyed now 31 } 32 assert!(width > 0, "width must be greater than 0"); 33 assert!(height > 0, "height must be greater than 0"); 34 assert!(row_stride > 0, "row_stride must be greater than 0"); 35 assert!( 36 bits_per_sample == 8, 37 "bits_per_sample == 8 is the only supported value" 38 ); 39 40 let width = width as usize; 41 let height = height as usize; 42 let row_stride = row_stride as usize; 43 let bits_per_sample = bits_per_sample as usize; 44 45 let n_channels = if has_alpha { 4 } else { 3 }; 46 let last_row_len = width * ((n_channels * bits_per_sample + 7) / 8); 47 48 let mut data: Box<T> = Box::new(data); 49 50 let ptr = { 51 let data: &mut [u8] = (*data).as_mut(); 52 assert!( 53 data.len() >= ((height - 1) * row_stride + last_row_len) as usize, 54 "data.len() must fit the width, height, and row_stride" 55 ); 56 data.as_mut_ptr() 57 }; 58 59 unsafe { 60 from_glib_full(ffi::gdk_pixbuf_new_from_data( 61 ptr, 62 colorspace.into_glib(), 63 has_alpha.into_glib(), 64 bits_per_sample as i32, 65 width as i32, 66 height as i32, 67 row_stride as i32, 68 Some(destroy::<T>), 69 Box::into_raw(data) as *mut _, 70 )) 71 } 72 } 73 74 // rustdoc-stripper-ignore-next 75 /// Creates a `Pixbuf` from a type implementing `Read` (like `File`). 76 /// 77 /// ```no_run 78 /// use std::fs::File; 79 /// use gdk_pixbuf::Pixbuf; 80 /// 81 /// let f = File::open("some_file.png").expect("failed to open image"); 82 /// let pixbuf = Pixbuf::from_read(f).expect("failed to load image"); 83 /// ``` from_read<R: Read + Send + 'static>(r: R) -> Result<Pixbuf, Error>84 pub fn from_read<R: Read + Send + 'static>(r: R) -> Result<Pixbuf, Error> { 85 Pixbuf::from_stream(&gio::ReadInputStream::new(r), None::<&gio::Cancellable>) 86 } 87 88 #[doc(alias = "gdk_pixbuf_new_from_file")] 89 #[doc(alias = "gdk_pixbuf_new_from_file_utf8")] from_file<T: AsRef<Path>>(filename: T) -> Result<Pixbuf, Error>90 pub fn from_file<T: AsRef<Path>>(filename: T) -> Result<Pixbuf, Error> { 91 #[cfg(not(windows))] 92 use ffi::gdk_pixbuf_new_from_file; 93 #[cfg(windows)] 94 use ffi::gdk_pixbuf_new_from_file_utf8 as gdk_pixbuf_new_from_file; 95 96 unsafe { 97 let mut error = ptr::null_mut(); 98 let ptr = gdk_pixbuf_new_from_file(filename.as_ref().to_glib_none().0, &mut error); 99 if error.is_null() { 100 Ok(from_glib_full(ptr)) 101 } else { 102 Err(from_glib_full(error)) 103 } 104 } 105 } 106 107 #[doc(alias = "gdk_pixbuf_new_from_file_at_size")] 108 #[doc(alias = "gdk_pixbuf_new_from_file_at_size_utf8")] from_file_at_size<T: AsRef<Path>>( filename: T, width: i32, height: i32, ) -> Result<Pixbuf, Error>109 pub fn from_file_at_size<T: AsRef<Path>>( 110 filename: T, 111 width: i32, 112 height: i32, 113 ) -> Result<Pixbuf, Error> { 114 #[cfg(not(windows))] 115 use ffi::gdk_pixbuf_new_from_file_at_size; 116 #[cfg(windows)] 117 use ffi::gdk_pixbuf_new_from_file_at_size_utf8 as gdk_pixbuf_new_from_file_at_size; 118 119 unsafe { 120 let mut error = ptr::null_mut(); 121 let ptr = gdk_pixbuf_new_from_file_at_size( 122 filename.as_ref().to_glib_none().0, 123 width, 124 height, 125 &mut error, 126 ); 127 if error.is_null() { 128 Ok(from_glib_full(ptr)) 129 } else { 130 Err(from_glib_full(error)) 131 } 132 } 133 } 134 135 #[doc(alias = "gdk_pixbuf_new_from_file_at_scale")] 136 #[doc(alias = "gdk_pixbuf_new_from_file_at_scale_utf8")] from_file_at_scale<T: AsRef<Path>>( filename: T, width: i32, height: i32, preserve_aspect_ratio: bool, ) -> Result<Pixbuf, Error>137 pub fn from_file_at_scale<T: AsRef<Path>>( 138 filename: T, 139 width: i32, 140 height: i32, 141 preserve_aspect_ratio: bool, 142 ) -> Result<Pixbuf, Error> { 143 #[cfg(not(windows))] 144 use ffi::gdk_pixbuf_new_from_file_at_scale; 145 #[cfg(windows)] 146 use ffi::gdk_pixbuf_new_from_file_at_scale_utf8 as gdk_pixbuf_new_from_file_at_scale; 147 148 unsafe { 149 let mut error = ptr::null_mut(); 150 let ptr = gdk_pixbuf_new_from_file_at_scale( 151 filename.as_ref().to_glib_none().0, 152 width, 153 height, 154 preserve_aspect_ratio.into_glib(), 155 &mut error, 156 ); 157 if error.is_null() { 158 Ok(from_glib_full(ptr)) 159 } else { 160 Err(from_glib_full(error)) 161 } 162 } 163 } 164 165 #[doc(alias = "gdk_pixbuf_new_from_stream_async")] from_stream_async< P: IsA<gio::InputStream>, Q: IsA<gio::Cancellable>, R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, >( stream: &P, cancellable: Option<&Q>, callback: R, )166 pub fn from_stream_async< 167 P: IsA<gio::InputStream>, 168 Q: IsA<gio::Cancellable>, 169 R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, 170 >( 171 stream: &P, 172 cancellable: Option<&Q>, 173 callback: R, 174 ) { 175 let cancellable = cancellable.map(|p| p.as_ref()); 176 let user_data: Box<R> = Box::new(callback); 177 unsafe extern "C" fn from_stream_async_trampoline< 178 R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, 179 >( 180 _source_object: *mut glib::gobject_ffi::GObject, 181 res: *mut gio::ffi::GAsyncResult, 182 user_data: glib::ffi::gpointer, 183 ) { 184 let mut error = ptr::null_mut(); 185 let ptr = ffi::gdk_pixbuf_new_from_stream_finish(res, &mut error); 186 let result = if error.is_null() { 187 Ok(from_glib_full(ptr)) 188 } else { 189 Err(from_glib_full(error)) 190 }; 191 let callback: Box<R> = Box::from_raw(user_data as *mut _); 192 callback(result); 193 } 194 let callback = from_stream_async_trampoline::<R>; 195 unsafe { 196 ffi::gdk_pixbuf_new_from_stream_async( 197 stream.as_ref().to_glib_none().0, 198 cancellable.to_glib_none().0, 199 Some(callback), 200 Box::into_raw(user_data) as *mut _, 201 ); 202 } 203 } 204 from_stream_async_future<P: IsA<gio::InputStream> + Clone + 'static>( stream: &P, ) -> Pin<Box<dyn Future<Output = Result<Pixbuf, Error>> + 'static>>205 pub fn from_stream_async_future<P: IsA<gio::InputStream> + Clone + 'static>( 206 stream: &P, 207 ) -> Pin<Box<dyn Future<Output = Result<Pixbuf, Error>> + 'static>> { 208 let stream = stream.clone(); 209 Box::pin(gio::GioFuture::new(&(), move |_obj, cancellable, send| { 210 Self::from_stream_async(&stream, Some(cancellable), move |res| { 211 send.resolve(res); 212 }); 213 })) 214 } 215 216 #[doc(alias = "gdk_pixbuf_new_from_stream_at_scale_async")] from_stream_at_scale_async< P: IsA<gio::InputStream>, Q: IsA<gio::Cancellable>, R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, >( stream: &P, width: i32, height: i32, preserve_aspect_ratio: bool, cancellable: Option<&Q>, callback: R, )217 pub fn from_stream_at_scale_async< 218 P: IsA<gio::InputStream>, 219 Q: IsA<gio::Cancellable>, 220 R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, 221 >( 222 stream: &P, 223 width: i32, 224 height: i32, 225 preserve_aspect_ratio: bool, 226 cancellable: Option<&Q>, 227 callback: R, 228 ) { 229 let cancellable = cancellable.map(|p| p.as_ref()); 230 let user_data: Box<R> = Box::new(callback); 231 unsafe extern "C" fn from_stream_at_scale_async_trampoline< 232 R: FnOnce(Result<Pixbuf, Error>) + Send + 'static, 233 >( 234 _source_object: *mut glib::gobject_ffi::GObject, 235 res: *mut gio::ffi::GAsyncResult, 236 user_data: glib::ffi::gpointer, 237 ) { 238 let mut error = ptr::null_mut(); 239 let ptr = ffi::gdk_pixbuf_new_from_stream_finish(res, &mut error); 240 let result = if error.is_null() { 241 Ok(from_glib_full(ptr)) 242 } else { 243 Err(from_glib_full(error)) 244 }; 245 let callback: Box<R> = Box::from_raw(user_data as *mut _); 246 callback(result); 247 } 248 let callback = from_stream_at_scale_async_trampoline::<R>; 249 unsafe { 250 ffi::gdk_pixbuf_new_from_stream_at_scale_async( 251 stream.as_ref().to_glib_none().0, 252 width, 253 height, 254 preserve_aspect_ratio.into_glib(), 255 cancellable.to_glib_none().0, 256 Some(callback), 257 Box::into_raw(user_data) as *mut _, 258 ); 259 } 260 } 261 from_stream_at_scale_async_future<P: IsA<gio::InputStream> + Clone + 'static>( stream: &P, width: i32, height: i32, preserve_aspect_ratio: bool, ) -> Pin<Box<dyn Future<Output = Result<Pixbuf, Error>> + 'static>>262 pub fn from_stream_at_scale_async_future<P: IsA<gio::InputStream> + Clone + 'static>( 263 stream: &P, 264 width: i32, 265 height: i32, 266 preserve_aspect_ratio: bool, 267 ) -> Pin<Box<dyn Future<Output = Result<Pixbuf, Error>> + 'static>> { 268 let stream = stream.clone(); 269 Box::pin(gio::GioFuture::new(&(), move |_obj, cancellable, send| { 270 Self::from_stream_at_scale_async( 271 &stream, 272 width, 273 height, 274 preserve_aspect_ratio, 275 Some(cancellable), 276 move |res| { 277 send.resolve(res); 278 }, 279 ); 280 })) 281 } 282 283 #[allow(clippy::mut_from_ref)] 284 #[allow(clippy::missing_safety_doc)] 285 #[doc(alias = "gdk_pixbuf_get_pixels_with_length")] 286 #[doc(alias = "get_pixels")] pixels(&self) -> &mut [u8]287 pub unsafe fn pixels(&self) -> &mut [u8] { 288 let mut len = 0; 289 let ptr = ffi::gdk_pixbuf_get_pixels_with_length(self.to_glib_none().0, &mut len); 290 slice::from_raw_parts_mut(ptr, len as usize) 291 } 292 put_pixel(&self, x: u32, y: u32, red: u8, green: u8, blue: u8, alpha: u8)293 pub fn put_pixel(&self, x: u32, y: u32, red: u8, green: u8, blue: u8, alpha: u8) { 294 assert!( 295 x < self.width() as u32, 296 "x must be less than the pixbuf's width" 297 ); 298 assert!( 299 y < self.height() as u32, 300 "y must be less than the pixbuf's height" 301 ); 302 303 unsafe { 304 let x = x as usize; 305 let y = y as usize; 306 let n_channels = self.n_channels() as usize; 307 assert!(n_channels == 3 || n_channels == 4); 308 let rowstride = self.rowstride() as usize; 309 let pixels = self.pixels(); 310 let pos = y * rowstride + x * n_channels; 311 312 pixels[pos] = red; 313 pixels[pos + 1] = green; 314 pixels[pos + 2] = blue; 315 if n_channels == 4 { 316 pixels[pos + 3] = alpha; 317 } 318 } 319 } 320 321 #[doc(alias = "gdk_pixbuf_get_file_info")] 322 #[doc(alias = "get_file_info")] file_info<T: AsRef<Path>>(filename: T) -> Option<(PixbufFormat, i32, i32)>323 pub fn file_info<T: AsRef<Path>>(filename: T) -> Option<(PixbufFormat, i32, i32)> { 324 unsafe { 325 let mut width = mem::MaybeUninit::uninit(); 326 let mut height = mem::MaybeUninit::uninit(); 327 let ret = ffi::gdk_pixbuf_get_file_info( 328 filename.as_ref().to_glib_none().0, 329 width.as_mut_ptr(), 330 height.as_mut_ptr(), 331 ); 332 if !ret.is_null() { 333 Some(( 334 from_glib_none(ret), 335 width.assume_init(), 336 height.assume_init(), 337 )) 338 } else { 339 None 340 } 341 } 342 } 343 344 #[doc(alias = "gdk_pixbuf_get_file_info_async")] 345 #[doc(alias = "get_file_info_async")] file_info_async< P: IsA<gio::Cancellable>, Q: FnOnce(Result<Option<(PixbufFormat, i32, i32)>, Error>) + Send + 'static, T: AsRef<Path>, >( filename: T, cancellable: Option<&P>, callback: Q, )346 pub fn file_info_async< 347 P: IsA<gio::Cancellable>, 348 Q: FnOnce(Result<Option<(PixbufFormat, i32, i32)>, Error>) + Send + 'static, 349 T: AsRef<Path>, 350 >( 351 filename: T, 352 cancellable: Option<&P>, 353 callback: Q, 354 ) { 355 let cancellable = cancellable.map(|p| p.as_ref()); 356 let user_data: Box<Q> = Box::new(callback); 357 unsafe extern "C" fn get_file_info_async_trampoline< 358 Q: FnOnce(Result<Option<(PixbufFormat, i32, i32)>, Error>) + Send + 'static, 359 >( 360 _source_object: *mut glib::gobject_ffi::GObject, 361 res: *mut gio::ffi::GAsyncResult, 362 user_data: glib::ffi::gpointer, 363 ) { 364 let mut error = ptr::null_mut(); 365 let mut width = mem::MaybeUninit::uninit(); 366 let mut height = mem::MaybeUninit::uninit(); 367 let ret = ffi::gdk_pixbuf_get_file_info_finish( 368 res, 369 width.as_mut_ptr(), 370 height.as_mut_ptr(), 371 &mut error, 372 ); 373 let result = if !error.is_null() { 374 Err(from_glib_full(error)) 375 } else if ret.is_null() { 376 Ok(None) 377 } else { 378 Ok(Some(( 379 from_glib_none(ret), 380 width.assume_init(), 381 height.assume_init(), 382 ))) 383 }; 384 let callback: Box<Q> = Box::from_raw(user_data as *mut _); 385 callback(result); 386 } 387 let callback = get_file_info_async_trampoline::<Q>; 388 unsafe { 389 ffi::gdk_pixbuf_get_file_info_async( 390 filename.as_ref().to_glib_none().0, 391 cancellable.to_glib_none().0, 392 Some(callback), 393 Box::into_raw(user_data) as *mut _, 394 ); 395 } 396 } 397 398 #[allow(clippy::type_complexity)] 399 #[doc(alias = "get_file_info_async_future")] file_info_async_future<T: AsRef<Path> + Clone + 'static>( filename: T, ) -> Pin<Box<dyn Future<Output = Result<Option<(PixbufFormat, i32, i32)>, Error>> + 'static>>400 pub fn file_info_async_future<T: AsRef<Path> + Clone + 'static>( 401 filename: T, 402 ) -> Pin<Box<dyn Future<Output = Result<Option<(PixbufFormat, i32, i32)>, Error>> + 'static>> 403 { 404 Box::pin(gio::GioFuture::new(&(), move |_obj, cancellable, send| { 405 Self::file_info_async(filename, Some(cancellable), move |res| { 406 send.resolve(res); 407 }); 408 })) 409 } 410 411 #[doc(alias = "gdk_pixbuf_save_to_bufferv")] save_to_bufferv(&self, type_: &str, options: &[(&str, &str)]) -> Result<Vec<u8>, Error>412 pub fn save_to_bufferv(&self, type_: &str, options: &[(&str, &str)]) -> Result<Vec<u8>, Error> { 413 unsafe { 414 let mut buffer = ptr::null_mut(); 415 let mut buffer_size = mem::MaybeUninit::uninit(); 416 let mut error = ptr::null_mut(); 417 let option_keys: Vec<&str> = options.iter().map(|o| o.0).collect(); 418 let option_values: Vec<&str> = options.iter().map(|o| o.1).collect(); 419 let _ = ffi::gdk_pixbuf_save_to_bufferv( 420 self.to_glib_none().0, 421 &mut buffer, 422 buffer_size.as_mut_ptr(), 423 type_.to_glib_none().0, 424 option_keys.to_glib_none().0, 425 option_values.to_glib_none().0, 426 &mut error, 427 ); 428 if error.is_null() { 429 Ok(FromGlibContainer::from_glib_full_num( 430 buffer, 431 buffer_size.assume_init() as usize, 432 )) 433 } else { 434 Err(from_glib_full(error)) 435 } 436 } 437 } 438 439 #[cfg(any(feature = "v2_36", feature = "dox"))] 440 #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_36")))] 441 #[doc(alias = "gdk_pixbuf_save_to_streamv")] save_to_streamv<P: IsA<gio::OutputStream>, Q: IsA<gio::Cancellable>>( &self, stream: &P, type_: &str, options: &[(&str, &str)], cancellable: Option<&Q>, ) -> Result<(), Error>442 pub fn save_to_streamv<P: IsA<gio::OutputStream>, Q: IsA<gio::Cancellable>>( 443 &self, 444 stream: &P, 445 type_: &str, 446 options: &[(&str, &str)], 447 cancellable: Option<&Q>, 448 ) -> Result<(), Error> { 449 let cancellable = cancellable.map(|p| p.as_ref()); 450 unsafe { 451 let mut error = ptr::null_mut(); 452 let option_keys: Vec<&str> = options.iter().map(|o| o.0).collect(); 453 let option_values: Vec<&str> = options.iter().map(|o| o.1).collect(); 454 let _ = ffi::gdk_pixbuf_save_to_streamv( 455 self.to_glib_none().0, 456 stream.as_ref().to_glib_none().0, 457 type_.to_glib_none().0, 458 option_keys.to_glib_none().0, 459 option_values.to_glib_none().0, 460 cancellable.to_glib_none().0, 461 &mut error, 462 ); 463 if error.is_null() { 464 Ok(()) 465 } else { 466 Err(from_glib_full(error)) 467 } 468 } 469 } 470 471 #[cfg(any(feature = "v2_36", feature = "dox"))] 472 #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_36")))] 473 #[doc(alias = "gdk_pixbuf_save_to_streamv_async")] save_to_streamv_async< P: IsA<gio::OutputStream>, Q: IsA<gio::Cancellable>, R: FnOnce(Result<(), Error>) + Send + 'static, >( &self, stream: &P, type_: &str, options: &[(&str, &str)], cancellable: Option<&Q>, callback: R, )474 pub fn save_to_streamv_async< 475 P: IsA<gio::OutputStream>, 476 Q: IsA<gio::Cancellable>, 477 R: FnOnce(Result<(), Error>) + Send + 'static, 478 >( 479 &self, 480 stream: &P, 481 type_: &str, 482 options: &[(&str, &str)], 483 cancellable: Option<&Q>, 484 callback: R, 485 ) { 486 let cancellable = cancellable.map(|p| p.as_ref()); 487 let user_data: Box<R> = Box::new(callback); 488 unsafe extern "C" fn save_to_streamv_async_trampoline< 489 R: FnOnce(Result<(), Error>) + Send + 'static, 490 >( 491 _source_object: *mut glib::gobject_ffi::GObject, 492 res: *mut gio::ffi::GAsyncResult, 493 user_data: glib::ffi::gpointer, 494 ) { 495 let mut error = ptr::null_mut(); 496 let _ = ffi::gdk_pixbuf_save_to_stream_finish(res, &mut error); 497 let result = if error.is_null() { 498 Ok(()) 499 } else { 500 Err(from_glib_full(error)) 501 }; 502 let callback: Box<R> = Box::from_raw(user_data as *mut _); 503 callback(result); 504 } 505 let callback = save_to_streamv_async_trampoline::<R>; 506 unsafe { 507 let option_keys: Vec<&str> = options.iter().map(|o| o.0).collect(); 508 let option_values: Vec<&str> = options.iter().map(|o| o.1).collect(); 509 ffi::gdk_pixbuf_save_to_streamv_async( 510 self.to_glib_none().0, 511 stream.as_ref().to_glib_none().0, 512 type_.to_glib_none().0, 513 option_keys.to_glib_none().0, 514 option_values.to_glib_none().0, 515 cancellable.to_glib_none().0, 516 Some(callback), 517 Box::into_raw(user_data) as *mut _, 518 ); 519 } 520 } 521 522 #[cfg(any(feature = "v2_36", feature = "dox"))] 523 #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_36")))] save_to_streamv_async_future<P: IsA<gio::OutputStream> + Clone + 'static>( &self, stream: &P, type_: &str, options: &[(&str, &str)], ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + 'static>>524 pub fn save_to_streamv_async_future<P: IsA<gio::OutputStream> + Clone + 'static>( 525 &self, 526 stream: &P, 527 type_: &str, 528 options: &[(&str, &str)], 529 ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + 'static>> { 530 let stream = stream.clone(); 531 let type_ = String::from(type_); 532 let options = options 533 .iter() 534 .map(|&(k, v)| (String::from(k), String::from(v))) 535 .collect::<Vec<(String, String)>>(); 536 Box::pin(gio::GioFuture::new(self, move |obj, cancellable, send| { 537 let options = options 538 .iter() 539 .map(|&(ref k, ref v)| (k.as_str(), v.as_str())) 540 .collect::<Vec<(&str, &str)>>(); 541 542 obj.save_to_streamv_async( 543 &stream, 544 &type_, 545 options.as_slice(), 546 Some(cancellable), 547 move |res| { 548 send.resolve(res); 549 }, 550 ); 551 })) 552 } 553 554 #[doc(alias = "gdk_pixbuf_savev")] savev<T: AsRef<Path>>( &self, filename: T, type_: &str, options: &[(&str, &str)], ) -> Result<(), Error>555 pub fn savev<T: AsRef<Path>>( 556 &self, 557 filename: T, 558 type_: &str, 559 options: &[(&str, &str)], 560 ) -> Result<(), Error> { 561 unsafe { 562 let mut error = ptr::null_mut(); 563 let option_keys: Vec<&str> = options.iter().map(|o| o.0).collect(); 564 let option_values: Vec<&str> = options.iter().map(|o| o.1).collect(); 565 let _ = ffi::gdk_pixbuf_savev( 566 self.to_glib_none().0, 567 filename.as_ref().to_glib_none().0, 568 type_.to_glib_none().0, 569 option_keys.to_glib_none().0, 570 option_values.to_glib_none().0, 571 &mut error, 572 ); 573 if error.is_null() { 574 Ok(()) 575 } else { 576 Err(from_glib_full(error)) 577 } 578 } 579 } 580 } 581