
Display an image with SDL2_image
The goal for this SDL2 tutorials is to simply display an image with SDL2_image and SDL2. The program is basic and simple.
- SDL2, SDL2_image
The goal is to display an image with SDL2_image, but before we need to set up the environnement.
Installation of SDL2_image
For the first program we will make a program display an image on the screen.
You will need to have a working project with SDL, and to load an image we will use an SDL extension : SDL2_image
To have a working project, you can do the following or use this tutorial as reference : Make a health bar with SDL
First, we add SDL2_image, then do the steps as before:
- Download and decompress Development librairies
- Add the include path of SDL-image to the project
- Add the lib path of SD_image to the project
- Add the new lib entry SDL2_image.lib
Then, copy the dlls in the lib directory, this time there are multiple dlls:
SDL2_image.dll– DLL of SDL2_imagelibjpeg-9.dll– DLL of libjpeg (add if you want to read JPEG images)libpng16-16.dll– DLL of libpng (add if you want to read PNG images)libtiff-5.dll– DLL of libtiff (add if you want to read TIFF images)libwebp-7.dll– DLL of libwebp (add if you want to read WEBP images)zlib1.dll– DLL of zlib (add if you want to read png images)
We can start writing the program.
Initialization of the program display an image with SDL2_image
The first thing to do is initialize SDL, there are multiple modules in SDL :
- SDL_INIT_TIMER – timer subsystem
- SDL_INIT_AUDIO – audio subsystem
- SDL_INIT_VIDEO – video subsystem; automatically initializes the events subsystem
- SDL_INIT_JOYSTICK – joystick subsystem; automatically initializes the events subsystem
- SDL_INIT_HAPTIC – haptic (force feedback) subsystem
- SDL_INIT_GAMECONTROLLER – controller subsystem; automatically initializes the joystick subsystem
- SDL_INIT_EVENTS – events subsystem
- SDL_INIT_EVERYTHING – all of the above subsystems
- SDL_INIT_NOPARACHUTE – compatibility; this flag is ignored
In this tutorial we use SDL_INIT_VIDEO and SDL_INIT_EVENTS.
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
std::cout << "Error SDL2 Initialization : " << SDL_GetError();
return 1;
}Next thing, the initilization of SDL2_image with IMG_Init
The flags for IMG_init are:
IMG_INIT_JPGIMG_INIT_PNGIMG_INIT_TIFIMG_INIT_WEBP
After that, we initialize the format PNG:
if (IMG_Init(IMG_INIT_PNG) == 0) {
std::cout << "Error SDL2_image Initialization";
return 2;
}The window
After the initialization, we create the window:
SDL_Window* window = SDL_CreateWindow("First program", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
if (window == NULL) {
std::cout << "Error window creation";
return 3;
}The first parameter is the name of the program.
The second parameter indicate the horizontal position of the window.
The third parameters indicate the vertical position of the window. You have two choice for the position of the window:
SDL_WINDOWPOS_CENTERED– position centeredSDL_WINDOWPOS_UNDEFINED– don’t care about the position
The fourth parameter is the width of the window.
The fifth is the height of the window.
The sixth is a flag to specify the mode of the window:
SDL_WINDOW_FULLSCREEN– fullscreen windowSDL_WINDOW_OPENGL– the window usable with OpenGL contextSDL_WINDOW_SHOWN– the window is shown (ignored by SDL_CreateWindow)SDL_WINDOW_HIDDEN– the window is not visibleSDL_WINDOW_BORDERLESS– the window have no decorationSDL_WINDOW_RESIZABLE– the window is resizableSDL_WINDOW_MINIMIZED– the window is minimizedSDL_WINDOW_MAXIMIZED– the window is maximizedSDL_WINDOW_INPUT_GRABBED– the window has grabbed input focusSDL_WINDOW_INPUT_FOCUS– the window has input focusSDL_WINDOW_MOUSE_FOCUS– the window has mouse focusSDL_WINDOW_FULLSCREEN_DESKTOP– ( SDL_WINDOW_FULLSCREEN | 0x00001000 )SDL_WINDOW_FOREIGN– the window not created by SDLSDL_WINDOW_ALLOW_HIGHDPI– the window created in high dpi modeSDL_WINDOW_MOUSE_CAPTURE– the window has mouse captured (unrelated to INPUT_GRABBED)SDL_WINDOW_ALWAYS_ON_TOP– the window should always be above othersSDL_WINDOW_SKIP_TASKBAR– the window is not added to the taskbarSDL_WINDOW_UTILITY– the window is a utility windowSDL_WINDOW_TOOLTIP– the window is a tooltipSDL_WINDOW_POPUP_MENU– the window is a popup menuSDL_WINDOW_VULKAN– the window usable for Vulkan surface
The renderer
Next thing to do is render the texture, we need a renderer:
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
std::cout << "Error renderer creation";
return 4;
}The first parameter is the window where rendering occurs.
The second parameter is the index of the rendering driver to initialize. If we set -1, the first driver to support the flags (next parameter) is initialized. The third parameter is the mode of the renderer:
SDL_RENDERER_SOFTWARE– The renderer is a software fallbackSDL_RENDERER_ACCELERATED– The renderer uses hardware accelerationSDL_RENDERER_PRESENTVSYNC– Present is synchronized with the refresh rateSDL_RENDERER_TARGETTEXTURE– The renderer supports rendering to texture
The image used for display an image with SDL2_image
We can start to load the image, for this tutorial I am using this image

