SDL第四课色彩键控

色彩键控

 

最后更新2008/06/25

接下来我们将学习色彩键控。通俗的讲,就是教你在显示画面的时候,如何去掉背景颜色。SDL_Surface结构体中有一个成员叫做色键。色键就是当位图传输时,你不想在画面中显示出来的颜色,也就是用来控制背景透明。假设你想把这个名字为Foo.png的图片,

 

粘贴到下面这个背景上:

 

但是你不想让粘贴的图片中带有蓝绿色的背景:

 

为了不显示蓝绿色的背景,你需要将背景的颜色(这里背景颜色为:Red 0Green FF Blue FF)设置为画面的色键。

 

色键的典型用法是在当加载图片时设置。

SDL_Surface *load_image( std::string filename )

{

    //The image that's loaded

    SDL_Surface* loadedImage = NULL;

   

    //The optimized image that will be used

    SDL_Surface* optimizedImage = NULL;

   

    //Load the image

    loadedImage = IMG_Load( filename.c_str() );

   

    //If the image loaded

    if( loadedImage != NULL )

    {

        //Create an optimized image

        optimizedImage = SDL_DisplayFormat( loadedImage );

       

        //Free the old image

        SDL_FreeSurface( loadedImage );

/*因此,在这里我们将修改图片的加载函数。首先和之前一样载入和优化图片*/

 

        //If the image was optimized just fine

        if( optimizedImage != NULL )

        {

            //Map the color key

            Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );

     /*然后,检查图片是否已经优化。如果优化完毕,我们需要绘制出来我们要设置为色键的色彩。调用SDL_MapRGB()函数,输入红、绿、蓝三基色的值,指定与画面相同的格式。关于像素,本章后有更详细的说明。*/

 

            //Set all pixels of color R 0, G 0xFF, B 0xFF to be transparent

            SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );

        }

/*开始实际的色彩键控。第一个参数是我们要进行键控的画面。第二个参数我们放置的标志位。SDL_SRCCOLORKEY标志位,确保当我们传输这个画面到另一个画面上时能够使用色键。第三个参数是我们设置的色键的颜色。就是我们刚刚绘制的颜色。*/

 

    //Return the optimized image

    return optimizedImage;

}

/*然后,画面加载函数返回优化并进行色彩键控后的画面。*/

 

    //Apply the surfaces to the screen

    apply_surface( 0, 0, background, screen );

    apply_surface( 240, 190, foo, screen );

   

    //Update the screen

    if( SDL_Flip( screen ) == -1 )

    {

        return 1;   

    }

    /*现在传输背景位图,再传要粘贴的输色彩键控后的图片。*/

 

这样,粘贴的图片就没有蓝绿色的背景了。那些你使用的透明的PNG图片,IMG_Load()函数会自动处理透明图片。试着色彩键控一个透明背景的图片,会得到一个蛮特别的结果。如果你用SDL_DisplayFormat()函数代替SDL_DisplayFormatAlpha()函数,你也会有alpha颜色透明失真。只要不去色彩键控它就能够保留PNG图片上的透明背景。IMG_Load()函数也能够处理TGA图片的alpha颜色。查看SDL文档,获得更多关于颜色键控的信息。

 

 

 

什么是像素?

最后更新时间2009/12/15

也许你知道图片是由像素构成的,但是知道像素是由什么构成的么?

            //Map the color key

            Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );

这是色彩键控教程里的一行代码。我说过SDL_MapRGB()返回一个像素,但是怎样构成一个“Uint32”的一个像素?

Uint32是一个:无符号的32位长度的整型数据。

怎样用一个数表示一个像素?也许你知道一些HTML,设置颜色用3个0到255数字组合:

<span style="color: rgb(Red,Green,Blue)">Text</span>

那么怎样用一个数字表示一个像素?上面你看到的HTML/CSS 代码在这里是用来改变文本的颜色的。红,绿,蓝值的组合可以得到所有你的计算机能显示的颜色,例如:

 

This由 Red 255, Green 255, and Blue 255构成。

This由 Red 255, Green 0, and Blue 0构成。

This由 Red 0, Green 0, and Blue 255构成。

This由Red 0, Green 0, and Blue 0构成。

This由Red 192, Green 192, and Blue 0构成。

This由 Red 0, Green 255, and Blue 255构成。

