Ensuring that an image always fits within the window, regardless of its size, is a common requirement in many applications. This involves scaling the image while maintaining its aspect ratio. Here's how you can implement this in SDL2:
#include <SDL.h>
#include <algorithm>
#include <iostream>
class ScalableImage {
public:
ScalableImage(const char* file) : surface{
SDL_LoadBMP(file)} {
if (!surface) {
std::cerr << "Failed to load image: " <<
SDL_GetError() << '\n';
}
}
void RenderFit(SDL_Surface* destSurface) {
if (!surface || !destSurface) return;
// Calculate scaling factors
float scaleX = static_cast<float>(
destSurface->w) / surface->w;
float scaleY = static_cast<float>(
destSurface->h) / surface->h;
float scale = std::min(scaleX, scaleY);
// Calculate new dimensions
int newWidth = static_cast<int>(surface->w *
scale);
int newHeight = static_cast<int>(surface->h
* scale);
// Calculate position to center the image
int x = (destSurface->w - newWidth) / 2;
int y = (destSurface->h - newHeight) / 2;
SDL_Rect srcRect{
0, 0, surface->w, surface->h};
SDL_Rect destRect{
x, y, newWidth, newHeight};
SDL_BlitScaled(surface, &srcRect,
destSurface, &destRect);
std::cout << "Rendered at: x=" << destRect.x
<< ", y=" << destRect.y
<< ", w=" << destRect.w << ", h=" <<
destRect.h << '\n';
}
~ScalableImage() {
if (surface) SDL_FreeSurface(surface);
}
private:
SDL_Surface* surface;
};
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window =
SDL_CreateWindow("Fit Image to Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_RESIZABLE);
SDL_Surface* screenSurface =
SDL_GetWindowSurface(window);
ScalableImage img{"example.bmp"};
bool quit = false;
SDL_Event e;
while (!quit) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
} else if (e.type == SDL_WINDOWEVENT &&
e.window.event ==
SDL_WINDOWEVENT_SIZE_CHANGED) {
screenSurface = SDL_GetWindowSurface(
window);
}
}
SDL_FillRect(screenSurface, nullptr,
SDL_MapRGB(screenSurface->format,
255, 255, 255));
img.RenderFit(screenSurface);
SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
This example introduces a ScalableImage
class with a RenderFit()
method that scales the image to fit within the window. Here's how it works:
SDL_BlitScaled()
instead of SDL_BlitSurface()
to perform the scaling.The key part is in the RenderFit()
 method:
float scaleX = static_cast<float>(destSurface->
w) / surface->w;
float scaleY = static_cast<float>(destSurface->
h) / surface->h;
float scale = std::min(scaleX, scaleY);
int newWidth = static_cast<int>(surface->w *
scale);
int newHeight = static_cast<int>(surface->h *
scale);
This ensures that the image is scaled to fit either the width or height of the window, whichever is smaller, thus guaranteeing it always fits.
In the main()
function, we've made the window resizable and added an event loop to handle window size changes. This allows us to demonstrate that the image continues to fit even as the window is resized.
Remember that SDL_BlitScaled()
might not provide the highest quality scaling for all types of images. For more advanced scaling techniques, you might want to consider using SDL2's rendering API with SDL_RenderCopy()
, or a dedicated image processing library.
This technique is useful for:
Answers to questions are automatically generated and may not have been reviewed.
Learn to precisely control image display using source and destination rectangles.