SDL_Surface* lettuce_sur = IMG_Load("lettuce.png");
if (lettuce_sur == NULL) {
std::cout << "Error loading image: " << IMG_GetError();
return 5;
}IMG_Load take one parameter, the path of the file
What is a SDL_Surface?
An array of pixel stored in RAM encoded in a specific format, most of the time RGBA.
Right, that is good, can we display the image?
Well we can, but only if we use a software renderer, for that you need to use the function SDL_CreateSoftwareRenderer.
Here the renderer use hardware acceleration
In computing, hardware acceleration is the use of computer hardware specially made to perform some functions more efficiently than is possible in software running on a general-purpose CPU.
So the image need to be diplayed by the graphic card, not the CPU. To do that we need to create a texture.
What is a SDL_Texture?
An array of pixel stored in VRAM encoded in a driver-specific format
We use OpenGL, so if you are interested check out the image formats used by OpenGL
Then we create the texture:
SDL_Texture* lettuce_tex = SDL_CreateTextureFromSurface(renderer, lettuce_sur);
if (lettuce_tex == NULL) {
std::cout << "Error creating texture";
return 6;
}
SDL_FreeSurface(lettuce_sur);The first parameter is the renderer.
The second parameter is the surface to transform into a texture.
After the texture creation, we do not need the surface anymore so we can free the memory with SDL_FreeSurface.
The event loop for displaying an image with SDL2_image
For the program to continu running indefinitely, we some kind of an infinite loop => An infinite loop with an exit condition
How about we use red the cross a the top right of the window as the exit condition. Sound good?
But, to make this exit condition we need to know when the user click on the red cross.
To catch the action “clicking on the red cross” we need to use events.
while (true) {
SDL_Event e;
if (SDL_WaitEvent(&e)) {
if (e.type == SDL_QUIT) {
break;
}
}So we begin with a SDL_Event e, but the event is empty.
We need to fill this event with the actions of the user. For instance, we use SDL_WaitEvent to fill the event.
This function wait indefinitely for an event to happen, if the event happen we fill the event and the loop continu.
So if we do nothing, then the loop stops?
Exactly, so for a game with some animations we will use SDL_PollEvent instead of SDL_WaitEvent because SDL_PollEvent suspend the loop.
In this case, we have only one image, so we can render the image once and wait for the user to exit the program.
But how can the image can be render if we block the loop at the second line of the loop ?
That’s simple, even if we do nothing (no key press, no mouse click…) some event still occurs such as SDL_WINDOWEVENT, when the window shows up.
Render the texture
To render the texture we need three lines:
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, lettuce_tex, NULL, NULL);
SDL_RenderPresent(renderer);
}The first one clear the renderer with the default color : black
The second line render the texture into a backbuffer:
The first parameter is the current renderer.
The second parameter is the texture we want to render.
The third parameter is the portion of texture to render, type SDL_Rect* passing NULL take the entire texture.
The fourth parameter is the destination of the texture to render, type SDL_Rect* passing NULL stretch the texture into the window.
Free the memory
The last thing to do after the loop is to free all the resources in the right order.
SDL_DestroyTexture(lettuce_tex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();Result
The full source code of the program to display an image with SDL2_image is:
#include <iostream>
#include "SDL.h"
#include "SDL2_image.h"
int main(int argc, char* argv[]) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) {
std::cout << "Error SDL2 Initialization : " << SDL_GetError();
return 1;
}
if (IMG_Init(IMG_INIT_PNG) == 0) {
std::cout << "Error SDL2_image Initialization";
return 2;
}
SDL_Window* window = SDL_CreateWindow("First program", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
if (window == NULL) {
std::cout << "Error window creation";
return 3;
}
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL) {
std::cout << "Error renderer creation";
return 4;
}
SDL_Surface* lettuce_sur = IMG_Load("lettuce.png");
if (lettuce_sur == NULL) {
std::cout << "Error loading image: " << IMG_GetError();
return 5;
}
SDL_Texture* lettuce_tex = SDL_CreateTextureFromSurface(renderer, lettuce_sur);
if (lettuce_tex == NULL) {
std::cout << "Error creating texture";
return 6;
}
SDL_FreeSurface(lettuce_sur);
while (true) {
SDL_Event e;
if (SDL_WaitEvent(&e)) {
if (e.type == SDL_QUIT) {
break;
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, lettuce_tex, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(lettuce_tex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
SDL_Quit();
return 0;
}