
圖片是指由圖形、圖像等構成的平面媒體。圖片的格式很多,但總體上可以分為點陣圖和矢量圖兩大類,我們常用BMP、JPG等格式都是點陣圖形,而SWF、CDR、AI等格式的圖形屬于矢量圖形。
有形式的事物,我們看到的,是圖畫、照片、拓片等的統稱。圖是技術制圖中的基礎術語,指用點、線、符號、文字和數字等描繪事物幾何特征、形態、位置及大小的一種形式。隨著數字采集技術和信號處理理論的發展,越來越多的圖片以數字形式存儲。
(相關資料圖)
在嵌入式開發中,常用的圖片格式有BMP、JPG/JPEG、PNG等。
BMP圖片位圖(外語簡稱:BMP、外語全稱:Bitmap),它是Windows操作系統中的標準圖像文件格式,能夠被多種Windows應用程序所支持。隨著Windows操作系統的流行與豐富的Windows應用程序的發,BMP位圖格式理所當然地被廣泛應用。這種格式的特點是包含的圖像信息較豐富,幾乎不進行壓縮,但由此導致了它與生俱來的缺點——占用磁盤空間過大,所以,BMP在單機上比較流行。
BMP圖片格式簡單,在不壓縮處理下可以最好的保存圖片原始顏色格式。
JPG圖片JPEG也是最常見的一種圖像格式,它是由聯合照片專家組(外語全稱:JointPhotographicExpertsGroup)開發并以命名為“ISO 10918-1”,JPEG僅僅是一種俗稱而已。JPEG文件的擴展名為.jpg或.jpeg,因其壓縮技術十分先進,它用有損壓縮方式去除冗余的圖像和彩色數據,獲取得極高的壓縮率的同時能展現十分豐富生動的圖像,換句話說,就是可以用最少的磁盤空間得到較好的圖像質量。
同時JPEG還是一種很靈活的格式,具有調節圖像質量的功能,允許你用不同的壓縮比例對這種文件壓縮,比如我們最高可以把1.38MB的BMP位圖文件壓縮至20.3KB。當然我們完全可以在圖像質量和文件尺寸之間找到平衡點。
由于JPEG優異的品質和杰出的表現,特別是在網絡和光盤讀物上,肯定都能找到它的影子。各類瀏覽器均支持JPEG這種圖像格式,因為JPEG格式的文件尺寸較小,下載速度快,使得Web頁有可能以較短的下載時間提供大量美觀的圖像,JPEG同時也就順理成章地成為網絡上最受歡迎的圖像格式。
PNG格式
便攜式網絡圖形(外語簡稱PNG、外語全稱:PortableNetworkGraphics)是一種新興的網絡圖像格式。在1994年底,由于Unysis公司宣布GIF擁有專利的壓縮方法,要求開發GIF軟件的作者須繳交一定費用,由此促使免費的png圖像格式的誕生。PNG一開始便結合GIF及JPG兩家之長,打算一舉取代這兩種格式。1996年10月1日由PNG向國際網絡聯盟提出并得到推薦認可標準,并且大部分繪圖軟件和瀏覽器開始支持PNG圖像瀏覽,從此PNG圖像格式生機煥發。
PNG是保證最不失真的格式,它汲取了GIF和JPG二者的優點,存貯形式豐富,兼有GIF和JPG的色彩模式;它的另一個特點能把圖像文件壓縮到極限以利于網絡傳輸,但又能保留所有與圖像品質有關的信息,因為PNG是采用無損壓縮方式來減少文件的大小,這一點與犧牲圖像品質以換取高壓縮率的JPG有所不同;它的第三個特點是顯示速度很快,只需下載1/64的圖像信息就可以顯示出低分辨率的預覽圖像;第四,PNG同樣支持透明圖像的制作,透明圖像在制作網頁圖像的時候很有用,我們可以把圖像背景設為透明,用網頁本身的顏色信息來代替設為透明的色彩,這樣可讓圖像和網頁背景很和諧地融合在一起。
PNG的缺點是不支持動畫應用效果,如果在這方面能有所加強,簡直就可以完全替代GIF和JPEG了。
BMP圖片格式簡單,可以不需要借助任何第三方庫即可完成圖片的各種操作處理,接下來將以C語言實現BMP圖片的旋轉。
/***********************順時針旋轉90°******************************形參:const char *new_bmp -- 順時針90°后圖片** const char *befor_bmp --原始圖片**返回值:0 -- 成功,其他值 -- 失敗**************************************************************/int BMP_ClockWise_Revolve90(const char *new_bmp,const char *befor_bmp){ FILE *fp[2]; fp[0]=fopen(befor_bmp,"rb"); if(fp[0]==NULL) { printf("[%s line %d]文件打開失敗",__FUNCTION__,__LINE__); return 1; } fp[1]=fopen(new_bmp,"w+b"); if(fp[1]==NULL) { printf("[%s line %d]文件打開或創建失敗",__FUNCTION__,__LINE__); return 2; } BMP_HEADER bmp_head; BMP_INFO bmp_info; fread(&bmp_head,sizeof(BMP_HEADER),1,fp[0]);//讀取頭數據 if(bmp_head.bfType!=0x4d42) { printf("[%s line %d]圖片格式錯誤\n",__FUNCTION__,__LINE__); fclose(fp[0]); fclose(fp[1]); return 3; } fwrite(&bmp_head,sizeof(BMP_HEADER),1,fp[1]);//頭數據寫入到新的文件中 int w,h;//旋轉90°寬和高需要互換 fread(&bmp_info,sizeof(BMP_INFO),1,fp[0]);//讀取位圖數據 h=bmp_info.biHeight; w=bmp_info.biWidth; bmp_info.biWidth=h;//旋轉后圖片寬度 bmp_info.biHeight=w;//旋轉后圖片高度 fwrite(&bmp_info,sizeof(BMP_INFO),1,fp[1]);//寫入位圖數據 printf("\n--------------------順時針旋轉90°----------------------\n"); printf("\t旋轉后圖片寬:%d\n",bmp_info.biWidth); printf("\t旋轉后圖片高:%d\n",bmp_info.biHeight); int befor_oneline_size=w*3;//之前圖片一行的字節數 while(befor_oneline_size%4)befor_oneline_size++;//按4字節對齊 int new_oneline_size=bmp_info.biWidth*3;//旋轉后圖片一行字節數 while(new_oneline_size%4)new_oneline_size++;//按4字節對齊 int i,j; int offset_count=0; int rgb=0; for(i=w-1;i>=0;i--) { for(j=0;j逆時針旋轉90°示例bmp_info.biWidth*3) { fwrite(&rgb,new_oneline_size-bmp_info.biWidth*3,1,fp[1]);//補全為4的倍數 } } fclose(fp[0]); fclose(fp[1]); return 0;}
/***********************逆時針旋轉90°******************************形參:const char *new_bmp -- 逆時針90°后圖片** const char *befor_bmp --原始圖片**返回值:0 -- 成功,其他值 -- 失敗**************************************************************/int BMP_antiClockWise_Revolve90(const char *new_bmp,const char *befor_bmp){ FILE *fp[2]; fp[0]=fopen(befor_bmp,"rb"); if(fp[0]==NULL) { printf("[%s line %d]文件打開失敗",__FUNCTION__,__LINE__); return 1; } fp[1]=fopen(new_bmp,"w+b"); if(fp[1]==NULL) { printf("[%s line %d]文件打開或創建失敗",__FUNCTION__,__LINE__); return 2; } BMP_HEADER bmp_head; BMP_INFO bmp_info; fread(&bmp_head,sizeof(BMP_HEADER),1,fp[0]);//讀取頭數據 if(bmp_head.bfType!=0x4d42) { printf("[%s line %d]圖片格式錯誤\n",__FUNCTION__,__LINE__); fclose(fp[0]); fclose(fp[1]); return 3; } fwrite(&bmp_head,sizeof(BMP_HEADER),1,fp[1]);//頭數據寫入到新的文件中 int w,h;//旋轉90°寬和高需要互換 fread(&bmp_info,sizeof(BMP_INFO),1,fp[0]);//讀取位圖數據 h=bmp_info.biHeight; w=bmp_info.biWidth; bmp_info.biWidth=h;//旋轉后圖片寬度 bmp_info.biHeight=w;//旋轉后圖片高度 fwrite(&bmp_info,sizeof(BMP_INFO),1,fp[1]);//寫入位圖數據 printf("\n--------------------逆時針旋轉90°----------------------\n"); printf("\t旋轉后圖片寬:%d\n",bmp_info.biWidth); printf("\t旋轉后圖片高:%d\n",bmp_info.biHeight); int befor_oneline_size=w*3;//之前圖片一行的字節數 while(befor_oneline_size%4)befor_oneline_size++;//按4字節對齊 int new_oneline_size=bmp_info.biWidth*3;//旋轉后圖片一行字節數 while(new_oneline_size%4)new_oneline_size++;//按4字節對齊 int i,j; int offset_count=0; int rgb=0; int cnt=0; unsigned char buff[new_oneline_size];//存放新圖片一行字節數 for(i=0;i=0;j--) { //先讀取最后一行的第一個像素點 offset_count=bmp_head.bfOffBits+i*3+j*befor_oneline_size; fseek(fp[0],offset_count,SEEK_SET); fread(&rgb,3,1,fp[0]);//讀取一個像素點數據 buff[cnt++]=(rgb)&0xff; buff[cnt++]=(rgb>>8)&0xff; buff[cnt++]=(rgb>>16)&0xff; } fwrite(buff,cnt,1,fp[1]);//將一行顏色數據寫入到新文件中 if(cnt!=new_oneline_size)//補全為4的整數倍 { rgb=0; fwrite(&rgb,new_oneline_size-cnt,1,fp[1]); } } fclose(fp[0]); fclose(fp[1]); return 0;}
水印添加實現原理:先獲取圖片大小,然后通過內存映射方式(mmap函數)將文件映射到內存中,接下來對內存的操作即為對文件的操作,內存地址偏移到BMP圖的RGB顏色位置。將要顯示的漢字加載到RGB顏色中即可。其中實現水印添加的核心函數為畫點函數,實現如下:
/*畫點函數形參:x,y --要繪制的位置 color --顏色值*/void Image_DrawPoint(int x,int y,int color){ unsigned char *p=(height-y-1)*width*3+x*3+image;//光標位置 /*寫入rgb顏色*/ *p=color&0xff; *(p+1)=(color>>8)&0xff; *(p+2)=(color>>16)&0xff;}
實現畫點函數之后,即可調用漢字字庫(點陣字庫或者矢量字庫均可),這里以點陣字庫為例,按照點陣字庫的算法將要顯示的漢字點陣碼取出,再調用畫點函數完成漢字繪制,實現如下:
/*顯示漢字*/void Image_DisplayFont(int x,int y,int size,int color,const unsigned char *font){ u8 *p=NULL; u8 H,L; u32 addr=0;//漢字偏移地址 u16 font_size=size*size/8;//漢字點陣大小(寬度保證為8的倍數) H=*font;//漢字高字節 L=*(font+1);//漢字的低字節 if(L<0x7F)L-=0x40; else L-=0x41; H-=0x81; addr=(190*H+L)*font_size;//漢字所在點陣中的偏移地址 p=malloc(font_size); if(p==NULL) { printf("申請空間失敗\r\n"); return ; } if(size == 32)//GBK_32 { fseek(font_fp, addr, SEEK_SET);//從文件頭開始偏移 fread(p,font_size,1,font_fp); } else { free(p);//釋放空間 return ; } int i=0,j=0; int x0=x; unsigned char temp; for(i=0;i有了上述函數,即可實現任意字符串的水印添加(要添加ascii碼則需要進一步添加ascii的點陣碼信息即可)。
2.3 BMP圖片的結構體定義格式
BMP圖片相比于其它格式圖片要簡單得多,格式定義為兩個結構體,固定大小為54個字節,機構體定義如下:
#pragma pack(1) /* 必須在結構體定義之前使用,這是為了讓結構體中各成員按1字節對齊*//*圖片頭*/typedef struct BitMapFileHEADER{ unsigned short bfType; //保存圖片類型。 "BM" unsigned int bfSize; //圖片文件的總大小,以字節為單位(3-6字節,低位在前) unsigned short bfReserved1;//位圖文件保留字,必須為0(7-8字節) unsigned short bfReserved2;//位圖文件保留字,必須為0(9-10字節) unsigned int bfOffBits; //RGB數據偏移地址,位圖數據的起始位置,以相對于位圖(11-14字節,低位在前)//文件頭的偏移量表示,以字節為單位}BMP_HEADER;/*圖片信息*/typedef struct BitMapFileInfo{ unsigned int biSize; //本結構所占用字節數(15-18字節) unsigned int biWidth; //位圖的寬度,以像素為單位(19-22字節) unsigned int biHeight; //位圖的高度,以像素為單位(23-26字節) unsigned short biPlanes; //目標設備的級別,必須為1(27-28字節) unsigned short biBitCount; //每個像素所需的位數,必須是1(雙色)(29-30字節),4(16色),8(256色)16(高彩色)或24(真彩色)之一 unsigned int biCompression;//位圖壓縮類型,必須是0(不壓縮),(31-34字節)//1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一 unsigned int biSizeImage; //位圖的大小(其中包含了為了補齊行數是4的倍數而添加的空字節),以字節為單位(35-38字節) unsigned int biXPelsPerMeter;//位圖水平分辨率,每米像素數(39-42字節) unsigned int biYPelsPerMeter;//位圖垂直分辨率,每米像素數(43-46字節) unsigned int biClrUsed; //位圖實際使用的顏色表中的顏色數(47-50字節) unsigned int biClrImportant; //位圖顯示過程中重要的顏色數(51-54字節)}BMP_INFO;#pragma pack()