1 
2 //          Copyright Michael D. Parker 2018.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 
7 module bindbc.sdl.image;
8 
9 import bindbc.sdl.config;
10 static if(bindSDLImage):
11 
12 import bindbc.sdl.bind.sdlerror : SDL_GetError, SDL_SetError;
13 import bindbc.sdl.bind.sdlrender : SDL_Renderer, SDL_Texture;
14 import bindbc.sdl.bind.sdlrwops : SDL_RWops;
15 import bindbc.sdl.bind.sdlsurface : SDL_Surface;
16 import bindbc.sdl.bind.sdlversion : SDL_version, SDL_VERSIONNUM;
17 
18 alias IMG_SetError = SDL_SetError;
19 alias IMG_GetError = SDL_GetError;
20 
21 enum SDLImageSupport {
22     noLibrary,
23     badLibrary,
24     sdlImage200 = 200,
25     sdlImage201,
26     sdlImage202,
27     sdlImage203,
28     sdlImage204,
29     sdlImage205,
30 }
31 
32 enum ubyte SDL_IMAGE_MAJOR_VERSION = 2;
33 enum ubyte SDL_IMAGE_MINOR_VERSION = 0;
34 
35 
36 version(SDL_Image_205) {
37     enum sdlImageSupport = SDLImageSupport.sdlImage205;
38     enum ubyte SDL_IMAGE_PATCHLEVEL = 5;
39 }
40 else version(SDL_Image_204) {
41     enum sdlImageSupport = SDLImageSupport.sdlImage204;
42     enum ubyte SDL_IMAGE_PATCHLEVEL = 4;
43 }
44 else version(SDL_Image_203) {
45     enum sdlImageSupport = SDLImageSupport.sdlImage203;
46     enum ubyte SDL_IMAGE_PATCHLEVEL = 3;
47 }
48 else version(SDL_Image_202) {
49     enum sdlImageSupport = SDLImageSupport.sdlImage202;
50     enum ubyte SDL_IMAGE_PATCHLEVEL = 2;
51 }
52 else version(SDL_Image_201) {
53     enum sdlImageSupport = SDLImageSupport.sdlImage201;
54     enum ubyte SDL_IMAGE_PATCHLEVEL = 1;
55 }
56 else {
57     enum sdlImageSupport = SDLImageSupport.sdlImage200;
58     enum ubyte SDL_IMAGE_PATCHLEVEL = 0;
59 }
60 
61 @nogc nothrow void SDL_IMAGE_VERSION(SDL_version* X)
62 {
63     X.major     = SDL_IMAGE_MAJOR_VERSION;
64     X.minor     = SDL_IMAGE_MINOR_VERSION;
65     X.patch     = SDL_IMAGE_PATCHLEVEL;
66 }
67 
68 // These were implemented in SDL_image 2.0.2, but are fine for all versions.
69 enum SDL_IMAGE_COMPILEDVERSION = SDL_VERSIONNUM!(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_PATCHLEVEL);
70 enum SDL_IMAGE_VERSION_ATLEAST(ubyte X, ubyte Y, ubyte Z) = SDL_IMAGE_COMPILEDVERSION >= SDL_VERSIONNUM!(X, Y, Z);
71 
72 enum {
73     IMG_INIT_JPG    = 0x00000001,
74     IMG_INIT_PNG    = 0x00000002,
75     IMG_INIT_TIF    = 0x00000004,
76     IMG_INIT_WEBP   = 0x00000008,
77 }
78 
79 static if(staticBinding) {
80     extern(C) @nogc nothrow {
81         int IMG_Init(int);
82         int IMG_Quit();
83         const(SDL_version)* IMG_Linked_Version();
84         SDL_Surface* IMG_LoadTyped_RW(SDL_RWops*,int,const(char)*);
85         SDL_Surface* IMG_Load(const(char)*);
86         SDL_Surface* IMG_Load_RW(SDL_RWops*,int);
87 
88         SDL_Texture* IMG_LoadTexture(SDL_Renderer*,const(char)*);
89         SDL_Texture* IMG_LoadTexture_RW(SDL_Renderer*,SDL_RWops*,int);
90         SDL_Texture* IMG_LoadTextureTyped_RW(SDL_Renderer*,SDL_RWops*,int,const(char)*);
91 
92         int IMG_isICO(SDL_RWops*);
93         int IMG_isCUR(SDL_RWops*);
94         int IMG_isBMP(SDL_RWops*);
95         int IMG_isGIF(SDL_RWops*);
96         int IMG_isJPG(SDL_RWops*);
97         int IMG_isLBM(SDL_RWops*);
98         int IMG_isPCX(SDL_RWops*);
99         int IMG_isPNG(SDL_RWops*);
100         int IMG_isPNM(SDL_RWops*);
101         int IMG_isTIF(SDL_RWops*);
102         int IMG_isXCF(SDL_RWops*);
103         int IMG_isXPM(SDL_RWops*);
104         int IMG_isXV(SDL_RWops*);
105         int IMG_isWEBP(SDL_RWops*);
106 
107         SDL_Surface* IMG_LoadICO_RW(SDL_RWops*);
108         SDL_Surface* IMG_LoadCUR_RW(SDL_RWops*);
109         SDL_Surface* IMG_LoadBMP_RW(SDL_RWops*);
110         SDL_Surface* IMG_LoadGIF_RW(SDL_RWops*);
111         SDL_Surface* IMG_LoadJPG_RW(SDL_RWops*);
112         SDL_Surface* IMG_LoadLBM_RW(SDL_RWops*);
113         SDL_Surface* IMG_LoadPCX_RW(SDL_RWops*);
114         SDL_Surface* IMG_LoadPNG_RW(SDL_RWops*);
115         SDL_Surface* IMG_LoadPNM_RW(SDL_RWops*);
116         SDL_Surface* IMG_LoadTGA_RW(SDL_RWops*);
117         SDL_Surface* IMG_LoadTIF_RW(SDL_RWops*);
118         SDL_Surface* IMG_LoadXCF_RW(SDL_RWops*);
119         SDL_Surface* IMG_LoadXPM_RW(SDL_RWops*);
120         SDL_Surface* IMG_LoadXV_RW(SDL_RWops*);
121         SDL_Surface* IMG_LoadWEBP_RW(SDL_RWops*);
122 
123         SDL_Surface* IMG_ReadXPMFromArray(char**);
124 
125         int IMG_SavePNG(SDL_Surface*,const(char)*);
126         int IMG_SavePNG_RW(SDL_Surface*,SDL_RWops*,int);
127 
128         static if(sdlImageSupport >= SDLImageSupport.sdlImage202) {
129             int IMG_isSVG(SDL_RWops*);
130             SDL_Surface* IMG_LoadSVG(SDL_RWops*);
131             int IMG_SaveJPG(SDL_Surface*,const(char)*,int);
132             int IMG_SaveJPG_RW(SDL_Surface*,SDL_RWops*,int,int);
133         }
134     }
135 }
136 else {
137     import bindbc.loader;
138 
139     extern(C) @nogc nothrow {
140         alias pIMG_Init = int function(int);
141         alias pIMG_Quit = int function();
142         alias pIMG_Linked_Version = const(SDL_version)* function();
143         alias pIMG_LoadTyped_RW = SDL_Surface* function(SDL_RWops*,int,const(char)*);
144         alias pIMG_Load = SDL_Surface* function(const(char)*);
145         alias pIMG_Load_RW = SDL_Surface* function(SDL_RWops*,int);
146 
147         alias pIMG_LoadTexture = SDL_Texture* function(SDL_Renderer*,const(char)*);
148         alias pIMG_LoadTexture_RW = SDL_Texture* function(SDL_Renderer*,SDL_RWops*,int);
149         alias pIMG_LoadTextureTyped_RW = SDL_Texture* function(SDL_Renderer*,SDL_RWops*,int,const(char)*);
150 
151         alias pIMG_isICO = int function(SDL_RWops*);
152         alias pIMG_isCUR = int function(SDL_RWops*);
153         alias pIMG_isBMP = int function(SDL_RWops*);
154         alias pIMG_isGIF = int function(SDL_RWops*);
155         alias pIMG_isJPG = int function(SDL_RWops*);
156         alias pIMG_isLBM = int function(SDL_RWops*);
157         alias pIMG_isPCX = int function(SDL_RWops*);
158         alias pIMG_isPNG = int function(SDL_RWops*);
159         alias pIMG_isPNM = int function(SDL_RWops*);
160         alias pIMG_isTIF = int function(SDL_RWops*);
161         alias pIMG_isXCF = int function(SDL_RWops*);
162         alias pIMG_isXPM = int function(SDL_RWops*);
163         alias pIMG_isXV = int function(SDL_RWops*);
164         alias pIMG_isWEBP = int function(SDL_RWops*);
165 
166         alias pIMG_LoadICO_RW = SDL_Surface* function(SDL_RWops*);
167         alias pIMG_LoadCUR_RW = SDL_Surface* function(SDL_RWops*);
168         alias pIMG_LoadBMP_RW = SDL_Surface* function(SDL_RWops*);
169         alias pIMG_LoadGIF_RW = SDL_Surface* function(SDL_RWops*);
170         alias pIMG_LoadJPG_RW = SDL_Surface* function(SDL_RWops*);
171         alias pIMG_LoadLBM_RW = SDL_Surface* function(SDL_RWops*);
172         alias pIMG_LoadPCX_RW = SDL_Surface* function(SDL_RWops*);
173         alias pIMG_LoadPNG_RW = SDL_Surface* function(SDL_RWops*);
174         alias pIMG_LoadPNM_RW = SDL_Surface* function(SDL_RWops*);
175         alias pIMG_LoadTGA_RW = SDL_Surface* function(SDL_RWops*);
176         alias pIMG_LoadTIF_RW = SDL_Surface* function(SDL_RWops*);
177         alias pIMG_LoadXCF_RW = SDL_Surface* function(SDL_RWops*);
178         alias pIMG_LoadXPM_RW = SDL_Surface* function(SDL_RWops*);
179         alias pIMG_LoadXV_RW = SDL_Surface* function(SDL_RWops*);
180         alias pIMG_LoadWEBP_RW = SDL_Surface* function(SDL_RWops*);
181 
182         alias pIMG_ReadXPMFromArray = SDL_Surface* function(char**);
183 
184         alias pIMG_SavePNG = int function(SDL_Surface*,const(char)*);
185         alias pIMG_SavePNG_RW = int function(SDL_Surface*,SDL_RWops*,int);
186     }
187 
188     __gshared {
189         pIMG_Init IMG_Init;
190         pIMG_Quit IMG_Quit;
191         pIMG_Linked_Version IMG_Linked_Version;
192         pIMG_LoadTyped_RW IMG_LoadTyped_RW;
193         pIMG_Load IMG_Load;
194         pIMG_Load_RW IMG_Load_RW;
195         pIMG_LoadTexture IMG_LoadTexture;
196         pIMG_LoadTexture_RW IMG_LoadTexture_RW;
197         pIMG_LoadTextureTyped_RW IMG_LoadTextureTyped_RW;
198         pIMG_isICO IMG_isICO;
199         pIMG_isCUR IMG_isCUR;
200         pIMG_isBMP IMG_isBMP;
201         pIMG_isGIF IMG_isGIF;
202         pIMG_isJPG IMG_isJPG;
203         pIMG_isLBM IMG_isLBM;
204         pIMG_isPCX IMG_isPCX;
205         pIMG_isPNG IMG_isPNG;
206         pIMG_isPNM IMG_isPNM;
207         pIMG_isTIF IMG_isTIF;
208         pIMG_isXCF IMG_isXCF;
209         pIMG_isXPM IMG_isXPM;
210         pIMG_isXV IMG_isXV;
211         pIMG_isWEBP IMG_isWEBP;
212         pIMG_LoadICO_RW IMG_LoadICO_RW;
213         pIMG_LoadCUR_RW IMG_LoadCUR_RW;
214         pIMG_LoadBMP_RW IMG_LoadBMP_RW;
215         pIMG_LoadGIF_RW IMG_LoadGIF_RW;
216         pIMG_LoadJPG_RW IMG_LoadJPG_RW;
217         pIMG_LoadLBM_RW IMG_LoadLBM_RW;
218         pIMG_LoadPCX_RW IMG_LoadPCX_RW;
219         pIMG_LoadPNG_RW IMG_LoadPNG_RW;
220         pIMG_LoadPNM_RW IMG_LoadPNM_RW;
221         pIMG_LoadTGA_RW IMG_LoadTGA_RW;
222         pIMG_LoadTIF_RW IMG_LoadTIF_RW;
223         pIMG_LoadXCF_RW IMG_LoadXCF_RW;
224         pIMG_LoadXPM_RW IMG_LoadXPM_RW;
225         pIMG_LoadXV_RW IMG_LoadXV_RW;
226         pIMG_LoadWEBP_RW IMG_LoadWEBP_RW;
227         pIMG_ReadXPMFromArray IMG_ReadXPMFromArray;
228         pIMG_SavePNG IMG_SavePNG;
229         pIMG_SavePNG_RW IMG_SavePNG_RW;
230     }
231 
232     static if(sdlImageSupport >= SDLImageSupport.sdlImage202) {
233         extern(C) @nogc nothrow {
234             alias pIMG_isSVG = int function(SDL_RWops*);
235             alias pIMG_LoadSVG_RW = SDL_Surface* function(SDL_RWops*);
236             alias pIMG_SaveJPG = int function(SDL_Surface*,const(char)*,int);
237             alias pIMG_SaveJPG_RW = int function(SDL_Surface*,SDL_RWops*,int,int);
238         }
239 
240         __gshared {
241             pIMG_isSVG IMG_isSVG;
242             pIMG_LoadSVG_RW IMG_LoadSVG;
243             pIMG_SaveJPG IMG_SaveJPG;
244             pIMG_SaveJPG_RW IMG_SaveJPG_RW;
245         }
246     }
247 
248     private {
249         SharedLib lib;
250         SDLImageSupport loadedVersion;
251     }
252 
253     void unloadSDLImage()
254     {
255         if(lib != invalidHandle) {
256             lib.unload();
257         }
258     }
259 
260     SDLImageSupport loadedSDLImageVersion() { return loadedVersion; }
261 
262     bool isSDLImageLoaded()
263     {
264         return  lib != invalidHandle;
265     }
266 
267 
268     SDLImageSupport loadSDLImage()
269     {
270         version(Windows) {
271             const(char)[][1] libNames = ["SDL2_image.dll"];
272         }
273         else version(OSX) {
274             const(char)[][6] libNames = [
275                 "libSDL2_image.dylib",
276                 "/usr/local/lib/libSDL2_image.dylib",
277                 "../Frameworks/SDL2_image.framework/SDL2_image",
278                 "/Library/Frameworks/SDL2_image.framework/SDL2_image",
279                 "/System/Library/Frameworks/SDL2_image.framework/SDL2_image",
280                 "/opt/local/lib/libSDL2_image.dylib"
281             ];
282         }
283         else version(Posix) {
284             const(char)[][6] libNames = [
285                 "libSDL2_image.so",
286                 "/usr/local/lib/libSDL2_image.so",
287                 "libSDL2_image-2.0.so",
288                 "/usr/local/lib/libSDL2_image-2.0.so",
289                 "libSDL2_image-2.0.so.0",
290                 "/usr/local/lib/libSDL2_image-2.0.so.0"
291             ];
292         }
293         else static assert(0, "bindbc-sdl is not yet supported on this platform.");
294 
295         SDLImageSupport ret;
296         foreach(name; libNames) {
297             ret = loadSDLImage(name.ptr);
298             if(ret != SDLImageSupport.noLibrary) break;
299         }
300         return ret;
301     }
302 
303     SDLImageSupport loadSDLImage(const(char)* libName)
304     {
305         lib = load(libName);
306         if(lib == invalidHandle) {
307             return SDLImageSupport.noLibrary;
308         }
309 
310         auto errCount = errorCount();
311         loadedVersion = SDLImageSupport.badLibrary;
312 
313         lib.bindSymbol(cast(void**)&IMG_Init,"IMG_Init");
314         lib.bindSymbol(cast(void**)&IMG_Quit,"IMG_Quit");
315         lib.bindSymbol(cast(void**)&IMG_Linked_Version,"IMG_Linked_Version");
316         lib.bindSymbol(cast(void**)&IMG_LoadTyped_RW,"IMG_LoadTyped_RW");
317         lib.bindSymbol(cast(void**)&IMG_Load,"IMG_Load");
318         lib.bindSymbol(cast(void**)&IMG_Load_RW,"IMG_Load_RW");
319         lib.bindSymbol(cast(void**)&IMG_LoadTexture,"IMG_LoadTexture");
320         lib.bindSymbol(cast(void**)&IMG_LoadTexture_RW,"IMG_LoadTexture_RW");
321         lib.bindSymbol(cast(void**)&IMG_LoadTextureTyped_RW,"IMG_LoadTextureTyped_RW");
322         lib.bindSymbol(cast(void**)&IMG_isICO,"IMG_isICO");
323         lib.bindSymbol(cast(void**)&IMG_isCUR,"IMG_isCUR");
324         lib.bindSymbol(cast(void**)&IMG_isBMP,"IMG_isBMP");
325         lib.bindSymbol(cast(void**)&IMG_isGIF,"IMG_isGIF");
326         lib.bindSymbol(cast(void**)&IMG_isJPG,"IMG_isJPG");
327         lib.bindSymbol(cast(void**)&IMG_isLBM,"IMG_isLBM");
328         lib.bindSymbol(cast(void**)&IMG_isPCX,"IMG_isPCX");
329         lib.bindSymbol(cast(void**)&IMG_isPNG,"IMG_isPNG");
330         lib.bindSymbol(cast(void**)&IMG_isPNM,"IMG_isPNM");
331         lib.bindSymbol(cast(void**)&IMG_isTIF,"IMG_isTIF");
332         lib.bindSymbol(cast(void**)&IMG_isXCF,"IMG_isXCF");
333         lib.bindSymbol(cast(void**)&IMG_isXPM,"IMG_isXPM");
334         lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV");
335         lib.bindSymbol(cast(void**)&IMG_isWEBP,"IMG_isWEBP");
336         lib.bindSymbol(cast(void**)&IMG_LoadICO_RW,"IMG_LoadICO_RW");
337         lib.bindSymbol(cast(void**)&IMG_LoadCUR_RW,"IMG_LoadCUR_RW");
338         lib.bindSymbol(cast(void**)&IMG_LoadBMP_RW,"IMG_LoadBMP_RW");
339         lib.bindSymbol(cast(void**)&IMG_LoadGIF_RW,"IMG_LoadGIF_RW");
340         lib.bindSymbol(cast(void**)&IMG_LoadJPG_RW,"IMG_LoadJPG_RW");
341         lib.bindSymbol(cast(void**)&IMG_LoadLBM_RW,"IMG_LoadLBM_RW");
342         lib.bindSymbol(cast(void**)&IMG_LoadPCX_RW,"IMG_LoadPCX_RW");
343         lib.bindSymbol(cast(void**)&IMG_LoadPNG_RW,"IMG_LoadPNG_RW");
344         lib.bindSymbol(cast(void**)&IMG_LoadPNM_RW,"IMG_LoadPNM_RW");
345         lib.bindSymbol(cast(void**)&IMG_LoadTGA_RW,"IMG_LoadTGA_RW");
346         lib.bindSymbol(cast(void**)&IMG_LoadTIF_RW,"IMG_LoadTIF_RW");
347         lib.bindSymbol(cast(void**)&IMG_LoadXCF_RW,"IMG_LoadXCF_RW");
348         lib.bindSymbol(cast(void**)&IMG_LoadXPM_RW,"IMG_LoadXPM_RW");
349         lib.bindSymbol(cast(void**)&IMG_LoadXV_RW,"IMG_LoadXV_RW");
350         lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV");
351         lib.bindSymbol(cast(void**)&IMG_LoadWEBP_RW,"IMG_LoadWEBP_RW");
352         lib.bindSymbol(cast(void**)&IMG_SavePNG,"IMG_SavePNG");
353         lib.bindSymbol(cast(void**)&IMG_SavePNG_RW,"IMG_SavePNG_RW");
354 
355         if(errorCount() != errCount) return SDLImageSupport.badLibrary;
356         else loadedVersion = (sdlImageSupport >= SDLImageSupport.sdlImage201) ? SDLImageSupport.sdlImage201 : SDLImageSupport.sdlImage200;
357 
358         static if(sdlImageSupport >= SDLImageSupport.sdlImage202) {
359             lib.bindSymbol(cast(void**)&IMG_isSVG,"IMG_isSVG");
360             lib.bindSymbol(cast(void**)&IMG_LoadSVG,"IMG_LoadSVG_RW");
361             lib.bindSymbol(cast(void**)&IMG_SaveJPG,"IMG_SaveJPG");
362             lib.bindSymbol(cast(void**)&IMG_SaveJPG_RW,"IMG_SaveJPG_RW");
363 
364             if(errorCount() != errCount) return SDLImageSupport.badLibrary;
365             else {
366                 loadedVersion = (sdlImageSupport >= SDLImageSupport.sdlImage205) ? SDLImageSupport.sdlImage205 : sdlImageSupport;
367             }
368         }
369 
370         return loadedVersion;
371     }
372 }