This由 Red 192, Green 128, and Blue 64构成。

This由 Red 186, Green 3, and Blue 207构成。

 

    我认为你已经了解了。Uint32只是一个数字。如果像素由一组数字构成,那么不是要表示成一个数组?事实上,确实如此。红,绿,蓝的值构成一个像素,取值范围是0到255。要记得0也是一个数字,在编程时我们总是从0开始。那么就有256个值。256是2的8次方,所以每个颜色值可以用一个8位的二进制数表示。一个Uint32就是这些二进数一个接一个的结合到一起形成的一个数。在内存中,基本像素看起来就像这样:
101010110010101101011011

既然它只是一个8位二进制数的数组,你所要做的就是从一个大的32位的二进制数中得到单独的颜色值构成一个8位二进制数的数组。

 

//Get the address of the pixel

Uint8 *colors = (Uint8*)&pixel;

 

//Get the individual colors

red = colors[ 0 ];

green = colors[ 1 ];

blue = colors[ 2 ];

 

但是你通常都不会这么做。为了得到单独的颜色值,应该使用SDL_GetRGB()函数。我将告诉你一点为什么?也许现在你有一点迷惑,每个颜色8位,3个颜色是24位,那么最后8位呢?那最后8为就是像素的alpha颜色(alpha通道)。Alpha颜色控制像素透明。255表示像素完全不透明,而0表示像素完全透明。下面是一个图片显示在白色背景上的例子。每一次alpha颜色的值都不同。

 

alpha值是255时,图片显示正常 。

 

Alpha值是192时。你可以看得出来,白色的背景开始显露来。

 

 

 

alpha 的值为128. 现在透明度大约是50%。

 

alpha 的值是 0 ,图片完全看不到了。

 

这就是32位的RGBA像素的构成,但是不是所有的像素构成都相同。有不同的像素格式。颜色顺序不同,像BGRA的颜色顺序就是蓝,绿,红,alpha。像素也可以有不同的大小,像24位的BGR位图。也有16位的颜色,由5位红色,5位绿色,5位蓝色,以及1位alpha颜色。除此之外还有许多像素的格式,在这里不准备细说。所有这些像素格式就是为什么要通过SDL_PixelFormat来调用绘制颜色函数SDL_MapRGB()和获取颜色函数SDL_GetRGB(),这样函数才能知道怎样处理像素。这也是为什么把颜色的各位直接组合起来不是一个好的方法,除非你能知道你处理的是哪一种像素格式。

像素格式的不同也是你不能一起传输两个画面的原因。如果你把ABGR格式的像素复制到RGBA格式的画面上,就会出错。SDL可以实时转化像素格式,但是像素转化会占用CPU。这就是为什么我们要把所有的画面通过load_image()函数转化为屏幕的格式。

像这样像素转换的工作特别多,不过你不必困扰,除非你工作在非常低的层面。到此,你知道所有建立图片区块的基础知识。

有一些值得想想是问题,因为所有的RGB都是3个数字的组合,可不可以通过遍历通过他们显示的每一种可能的颜色?如果图像是由像素合成的,可不可以遍历每一种像素的组合并显示每一个可能存在的图片?

迷糊了没有?*_#








C语言 + SDL编写俄罗斯方块(四)----去除图片的背景

在加载一些图片时我们不希望在屏幕上看到素材图片的背景,我们更愿意使用背景透明的素材,然而,如果按照普通的图片显示方法显示图片,不可避免的将背景一起显示到屏幕上。下面提供两种方案来解决这一问题。

方案一:美工处理
使用photoshop或fireworks等工具处理图片时,将图片背景去掉,然后存储的时候存为.gif的格式,这样图片本身就是没有背景的,不过在使用SDL显示图片的时候,由于SDL本身只能显示.BMP格式的图片,所以必须使用高级的图片显示方法(我前面的文章有介绍),比如:下面图片,处理前有白色背景,

C语言+SDL编写俄罗斯方块(四)

处理后,另存为.gif图片就变成了这个样子:

C语言+SDL编写俄罗斯方块(四)

然后显示到屏幕上就是没有背景色的。

方案二:技术手段

#include <stdio.h>
#include <stdlib.h>
#include <sdl/sdl.h>

//全局声明

#define WIDTH   600

#define HEIGHT  400

