You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SDL_BlitSurface指定目标矩形仍全屏复制问题求助

SDL_BlitSurface 复制完整源表面问题排查

问题场景

明明给SDL_BlitSurface设置了比屏幕尺寸小的目标矩形,但它还是将整个源表面复制到了目标表面上。相关代码片段如下:

SDL_Rect rect;
rect.x = 0;                             
rect.y = 0;
rect.w = SCREEN_WIDTH-200;
rect.h = SCREEN_HEIGHT-200;
SDL_BlitSurface(optimizedSurface, NULL, screenSurface, &rect);
//Update the surface
SDL_UpdateWindowSurface( window );

当前实际显示为完整图片铺满窗口,而期望效果是仅显示图片左上角一部分,尺寸为 SCREEN_WIDTH-200 × SCREEN_HEIGHT-200。

问题原因

对SDL_BlitSurface的参数逻辑理解有误:

  • 当第二个参数(源矩形)为NULL时,SDL会默认取整个源表面作为复制区域。
  • 第四个参数(目标矩形)的作用是将源区域缩放后绘制到目标表面的指定位置,而非裁剪目标区域。所以即便你设置了更小的目标矩形,SDL也会把整个源表面缩放到该矩形尺寸后填满目标位置,最终看起来还是完整图片被缩放显示。

修正方案

如果要仅绘制源表面的一部分到目标表面,需要同时指定源矩形和目标矩形:

  • 源矩形:定义从源表面复制的区域范围
  • 目标矩形:定义该区域在目标表面的绘制位置(若不需要缩放,宽高需与源矩形一致;若要缩放则设置为目标尺寸)

修正后的代码片段

// 定义源矩形:取源表面左上角的指定区域
SDL_Rect srcRect;
srcRect.x = 0;
srcRect.y = 0;
srcRect.w = SCREEN_WIDTH-200;
srcRect.h = SCREEN_HEIGHT-200;

// 定义目标矩形:绘制到目标表面的(0,0)位置,尺寸与源矩形一致(不缩放)
SDL_Rect destRect;
destRect.x = 0;
destRect.y = 0;
destRect.w = srcRect.w;
destRect.h = srcRect.h;

SDL_BlitSurface(optimizedSurface, &srcRect, screenSurface, &destRect);
SDL_UpdateWindowSurface(window);

完整修正代码

//Using SDL and standard IO
#include <SDL2/SDL.h>
#include <stdio.h>
#include <cstring>
#include <bits/atomic_base.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//The window we'll be rendering to
SDL_Window* window = NULL;

//The surface contained by the window
SDL_Surface* screenSurface = NULL;

//The surface of the loaded media
SDL_Surface* optimizedSurface = NULL;

bool loadMedia() {
    bool success = true;

    char path[] = "/home/gras/CLionProjects/SDLBonanza/resources/cock.bmp";


    SDL_Surface* loadSurface = SDL_LoadBMP(path);

    if(loadSurface == NULL) {
        printf("Unable to load image: %s with error msg: %s", path, SDL_GetError());
        success = false;
    }
    //optimize image on load to remove conversion when blitting
    optimizedSurface = SDL_ConvertSurface(loadSurface, screenSurface->format, NULL);

    if(optimizedSurface == NULL) {
        printf("The optimised image could not be computed with error: %s", SDL_GetError());
        success = false;
    }
    SDL_FreeSurface(loadSurface);

    return success;
}

bool init() {
    bool success = true;

    //initialize sdl
    if( SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL could not initialize with error code: %s", SDL_GetError());
        success = false;
    }
    else {
        window = SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);

        if(window == NULL) {
            printf("The window could not be created with error: %s", SDL_GetError());
            success = false;
        }
        else {
            screenSurface = SDL_GetWindowSurface(window);
            if(screenSurface == NULL) {
                printf("The screen surface could not be created with error: %s", SDL_GetError());
                success = false;
            }
        }
    }
    return success;
}

void close() {
    //dealocate surface
    SDL_FreeSurface(screenSurface);
    screenSurface = NULL;

    //dealocate window
    SDL_DestroyWindow(window);
    window = NULL;

    //quit sdl subsystem
    SDL_Quit();
}

void negative() {
    for(int i=0; i<optimizedSurface->h; i++) {
        for(int j=0; j<optimizedSurface->w; j++) {
            Uint8* pixel = ((Uint8*)optimizedSurface->pixels + i * optimizedSurface->pitch + j * optimizedSurface->format->BytesPerPixel);
            for(int k=0; k< optimizedSurface->format->BytesPerPixel; k++) {
                *(pixel+k) = 0xFF - *(pixel+k);
            }
        }
    }
}

int main( int argc, char* args[] )
{
    if(!init()) {
        printf("The initialization failed!");
    }
    else
        if(!loadMedia()) {
            printf("The media could not be loaded!");
        }
        else
        {
            //Update the surface
            SDL_UpdateWindowSurface( window );

            //Hack to get window to stay up
            SDL_Event e;
            bool quit = false;
            while( quit == false ) {
                while( SDL_PollEvent( &e ) ) {
                    if( e.type == SDL_QUIT )
                        quit = true;
                    if( e.type == SDL_KEYDOWN) {
                        switch(e.key.keysym.sym) {
                            case(SDLK_UP):
                                negative();

                                // 定义源矩形:取源表面左上角的指定区域
                                SDL_Rect srcRect;
                                srcRect.x = 0;
                                srcRect.y = 0;
                                srcRect.w = SCREEN_WIDTH-200;
                                srcRect.h = SCREEN_HEIGHT-200;

                                // 定义目标矩形:绘制到目标表面的(0,0)位置
                                SDL_Rect destRect;
                                destRect.x = 0;
                                destRect.y = 0;
                                destRect.w = srcRect.w;
                                destRect.h = srcRect.h;

                                SDL_BlitSurface(optimizedSurface, &srcRect, screenSurface, &destRect);

                                //Update the surface
                                SDL_UpdateWindowSurface( window );

                                break;
                            default:
                                break;
                        }
                    }

                }
            }
        }

    //free and destroy window
    close();

    return 0;
}

内容的提问来源于stack exchange,提问作者Cristian Cutitei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:45:08