1 
2 //          Copyright 2018 - 2021 Michael D. Parker
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 flags);
82         int IMG_Quit();
83         const(SDL_version)* IMG_Linked_Version();
84         SDL_Surface* IMG_LoadTyped_RW(SDL_RWops* src, int freesrc, const(char)* type);
85         SDL_Surface* IMG_Load(const(char)* file);
86         SDL_Surface* IMG_Load_RW(SDL_RWops* src, int freesrc);
87 
88         SDL_Texture* IMG_LoadTexture(SDL_Renderer* renderer, const(char)* file);
89         SDL_Texture* IMG_LoadTexture_RW(SDL_Renderer* renderer, SDL_RWops* src, int freesrc);
90         SDL_Texture* IMG_LoadTextureTyped_RW(SDL_Renderer* renderer, SDL_RWops* src, int freesrc, const(char)* type);
91 
92         int IMG_isICO(SDL_RWops* src);
93         int IMG_isCUR(SDL_RWops* src);
94         int IMG_isBMP(SDL_RWops* src);
95         int IMG_isGIF(SDL_RWops* src);
96         int IMG_isJPG(SDL_RWops* src);
97         int IMG_isLBM(SDL_RWops* src);
98         int IMG_isPCX(SDL_RWops* src);
99         int IMG_isPNG(SDL_RWops* src);
100         int IMG_isPNM(SDL_RWops* src);
101         int IMG_isTIF(SDL_RWops* src);
102         int IMG_isXCF(SDL_RWops* src);
103         int IMG_isXPM(SDL_RWops* src);
104         int IMG_isXV(SDL_RWops* src);
105         int IMG_isWEBP(SDL_RWops* src);
106 
107         SDL_Surface* IMG_LoadICO_RW(SDL_RWops* src);
108         SDL_Surface* IMG_LoadCUR_RW(SDL_RWops* src);
109         SDL_Surface* IMG_LoadBMP_RW(SDL_RWops* src);
110         SDL_Surface* IMG_LoadGIF_RW(SDL_RWops* src);
111         SDL_Surface* IMG_LoadJPG_RW(SDL_RWops* src);
112         SDL_Surface* IMG_LoadLBM_RW(SDL_RWops* src);
113         SDL_Surface* IMG_LoadPCX_RW(SDL_RWops* src);
114         SDL_Surface* IMG_LoadPNG_RW(SDL_RWops* src);
115         SDL_Surface* IMG_LoadPNM_RW(SDL_RWops* src);
116         SDL_Surface* IMG_LoadTGA_RW(SDL_RWops* src);
117         SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src);
118         SDL_Surface* IMG_LoadXCF_RW(SDL_RWops* src);
119         SDL_Surface* IMG_LoadXPM_RW(SDL_RWops* src);
120         SDL_Surface* IMG_LoadXV_RW(SDL_RWops* src);
121         SDL_Surface* IMG_LoadWEBP_RW(SDL_RWops* src);
122 
123         SDL_Surface* IMG_ReadXPMFromArray(char** xpm);
124 
125         int IMG_SavePNG(SDL_Surface* surface, const(char)* file);
126         int IMG_SavePNG_RW(SDL_Surface* surface, SDL_RWops* dst, int freedst);
127 
128         static if(sdlImageSupport >= SDLImageSupport.sdlImage202) {
129             int IMG_isSVG(SDL_RWops* src);
130             SDL_Surface* IMG_LoadSVG(SDL_RWops* src);
131             int IMG_SaveJPG(SDL_Surface* surface, const(char)* file, int quality);
132             int IMG_SaveJPG_RW(SDL_Surface* surface, SDL_RWops* dst, int freedst, int quality);
133         }
134     }
135 }
136 else {
137     import bindbc.loader;
138 
139     extern(C) @nogc nothrow {
140         alias pIMG_Init = int function(int flags);
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* src, int freesrc, const(char)* type);
144         alias pIMG_Load = SDL_Surface* function(const(char)* file);
145         alias pIMG_Load_RW = SDL_Surface* function(SDL_RWops* src, int freesrc);
146 
147         alias pIMG_LoadTexture = SDL_Texture* function(SDL_Renderer* renderer, const(char)* file);
148         alias pIMG_LoadTexture_RW = SDL_Texture* function(SDL_Renderer* renderer, SDL_RWops* src, int freesrc);
149         alias pIMG_LoadTextureTyped_RW = SDL_Texture* function(SDL_Renderer* renderer, SDL_RWops* src, int freesrc, const(char)* type);
150 
151         alias pIMG_isICO = int function(SDL_RWops* src);
152         alias pIMG_isCUR = int function(SDL_RWops* src);
153         alias pIMG_isBMP = int function(SDL_RWops* src);
154         alias pIMG_isGIF = int function(SDL_RWops* src);
155         alias pIMG_isJPG = int function(SDL_RWops* src);
156         alias pIMG_isLBM = int function(SDL_RWops* src);
157         alias pIMG_isPCX = int function(SDL_RWops* src);
158         alias pIMG_isPNG = int function(SDL_RWops* src);
159         alias pIMG_isPNM = int function(SDL_RWops* src);
160         alias pIMG_isTIF = int function(SDL_RWops* src);
161         alias pIMG_isXCF = int function(SDL_RWops* src);
162         alias pIMG_isXPM = int function(SDL_RWops* src);
163         alias pIMG_isXV = int function(SDL_RWops* src);
164         alias pIMG_isWEBP = int function(SDL_RWops* src);
165 
166         alias pIMG_LoadICO_RW = SDL_Surface* function(SDL_RWops* src);
167         alias pIMG_LoadCUR_RW = SDL_Surface* function(SDL_RWops* src);
168         alias pIMG_LoadBMP_RW = SDL_Surface* function(SDL_RWops* src);
169         alias pIMG_LoadGIF_RW = SDL_Surface* function(SDL_RWops* src);
170         alias pIMG_LoadJPG_RW = SDL_Surface* function(SDL_RWops* src);
171         alias pIMG_LoadLBM_RW = SDL_Surface* function(SDL_RWops* src);
172         alias pIMG_LoadPCX_RW = SDL_Surface* function(SDL_RWops* src);
173         alias pIMG_LoadPNG_RW = SDL_Surface* function(SDL_RWops* src);
174         alias pIMG_LoadPNM_RW = SDL_Surface* function(SDL_RWops* src);
175         alias pIMG_LoadTGA_RW = SDL_Surface* function(SDL_RWops* src);
176         alias pIMG_LoadTIF_RW = SDL_Surface* function(SDL_RWops* src);
177         alias pIMG_LoadXCF_RW = SDL_Surface* function(SDL_RWops* src);
178         alias pIMG_LoadXPM_RW = SDL_Surface* function(SDL_RWops* src);
179         alias pIMG_LoadXV_RW = SDL_Surface* function(SDL_RWops* src);
180         alias pIMG_LoadWEBP_RW = SDL_Surface* function(SDL_RWops* src);
181 
182         alias pIMG_ReadXPMFromArray = SDL_Surface* function(char** xpm);
183 
184         alias pIMG_SavePNG = int function(SDL_Surface* surface, const(char)* file);
185         alias pIMG_SavePNG_RW = int function(SDL_Surface* surface, SDL_RWops* dst, int freedst);
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* src);
235             alias pIMG_LoadSVG_RW = SDL_Surface* function(SDL_RWops* src);
236             alias pIMG_SaveJPG = int function(SDL_Surface* surface, const(char)* file, int quality);
237             alias pIMG_SaveJPG_RW = int function(SDL_Surface* surface, SDL_RWops* dst, int freedst, int quality);
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 @nogc nothrow:
254     void unloadSDLImage()
255     {
256         if(lib != invalidHandle) {
257             lib.unload();
258         }
259     }
260 
261     SDLImageSupport loadedSDLImageVersion() { return loadedVersion; }
262 
263     bool isSDLImageLoaded()
264     {
265         return  lib != invalidHandle;
266     }
267 
268 
269     SDLImageSupport loadSDLImage()
270     {
271         version(Windows) {
272             const(char)[][1] libNames = ["SDL2_image.dll"];
273         }
274         else version(OSX) {
275             const(char)[][6] libNames = [
276                 "libSDL2_image.dylib",
277                 "/usr/local/lib/libSDL2_image.dylib",
278                 "../Frameworks/SDL2_image.framework/SDL2_image",
279                 "/Library/Frameworks/SDL2_image.framework/SDL2_image",
280                 "/System/Library/Frameworks/SDL2_image.framework/SDL2_image",
281                 "/opt/local/lib/libSDL2_image.dylib"
282             ];
283         }
284         else version(Posix) {
285             const(char)[][6] libNames = [
286                 "libSDL2_image.so",
287                 "/usr/local/lib/libSDL2_image.so",
288                 "libSDL2_image-2.0.so",
289                 "/usr/local/lib/libSDL2_image-2.0.so",
290                 "libSDL2_image-2.0.so.0",
291                 "/usr/local/lib/libSDL2_image-2.0.so.0"
292             ];
293         }
294         else static assert(0, "bindbc-sdl is not yet supported on this platform.");
295 
296         SDLImageSupport ret;
297         foreach(name; libNames) {
298             ret = loadSDLImage(name.ptr);
299             if(ret != SDLImageSupport.noLibrary) break;
300         }
301         return ret;
302     }
303 
304     SDLImageSupport loadSDLImage(const(char)* libName)
305     {
306         lib = load(libName);
307         if(lib == invalidHandle) {
308             return SDLImageSupport.noLibrary;
309         }
310 
311         auto errCount = errorCount();
312         loadedVersion = SDLImageSupport.badLibrary;
313 
314         lib.bindSymbol(cast(void**)&IMG_Init,"IMG_Init");
315         lib.bindSymbol(cast(void**)&IMG_Quit,"IMG_Quit");
316         lib.bindSymbol(cast(void**)&IMG_Linked_Version,"IMG_Linked_Version");
317         lib.bindSymbol(cast(void**)&IMG_LoadTyped_RW,"IMG_LoadTyped_RW");
318         lib.bindSymbol(cast(void**)&IMG_Load,"IMG_Load");
319         lib.bindSymbol(cast(void**)&IMG_Load_RW,"IMG_Load_RW");
320         lib.bindSymbol(cast(void**)&IMG_LoadTexture,"IMG_LoadTexture");
321         lib.bindSymbol(cast(void**)&IMG_LoadTexture_RW,"IMG_LoadTexture_RW");
322         lib.bindSymbol(cast(void**)&IMG_LoadTextureTyped_RW,"IMG_LoadTextureTyped_RW");
323         lib.bindSymbol(cast(void**)&IMG_isICO,"IMG_isICO");
324         lib.bindSymbol(cast(void**)&IMG_isCUR,"IMG_isCUR");
325         lib.bindSymbol(cast(void**)&IMG_isBMP,"IMG_isBMP");
326         lib.bindSymbol(cast(void**)&IMG_isGIF,"IMG_isGIF");
327         lib.bindSymbol(cast(void**)&IMG_isJPG,"IMG_isJPG");
328         lib.bindSymbol(cast(void**)&IMG_isLBM,"IMG_isLBM");
329         lib.bindSymbol(cast(void**)&IMG_isPCX,"IMG_isPCX");
330         lib.bindSymbol(cast(void**)&IMG_isPNG,"IMG_isPNG");
331         lib.bindSymbol(cast(void**)&IMG_isPNM,"IMG_isPNM");
332         lib.bindSymbol(cast(void**)&IMG_isTIF,"IMG_isTIF");
333         lib.bindSymbol(cast(void**)&IMG_isXCF,"IMG_isXCF");
334         lib.bindSymbol(cast(void**)&IMG_isXPM,"IMG_isXPM");
335         lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV");
336         lib.bindSymbol(cast(void**)&IMG_isWEBP,"IMG_isWEBP");
337         lib.bindSymbol(cast(void**)&IMG_LoadICO_RW,"IMG_LoadICO_RW");
338         lib.bindSymbol(cast(void**)&IMG_LoadCUR_RW,"IMG_LoadCUR_RW");
339         lib.bindSymbol(cast(void**)&IMG_LoadBMP_RW,"IMG_LoadBMP_RW");
340         lib.bindSymbol(cast(void**)&IMG_LoadGIF_RW,"IMG_LoadGIF_RW");
341         lib.bindSymbol(cast(void**)&IMG_LoadJPG_RW,"IMG_LoadJPG_RW");
342         lib.bindSymbol(cast(void**)&IMG_LoadLBM_RW,"IMG_LoadLBM_RW");
343         lib.bindSymbol(cast(void**)&IMG_LoadPCX_RW,"IMG_LoadPCX_RW");
344         lib.bindSymbol(cast(void**)&IMG_LoadPNG_RW,"IMG_LoadPNG_RW");
345         lib.bindSymbol(cast(void**)&IMG_LoadPNM_RW,"IMG_LoadPNM_RW");
346         lib.bindSymbol(cast(void**)&IMG_LoadTGA_RW,"IMG_LoadTGA_RW");
347         lib.bindSymbol(cast(void**)&IMG_LoadTIF_RW,"IMG_LoadTIF_RW");
348         lib.bindSymbol(cast(void**)&IMG_LoadXCF_RW,"IMG_LoadXCF_RW");
349         lib.bindSymbol(cast(void**)&IMG_LoadXPM_RW,"IMG_LoadXPM_RW");
350         lib.bindSymbol(cast(void**)&IMG_LoadXV_RW,"IMG_LoadXV_RW");
351         lib.bindSymbol(cast(void**)&IMG_isXV,"IMG_isXV");
352         lib.bindSymbol(cast(void**)&IMG_LoadWEBP_RW,"IMG_LoadWEBP_RW");
353         lib.bindSymbol(cast(void**)&IMG_SavePNG,"IMG_SavePNG");
354         lib.bindSymbol(cast(void**)&IMG_SavePNG_RW,"IMG_SavePNG_RW");
355 
356         if(errorCount() != errCount) return SDLImageSupport.badLibrary;
357         else loadedVersion = (sdlImageSupport >= SDLImageSupport.sdlImage201) ? SDLImageSupport.sdlImage201 : SDLImageSupport.sdlImage200;
358 
359         static if(sdlImageSupport >= SDLImageSupport.sdlImage202) {
360             lib.bindSymbol(cast(void**)&IMG_isSVG,"IMG_isSVG");
361             lib.bindSymbol(cast(void**)&IMG_LoadSVG,"IMG_LoadSVG_RW");
362             lib.bindSymbol(cast(void**)&IMG_SaveJPG,"IMG_SaveJPG");
363             lib.bindSymbol(cast(void**)&IMG_SaveJPG_RW,"IMG_SaveJPG_RW");
364 
365             if(errorCount() != errCount) return SDLImageSupport.badLibrary;
366             else {
367                 loadedVersion = (sdlImageSupport >= SDLImageSupport.sdlImage205) ? SDLImageSupport.sdlImage205 : sdlImageSupport;
368             }
369         }
370 
371         return loadedVersion;
372     }
373 }