日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图片播放器小项目(详解)

發布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图片播放器小项目(详解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下內容源于朱有鵬《物聯網大講堂》課程的學習整理,如有侵權,請告知刪除。


一、開始動手寫代碼

1、Makefile介紹

(1)這是一個通用的項目管理的Makefile體系,自己寫的(有子文件夾組織的)項目可以直接套用這套Makefile體系。

(2)包含三類:頂層Makefile、Makefile.build(完全不需要改動)、子文件夾下面的Makefile。

  • 子文件夾下的Makefile一般是類似下面的內容。


(3)可以參考:http://www.cnblogs.com/lidabo/p/4521123.html。

2、使用SI建立工程


二、framebuffer基本操作代碼

顯示圖片,需要framebuffer。


三、圖片顯示原理和實踐

1、圖片顯示原理

(1)概念1:像素

(2)概念2:點陣(像素點構成的陣列)

(3)分辨率

  • 物理分辨率:物理屏幕像素點的真實個數;
  • 顯示分辨率:可以小于等于物理分辨率;(通過抽樣)

(4)清晰度(與分辨率和像素間距有關,主觀概念)

  • 像素間距相同時(物理尺寸固定了,則像素間距就固定了),分辨率越大越清晰;分辨率相同時,像素間距越小越清晰。

(5)bpp(RGB565、RGB888)

  • 像素深度,每個像素用多少bit數據表示。
  • 一般每個像素點使用32bit(4個字節),但一般是24位色(高八位一般沒用或者用著其他標識,用00或者ff填充以達到內存對齊);
  • RGB888表示紅用8位,綠8位,藍8位。

(6)顏色序(RGB、BGR)

2、圖片點陣數據獲取

(1)Image2LCD軟件提取

(2)通過圖片/視頻文件直接代碼方式提取


四、圖片數據提取和顯示

1、Image2LCD提取圖片數據

(1)軟件下載:http://www.cr173.com/soft/43222.html

(2)軟件使用

  • 一般不要圖像頭數據,只需要純數據;
  • 一般水平掃描;
  • 一般選24位真彩色(即RGB888);
  • 選1024*600后,點右邊按鈕更新;
  • 輸出圖像調整中,可以調整RGB。
  • 最后點擊保存。

2、圖片顯示編碼與實踐

void fb_draw_picture(void) {unsigned char* pdata=gImage_1024600;unsigned int i,j,cnt;unsigned int*p=pfb;for(i=0;i<HEIGHT;i++){for(j=0;j<WIDTH;j++){cnt=i*WIDTH+j;cnt*=3;*p=((pdata[cnt+0]<<0)|(pdata[cnt+1]<<8)|(pdata[cnt+2]<<16));//可以在這里修改,達到正確的顯示(當RB相反時)p++;}} }

五、圖片顯示的高級話題

1、RGB順序調整

(1)RGB順序有三個地方都有影響

  • 第一個是fb驅動中的排布;
  • 第二個是應用程序中的排布;
  • 第三個是圖像數據本身排布(Image2LCD中調整RGB順序);

(2)如果三個點中RGB順序是一致的就會顯示正常。如果三個設置不一致就可能會導致顯示結果中R和B相反了;

(3)實際寫程序時,一般不去分析這東西,而是根據實際顯示效果去調。如果反了就去調正應用程序中的RGB順序就行了,這樣最簡單。

2、顯示函數的其他寫法

void fb_draw_picture2(void) {unsigned char* pdata=gImage_1024600;unsigned int x,y,cnt;for(y=0;y<HEIGHT;y++){for(x=0;x<WIDTH;x++){cnt=y*WIDTH+x;*(pfb+cnt)=((pdata[cnt*3+0]<<16)|(pdata[cnt*3+1]<<8)|(pdata[cnt*3+2]<<0));//這里的像素矩陣和cnt有線性關系,所以可以這樣寫}} }

六、任意分辨率大小圖片顯示

(1)圖片比屏幕分辨率大

  • 這種情況下多出來的部分肯定是沒法顯示的。處理方法是直接在顯示函數中把多余不能被顯示的部分給丟掉。

(2)圖片大小比屏幕大小要小

  • 這種情況下圖片只是填充屏幕中一部分,剩余部分仍然保持原來的底色。
  • 在獲取圖片數據時,大小和圖片實際大小在這里是一致的。假如不一致呢?

void fb_draw_picture3(void) {unsigned char* pdata=gImage_500281;unsigned int x,y,cnt;unsigned int a=0;for(y=0;y<281;y++){for(x=0;x<500;x++){cnt=y*WIDTH+x;/*cnt始終都是framebuff像素點的編號*/*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));a+=3;/*由于空缺一部分,像素點編號與像素點矩陣不存在倍數關系了,此時應該三個三個地傳送進來*/}} }

七、任意起點位置圖片顯示

1、小圖片任意起點(但整個圖片顯示沒有超出屏幕范圍內)

算法1:

void fb_draw_picture4(unsigned int x0,unsigned int y0) {unsigned char* pdata=gImage_500281;unsigned int x,y,cnt;unsigned int cnt1,cnt2;for(y=y0;y<281+y0;y++){for(x=x0;x<500+x0;x++){cnt1=y*WIDTH+x;/*cnt始終都是fb 緩沖區整體中的像素點的編號*/cnt2=500*(y-y0)+(x-x0);*(pfb+cnt1)=((pdata[cnt2*3+0]<<16)|(pdata[cnt2*3+1]<<8)|(pdata[cnt2*3+2]<<0));/*左值考慮當前像素點在fb中的偏移量*//*右值考慮當前像素點在圖像數據數組的下標(這里是三個為一個元素的數組的下標,因此上面會*3)*/}} }

算法2:(因為每循環一次,+3)


2、起點導致圖片超出屏幕外

(1)現象

  • 左右超出去,會在相反方向補全:這是內部for循環可能超過1024的界定(但沒有超出fb的大小)造成的。
  • 上下超出去,則會消失:因為雙緩沖進到了另一幀。如果沒有雙緩沖,則會內存溢出。

(2)修改代碼,使得超出部分不再顯示。

法一:

void fb_draw_picture5(unsigned int x0,unsigned int y0) {unsigned char* pdata=gImage_500281;unsigned int x,y,cnt;unsigned int a=0;for(y=y0;y<281+y0;y++){if(y>=HEIGHT)//y方向超出{a+=3;break;//最后一行已經顯示了,剩下的不用考慮了}for(x=x0;x<500+x0;x++){if(x>=WIDTH)//x方向超出了{a+=3;continue;}cnt=y*WIDTH+x;/*cnt始終都是像素點的編號*/*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));a+=3;/*因此,像素點矩陣也應該三個三個地傳送進來*/}} } 法二:

void fb_draw_picture4(unsigned int x0,unsigned int y0) {unsigned char* pdata=gImage_500281;unsigned int x,y,cnt;unsigned int cnt1,cnt2;for(y=y0;y<281+y0;y++){for(x=x0;x<500+x0;x++){if(x>=WIDTH)//x方向超出了{///a+=3;注意這里被詮釋了continue;}cnt1=y*WIDTH+x;/*cnt始終都是fb 緩沖區整體中的像素點的編號*/cnt2=500*(y-y0)+(x-x0);*(pfb+cnt1)=((pdata[cnt2*3+0]<<16)|(pdata[cnt2*3+1]<<8)|(pdata[cnt2*3+2]<<0));/*左值考慮當前像素點在fb中的偏移量*//*右值考慮當前像素點在圖像數據數組的下標*/}} }

八、BMP圖片的顯示

1、圖片文件的本質

(1)圖片文件是二進制文件。

  • 文件分兩種,即二進制文件、文本文件;


(2)不同格式的圖片文件的差別。

  • 圖片被壓縮與否的區別。

(3)BMP圖片的基本特征

  • 未被壓縮的元素位圖格式(bit map)。

2、BMP圖片詳解

(1)如何識別BMP文件?

  • 每種圖片格式都有定義好的一種識別方法,BMP圖片特征是以0x424D開頭


(2)BMP文件組成

  • 頭信息+有效信息

3、BMP文件頭信息、圖片有效數據區

見博客:https://www.2cto.com/kf/201310/252434.html

(1)文件大小

(2)有效數據開始的位置


(3)信息頭的大小:40個字節

(4)分辨率


(5)24位真彩色


(6)……

4、寫代碼解析BMP圖片

第一步:打開BMP圖片

第二步:判斷圖片格式是否真是BMP

第三步:解析頭信息,得到該BMP圖片的詳細信息

第四步:根據第三步得到的信息,去合適位置提取真正的有效圖片信息

第五步:將得到的有效數據丟到fb中去顯示

這樣實際比較繁瑣!使用結構體比較好!

//path是bmp圖片的pathname //該函數解析path圖片,并將圖片數據丟到bmp_buf中 //返回值錯誤時返回-1,正確返回0 int bmp_analyze(unsigned char *path) {int fd=-1;unsigned char buf[54]={0};ssize_t ret=0;//打開bmp文件fd=open(path,O_RDONLY);if(fd<0){fprintf(stderr,"open %s error.\n",path);return -1;}//讀取文件頭信息ret=read(fd,buf,54);if(ret!=54){fprintf(stderr,"read file header error.\n");return -1;}//解析頭//判斷是否BMP圖片if(buf[0]!='B'||buf[1]!='M'){fprintf(stderr,"file %s is not a bmp picture.\n",path);return -1;}printf("file %s is a bmp picture.\n",path);printf("width is %d\n",*((unsigned int*)(buf+0x12)));printf("hith is %d\n",*((unsigned int*)(buf+0x16)));//成功則說明小端模式close(fd);return 0;}

5、用結構體方式解析BMP文件頭

6、用結構體方式解析BMP信息頭

#ifndef __BMP_H__ #define __BMP_H__typedef struct {unsigned char bfType[2];//文件類?unsigned long bfSize; //位圖大小 unsigned short bfReserved1; //位0 unsigned short bfReserved2; //位0 unsigned long bfOffBits;//到數據偏移量 }__attribute__((packed))BitMapFileHeader;//使編譯器不優化,其大小為14字節 //信息頭結構體 typedef struct { unsigned long biSize;// BitMapFileHeader 字節數long biWidth;//位圖寬度 long biHeight;//位圖高度,正位正向,反之為倒圖 unsigned short biPlanes;//為目標設備說明位面數,其值將總是被設為1unsigned short biBitCount;//說明比特數/象素,為1、4、8、16、24、或32。 unsigned long biCompression;//圖象數據壓縮的類型沒有壓縮的類型:BI_RGB unsigned long biSizeImage;//說明圖象的大小,以字節為單位 long biXPelsPerMeter;//說明水平分辨率 long biYPelsPerMeter;//說明垂直分辨率 unsigned long biClrUsed;//說明位圖實際使用的彩色表中的顏色索引數unsigned long biClrImportant;//對圖象顯示有重要影響的索引數,0都重要。 } __attribute__((packed)) BitMapInfoHeader; #endif void fb_draw(const unsigned char* ppic) {unsigned char* pdata=ppic;unsigned int x,y;unsigned int a=0;unsigned int cnt=0;a=281*500*3-3;for(y=0;y<281;y++){for(x=0;x<500;x++){cnt=y*WIDTH+x;*(pfb+cnt)=((pdata[a+0]<<16)|(pdata[a+1]<<8)|(pdata[a+2]<<0));a-=3;}//a表示每個像素的三個字節數據的首字節編號} }

//path是bmp圖片的pathname //該函數解析path圖片,并將圖片數據丟到bmp_buf中 //返回值錯誤時返回-1,正確返回0 int bmp_analyze(unsigned char *path) {int fd=-1;BitMapFileHeader fheader ;BitMapInfoHeader info;ssize_t ret=0;int i;unsigned long len;//打開bmp文件fd=open(path,O_RDONLY);if(fd<0){fprintf(stderr,"open %s error.\n",path);return -1;}ret= read(fd,&fheader,sizeof(fheader));printf("bfsize =%d.\n",fheader.bfSize);//位圖大小printf("boffsize =%d.\n",fheader.bfOffBits);//有效信息偏移量#if 0for( i=0;i<sizeof(fheader);i++){printf("%x ",*((unsigned char *)&fheader+i));}printf("\n"); #endifret= read(fd,&info,sizeof(info));/*會沿著繼續讀下去*/printf("picture resolution : %d * %d.\n",info.biHeight,info.biWidth);printf("picture bpp : %d \n",info.biBitCount);//讀取圖片有效信息//先把文件指針移動到有效信息的偏移量處(lseek函數)//然后讀出info.biHeight*info.biWidth*info.biBitCount/8個字節lseek(fd,fheader.bfOffBits,SEEK_SET);//從文件開始的位置開始len=info.biHeight*info.biWidth*info.biBitCount /8;printf("len put to buff :%ld.\n",len);read(fd,bmp_buf,len);//把內容丟到fb中去顯示fb_draw(bmp_buf);/*數據和使用image2lcd獲取的不一樣*這里會旋轉180度顛倒*即第一個像素放到最后一個像素點像素,依次類推了*/close(fd);return 0; }

注意:

  • 使用結構體來解析圖片數據時,和使用image2lcd不一樣。
  • 這里會旋轉180度顛倒,即第一個像素放到最后一個像素點像素,依次類推了。
  • 因此在fb_draw()函數中,需要將最后一個像素點數據放在第一個像素處顯示,以此類推。

---------------以上代碼寫得不規整,要進行規整--------------------

九、及時規整

1、再次強調規范問題

(1)函數、變量起名字要合法合理;

  • 小寫函數;

(2)要寫注釋;

  • 第一步,第二步……可以先寫注釋再寫代碼;

(3)函數長短要合適;

(4)多文件組織,每個東西丟到合理的位置

2、為什么要規整項目?

(1)完全自由寫項目時不可能一步到位,只能先重內容和功能,后補條理和規范;

(2)規整的過程也是一個梳理邏輯和分析架構的過程。

3、對本項目進行規整

(1)去掉測試顯示時頭文件形式提供的圖片顯示相關的東西

  • 即去除fb_draw_picture_n()測試函數,因為我們的最終目的是解析bmp格式圖片(已經實現了,因此要刪除之前的測試函數)

4、一些重構代碼的技巧

(1)用#if 0 ? #endif來屏幕不需要的代碼,不要用/* ?*/;

(2)暫時不要的代碼先不要刪除,而是屏幕掉


5、添加DEBUG宏以控制調試信息輸出

debug宏添加好后,要使能輸出可以有2種方式:

  • 第一種:在debug宏定義之前定義DEBUG宏。見http://blog.csdn.net/oqqhutu12345678/article/details/78873195
  • 第二種:在編譯參數中添加-DDEBUG編譯選項。(在makefile中添加)

6、圖片信息用結構體來封裝傳遞

//封裝圖片各種信息 typedef struct pic_info {char* pathname;//路徑和文件名字unsigned int width;unsigned int height;unsigned int bpp;unsigned char *pData;//指向圖片有效數據存儲的buff}pic_info;

從而需要修改相關代碼。


十、jpg圖片的顯示原理分析

1、認識jpg圖片

(1)屬于二進制文件。

(2)有其固定的識別特征:http://www.cnblogs.com/Wendy_Yu/archive/2011/12/27/2303118.html

(3)是經過壓縮的圖片格式。

2、jpg圖片如何顯示

(1)jpg圖片中的二進制數并不對應像素數據。

(2)LCD顯示器的接口仍然是framebuffer。

(3)要顯示jpg圖片必須先解碼jpg得到相應的位圖數據

3、如何解碼jpg圖片

(1)圖片編碼和解碼對應著壓縮和解壓縮過程

(2)編碼和解碼其實就是一些數學運算(壓縮度、算法復雜度、時間、清晰度)

(3)軟件編解碼和硬件編解碼

  • 需要頻繁進行編解碼的話,一般使用硬件編解碼。

(4)不同的圖片格式其實就是編解碼的算法不同,結果是圖片特征不同

(5)編程實戰:使用開源編解碼庫


十一、libjpeg介紹及開源庫的使用方法

1、libjpeg介紹

(1)基于linux的開源軟件;

(2)C語言編寫(gcc、使用Makefile管理);

(3)提供JPEG圖片的編解碼算法實現;

2、libjpeg版本及下載資源

(1)經典版本v6b:https://sourceforge.net/projects/libjpeg/files/libjpeg/6b/

(2)最新版本v9b:http://www.ijg.org/

3、開源庫的使用方法

(1)移植(源碼下載、解壓、配置、修改Makefile、編譯或交叉編譯)

  • 移植的目的是由源碼得到三個東西:動態庫.so,靜態庫.a,頭文件.h。

(2)部署(部署動態庫so、部署靜態庫.a和頭文件.h)

  • 動態庫是程序在運行時才需要的,編譯程序時不需要。
  • 靜態庫是靜態連接時才需要,動態鏈接時不需要。
  • 頭文件.h是在編譯程序時使用的,運行時不需要的。
  • 靜態庫和頭文件,是在編譯鏈接過程中需要的,因此要把靜態庫.a文件和頭文件.h文件放到ubuntu的文件系統中。
  • 動態庫是在運行時需要的,所以動態庫so文件要放到開發板的文件系統中(放的過程就叫部署),。

(3)注意三個編譯鏈接選項:-I ?-l(小L) ?-L

舉例如-I:


  • -I是編譯選項(準確的是說是makefile預處理選項CFLAGS或者CPPFLAGS中指定),用來指定預處理時查找頭文件的范圍的
  • -l(小寫L)是鏈接選項(LDFLAGS中指定),用來指定鏈接額外的庫的名字(譬如我們用到了數學函數,就用-lm,鏈接器就會去鏈接libm.so;那么我們使用了libjpeg,對應的庫名字就叫libjpeg.so,就需要用-ljpeg選項去鏈接)。
  • -L是鏈接選項(LDFLAGS中指定),用來指定鏈接器到哪個路徑下面去找動態鏈接庫
  • 總結:-l(小寫L)是告訴鏈接器要鏈接的動態庫的名字,而-L是告訴鏈接器要鏈接的動態庫的路徑。

十二、libjpeg的移植實戰

1、移植

(1)源碼下載、解壓至/tmp/decodeporting目錄下。

(2)編譯前的配置(分析configure文件的usage、借鑒前輩的設置,得到應該執行下面命令)

  • ./configure --prefix=/opt/libcode --exec-prefix=/opt/libcode --enable-shared --enable-static-build=i386 -host=arm
  • ? ? ? ? ? ? ? ? ? 指定編譯結果放置的目錄(如果沒有則需要先建立相應的目錄)
  • 配置生成了makefile文件,通過查看知道需要在/opt/libcode中創建include、bin、lib目錄。

(3)Makefile檢查,主要查看交叉編譯設置是否正確

  • CC=gcc 改為 CC=arm-linux-gcc //編譯器,如果不改,只能在ubuntu使用,不能在開發板使用。
  • AR=ar rc 改為 AR=arm-linux-ar rc
  • AR2=ranlib 改為 AR2=arm-linux-ranlib

(4)編譯:執行make命令。

(5)安裝

  • 執行make install-lib;
  • 安裝就是將編譯生成的庫文件、頭文件、可執行文件分別裝載到--prefix ?--exec-prefix所指定的那些目錄中去。

2、部署

前面只是完成移植,相關文件都在ubuntu上。我們要把動態鏈接庫(.so文件)放到開發板的根文件系統中(/root/rootfs/),可以考慮三者之一:

  • 第一個:/lib
  • 第二個:/usr/lib(前兩個在程序運行時,可以自動找到。后面任意目錄時,需要在程序中指定)
  • 第三個:任意指定目錄


十三、使用libjpeg解碼顯示jpg圖片

1、如何使用一個新的庫

(1)思路一:網絡上找別人使用過后寫的文檔、博客等作為參考。

(2)思路二:看庫源碼自帶的文檔(說明文檔和示例代碼)。我們從思路二出發。

2、libjpeg說明文檔和示例代碼

(1)說明文檔:README和libjpeg.doc

(2)示例代碼:example.c

3、結合說明文檔來實踐


4、解讀example.c和移植


5、代碼問題

(1)測試代碼,先試圖讀取jpg圖片頭信息。

(2)問題排除
  • 編譯時問題:主要就是頭文件包含,除了在代碼中包含頭文件外,還要注意指明頭文件的路徑
  • 因為盡管包含了頭文件,但只會在當前的目錄和path指定的路徑中尋找。我們應該在總Makefile中指定。




  • 注意-I、-l、-L三個編譯鏈接選項的使用

6、部署動態庫以使程序運行起來


(1)一般放到開發板根文件系統/lib或者/usr/lib下

  • 這樣不需要給系統指定庫路徑,就能自動找到。
  • 強調一下是開發板根文件系統下的路徑,千萬不要弄成了ubuntu的根文件系統下的目錄。

(2)放到自定義的第三方的目錄

  • 將該自定義第三方目錄導出到環境變量LD_LIBRARY_PATH下即可。

  • 可以使用echo $LD_LIBRARY_PATH查看當前的路徑環境變量包含哪些路徑。
  • 可以把上述操作寫進到run.sh文件中,省得每次都要這樣操作。

7、測試讀取頭信息


十四、解決解碼顯示中的問題

1、問題分析及解決記錄

(1)根據LCD錯誤的顯示狀態,分析有可能是顯示函數fb_draw中的圖片寬高數據有誤,于是在fb_draw函數中添加debug打印出寬和高來。結果發現是對的。

(2)顯示函數中的圖片寬高和fb寬高都是對的,結果顯示時還是只有一溜(其余位置黑屏),可能的一個原因就是:顯示數據本身不對,很多都是0。

  • 如何驗證?只要把顯示數據打印出來看一看就知道了。
  • 結果發現打印出的待顯示數據果然是很多0,說明給顯示函數的待顯示數據就是錯的。


(3)這些待顯示數據為什么會錯?

  • 第一種可能性就是libjpeg解碼出來的數據就是錯的;
  • 第二種可能性是解碼一行出來暫存到buffer的時候,或者memcpy從暫存的buffer拿出來給pData指向的空間的時候給搞錯了。
  • 相對來說第二種很好驗證而第一種不好驗證。只需要在jpeg_read_scanlines函數后面直接打印顯示解碼出來的一行數據,就可以知道是不是第二種情況。
  • 結果打印出來好多0,說明是第一種情況。

(4)截至目前已經鎖定問題,就是jpeg_read_scanlines解碼出來的數據本身就不對。

(5)可能的問題

  • 有可能是libjpeg本身就有問題;
  • 有可能我們對libjpeg的部署不對導致他工作不對;
  • 有可能我們寫的代碼不對,也就是說我們沒用正確的方法來使用libjpeg。

(6)沒有思路怎么辦

  • 去網上找一些別人寫的libjpeg解碼顯示圖片的示例代碼,多看幾個,對著和我們的關鍵部位對比,尋找思路。
  • 如果在網上找不到相關資料,這時候就只有硬著頭皮去看源碼了。譬如去libjpeg的源碼中查看:jpeg_read_scanlines、cinfo.mem->alloc_sarray等。

(7)解決了buffer申請導致的問題之后,我們再來解決2個遺留的問題

  • 一個就是RGB順序問題,另一個是圖像轉了180度的問題。

(8)添加了fb_draw2函數并且調用后,2個遺留問題徹底解決。至此,jpg圖片顯示完美實現。

2、結束jpg圖片部分

(1)加上jpg圖片格式識別:判斷開頭和結尾的特征字節。

(2)對外封裝好用的jpg圖片顯示函數

(3)對外封裝好用的bmp圖片顯示函數




十五、解碼顯示png圖片

1、思路分析

(1)png更像是jpg而不像是bmp;

(2)png和jpg都是壓縮格式的圖片,都是二進制文件,不同之處是壓縮和解壓縮的算法不同。

(3)通過libjpeg來編解碼jpg圖片,那么同樣有一個libpng用來編解碼png圖片。

(4)工作思路和順序

  • 找到并移植并部署libpng,然后查readme和其他文檔示例代碼等來使用libpng提供的API來對png圖片進行解碼,并將解碼出來的數據丟到framebuffer中去顯示。

2、libpng移植

(1)下載源碼包:

(2)解壓、配置、修改Makefile、編譯、部署。注意實際路徑。

  • ./configure --host=arm-linux --enable-shared --enable-static --prefix=/opt/libdecode

(3)配置出錯,報錯信息:configure: error: zlib not installed

  • 分析問題是因為libpng依賴于zlib庫,所以要先移植zlib庫才可以。

(4)移植了zlib后再過來配置,還是報錯,原因是因為沒有導出相關環境變量,所以libpng在配置的時候找不到剛才移植的zlib庫的庫文件和頭文件。

(5)解決方案就是使用epport臨時性的導出,在scrt中輸入:

# export LDFLAGS="-L/opt/libdecode/lib" # export CFLAGS="-I/opt/libdecode/include" # export CPPFLAGS="-I/opt/libdecode/include"

(6)導出后再次配置就過了,然后編譯和安裝

(7)make && make install

3、zlib移植

(1)下載:http://www.zlib.net/,并解壓

(2)配置:export CC=arm-linux-gcc ? ? ?

./configure -shared --prefix=/opt/libdecode

(3)make && make install

(4)make install后/opt/libdecode目錄下的lib和include目錄下就有了zlib的靜態庫動態庫和頭文件了,然后再回去繼續libpng的移植。


4、參考源碼包自帶的資料開始編程

(1)readme

(2)libpng-manual.txt

(3)example.c 和 pngtest.c


十六、圖片文件的管理和檢索

1、圖片文件的管理

(1)在物理磁盤存儲層次上,用一個文件夾來管理;

(2)在程序中,用數據結構來管理。

  • 用數組管理
  • 用鏈表管理

(4)編程實戰(細節見代碼,下面是關鍵點)

a、新建一個文件夾,記得要在makefile中添加新建的文件夾路徑,以及在新建文件夾中新建makefile來管理文件。

b、文件夾的打開操作、讀取操作


2、圖片信息的自動檢索

(1)讀取文件類型

(2)普通文件和文件夾分類處理

(3)普通文件區分,將其中的圖片按格式存儲到圖片管理數組/鏈表中

typedef enum image_type {IMAGE_TYPE_BMP,IMAGE_TYPE_JPG,IMAGE_TYPE_UNKNOWN, }image_type_e;typedef struct image_info {char pathname[PATHNAME_LEN];image_type_e type; }image_info_t;

int scan_image2(const char *path) {// 在本函數中遞歸檢索path文件夾,將其中所有圖片填充到iamges數組中去DIR *dir;struct dirent *ptr;char base[1000];struct stat sta;if ((dir = opendir(path)) == NULL){perror("Open dir error...");exit(1);}// readdir函數每調用一次就會返回opendir打開的basepath目錄下的一個文件,直到// basepath目錄下所有文件都被讀完之后,就會返回NULLwhile ((ptr = readdir(dir)) != NULL){if(strcmp(ptr->d_name, ".")==0 || strcmp(ptr->d_name, "..")==0) ///current dir OR parrent dircontinue;// 用lstat來讀取文件屬性并判斷文件類型memset(base,'\0',sizeof(base));//strcpy(base,path);strcat(base,"/");strcat(base,ptr->d_name);lstat(base, &sta);if (S_ISREG(sta.st_mode)){//printf("regular file.\n");//printf("d_name:%s/%s\n", path, ptr->d_name);// 如果是普通文件,就要在這里進行處理:// 處理思路就是 先判定是否屬于已知的某種圖片格式,如果是則放到images數組中// 如果都不屬于則不理他if (!is_bmp(base)){strcpy(images[image_index].pathname, base);images[image_index].type = IMAGE_TYPE_BMP;}if (!is_jpg(base)){strcpy(images[image_index].pathname, base);images[image_index].type = IMAGE_TYPE_JPG;}image_index++;}if (S_ISDIR(sta.st_mode)){//printf("directory.\n");//printf("d_name:%s/%s\n", path, ptr->d_name);scan_image2(base);}} } void show_images(void) {int i;for (i=0; i<image_index; i++){switch (images[i].type){case IMAGE_TYPE_BMP:display_bmp(images[i].pathname); break;case IMAGE_TYPE_JPG:display_jpg(images[i].pathname); break;default:break;}sleep(2);} }

十七、添加觸摸翻頁功能

1、讀取觸摸坐標數據

  • 開發板上的觸摸屏是/dev/input/event2(我這里是event2)

2、使用觸摸坐標判斷并執行翻頁操作

(1)執行./run.sh后會阻塞,如果點擊觸摸屏,會在scrt中顯示測試的內容。

  • code 0表示x坐標,value為x的值;code 1表示y坐標,value為y的值。

(2)在不同區域點一下,有不同的效果。



十八、總結與回顧

1、bug解決

2、項目總結

(1)項目描述:軟硬件平臺等

(2)重點和難點

3、項目展望與擴展功能

(1)劃屏翻頁

(2)圖片放大與縮小顯示

(3)動畫

(4)開機畫面

(5)背景音樂


總結

以上是生活随笔為你收集整理的图片播放器小项目(详解)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。