1 //!
2 //! A binding for the library `SDL2_image`
3 //!
4 //!
5 //! Note that you need to build with the
6 //! feature `image` for this module to be enabled,
7 //! like so:
8 //!
9 //! ```bash
10 //! $ cargo build --features "image"
11 //! ```
12 //!
13 //! If you want to use this with from inside your own
14 //! crate, you will need to add this in your Cargo.toml
15 //!
16 //! ```toml
17 //! [dependencies.sdl2]
18 //! version = ...
19 //! default-features = false
20 //! features = ["image"]
21 //! ```
22 
23 use std::os::raw::{c_int, c_char};
24 use std::ffi::CString;
25 use std::path::Path;
26 use surface::Surface;
27 use render::{TextureCreator, Texture};
28 use rwops::RWops;
29 use version::Version;
30 use get_error;
31 use sys;
32 
33 /// InitFlags are passed to init() to control which subsystem
34 /// functionality to load.
35 bitflags! {
36     pub struct InitFlag : u32 {
37         const JPG  = sys::image::IMG_InitFlags_IMG_INIT_JPG as u32;
38         const PNG  = sys::image::IMG_InitFlags_IMG_INIT_PNG as u32;
39         const TIF  = sys::image::IMG_InitFlags_IMG_INIT_TIF as u32;
40         const WEBP = sys::image::IMG_InitFlags_IMG_INIT_WEBP as u32;
41     }
42 }
43 
44 // This is used for error message for init
45 impl ::std::fmt::Display for InitFlag {
fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result46     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
47         if self.contains(InitFlag::JPG) {
48             try!(f.write_str("INIT_JPG "));
49         }
50         if self.contains(InitFlag::PNG) {
51             try!(f.write_str("INIT_PNG "));
52         }
53         if self.contains(InitFlag::TIF) {
54             try!(f.write_str("INIT_TIF "));
55         }
56         if self.contains(InitFlag::WEBP) {
57             try!(f.write_str("INIT_WEBP "));
58         }
59         Ok(())
60     }
61 }
62 
63 
64 /// Static method extensions for creating Surfaces
65 pub trait LoadSurface: Sized {
66     // Self is only returned here to type hint to the compiler.
67     // The syntax for type hinting in this case is not yet defined.
68     // The intended return value is Result<~Surface, String>.
from_file<P: AsRef<Path>>(filename: P) -> Result<Self, String>69     fn from_file<P: AsRef<Path>>(filename: P) -> Result<Self, String>;
from_xpm_array(xpm: *const *const i8) -> Result<Self, String>70     fn from_xpm_array(xpm: *const *const i8) -> Result<Self, String>;
71 }
72 
73 /// Method extensions to Surface for saving to disk
74 pub trait SaveSurface {
save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String>75     fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String>;
save_rw(&self, dst: &mut RWops) -> Result<(), String>76     fn save_rw(&self, dst: &mut RWops) -> Result<(), String>;
77 }
78 
79 impl<'a> LoadSurface for Surface<'a> {
from_file<P: AsRef<Path>>(filename: P) -> Result<Surface<'a>, String>80     fn from_file<P: AsRef<Path>>(filename: P) -> Result<Surface<'a>, String> {
81         //! Loads an SDL Surface from a file
82         unsafe {
83             let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
84             let raw = sys::image::IMG_Load(c_filename.as_ptr() as *const _);
85             if (raw as *mut ()).is_null() {
86                 Err(get_error())
87             } else {
88                 Ok(Surface::from_ll(raw))
89             }
90         }
91     }
92 
from_xpm_array(xpm: *const *const i8) -> Result<Surface<'a>, String>93     fn from_xpm_array(xpm: *const *const i8) -> Result<Surface<'a>, String> {
94         //! Loads an SDL Surface from XPM data
95         unsafe {
96             let raw = sys::image::IMG_ReadXPMFromArray(xpm as *mut *mut c_char);
97             if (raw as *mut ()).is_null() {
98                 Err(get_error())
99             } else {
100                 Ok(Surface::from_ll(raw))
101             }
102         }
103     }
104 }
105 
106 impl<'a> SaveSurface for Surface<'a> {
save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String>107     fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String> {
108         //! Saves an SDL Surface to a file
109         unsafe {
110             let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
111             let status = sys::image::IMG_SavePNG(self.raw(), c_filename.as_ptr() as *const _);
112             if status != 0 {
113                 Err(get_error())
114             } else {
115                 Ok(())
116             }
117         }
118     }
119 
save_rw(&self, dst: &mut RWops) -> Result<(), String>120     fn save_rw(&self, dst: &mut RWops) -> Result<(), String> {
121         //! Saves an SDL Surface to an RWops
122         unsafe {
123             let status = sys::image::IMG_SavePNG_RW(self.raw(), dst.raw(), 0);
124 
125             if status != 0 {
126                 Err(get_error())
127             } else {
128                 Ok(())
129             }
130         }
131     }
132 }
133 
134 /// Method extensions for creating Textures from a `TextureCreator`
135 pub trait LoadTexture {
load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String>136     fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String>;
137 }
138 
139 impl<T> LoadTexture for TextureCreator<T> {
load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String>140     fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String> {
141         //! Loads an SDL Texture from a file
142         unsafe {
143             let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
144             let raw = sys::image::IMG_LoadTexture(self.raw(), c_filename.as_ptr() as *const _);
145             if (raw as *mut ()).is_null() {
146                 Err(get_error())
147             } else {
148                 Ok(self.raw_create_texture(raw))
149             }
150         }
151     }
152 }
153 
154 /// Context manager for `sdl2_image` to manage quitting. Can't do much with it but
155 /// keep it alive while you are using it.
156 pub struct Sdl2ImageContext;
157 
158 impl Drop for Sdl2ImageContext {
drop(&mut self)159     fn drop(&mut self) {
160         unsafe {
161             sys::image::IMG_Quit();
162         }
163     }
164 }
165 
166 /// Initializes `SDL2_image` with `InitFlags`.
167 /// If not every flag is set it returns an error
init(flags: InitFlag) -> Result<Sdl2ImageContext, String>168 pub fn init(flags: InitFlag) -> Result<Sdl2ImageContext, String> {
169     let return_flags = unsafe {
170         let used = sys::image::IMG_Init(flags.bits() as c_int);
171         InitFlag::from_bits_truncate(used as u32)
172     };
173     if !flags.intersects(return_flags) {
174         // According to docs, error message text is not always set
175         let mut error = get_error();
176         if error.is_empty() {
177             let un_init_flags = return_flags ^ flags;
178             error = format!("Could not init: {}", un_init_flags);
179             let _ = ::set_error(&error);
180         }
181         Err(error)
182     } else {
183         Ok(Sdl2ImageContext)
184     }
185 }
186 
187 /// Returns the version of the dynamically linked `SDL_image` library
get_linked_version() -> Version188 pub fn get_linked_version() -> Version {
189     unsafe { Version::from_ll(*sys::image::IMG_Linked_Version()) }
190 }
191 
192 #[inline]
to_surface_result<'a>(raw: *mut sys::SDL_Surface) -> Result<Surface<'a>, String>193 fn to_surface_result<'a>(raw: *mut sys::SDL_Surface) -> Result<Surface<'a>, String> {
194     if (raw as *mut ()).is_null() {
195         Err(get_error())
196     } else {
197         unsafe { Ok(Surface::from_ll(raw)) }
198     }
199 }
200 
201 pub trait ImageRWops {
202     /// load as a surface. except TGA
load(&self) -> Result<Surface, String>203     fn load(&self) -> Result<Surface, String>;
204     /// load as a surface. This can load all supported image formats.
load_typed(&self, _type: &str) -> Result<Surface, String>205     fn load_typed(&self, _type: &str) -> Result<Surface, String>;
206 
load_cur(&self) -> Result<Surface, String>207     fn load_cur(&self) -> Result<Surface, String>;
load_ico(&self) -> Result<Surface, String>208     fn load_ico(&self) -> Result<Surface, String>;
load_bmp(&self) -> Result<Surface, String>209     fn load_bmp(&self) -> Result<Surface, String>;
load_pnm(&self) -> Result<Surface, String>210     fn load_pnm(&self) -> Result<Surface, String>;
load_xpm(&self) -> Result<Surface, String>211     fn load_xpm(&self) -> Result<Surface, String>;
load_xcf(&self) -> Result<Surface, String>212     fn load_xcf(&self) -> Result<Surface, String>;
load_pcx(&self) -> Result<Surface, String>213     fn load_pcx(&self) -> Result<Surface, String>;
load_gif(&self) -> Result<Surface, String>214     fn load_gif(&self) -> Result<Surface, String>;
load_jpg(&self) -> Result<Surface, String>215     fn load_jpg(&self) -> Result<Surface, String>;
load_tif(&self) -> Result<Surface, String>216     fn load_tif(&self) -> Result<Surface, String>;
load_png(&self) -> Result<Surface, String>217     fn load_png(&self) -> Result<Surface, String>;
load_tga(&self) -> Result<Surface, String>218     fn load_tga(&self) -> Result<Surface, String>;
load_lbm(&self) -> Result<Surface, String>219     fn load_lbm(&self) -> Result<Surface, String>;
load_xv(&self) -> Result<Surface, String>220     fn load_xv(&self) -> Result<Surface, String>;
load_webp(&self) -> Result<Surface, String>221     fn load_webp(&self) -> Result<Surface, String>;
222 
is_cur(&self) -> bool223     fn is_cur(&self) -> bool;
is_ico(&self) -> bool224     fn is_ico(&self) -> bool;
is_bmp(&self) -> bool225     fn is_bmp(&self) -> bool;
is_pnm(&self) -> bool226     fn is_pnm(&self) -> bool;
is_xpm(&self) -> bool227     fn is_xpm(&self) -> bool;
is_xcf(&self) -> bool228     fn is_xcf(&self) -> bool;
is_pcx(&self) -> bool229     fn is_pcx(&self) -> bool;
is_gif(&self) -> bool230     fn is_gif(&self) -> bool;
is_jpg(&self) -> bool231     fn is_jpg(&self) -> bool;
is_tif(&self) -> bool232     fn is_tif(&self) -> bool;
is_png(&self) -> bool233     fn is_png(&self) -> bool;
is_lbm(&self) -> bool234     fn is_lbm(&self) -> bool;
is_xv(&self) -> bool235     fn is_xv(&self) -> bool;
is_webp(&self) -> bool236     fn is_webp(&self) -> bool;
237 }
238 
239 impl<'a> ImageRWops for RWops<'a> {
load(&self) -> Result<Surface, String>240     fn load(&self) -> Result<Surface, String> {
241         let raw = unsafe { sys::image::IMG_Load_RW(self.raw(), 0) };
242         to_surface_result(raw)
243     }
load_typed(&self, _type: &str) -> Result<Surface, String>244     fn load_typed(&self, _type: &str) -> Result<Surface, String> {
245         let raw = unsafe {
246             let c_type = CString::new(_type.as_bytes()).unwrap();
247             sys::image::IMG_LoadTyped_RW(self.raw(), 0, c_type.as_ptr() as *const _)
248         };
249         to_surface_result(raw)
250     }
251 
load_cur(&self) -> Result<Surface, String>252     fn load_cur(&self) -> Result<Surface, String> {
253         let raw = unsafe { sys::image::IMG_LoadCUR_RW(self.raw()) };
254         to_surface_result(raw)
255     }
load_ico(&self) -> Result<Surface, String>256     fn load_ico(&self) -> Result<Surface, String> {
257         let raw = unsafe { sys::image::IMG_LoadICO_RW(self.raw()) };
258         to_surface_result(raw)
259     }
load_bmp(&self) -> Result<Surface, String>260     fn load_bmp(&self) -> Result<Surface, String> {
261         let raw = unsafe { sys::image::IMG_LoadBMP_RW(self.raw()) };
262         to_surface_result(raw)
263     }
load_pnm(&self) -> Result<Surface, String>264     fn load_pnm(&self) -> Result<Surface, String> {
265         let raw = unsafe { sys::image::IMG_LoadPNM_RW(self.raw()) };
266         to_surface_result(raw)
267     }
load_xpm(&self) -> Result<Surface, String>268     fn load_xpm(&self) -> Result<Surface, String> {
269         let raw = unsafe { sys::image::IMG_LoadXPM_RW(self.raw()) };
270         to_surface_result(raw)
271     }
load_xcf(&self) -> Result<Surface, String>272     fn load_xcf(&self) -> Result<Surface, String> {
273         let raw = unsafe { sys::image::IMG_LoadXCF_RW(self.raw()) };
274         to_surface_result(raw)
275     }
load_pcx(&self) -> Result<Surface, String>276     fn load_pcx(&self) -> Result<Surface, String> {
277         let raw = unsafe { sys::image::IMG_LoadPCX_RW(self.raw()) };
278         to_surface_result(raw)
279     }
load_gif(&self) -> Result<Surface, String>280     fn load_gif(&self) -> Result<Surface, String> {
281         let raw = unsafe { sys::image::IMG_LoadGIF_RW(self.raw()) };
282         to_surface_result(raw)
283     }
load_jpg(&self) -> Result<Surface, String>284     fn load_jpg(&self) -> Result<Surface, String> {
285         let raw = unsafe { sys::image::IMG_LoadJPG_RW(self.raw()) };
286         to_surface_result(raw)
287     }
load_tif(&self) -> Result<Surface, String>288     fn load_tif(&self) -> Result<Surface, String> {
289         let raw = unsafe { sys::image::IMG_LoadTIF_RW(self.raw()) };
290         to_surface_result(raw)
291     }
load_png(&self) -> Result<Surface, String>292     fn load_png(&self) -> Result<Surface, String> {
293         let raw = unsafe { sys::image::IMG_LoadPNG_RW(self.raw()) };
294         to_surface_result(raw)
295     }
load_tga(&self) -> Result<Surface, String>296     fn load_tga(&self) -> Result<Surface, String> {
297         let raw = unsafe { sys::image::IMG_LoadTGA_RW(self.raw()) };
298         to_surface_result(raw)
299     }
load_lbm(&self) -> Result<Surface, String>300     fn load_lbm(&self) -> Result<Surface, String> {
301         let raw = unsafe { sys::image::IMG_LoadLBM_RW(self.raw()) };
302         to_surface_result(raw)
303     }
load_xv(&self) -> Result<Surface, String>304     fn load_xv(&self) -> Result<Surface, String> {
305         let raw = unsafe { sys::image::IMG_LoadXV_RW(self.raw()) };
306         to_surface_result(raw)
307     }
load_webp(&self) -> Result<Surface, String>308     fn load_webp(&self) -> Result<Surface, String> {
309         let raw = unsafe { sys::image::IMG_LoadWEBP_RW(self.raw()) };
310         to_surface_result(raw)
311     }
312 
is_cur(&self) -> bool313     fn is_cur(&self) -> bool {
314         unsafe { sys::image::IMG_isCUR(self.raw()) == 1 }
315     }
is_ico(&self) -> bool316     fn is_ico(&self) -> bool {
317         unsafe { sys::image::IMG_isICO(self.raw()) == 1 }
318     }
is_bmp(&self) -> bool319     fn is_bmp(&self) -> bool {
320         unsafe { sys::image::IMG_isBMP(self.raw()) == 1 }
321     }
is_pnm(&self) -> bool322     fn is_pnm(&self) -> bool {
323         unsafe { sys::image::IMG_isPNM(self.raw()) == 1 }
324     }
is_xpm(&self) -> bool325     fn is_xpm(&self) -> bool {
326         unsafe { sys::image::IMG_isXPM(self.raw()) == 1 }
327     }
is_xcf(&self) -> bool328     fn is_xcf(&self) -> bool {
329         unsafe { sys::image::IMG_isXCF(self.raw()) == 1 }
330     }
is_pcx(&self) -> bool331     fn is_pcx(&self) -> bool {
332         unsafe { sys::image::IMG_isPCX(self.raw()) == 1 }
333     }
is_gif(&self) -> bool334     fn is_gif(&self) -> bool {
335         unsafe { sys::image::IMG_isGIF(self.raw()) == 1 }
336     }
is_jpg(&self) -> bool337     fn is_jpg(&self) -> bool {
338         unsafe { sys::image::IMG_isJPG(self.raw()) == 1 }
339     }
is_tif(&self) -> bool340     fn is_tif(&self) -> bool {
341         unsafe { sys::image::IMG_isTIF(self.raw()) == 1 }
342     }
is_png(&self) -> bool343     fn is_png(&self) -> bool {
344         unsafe { sys::image::IMG_isPNG(self.raw()) == 1 }
345     }
is_lbm(&self) -> bool346     fn is_lbm(&self) -> bool {
347         unsafe { sys::image::IMG_isLBM(self.raw()) == 1 }
348     }
is_xv(&self) -> bool349     fn is_xv(&self) -> bool {
350         unsafe { sys::image::IMG_isXV(self.raw()) == 1 }
351     }
is_webp(&self) -> bool352     fn is_webp(&self) -> bool {
353         unsafe { sys::image::IMG_isWEBP(self.raw()) == 1 }
354     }
355 }
356