简体   繁体   English

SDL2 透明背景

[英]SDL2 transparent background

I'm trying to create a.PNG image from a larger.PNG image.我正在尝试从更大的.PNG 图像创建一个.PNG 图像。 Basically clip a rect area of the original and save the result as another.PNG Sort of like a texture unpacker, if you will.基本上剪辑原始的矩形区域并将结果另存为 another.PNG 有点像纹理解包器,如果你愿意的话。

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);使用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).之前RenderCopy ,否则你会得到错误的颜色(与默认黑色混合 - 结果会比它应该的更暗)。 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.有关在不同混合模式中使用的公式,请参阅SDL_SetTextureBlendMode文档。

  2. Your resulting surface don't have alpha channel so there is nowhere to copy result.您生成的表面没有 Alpha 通道,因此无处复制结果。 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".检查SDL_CreateRGBSurface的文档:虽然它允许将0用于颜色蒙版以推断默认值,但它明确不允许将其用于 alpha 通道,因此0代替amask会导致“我不想要 alpha 通道,只是 RGB” . Your resulting format is RGB888 packed to 32bit.您生成的格式是 RGB888 打包为 32 位。 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.你想要 alpha,所以你应该使用正确的颜色掩码 - 从文档中获取一个,在你的情况下,你甚至不需要检查字节序,但它永远不会受到伤害。

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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