第四章 載入並顯示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
的匯入庫。
- 用 pexports (從網上搜尋下載)匯出
SDL_image.dll
中的函式定義:pexports SDL_image.dll > SDL_image.def
。生成的SDL_image.def
是個文字檔案,可以用文字編輯器檢視。 - 用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
,最簡單的方式是使用SDL_image
的IMG_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
頁面,可以傳遞NULL
給dstrect
。color
指定要填充的顏色,我們用十六進位制來表示這個值,這次我們給它的值是:0xff009900
。0x
之後每兩位數表示一個位元組,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。
這一章中,我們學到了哪些新東西呢?
- 在MinGW下安裝
SDL_image
開發庫。 - 給定dll檔案,如何在MinGW下生成匯出庫。(注意,這個方法可能要視dll中函式的呼叫方式做適當調整)
- 用
SDL_image
的IMG_Load
的函式載入PNG, JPG, GIF等格式的圖片。當然,用IMG_Load
一樣可以載入BMP圖片。 - 用
SDL_FillRect
填充螢幕背景。 - 用
SDL_SetColorKey
設定頁面的關鍵色,這樣當該頁面Blit到其它頁面上時,關鍵色將被過濾掉。
下一章,我們將學習更激動人心的內容:動起來的畫面。
如果你喜歡我的文章,可以點 這裡 給我打賞,五分一毛也是對我的認同。
相關文章
- AXIOS從伺服器載入圖片並顯示iOS伺服器
- 預載入顯示圖片的藝術
- IE10與IMG圖片PNG顯示不了 WP中的WebBrowser中無法檢視PNG格式的圖片IE10Web
- 載入網路圖片所顯示的轉圈效果及載入成功前與失敗後所顯示的圖示
- QLabel顯示圖片 ,並實現縮放
- qt標題,解決title的png圖片scaled後顯示有明顯鋸齒QT
- js實現canvas儲存圖片為png格式並下載到本地JSCanvas
- QML中載入圖片不顯示,路徑出錯問題
- img圖片無法顯示利用onerror事件顯示替代圖片Error事件
- DHTML:預載入圖片輪顯(轉)HTML
- ReactNative IOS下Image標籤載入網路圖片不顯示ReactiOS
- Django實現圖片上傳並前端頁面顯示Django前端
- 瀏覽器更新HTTP伺服器圖片並顯示瀏覽器HTTP伺服器
- Android圖片處理:識別影象方向並顯示Android
- 使用jpeg圖片庫,顯示圖片並簡單實現LCD的觸屏功能
- 第三章 載入並顯示BMP影像
- LCD螢幕顯示PNG影像
- PNG圖片原理二三事
- 【學習圖片】06:PNG
- PNG圖片格式詳解
- Java——圖片滾動顯示Java
- 完美解決IE中PNG格式透明背景圖片顯示異常的各種方法【Z】
- Swift - 非同步載入各網站的favicon圖示,並在單元格中顯示Swift非同步網站
- opencv圖片上如何顯示兩個小圖片OpenCV
- win7圖片只顯示圖示不顯示預覽圖解決方案Win7圖解
- 網頁圖片不能顯示 網頁圖片顯示不出來的解決辦法網頁
- iOS設定tabbar不顯示文字,只顯示圖片iOStabBar
- 小程式button背景顯示圖片
- CSS圖片的灰色顯示效果CSS
- ImageView顯示網路上的圖片View
- vue el-image 顯示圖片Vue
- Flutter 圖片載入Flutter
- 圖片懶載入
- 預載入圖片
- 圖片載入事件事件
- 載入圖片方式
- [分享]iOS開發 - 批量載入圖片資源時模擬器的顯示而真機不顯示的問題iOS
- asp.net 使用FileUpload控制元件上傳並顯示圖片ASP.NET控制元件