简体   繁体   中英

SDL2 transparent background

I'm trying to create a.PNG image from a larger.PNG image. Basically clip a rect area of the original and save the result as another.PNG Sort of like a texture unpacker, if you will.

My issue is that the portions that were transparent in the original image are colored in the clipped image.

Initially I used hardware acceleration and the background was white with speckles, switching to software renderer just changed the background to Black.

I would like to maintain the transparency of the original image.

#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>


void save_texture(const char* file_name, SDL_Renderer* renderer, SDL_Texture* texture); // 
save png to disk
SDL_Texture* clipTexture(SDL_Rect rect, SDL_Renderer* renderer, SDL_Texture* source); // get 
a new texture that is clipped from the original


int main(int argc, const char * argv[])
{

    SDL_Init(SDL_INIT_VIDEO);

    IMG_Init(IMG_INIT_PNG);
    SDL_Surface* surface = IMG_Load("LevelItems.png");
    SDL_Renderer* renderer = SDL_CreateSoftwareRenderer(surface);

    SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_Rect frame_rect = { 189, 243,115, 50 };
    SDL_Texture* tex_clip = clipTexture( frame_rect, renderer, texture );

    save_texture("test1.png", renderer, tex_clip);

    SDL_FreeSurface(surface);

    return 0;
}

// return a new texture that is a part of the original texture.

SDL_Texture* clipTexture(SDL_Rect rect, SDL_Renderer* renderer, SDL_Texture* source)
{
    SDL_Texture* result = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, 
SDL_TEXTUREACCESS_TARGET, rect.w, rect.h);
SDL_SetRenderTarget(renderer, result);
SDL_RenderCopy(renderer, source, &rect, NULL);

return result;
}


// save png to disk
void save_texture(const char* file_name, SDL_Renderer* renderer, SDL_Texture* texture)
{
    int width, height;
    SDL_QueryTexture(texture, NULL, NULL, &width, &height);
    SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);

    SDL_RenderReadPixels(renderer, NULL, surface->format->format, surface->pixels, surface- 
  >pitch);
    IMG_SavePNG(surface, file_name);
    SDL_FreeSurface(surface);
}

There are two problems:

  1. Disable blending. Use SDL_SetTextureBlendMode(source, SDL_BLENDMODE_NONE); before RenderCopy , otherwise you'll get wrong colour (blended with default black - result would be darker than it shound be). Blending tied to texture so if you want to use this texture later you probably should reset blending mode right away. See SDL_SetTextureBlendMode doc for formulas used in different blend modes.

  2. Your resulting surface don't have alpha channel so there is nowhere to copy result. Check documentation for SDL_CreateRGBSurface : while it allows to use 0 for colour masks to deduce default values, it explicitly don't allow it for alpha channel, so 0 in place of amask results in "I don't want alpha channel, just RGB". Your resulting format is RGB888 packed to 32bit. You want alpha, so you should use correct colour masks - get one from docs, in your case you don't even need to check for endianess, but it never hurts.

To sum it up:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>


void save_texture(const char* file_name, SDL_Renderer* renderer, SDL_Texture* texture);
SDL_Texture* clipTexture(SDL_Rect rect, SDL_Renderer* renderer, SDL_Texture* source);

int main(int argc, const char * argv[])
{

    SDL_Init(SDL_INIT_VIDEO);

    IMG_Init(IMG_INIT_PNG);
    SDL_Surface* surface = IMG_Load("test.png");
    SDL_Renderer* renderer = SDL_CreateSoftwareRenderer(surface);

    SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
    SDL_Rect frame_rect = { 189, 243,115, 50 };
    SDL_Texture* tex_clip = clipTexture( frame_rect, renderer, texture );

    save_texture("test1.png", renderer, tex_clip);

    SDL_FreeSurface(surface);

    return 0;
}

// return a new texture that is a part of the original texture.

SDL_Texture* clipTexture(SDL_Rect rect, SDL_Renderer* renderer, SDL_Texture* source)
{
    SDL_Texture* result = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, 
SDL_TEXTUREACCESS_TARGET, rect.w, rect.h);
SDL_SetRenderTarget(renderer, result);
SDL_SetTextureBlendMode(source, SDL_BLENDMODE_NONE);
SDL_RenderCopy(renderer, source, &rect, NULL);

return result;
}


// save png to disk
void save_texture(const char* file_name, SDL_Renderer* renderer, SDL_Texture* texture)
{
    int width, height;
    SDL_QueryTexture(texture, NULL, NULL, &width, &height);

    Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    rmask = 0xff000000;
    gmask = 0x00ff0000;
    bmask = 0x0000ff00;
    amask = 0x000000ff;
#else
    rmask = 0x000000ff;
    gmask = 0x0000ff00;
    bmask = 0x00ff0000;
    amask = 0xff000000;
#endif

    SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask);

    SDL_RenderReadPixels(renderer, NULL, surface->format->format, surface->pixels, surface->pitch);
    IMG_SavePNG(surface, file_name);
    SDL_FreeSurface(surface);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM