在Linux控制臺下使用libjpeg顯示JPEG圖像在framebuffer上_第1頁
在Linux控制臺下使用libjpeg顯示JPEG圖像在framebuffer上_第2頁
在Linux控制臺下使用libjpeg顯示JPEG圖像在framebuffer上_第3頁
在Linux控制臺下使用libjpeg顯示JPEG圖像在framebuffer上_第4頁
在Linux控制臺下使用libjpeg顯示JPEG圖像在framebuffer上_第5頁
已閱讀5頁,還剩13頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、在 Linux 控制臺下使用 libjpeg 顯示 JPEG 圖像在 framebuffer1、引言通常情況下,在Linux控制臺下是無法查看圖像文件的,要想查看圖像文件,比如要查看JPEG格式的圖像文件,可能必須啟動 X-Windows,通過GNOME或者KDE之類的桌面管理器提供的圖像查看工具查看圖片內容。 那么,能不能有辦法在控制臺下面簡單地瀏覽圖像內容呢。 實際上,這是完全可以的。在 Linux 下有一個名為 zgv 的看圖軟件就是工作在控制臺下的。 不過,由于它所使用的底層圖形庫 svgalib 已經是一個比較“古老”的圖形庫了,所以現在 知道 zgv 的人并不是很多,用的人就更少了

2、。目前 Linux 上的底層圖形支持通常是由 Framebuffer 提供的,因此,作者試圖在本文中說明 如何通過 Framebuffer 和 libjpeg 在控制臺上顯示 JPEG 圖像。需要說明的是,本文中所編寫 的程序 fv 并非 zgv 的替代品,而只是一個出于驗證想法的簡單程序(fv 的含義是 FramebufferVision )。本文將先對 Framebufer和libjpeg的編程做一個簡略的說明,然后再給出程序fv的具體實現。2、Framebuffer 介紹Framebuffer 在 Linux 中是作為設備來實現的,它是對圖形硬件的一種抽象 1 ,代表著顯卡 中的幀緩沖區

3、 (Framebuffer )。通過 Framebuffer 設備, 上層軟件可以通過一個良好定義的軟 件接口訪問圖形硬件, 而不需要關心底層圖形硬件是如何工作的, 比如, 上層軟件不用關心 應該如何讀寫顯卡寄存器, 也不需要知道顯卡中的幀緩沖區從什么地址開始, 所有這些工作 都由 Framebuffer 去處理,上層軟件只需要集中精力在自己要做的事情上就是了。Framebuffer 的優點在于它是一種低級的通用設備,而且能夠跨平臺工作,比如Framebuffer既可以工作在 x86平臺上,也能工作在 PPC平臺上,甚至也能工作在 m68k和SPARC等平 臺上,在很多嵌入式設備上 Frame

4、buffer 也能正常工作。諸如 Minigui 之類的 GUI 軟件包也 傾向于采用 Framebuffer 作為硬件抽象層( HAL )。從用戶的角度來看, Framebuffer 設備與其它設備并沒有什么不同。 Framebuffer 設備位于 /dev 下,通常設備名為fb*,這里*的取值從0到31。對于常見的計算機系統而言,32個Framebufer 設備已經綽綽有余了(至少作者還沒有看到過有32 個監視器的計算機) 。最常用到的Framebuffer 設備是 /dev/fb0 。通常,使用 Framebuffer 的程序通過環境變量 FRAMEBUFFER 來取得要使用的 Fram

5、ebuffer 設備,環境變量 FRAMEBUFFER 通常被設置為” /dev/fb0 ”。從程序員的角度來看, Framebuffer 設備其實就是一個文件而已,可以像對待普通文件那樣 讀寫Framebufer設備文件,可以通過 mmap()將其映射到內存中,也可以通過ioctl()讀取或者設置其參數,等等。最常見的用法是將 Framebufer設備通過mmap()映射到內存中,這樣 可以大大提高 IO 效率。要在PC平臺上啟用Framebufer,首先必須要內核支持,這通常需要重新編譯內核。另外,還需要修改內核啟動參數。 在作者的系統上,為了啟用Framebufer,需要將/boot/g

6、rub/menu.lst 中的下面這一行:kernel /boot/vmlinuz-2.4.20-8 ro root=LABEL=/1修改為kernel /boot/vmlinuz-2.4.20-8 ro root=LABEL=/1 vga=0x0314即增加了 vga=0x0314 這樣一個內核啟動參數。 這個內核啟動參數表示的意思是: Framebuffer 設備的大小是800x600,顏色深度是16bits/像素。下面, 來了解一下如何編程使用 Framebuffer 設備。由于對 Framebuffer 設備的讀寫應該是不 緩沖的,但是標準 IO 庫默認是要進行緩沖的,因此通常不使用標

7、準 IO 庫讀寫 Framebuffer 設備,而是直接通過 read()、write() 或者 mmap() 等系統調用來完成與 Framebuffer 有關的 IO 操作。 又由于 mmap() 能夠大大降低 IO 的開銷, 因此與 Framebuffer 設備有關的 IO 通常都是 通過mmap()系統調用來完成的。mmap()的函數原型如下(Linux系統上的定義):#include <sys/mman.h>#ifdef _POSIX_MAPPED_FILESvoid * mmap(void *start, size_t length, int prot , int fla

8、gs, int fd,off_t offset);int munmap(void *start, size_t length);#endif系統調用 mmap() 用來實現內存映射 IO 。所謂內存映射 IO ,是指將一個磁盤文件的內容與內 存中的一個空間相映射。 當從這個映射內存空間中取數據時, 就相當于從文件中讀取相應的 字節, 而當向此映射內存空間寫入數據時, 就相當于向磁盤文件中寫入數據。 這就是內存映 射 IO 的含義。具體到對mmap()而言,當調用成功時,返回值就是與磁盤文件建立了映射關系的內存空間 的起始地址,當調用失敗時,mmap()的返回值是-1。第一個參數start通常設

9、置為0,表示由系統選擇映射內存空間; 第二個參數 length 指定了要映射的字節數; 第三個參數指明了映射 內存空間的保護屬性,對于 Framebuffer 通常將其設置為 PROT_READ | PROT_WRITE ,表 示既可讀也可寫;第四個參數 flags 指明了影響映射內存空間行為的標志,對于 Framebuffer 編程而言,要將 flags 設置為 MAP_SHARED ,表明當向映射內存空間寫入數據時,將數據 寫入磁盤文件中;第五個參數 fd 是要映射的文件的文件描述符;第六個參數 offset 指明了 要映射的字節在文件中的偏移量。如果mmap()調用成功,就可以在程序中對

10、得到的映射內存空間進行讀寫操作了。所有的讀 寫都將由操作系統內核轉換成 IO 操作。在使用完映射內存空間之后, 應當將其釋放, 這是通過 munmap() 系統調用完成的。 munmap() 的第一個參數是映射內存空間的起始地址, 第二個參數 length 是映射內存空間的長度, 單位 為字節。如果釋放成功, munmap() 返回 0,否則返回 -1 。如果應用程序需要知道 Framebuffer 設備的相關參數,必須通過 ioctl() 系統調用來完成。在 頭文件 <linux/fb.h> 中定義了所有的 ioctl 命令字, 不過,最常用的 ioctl 命令字是下面這兩個:

11、FBIOGET_FSCREENINFO 和 FBIOGET_VSCREENINFO ,前者返回與 Framebuffer 有關的固 定的信息, 比如圖形硬件上實際的幀緩存空間的大小、 能否硬件加速等信息; 而后者返回的 是與 Framebuffer 有關的可變信息,之所以可變,是因為對同樣的圖形硬件,可以工作在不 同的模式下, 簡單來講, 一個支持 1024x768x24 圖形模式的硬件通常也能工作在 800x600x16 的圖形模式下,可變的信息就是指 Framebuffer 的長度、寬度以及顏色深度等信息。這兩個 命令字相關的結構體有兩個: struct fb_fix_screeninfo

12、 和 struct fb_var_screeninfo ,這兩個結構 體都比較大, 前者用于保存 Framebuffer 設備的固定信息, 后者用于保存 Framebuffer 設備的 可變信息。在調用 ioctl() 的時候,要用到這兩個結構體。應用程序中通常要用到 struct fb_var_screeninfo 的下面這幾個字段: xres、 yres、bits_per_pixel ,分別表示 x 軸的分辨率、 y 軸的分辨率以及每像素的顏色深度 (顏色深度的單位為 bit/pixel ),其類型定義都是無符號 32 位整型數。3、libjpeg 函數庫介紹JPEG是CCITT和ISO定

13、義的一種連續色調圖像壓縮標準2。JPEG是一種有損圖像壓縮標準,其基礎是 DCT 變換(離散余弦變換) 。 JPEG 圖像的壓縮過程分為三步: DCT 計算,量 化,變長編碼分配。盡管CCITT定義了 JPEG圖像壓縮標準,但是卻并沒有為JPEG定義標 準的文件格式。 這導致了現實世界中出現了各種各樣的 JPEG 文件格式, 而一種被稱為 JFIF 的 JPEG 文件格式逐漸成為 JPEG 文件格式的主流。libjpeg是一個被廣泛使用的JPEG壓縮/解壓縮函數庫(至少在Unix類系統下是廣泛使用的), 它能夠讀寫JFIF格式的JPEG圖像文件,通常這類文件是以.jpg或者.jpeg為后綴名的

14、。通 過libjpeg庫,應用程序可以每次從JPEG壓縮圖像中讀取一個或多個掃描線(scanline,所謂掃描線, 是指由一行像素點構成的一條圖像線條) ,而諸如顏色空間轉換、 降采樣 /增采樣、 顏色量化之類的工作則都由 libjpeg 去完成了。要使用libjpeg,需要讀者對數字圖像的基本知識有初步的了解。對于libjpeg而言,圖像數據是一個二維的像素矩陣。對于彩色圖像,每個像素通常用三個分量表示,即R(Red)、G(Green)、B( Blue)三個分量,每個分量用一個字節表示,因此每個分量的取值范圍從0到 255;對于灰度圖像,每個像素通常用一個分量表示,一個分量同樣由一個字節表示

15、,取 值范圍從 0 到 255。由于本文不會涉及到索引圖像,因此這里略去對索引圖像的說明。在 libjpeg 中,圖像數據是以掃描線的形式存放的。每一條掃描線由一行像素點構成,像素 點沿著掃描線從左到右依次排列。 對于彩色圖像, 每個分量由三個字節組成, 因此這三個字 節以 R、 G、 B 的順序構成掃描線上的一個像素點。一個典型的掃描線形式如下:R,G,B,R,G,B,R,G,B,通過 libjpeg 解壓出來的圖像數據也是以掃描線的形式存放的。在本文中,只涉及到 JPEG 的解壓縮,因此只對 libjpeg 的解壓過程進行說明,有關 libjpeg 的壓縮過程和其它高級用法,請參考3 。一

16、般地, libjpeg 的解壓過程如下:1、 分配并初始化一個 JPEG解壓對象(本文中將 JPEG解壓對象命名為cinfo ):struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);2、指定要解壓縮的圖像文件:FILE * infile;if (infile = fopen(filename, "rb") = NULL) fprintf(stderr, &q

17、uot;can't open %sn", filename);exit(1);jpeg_stdio_src(&cinfo, infile);3、調用jpeg_read_header()獲取圖像信息:jpeg_read_header(&cinfo, TRUE);4、 這是一個可選步驟,用于設置JPEG 解壓縮對象 cinfo 的一些參數,本文可忽略;5、調用 jpeg_start_decompress()開始解壓過程:jpeg_start_decompress(&cinfo);調用jpeg_start_decompress()函數之后,JPEG解壓縮對象

18、cinfo中的下面這幾個字段將會比 較有用:l output_width這是圖像輸出的寬度l output_height 這是圖像輸出的高度l output_components 每個像素的分量數,也即字節數這是因為在調用 jpeg_start_decompress() 之后往往需要為解壓后的掃描線上的所有像素點分 配存儲空間,這個空間的大小可以通過 output_width * output_componets 確定,而要讀取的 掃描線的總數為 output_height 行。6、讀取一行或者多行掃描線數據并處理,通常的代碼是這樣的:while (cinfo.output_scanline

19、< cinfo.ouput_height) jpeg_read_scanlines();/* deal with scanlines */對掃描線的讀取是按照從上到下的順序進行的,也就是說圖像最上方的掃描線最先被 jpeg_read_sca nli nes()讀入存儲空間中,緊接著是第二個掃描線,最后是圖像底邊的掃描線被讀入存儲空間中。7、調用 jpeg_finish_decompress() 完成解壓過程:jpeg_finish_decompress(&cinfo);&調用 jpeg_destroy_decompress()釋放 JPEG 解壓對象 cinfo :jpe

20、g_destroy_decompress(&cinfo);以上就是通過 libjpeg 函數解壓 JPEG 壓縮圖像的基本過程,由于本文不涉及 libjpeg 的高級 特性和用法,因此,上面的介紹對于說明本文中要用到的libjpeg 的功能已經足夠了。另外一個需要說明地方是:由于作者所用的 Framebuffer 設備的顏色深度為 16 位,顏色格式為5-6-5格式一一即 R (紅色)在16bit中占據高5位,G (綠色)在16bit中占據中間6位, B (藍色)在16bit中占據低5位;而libjpeg解壓出來的圖像數據為 24位RGB格式,因此 必須進行轉換。對于 24位的RGB,

21、每個字節表示一個顏色分量,因此轉換的方式為:對于 R 字節,右移 3 位,對于 G 字節,右移 2 位,對于 B 字節,右移 3 位,然后將右移得到的 值拼接起來,就得到了 16 位的顏色值。在后面的程序中,將把 24位的顏色稱為 RGB888, 而把16位顏色值稱為 RGB565,這種命名方式可能不太規范,不過無論如何,在本文中就 這樣稱呼了。 另外, 讀者可能會想到, 上面這種直接將顏色分量的低位丟棄的方式不是會導致圖像細節的丟失嗎?比如,對于 24 位顏色的 R 字節,假如原來低 3 位的值在 07 之間均 勻分布,轉換之后,所有這低 3 位的值全部都變成了 0,這就是顏色細節的丟失。為

22、了處理 這個問題, 可以采用誤差擴散算法或者抖動算法來完成顏色轉換。 為了保持程序的簡單, 本 文中仍然只采用上面提到的最簡單的轉換方式而且事實表明,這樣做得到的結果并不 差。4、程序實現 以下就是程序的完整實現,鑒于已經對 Framebuffer 和 libjpeg 的編程接口做了說明,以下不 再對代碼進行說明:/* $Id: fv.c* $Desp: draw jpeg to framebuffer* $Author: rockins* $Date: Wed Jan 3 20:15:49 CST 2007*/#include <stdio.h>#include <stdl

23、ib.h>#include <fcntl.h>#include <linux/fb.h> #include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <jpeglib.h>#include <jerror.h>#define FB_DEV "/dev/fb0"* function declaration *voidusage(char *msg);unsigned short RGB888toRGB5

24、65(unsigned char red,unsigned char green, unsignedchar blue);intfb_open(char *fb_device);intfb_close(int fd);intfb_stat(int fd, int *width, int *height, int *depth);void*fb_mmap(int fd, unsigned int screensize);intfb_munmap(void *start, size_t length);intfb_pixel(void *fbmem, int width, int height,i

25、nt x, int y, unsigned short color);/* function implementation*int main(int argc, char *argv)/* declaration for jpeg decompression*/struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;FILE *infile;unsigned char *buffer;/* declaration for framebuffer device */intfbdev;char*fb_device;unsigne

26、d char*fbmem;unsigned intscreensize;unsigned intfb_width;unsigned intfb_height;unsigned intfb_depth;unsigned intx;unsigned inty;/* check auguments*/if (argc != 2) usage("insuffient auguments");exit(-1);/* open framebuffer device*/if (fb_device = getenv("FRAMEBUFFER") = NULL) fb_d

27、evice = FB_DEV ;fbdev = fb_open(fb_device);/* get status of framebuffer device*/fb_stat(fbdev, &fb_width, &fb_height, &fb_depth);/* map framebuffer device to shared memory*/screensize = fb_width * fb_height * fb_depth / 8;fbmem = fb_mmap(fbdev , screensize);/* open input jpeg file*/if (i

28、nfile = fopen(argv1, "rb") = NULL) fprintf(stderr, "open %s failedn", argv1); exit(-1);/* init jpeg decompress object error handler*/cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);/* bind jpeg decompress object to infile*/jpeg_stdio_src(&cinfo, infil

29、e);/* read jpeg header*/jpeg_read_header(&cinfo, TRUE);/* decompress process.* note: after jpeg_start_decompress() is called* the dimension infomation will be known,* so allocate memory buffer for scanline immediately*/jpeg_start_decompress(&cinfo);if (cinfo.output_width > fb_width) |(cin

30、fo.output_height > fb_height) printf("too large JPEG file,cannot displayn"); return (-1);buffer = (unsigned char *) malloc(cinfo.output_width * cinfo.output_components);y = 0;while (cinfo.output_scanline < cinfo.output_height) jpeg_read_scanlines(&cinfo, &buffer, 1);if (fb_de

31、pth = 16) unsigned short color;for (x = 0; x < cinfo.output_width; x+) color = RGB888toRGB565(bufferx * 3,bufferx * 3 + 1, bufferx * 3 + 2); fb_pixel(fbmem, fb_width, fb_height, x, y, color); else if (fb_depth = 24) memcpy(unsigned char *) fbmem + y * fb_width * 3,buffer, cinfo.output_width * cin

