ETH官方钱包

創作內容

1 GP

【程式】讀取圖檔的方法-Linux篇

作者:Shark│2016-11-29 23:34:11│巴幣:2│人氣:952
有Windows篇當然也會寫一篇Linux的。
Windows篇在此

Linux有兩個常用的視窗系統函式庫:GTK和QT,其他跟圖形介面有關的函式庫也大約分成這兩個體系,開發Linux程式基本上要在兩者之間選一個然後學習它的用法。
Linux的視窗系統不是只有這兩種,不過要考慮使用者的電腦上可能預設沒有安裝,還要先安裝函式庫才能用你的軟體,儘量用普遍的東西比較好。

本篇使用GTK體系的圖檔讀取函式庫gdk-pixbuf,QT我就沒試過了。
GTK雖然語言是純C,但有物件繼承多型的概念,下面就可以看到GdkPixbuf繼承GObject,所以操作GObject的函式也可以用在GdkPixbuf。
不過為了用沒有物件概念的C語言去模擬物件,程式碼就很冗長。
例如這個函式,名稱裡有gdk_pixbuf代表class名稱,物件放在第一個參數,有的函式還要多一個macro用來轉型。
gdk_pixbuf_get_width(pixbuf);

C++的寫法是這樣。
pixbuf->get_width();

需求跟Windows篇同樣,輸入要能給檔名和記憶體區塊兩種。
實驗用的發行版是LinuxMint 17.2,別的發行版可能套件名稱和編譯時的參數不一樣,要自己試。
同樣不詳細說明每個函式、struct、常數的用法,本篇下面有官方文件連結,請自己查。



1.首先要安裝開發用套件
名稱通常是函式庫名稱後面加上-dev或-devel,依發行版而異,自己用套件管理器找找看,例如筆者的是libgdk-pixbuf2.0-dev。

2.include header
#include<gdk-pixbuf/gdk-pixbuf.h>
#include<gio/gio.h>
gdk-pixbuf不需要呼叫特別的函式初始化。

再來產生一個GdkPixbuf物件
3a.如果輸入是檔名
GError* error=NULL;
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file("fileName.png",&error);

3b.輸入是記憶體的話,雖然有gdk_pixbuf_new_from_bytes和gdk_pixbuf_new_from_data可以傳入指標,但這些要的是解碼後的RGBA值。
圖檔原封不動放在記憶體的情況則跟Windows篇一樣,用一個stream包起來再丟給GdkPixbuf,使用的class是GInputStream
GError* error=NULL;
GInputStream* stream=g_memory_input_stream_new_from_data(buffer,
  bufferSize,NULL);  //reference=1
GdkPixbuf* pixbuf=gdk_pixbuf_new_from_stream(stream,NULL,
  &error);  //reference增加
g_object_unref(stream);  //reference減1
可以看到為了用C語言去模擬物件,建立物件的方法不是用建構子,而是呼叫名稱裡有new的函式。
這裡跟Windows篇一樣是用reference count,可能不是所有人都看過Windows版,所以再介紹一次:物件內部有個計數器,記錄有多少物件參考到它,釋放資源的方法是計數器減到0才刪除,而不是直接用delete關鍵字。
建好pixbuf之後就把g_memory_input_stream_new_from_data的reference扣掉,之後刪除pixbuf時就自動刪除stream。
GObject是GTK的一個底層class ,整個GTK分成從基礎到高階的很多函式庫,用底層的當基礎架構出上層。有繼承GObject的物件管理方式是用g_object_ref和g_object_unref增減reference count。

4.取得圖的尺寸,這樣才知道要malloc多少記憶體
int w = gdk_pixbuf_get_width(pixbuf);
int h = gdk_pixbuf_get_height(pixbuf);
uint32_t* pixels = (uint32_t*)malloc(w*h*4);

5.解出RGBA值,建立另一個GdkPixbuf物件用來轉換格式
GdkPixbuf* outPixbuf=gdk_pixbuf_new_from_data((uint8_t*)pixels,
  GDK_COLORSPACE_RGB, 1,8,w,h,w*4,NULL,0);
gdk_pixbuf_copy_area(pixbuf,0,0,w,h,outPixbuf,0,0);
第一行的參數是指定輸出格式,以及輸出到剛剛malloc的記憶體。
第二行其實是把一個點陣圖複製到另一個,它會根據目的圖的格式自動轉換格式,這時候pixels就是解碼出來的RGBA值了。
byte順序只支援RGBA,如果想要BGRA要之後另外處理。

6.此時可以把物件刪除了,GdkPixbuf也繼承了GObject所以刪除方法是g_object_unref
g_object_unref(pixbuf);
g_object_unref(outPixbuf);
gdk-pixbuf沒有初始化函式,同樣也不需要呼叫函式結束系統。

筆者的發行版要用這個命令列產生可執行檔
gcc test.c -o test -O2 -s `pkg-config --cflags --libs gdk-pixbuf-2.0 gio-2.0`
如果不是編譯同時連結,那分別把這兩個放在compiler和linker參數
`pkg-config --cflags gdk-pixbuf-2.0 gio-2.0`
`pkg-config --libs gdk-pixbuf-2.0 gio-2.0`

gio-2.0是因為有用到GInputStream。
編譯這個程式時參數要加很多include路徑和library,pkg-config是一個命令列工具幫你加上這些參數,會把它的stdout填入gcc的命令列。
在終端機打pkg-config --cflags --libs gdk-pixbuf-2.0 gio-2.0,看它跳出什麼就知道是怎麼回事了。



Cyber Sprite一代不是用這個方法而是直接用libpng和libjpeg讀檔,這樣每個格式都要寫不同的code去呼叫函式庫挺費事的。
另外Cyber Sprite發售後發生一個問題,新出的Linux發行版把預設的libjpeg版本從6.2換成8,這樣遊戲讀不到6.2版就無法執行,1.04 patch有一項就是解決這個問題。
……Linux縱向相容性差我已經司空見慣了,縱向相容性是指同一發行版的新舊版之間,不是不同發行版的相容性。(這是個人覺得Linux軟體難開發的原因之一)

想說能不能像Windows的GDI+一樣,可以自動判斷圖檔格式,然後找系統裡有安裝的函式庫,於是決定改用gdk-pixbuf。

接下來的問題是,找說明文件只找到reference(解說每個函式是做什麼用的),沒找到tutorial(從零開始一步步教你用)
gdk-pixbuf官方文件,主要看The GdkPixbuf Structure和File Loading這兩頁
GInputStream官方文件
只能看函式名稱並根據自己對GObject的了解猜用途,再自己寫程式,試著把參數改來改去摸索它的性能。

雖然可能也有比較用心的函式庫,但是寫Linux程式常常遇到說明文件沒寫清楚的,就只能靠自己做實驗,什麼都試試看它什麼情況會掛掉這種的。(Linux軟體難開發的原因之二)
相較之下Windows對軟體作者很親切,官方文件MSDN寫得清楚明白,向後相容也維護得很好。

利用gdk-pixbuf自動找解碼函式庫應該能減輕相容性問題了,再來祈禱gdk-pixbuf不要哪天改library名稱,讓相容性斷掉。
引用網址:http://www.jamesdambrosio.com/TrackBack.php?sn=3400258
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:程式|Linux|Linux程式設計|GTK

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

1喜歡★shark0r 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:「淺談遊戲引擎」觀後感... 後一篇:20週年站聚遊記...


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情? 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】