SaveJPG in SDL2 Example Code

Discussions related to graphics (2D and 3D), animation and games programming
TonyTooth
Posts: 7
Joined: Mon 07 Aug 2023, 18:37

SaveJPG in SDL2 Example Code

Post by TonyTooth »

Having finally managed to save an SDL surface as a JPG, here is how I did it; it was not trivial.
Firstly, the required "SaveJPG" function resides in SDL2_image.dll, which must be installed, as per the ... sys "LoadLibraryA" ... command in the example code. (Don't miss out the "A" or it will not work.) It is a 32-bit DLL. I found it on DLL-files.com, as well as the other two DLLs needed - both of which need to be the 32-bit versions. On a Windows machine, all 3 DLLs must be copied to the Windows/SysWOW64 file NOT the Windows/System32 file. The addresses within the SDL2_image DLL for 3 functions are needed: IMG_Init, IMG_SaveJPG, IMG_Quit.
To convert a surface to a JPG (as opposed to another format such as PNG) you must include the command ... sys imgInit%%,1 to n% ... where imgInit%% is the address for the IMG_Init function. The "1" tells the function you want to convert to a JPG - and it will go looking for the following two 32-bit DLLs: libjpeg-9.dll and zlib1.dll. There seem to be several versions all called exactly the same thing on the website, but I used the ones of size 1.4MB and 72KB respectively. The n% will be a "1" on successful initialisation, "0" if it fails.

Note that one should work on an SDL surface not a texture, and SaveJPG only works on surfaces anyway. I simply converted a colour photo to standard greyscale, then saved it as a 100% quality JPG. This meant I had to modify the ... imgLoad ... library function so as NOT to free the surface, but return it. An SDL surface is a sort-of non-standard Bitmap with the pixels in RGB order rather than the standard Windows Bitmap BGR order. The width of each row is at !(jj%% + 16) where jj%% is the address of the surface, and the address for the data is stored at !(jj%% + 20)

Preamble code is:

on error proc_imgExit : sys "FreeLibrary", sdlimg%% : quit
on close proc_imgExit : sys "FreeLibrary", sdlimg%% : quit
himem = lomem + 100000000
*FLOAT80

install @lib$+"sortlib"
install @lib$+"stringlib"
install @lib$+"Myfiledlg"
install @lib$+"imglib"

rem Load SDL2_image dll
sys "LoadLibraryA", "SDL2_image.dll" to sdlimg%%
sys "GetProcAddress", sdlimg%%, "IMG_Init" to imgInit%%
sys "GetProcAddress", sdlimg%%, "IMG_SaveJPG" to savejpg%%
sys "GetProcAddress", sdlimg%%, "IMG_Quit" to imgQuit%%


Followed by:

rem Initialise graphics
proc_imgInit
sys imgInit%%,1 to n%
print n%

Having created the greyscale simply replacing the pixels in the surface at address jj%% I then save it and exit with:

sys savejpg%%, jj%%, fileGS$, 100 to r%
sys "SDL_FreeSurface", jj%%
sys imgQuit%%

a$ = get$
proc_imgExit
sys "FreeLibrary", sdlimg%%
quit

Note that it's necessary to "Quit" SDL2_image in addition to the library function proc_imgExit.
Hated Moron

Re: SaveJPG in SDL2 Example Code

Post by Hated Moron »

TonyTooth wrote: Fri 29 Dec 2023, 06:09 Having finally managed to save an SDL surface as a JPG, here is how I did it; it was not trivial.
Thanks for that. Unfortunately you've incorporated several Windows API calls, which of course should not be present in BBCSDL code because it will make it unnecessarily platform-specific. Actually I'm surprised that you made that mistake, because I listed the correct code in a reply in the other thread. :o

So instead of this:

Code: Select all

      ON ERROR PROC_imgExit : SYS "FreeLibrary", sdlimg%% : QUIT
      ON CLOSE PROC_imgExit : SYS "FreeLibrary", sdlimg%% : QUIT
you should have this:

Code: Select all

      ON ERROR PROC_imgExit : SYS "SDL_UnloadObject", sdlimg%% : QUIT
      ON CLOSE PROC_imgExit : SYS "SDL_UnloadObject", sdlimg%% : QUIT
Instead of this:

Code: Select all

      SYS "LoadLibraryA", "SDL2_image.dll" TO sdlimg%%
      SYS "GetProcAddress", sdlimg%%, "IMG_Init" TO imgInit%%
      SYS "GetProcAddress", sdlimg%%, "IMG_SaveJPG" TO savejpg%%
      SYS "GetProcAddress", sdlimg%%, "IMG_Quit" TO imgQuit%%
you should have this:

Code: Select all

      SYS "SDL_LoadObject", "SDL2_image.dll" TO sdlimg%%
      SYS "SDL_LoadFunction", sdlimg%%, "IMG_Init" TO imgInit%%
      SYS "SDL_LoadFunction", sdlimg%%, "IMG_SaveJPG" TO savejpg%%
      SYS "SDL_LoadFunction", sdlimg%%, "IMG_Quit" TO imgQuit%%
And instead of this:

Code: Select all

      SYS "FreeLibrary", sdlimg%%
you should have this:

Code: Select all

      SYS "SDL_UnloadObject", sdlimg%%
Too much time spent coding for BB4W perhaps. :lol:
Hated Moron

Re: SaveJPG in SDL2 Example Code

Post by Hated Moron »

TonyTooth wrote: Fri 29 Dec 2023, 06:09 On a Windows machine, all 3 DLLs must be copied to the Windows/SysWOW64 file NOT the Windows/System32 file.
On the contrary, you should never copy files into C:\Windows or a subdirectory since that is a shared 'system' location. Rather you should put custom DLLs into the same directory as your executable (which would be the directory containing 'bbcsdl.exe' in the case of running the program from the IDE in Windows). Windows searches the directory containing the executable file before looking in any other locations.

This is very important, because of DLL Hell. Applications can sometimes depend on specific versions of DLLs and by placing the DLL that your particular application needs in a location shared by all applications (like C:\Windows), you could cause other applications to stop working!
This meant I had to modify the ... imgLoad ... library function so as NOT to free the surface, but return it.
You could have avoided that complication by calling FN_gfxLoadTextureAndSurface() in gfxlib.bbc, which returns a surface as well as a texture. It's documented here.