32、fo.output_components);y+;/ next scanline/* finish decompress, destroy decompress object*/jpeg_finish_decompress(&cinfo);jpeg_destroy_decompress(&cinfo);/* release memory buffer*/free(buffer);/* close jpeg inputing file*/fclose(infile);/* unmap framebuffer's shared memory*/fb_munmap(fbmem

33、, screensize);/* close framebuffer device*/fb_close(fbdev);return (0);voidusage(char *msg)fprintf(stderr, "%sn", msg);printf("Usage: fv some-jpeg-file.jpgn");/* convert 24bit RGB888 to 16bit RGB565 color format*/unsigned shortRGB888toRGB565(unsigned char red, unsigned char green,

34、 unsigned char blue)unsigned shortB = (blue >> 3) & 0x001F;unsigned shortG = (green >> 2) << 5) & 0x07E0;unsigned shortR = (red >> 3) << 11) & 0xF800;return (unsigned short) (R | G | B);/* open framebuffer device.* return positive file descriptor if success,

35、* else return -1.*/intfb_open(char *fb_device)intfd;if (fd = open(fb_device, O_RDWR) < 0) perror(_func_);return (-1);return (fd);/* get framebuffer's width,height,and depth.* return 0 if success, else return -1.*/intfb_stat(int fd, int *width, int *height, int *depth)struct fb_fix_screeninfo

36、fb_finfo;struct fb_var_screeninfo fb_vinfo;if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo) perror(_func_);return (-1);if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo) perror(_func_);return (-1);*width = fb_vinfo.xres;*height = fb_vinfo.yres;*depth = fb_vinfo.bits_per_pixel;return (0);/* map shared memory to framebuffer device.* retur

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論