linux下BMP圖片旋轉
??MP是英文Bitmap(位圖)的簡寫,它是Windows作業系統中的標準影像檔案格式,能夠被多種Windows應用程式所支持,隨著Windows作業系統的流行與豐富的Windows應用程式的開發,BMP位圖格式理所當然地被廣泛應用,這種格式的特點是包含的影像資訊較豐富,幾乎不進行壓縮,但由此導致了它與生俱來的缺點–占用磁盤空間過大,所以,目前BMP在單機上比較流行,
??在使用圖片時我們經常需要用到旋轉,本示例主要完成對BMP圖片的順時針旋轉90°和逆時針旋轉90°,
-
原始圖片

-
程式執行效果:
[xsw@xsw BMP_stady]$ gcc rivolve.c
[xsw@xsw BMP_stady]$ ./a.out
格式:./a.out <new.bmp> <source.bmp>
[xsw@xsw BMP_stady]$ ./a.out new.bmp watermark.bmp
--------------------順時針旋轉90°----------------------
旋轉后圖片寬:314
旋轉后圖片高:504
--------------------逆時針旋轉90°----------------------
旋轉后圖片寬:314
旋轉后圖片高:504
[xsw@xsw BMP_stady]$


- 順時針旋轉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;j<h;j++)
{
offset_count=j*befor_oneline_size+i*3+bmp_head.bfOffBits;//從第一行的最后一個像素點開始
fseek(fp[0],offset_count,SEEK_SET);
fread(&rgb,bmp_info.biBitCount/8,1,fp[0]);
fwrite(&rgb,bmp_info.biBitCount/8,1,fp[1]);
}
if(new_oneline_size>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°示例
/***********************逆時針旋轉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<w;i++)
{
cnt=0;
for(j=h-1;j>=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;
}
- BMP位圖結構體
#pragma pack(1) /* 必須在結構體定義之前使用,這是為了讓結構體中各成員按1位元組對齊*/
/*圖片頭*/
typedef struct BitMapFileHEADER
{
unsigned short bfType; //保存圖片型別, 'BM'
unsigned long bfSize; //圖片檔案的總大小,以位元組為單位(3-6位元組,低位在前)
unsigned short bfReserved1;//位圖檔案保留字,必須為0(7-8位元組)
unsigned short bfReserved2;//位圖檔案保留字,必須為0(9-10位元組)
unsigned long bfOffBits; //RGB資料偏移地址,位圖資料的起始位置,以相對于位圖(11-14位元組,低位在前)//檔案頭的偏移量表示,以位元組為單位
}BMP_HEADER;
/*圖片資訊*/
typedef struct BitMapFileInfo{
unsigned long biSize; //本結構所占用位元組數(15-18位元組)
unsigned long biWidth; //位圖的寬度,以像素為單位(19-22位元組)
unsigned long biHeight; //位圖的高度,以像素為單位(23-26位元組)
unsigned short biPlanes; //目標設備的級別,必須為1(27-28位元組)
unsigned short biBitCount; //每個像素所需的位數,必須是1(雙色)(29-30位元組),4(16色),8(256色)16(高彩色)或24(真彩色)之一
unsigned long biCompression;//位圖壓縮型別,必須是0(不壓縮),(31-34位元組)
//1(BI_RLE8壓縮型別)或2(BI_RLE4壓縮型別)之一
unsigned long biSizeImage; //位圖的大小(其中包含了為了補齊行數是4的倍數而添加的空位元組),以位元組為單位(35-38位元組)
unsigned long biXPelsPerMeter;//位圖水平解析度,每米像素數(39-42位元組)
unsigned long biYPelsPerMeter;//位圖垂直解析度,每米像素數(43-46位元組)
unsigned long biClrUsed; //位圖實際使用的顏色表中的顏色數(47-50位元組)
unsigned long biClrImportant; //位圖顯示程序中重要的顏色數(51-54位元組)
}BMP_INFO;
- 主函式
int main(int argc,char **argv)
{
if(argc!=3)
{
printf("格式:./a.out <new.bmp> <source.bmp>\n");
return 0;
}
int stat=0;
char buff[20];
stat=BMP_ClockWise_Revolve90(argv[1],argv[2]);//順時針90°
if(stat)
printf("[%s line %d] err %d\n",__FUNCTION__,__LINE__,stat);
else
{
snprintf(buff,sizeof(buff),"eog %s",argv[1]);//字串拼接
system(buff);//創建行程
}
stat=BMP_antiClockWise_Revolve90(argv[1],argv[2]);//逆時針旋轉90°
if(stat)
printf("[%s line %d] err %d\n",__FUNCTION__,__LINE__,stat);
else
{
snprintf(buff,sizeof(buff),"eog %s",argv[1]);//字串拼接
system(buff);//創建行程
}
return 0;
}
在對BMP圖片進行90°旋轉時需要注意的點:
??1.每一行的位元組數,當行位元組數不是4的倍數需要用0補齊
??2.旋轉后的圖片的寬=原圖片的高;新圖片的高=原圖片的寬
- 注:以上示例均在32位redHat6.3 linux下實作,若是64位linux系統需要注意結構體大小,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/254842.html
標籤:其他
