第4章 载入并显示PNG图片

在第三章中,我们讲解了如何在SDL程序中载入并显示BMP图像。虽然SDL直接支持BMP图片的载入,但BMP格式的图片占用较多的硬盘空间。如果游戏的图片资源都使用BMP格式,会增大我们小游戏的体积。

那么我们可以使用别的图片格式吗?SDL_image帮我们提供了解决方案。使用SDL_image,可以载入JPG,PNG,GIF,TIF等多种图片格式。我们将使用流行的PNG格式。

一、安装SDL_image

这一节其实主要为在windows下使用MinGW的用户写的,因为Linux上安装SDL_image的开发包是非常简单的事。

下面主要讲解怎么在MinGw中安装SDL_image,使用Linux的用户可以直接跳到下一节。

SDL_image 1.2的主页在这里:http://www.libsdl.org/projects/SDL_image/release-1.2.html,我们要从这里下载 SDL_image的开发包。咦?怎么只有VC的开发包,没有MinGW的开发包呢?

没有关系,就下载VC的开发包吧:http://www.libsdl.org/projects/SDL_image/release/SDL_image-devel-1.2.12-VC.zip

一个开发库如果以动态链接库的形式发布,包含三个组成部分:头文件、动态库、导入库。下面我们一一搞定。

  • 解压压缩包,把include目录中的SDL_image.h拷贝到MinGW的include/SDL目录中,头文件搞定。
  • 打开开发包中的lib目录,发现有SDL_image.dll和jpeg、png等图片格式的解码库,把这些动态库全部放入MinGW中的bin目录中,动态库搞定。
  • lib目录中还有一个SDL_image.lib,这是VC格式的导入库,MinGW能识别吗?把它放入MinGW的lib目录中,我们试试吧。

修改makefile,在链接选项后增加 -lSDL_image,表示生成执行程序时,链接SDL_image库。

game: main.c
    gcc -o game main.c `sdl-config --cflags --libs` -lSDL_image

make一下,发现成功了。原来MinGW可以识别VC的lib格式的导入库,真是宽容,真是伟大!

其实,如果没有VC的导入库,MinGW还是有办法自己生成导入库的。比如我们有头文件和SDL_image.dll,分两步生成SDL_image.dll的导入库。

  1. pexports (从网上搜索下载)导出SDL_image.dll中的函数定义: pexports SDL_image.dll > SDL_image.def。生成的SDL_image.def是个文本文件,可以用文本编辑器查看。
  2. 用mingw自带的dlltool生成导入库: dlltool -d SDL_image.def -l libSDL_image.dll.a,会生成libSDL_image.dll.a,这就是我们需要的东西,dll.a的后缀名告诉MinGW这是对应dll的导入库。把它放入MinGW的lib目录就可以了。

SDL_image安装好后,还有一件事,就是SDL_image的文档,文档页面在这里: http://www.libsdl.org/projects/SDL_image/docs/SDL_image.html。可以下载下来看,也可以在线看。

二、装载和显示PNG图片

这里我们以下面图片(文件名: 200x125-skill.png)为例:

200x125-skill.png

如何装载 200x125-skill.png,最简单的方式是使用SDL_imageIMG_Load函数,原型如下:

SDL_Surface *IMG_Load(const char *file)

给定该函数一个图片路径,得到一个包含图像数据的SDL surface。得到surface后,后续的处理就和上面一样了。代码片段如下:

/* 装载PNG图片,得到一个SDL页面 */
SDL_Surface *temp = IMG_Load("200x125-skill.png");
/* 转换SDL页面,得到一个像素格式和screen相同的页面 */
SDL_Surface *skill_surface = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);

/* 在screen的中间选定一个矩形区域来显示图像 */
SDL_Rect dest_rect = {(screen->w - 200)/2, (screen->h - 125)/2, 200, 125};
SDL_BlitSurface(skill_surface, NULL, screen, &dest_rect);
SDL_Flip(screen);

注意,别忘了在程序开头#include <SDL_image.h>make然后运行一下程序,看看效果如何。

三、设置屏幕背景色

我们使用的图片背景色是黑色,刚好screen默认的页面颜色也是黑色,如果screen是其它的背景色,显示效果就没有那么好了。

现在我们用SDL_FillRect函数把屏幕显示区域填充成别的颜色。

int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color);
  • dst表示要填充颜色的页面, 我们要填充的是screen页面。
  • dstrect指向要填充的矩形区域,我们要填充整个screen页面,可以传递NULLdstrect
  • color指定要填充的颜色,我们用十六进制来表示这个值,这次我们给它的值是:0xff0099000x之后每两位数表示一个字节,4个字节一次表示Alpha值(透明度)、红色分量R、绿色分量G和蓝色分量B。这里我们将红色分量和蓝色分量置为0,而绿色分量是0x99。因此0xff009900表示一个暗绿色。