#define CPP        32


SDL_Surface *screen = NULL;


//function name : delColor(SDL_Color &aColor, SDL_Surface *aImg)

//parameter:

//     SDL_Color &aColor : the color want to delete

//          SDL_Surface *aImg : the image handler


int delColor(SDL_Color &aColor, SDL_Surface *aImg)

{

         if(aImg != NULL)

         {

                   Uint32 colorKey = SDL_MapRGB(aImg -> format, aColor.r, aColor.g, aColor.b);

             SDL_SetColorKey(aImg,SDL_SRCCOLORKEY | SDL_RLEACCEL,colorKey);

                   return 1;

         }

         return 0;

}

搭配下面的代码使用:


//function name: initSDL

//parameter: none

//return: int

//0:  initial SDL normally

//1: initial SDL abnormally

//function: initial SDL


int initSDL()

{

        

         //init all SDL sub-system

         if(SDL_Init(SDL_INIT_EVERYTHING) == -1)

         {

                   printf("SDL init failed...\n");

                   return 0;    //init failed

         }

        

         //init screen

         screen = SDL_SetVideoMode(WIDTH,HEIGHT,CPP,SDL_SWSURFACE|SDL_DOUBLEBUF);    

         if(screen == NULL)

         {

                   printf("init screen failed, please check your display card\n");

                   return 0;    //init screen failed   

         }

         SDL_WM_SetCaption("SDL show picture",NULL);

         return 1;

}



//function name: initImg

//parameter: const char *aFileName, SDL_Surface **aImg

//parameter note:

//aFileName is a pointer use to save the name of image file

//aImg is a pointer of image

//return: int

//function: load image to memory


int initImg(const char *aFileName, SDL_Surface **aImg)

{

         SDL_Surface *pTemp;

        

         //必须使用BMP图片,否则背景色去除不彻底

         pTemp = SDL_LoadBMP(aFileName);

 

         //format BMP file

         *aImg = SDL_DisplayFormat(pTemp);    

 

         if (pTemp == NULL || aImg == NULL)

         {

                   printf("%s cann't load...\n",aFileName);;

                   return 0;

         }

 

         //free temporary pointer

         SDL_FreeSurface(pTemp);

 

         return 1;

}

 


//function name: showImg

//parameter: SDL_Surface *aSource, int aLeft , int aTop , int aWidth , int aHeight , SDL_Surface *aDestination

//parameter note:

//aSource is the handler of image

//aLeft is the left of image

//aTop is the top of image

//aWidth is the width of image

//aHeight is the height of image

//aDestination is screen handler

//return: void

//function: show image to display memory


void showImg(SDL_Surface *aSource, int aLeft , int aTop , int aWidth , int aHeight , SDL_Surface *aDestination)

{

        

         SDL_Rect picPosition;

        

         picPosition.x = aLeft;

         picPosition.y = aTop;

         picPosition.w = (aWidth == 0)? aSource-> w : aWidth;

         picPosition.h = (aHeight == 0)? aSource-> h : aHeight;

        

         SDL_BlitSurface(aSource,NULL,aDestination,&picPosition);

}



//function name: showScreen

//parameter: none

//return: void

//function: show screen


void showScreen()

{

         SDL_Flip(screen);

}


//function name: quitSDL

//parameter: SDL_Surface *aImg

//parameter note: aImg is a pointer of image

//return: void

//function: close SDL


void quitSDL(SDL_Surface *aImg)

{

         if(aImg != NULL)

         {

                   SDL_FreeSurface(aImg);

         }

         SDL_Quit();

}



//main function

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

{

         SDL_Surface *pImg;

 

         //define the color want to delete

         SDL_Color color;

 

         //set color white

         color.r = 255;

         color.g = 255;

         color.b = 255;

 

         //initial SDL

         initSDL();

        

         //load picture to memory

         initImg("test.bmp", &pImg);

 

         //delete color

         delColor(color, pImg);

 

         //load picture to display memory

         showImg(pImg,0,0,0,0,screen);

 

         //show the display memory to screen

         showScreen();

 

         //delay 5s

         SDL_Delay(5000);

        

         //close SDL

         quitSDL(pImg);

 

         system("pause");

         return 0;

}

方案二可以去除纯色背景,对于复杂背景就必须使用 方案一了。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值