【速看料】Linux下圖片處理

2023-01-14 19:29:40 來源:51CTO博客

Linux下圖片處理

圖片是指由圖形、圖像等構成的平面媒體。圖片的格式很多,但總體上可以分為點陣圖和矢量圖兩大類,我們常用BMP、JPG等格式都是點陣圖形,而SWF、CDR、AI等格式的圖形屬于矢量圖形。

有形式的事物,我們看到的,是圖畫、照片、拓片等的統稱。圖是技術制圖中的基礎術語,指用點、線、符號、文字和數字等描繪事物幾何特征、形態、位置及大小的一種形式。隨著數字采集技術和信號處理理論的發展,越來越多的圖片以數字形式存儲。


(相關資料圖)

1.常見的圖片格式

在嵌入式開發中,常用的圖片格式有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了。

2.BMP圖片處理

BMP圖片格式簡單,可以不需要借助任何第三方庫即可完成圖片的各種操作處理,接下來將以C語言實現BMP圖片的旋轉。

2.1 BMP圖片旋轉處理

原始圖片如下順時針旋轉90°效果:逆時針旋轉90°效果:順時針旋轉90°示例
/***********************順時針旋轉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;jbmp_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°示例
/***********************逆時針旋轉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;}

2.2 BMP圖片水印添加

添加水印效果:

水印添加實現原理:先獲取圖片大小,然后通過內存映射方式(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()

標簽: 圖片格式 圖像格式 逆時針旋轉

上一篇:【獨家】楊氏矩陣
下一篇:【世界快播報】PHP后門反彈演示