综上,SDL_FillRect(screen, NULL, 0xff009900);将把屏幕填充成暗绿色。
改写原来的代码片段,增加SDL_FillRect语句:

/* Fill screen with some color */
SDL_FillRect(screen, NULL, 0xff009900);

/* Load PNG and Display */
SDL_Surface *temp = IMG_Load("200x125-skill.png");
SDL_SetColorKey(temp, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0x00000000);
SDL_Surface *skill_surface = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);

SDL_Rect dest_rect = {(screen->w - 200)/2, (screen->h - 125)/2, 200, 125};
SDL_BlitSurface(skill_surface, NULL, screen, &dest_rect);
SDL_Flip(screen);

make然后运行程序,效果如图:

图像的黑色背景很突兀

现在图像的黑色背景给人的感觉很不好。

四、去除图片背景色

在显示一个页面时,怎么把它的背景色去掉呢?使用SDL_SetColorKey来设置页面的透明色。

int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key);

surface是要设置关键色的页面,我们这里要过滤背景的页面是skill_surface

flag的值通常是 SDL_SRCCOLORKEY | SDL_RLEACCEL, 其中 SDL_SRCCOLORKEY 表示为页面设置的关键色在BlitSurface时将被过滤掉。SDL_RLEACCEL表示用 行程编码 (?) 提高BlitSurface的效率。

key是要设置的关键色,即在BlitSurface时要过滤掉的透明色。是32位整数,包含4个字节。可以表示为0xAARRGGBB。其中AA是表示alpha通道的字节,RR, GG, BB分别表示红绿蓝三个分量。因为我们图片的背景色是纯黑,直接把0传递给key即可。

注意:当你知道图片的背景色(即你知道RGB的分量各是多少)时,你并不能直接用这个值来设置关键色。因为你图片的像素格式转换成screen的像素格式时,背景色RGB的值极可能改变,这样,背景色仍然过滤不掉。这时候,我们可以把RGB的值传递给SDL_MapRGB函数,从而得到一个转换后的Uint32的关键色表示。如果用黑色做图片的背景色,则可以省略这一步,因为不管像素格式怎么变,RGB分量的值始终是0。

综上,我们可以调用SDL_SetColorKey(skill_surface, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0)来将skill_surface的黑色背景色设为透明色。

加载并显示图片的代码变为:

/* Load PNG */
SDL_Surface *temp = IMG_Load("200x125-skill.png");
/* set transparent color before converting surface with SDL_DisplayFormat */
/* in order to take advantage of hardware acceleration*/
SDL_SetColorKey(temp, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0x00000000);
SDL_Surface *skill_surface = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);

SDL_Rect dest_rect = {(screen->w - 200)/2, (screen->h - 125)/2, 200, 125};
SDL_BlitSurface(skill_surface, NULL, screen, &dest_rect);
SDL_Flip(screen);

重新make,运行./game,效果如图:

滤掉背景色的图像显示

五、小结

第4章的源代码和资源可以从这里查看、下载: https://github.com/jollywing/make-linux-rpg/tree/master/chap04

这一章中,我们学到了哪些新东西呢?

  1. 在MinGW下安装SDL_image开发库。
  2. 给定dll文件,如何在MinGW下生成导出库。(注意,这个方法可能要视dll中函数的调用方式做适当调整)
  3. SDL_imageIMG_Load的函数加载PNG, JPG, GIF等格式的图片。当然,用IMG_Load一样可以加载BMP图片。
  4. SDL_FillRect填充屏幕背景。
  5. SDL_SetColorKey设置页面的关键色,这样当该页面Blit到其它页面上时,关键色将被过滤掉。

下一章,我们将学习更激动人心的内容:动起来的画面


如果你喜欢我的文章,可以点 这里 给我打赏,五分一毛也是对我的认同。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,424评论 25 707
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,650评论 0 3
  • 一、向屏幕画图:SDL_BlitSurface 怎么显示一个图像?显然,首先要将它从硬盘载入内存。载入内存之后呢?...
    江欲行阅读 811评论 0 2
  • 最近和朋友聊到做人,她说想做一个和多数人不一样的人,当时我很是赞同。但现在仔细想想,却又觉得十分艰难。古来有...
    临渊不羡于阅读 234评论 0 0
  • 我喜欢的热干面,现在是一种很难吃到的味道,而你们讨厌这个味道,觉得它太干,如今是不是也想那碗热干面了呢?除了面,更...
    一抹泪痕一抹微笑阅读 338评论 2 1