0
votes

So, I have an image that I open in a window with SDL2. I want to implement a zoom function for the image that works as following: I click on two points of the image and I make a rectangle with those points as opposite corners. Then I make a copy of the rectangle and update the window to show the part of the image I selected, and this new image has a bigger width and height than the rectangle I chose because it will be the height and the width of the whole window. I can detect the mouse clicks, and from the mouse clicks calculate the top left corner of the rectangle in x and y coordinates. However, I don't know how to make a copy of the pixels in those rectangles, nor how to make the window now show the zoomed in part. I've been googling a lot but I don't know what functions to use or how to code my own. How would I write such a function?

Here's what I have so far. The image I want to be able to zoom into is "map.jpg"

SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = NULL;
window = SDL_CreateWindow("WarmingUp", TOP_LEFT_CORNER_X,
                          TOP_LEFT_CORNER_Y, IMAGE_WIDTH, IMAGE_HEIGHT, 0);
if(window == NULL){
    printf("Erro a abrir janela gráfica\n");
    exit(EXIT_FAILURE);
}

SDL_Renderer *renderer = NULL;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL){
    printf("Erro a criar renderer\n");
    exit(EXIT_FAILURE);
}

SDL_Surface *jpgSurface = NULL;
jpgSurface = IMG_Load("map.jpg");
if(jpgSurface == NULL){
    printf("Erro a abrir imagem\n");
    exit(EXIT_FAILURE);
}
SDL_Texture *jpgTexture = NULL;
jpgTexture = SDL_CreateTextureFromSurface(renderer, jpgSurface);
if(jpgTexture == NULL){
    printf("Erro a criar superfície através de imagem\n");
    exit(EXIT_FAILURE);
}
SDL_FreeSurface(jpgSurface);
SDL_Event e;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, jpgTexture, NULL, NULL);    
while(!quit){
    while(SDL_PollEvent(&e)){
        if(e.type == SDL_QUIT)
            quit = 1;

        SDL_RenderPresent(renderer);
        SDL_Delay(15);
SDL_DestroyTexture(jpgTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();

I know that to make the mouse interaction in my while &eventloop I need to check for if ( event.type == SDL_MOUSEBUTTONUP ), and I can also show you the code to calculate the top left corner x and y position of the desired rectangle to be cropped, but I really can't go any further.

1
How do you draw (SDL window surface, SDL_Renderer, ...)?keltar
@keltar do you understand now???chilliefiber
You can allocate surface of required size and use SDL_RenderReadPixels to get source pixels, then create window/renderer, and push surface to texture on second renderer.keltar
@keltar can you explain that a little bit with code? Say, the rectangle I want to zoom starts at x = 50 px and y = 50 px, width is 50px and height is 70 px. The image I show to the user has width (IMAGE_WIDTH)1024 and height (IMAGE_HEIGHT) 515. What do I do?chilliefiber

1 Answers

0
votes

Here is modified code from question:

#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>

#define IMAGE_WIDTH 1024
#define IMAGE_HEIGHT 768

int main(int argc, char **argv) {
    (void)argc, (void)argv;

    int quit = 0;

    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_Window *window = NULL;
    window = SDL_CreateWindow("WarmingUp",
            SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
            IMAGE_WIDTH, IMAGE_HEIGHT, 0);
    if(window == NULL){
        printf("Erro a abrir janela gráfica\n");
        exit(EXIT_FAILURE);
    }

    SDL_Renderer *renderer = NULL;
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == NULL){
        printf("Erro a criar renderer\n");
        exit(EXIT_FAILURE);
    }

    SDL_Surface *jpgSurface = NULL;
    jpgSurface = IMG_Load("map.jpg");
    if(jpgSurface == NULL){
        printf("Erro a abrir imagem\n");
        exit(EXIT_FAILURE);
    }
    SDL_Texture *jpgTexture = NULL;
    jpgTexture = SDL_CreateTextureFromSurface(renderer, jpgSurface);
    if(jpgTexture == NULL){
        printf("Erro a criar superfície através de imagem\n");
        exit(EXIT_FAILURE);
    }
    SDL_FreeSurface(jpgSurface);
    SDL_Event e;

    // rectangle to upscale in second window
    const SDL_Rect srcrect = {600, 500, 250, 250};
    SDL_Window *second_window = NULL;
    SDL_Renderer *second_renderer = NULL;
    SDL_Texture *magnified_fragment_texture = NULL;

    while(!quit){
        while(SDL_PollEvent(&e)){
            if(e.type == SDL_QUIT ||
                    (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE)) {
                quit = 1;
            } else if(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_t &&
                    !second_window) {
                // create empty surface of adequate size
                SDL_Surface *const surf = SDL_CreateRGBSurface(0, srcrect.w, srcrect.h, 32,
                        0xff000000, 0xff0000, 0xff00, 0xff);
                SDL_FillRect(surf, NULL, 0);

                // copy pixels
                SDL_RenderReadPixels(renderer, &srcrect, SDL_PIXELFORMAT_RGBA8888,
                        surf->pixels, surf->pitch);

                // error checking should be done...
                second_window = SDL_CreateWindow("mag",
                        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                        srcrect.w*2, srcrect.h*2, 0);
                second_renderer = SDL_CreateRenderer(second_window, -1, SDL_RENDERER_ACCELERATED);
                magnified_fragment_texture = SDL_CreateTextureFromSurface(second_renderer, surf);
                SDL_FreeSurface(surf);
            }
        }

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, jpgTexture, NULL, NULL);    
        SDL_RenderPresent(renderer);

        if(second_renderer) {
            const SDL_Rect dstrect = {0, 0, srcrect.w*2, srcrect.h*2};
            SDL_RenderClear(second_renderer);

            // RenderCopy scales texture to destination rect
            SDL_RenderCopy(second_renderer, magnified_fragment_texture, NULL, &dstrect);
            SDL_RenderPresent(second_renderer);
        }

        SDL_Delay(15);
    }

    SDL_DestroyTexture(jpgTexture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

In keypress event handler it creates second window/renderer/texture (not the best place for it), and later it renders second window if it exists.