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