C語言實現BMP圖片的放大縮小

唐益協發表於2017-12-31

                                        C語言實現BMP圖片的放大縮小

BMP圖片簡介:BMP圖片是windows作業系統中的標準影象檔案格式,可以分為兩類:裝置相關點陣圖(DDB)和裝置無關點陣圖(DIB),使用廣泛。它採用位對映儲存格式,除了影象深度可選以外,不採用其他任何壓縮,因此,BMP檔案所佔用的空間很大。BMP檔案的影象深度可選lbit、4bit、8bit及24bit。BMP檔案儲存資料時,影象的掃描方式是按從左到右、從下到上的順序。由於BMP檔案格式是Windows環境中交換與圖有關的資料的一種標準,因此在Windows環境中執行的圖形影象軟體都支援BMP影象格式。

BMP圖片的儲存:

1:點陣圖標頭檔案資料結構,它包含BMP影象檔案的型別、顯示內容等資訊;
2:點陣圖資訊資料結構,它包含有BMP影象的寬、高、壓縮方法,以及定義顏色等資訊;
3:調色盤,這個部分是可選的,有些點陣圖需要調色盤,有些點陣圖,比如真彩色圖(24位的BMP)就不需要調色盤;
4:點陣圖資料,這部分的內容根據BMP點陣圖使用的位數不同而不同,在24點陣圖中直接使用RGB,而其他的小於24位的使用調色盤中顏色索引值。

C 語言程式設計思路:

1、定義一個儲存標頭檔案資料結構體
typedef struct tagBITMAPFILEHEADER
{
 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位元組,低位在前)
}BITMAPFILEHEADER;

2定義一個儲存點陣圖資訊的結構體
typedef struct tagBITMAPINFOHEADER
{
 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位元組)
}BITMAPINFOHEADER;

3、圖片縮小的原則就是按照一定的比例從範圍內的畫素點中抽去畫素點。而放大的原則正好相反,將一個或多個畫素點按照比例複製在其周圍。


程式實現:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#pragma pack(1)  /* 必須在結構體定義之前使用,這是為了讓結構體中各成員按1位元組對齊*/
typedef struct tagBITMAPFILEHEADER
{
 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位元組,低位在前)
}BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
 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位元組)
}BITMAPINFOHEADER;

/*
 函式名稱:Bmp_Smaller
 函式功能:圖片放大縮小
 引數:BITMAPFILEHEADER head,BITMAPINFOHEADER info-原照片頭資訊
 返回值:void
 */
void Bmp_Bigger_And_Smaller(BITMAPFILEHEADER head,BITMAPINFOHEADER info)
{
 FILE *fpr1=fopen("src.bmp","rb");
 FILE *fpw2=fopen("new.bmp","wb");
 if(fpr1==NULL||fpw2==NULL)
 {
  printf("圖片開啟失敗!\n");
  return ;
 }
 //讀取原照片的頭資訊
 fread(&head,sizeof(BITMAPFILEHEADER),1,fpr1);
 fread(&info,sizeof(BITMAPINFOHEADER),1,fpr1);

 unsigned int old_width=info.biWidth;//獲取原圖片的寬
 unsigned int old_height=info.biHeight;//獲取原圖片的高

 //獲取原圖片的點陣圖資料
 unsigned char *src_data=malloc(old_width*old_height*3);
 fseek(fpr1,54,SEEK_SET);
 fread(src_data,old_width*old_height*3,1,fpr1);

 printf("原圖片的寬:%d\n",old_width);
 printf("原圖片的高:%d\n",old_height);

 //修改原照片的寬高
 unsigned int new_Width,new_Height;
 printf("請輸入新圖片的寬:\n");
 scanf("%d",&new_Width);
 printf("請輸入新圖片的高:\n");
 scanf("%d",&new_Height);
 head.bfSize=new_Width*new_Height*3+54;
 info.biWidth=new_Width;
 info.biHeight=new_Height;

 //將修改過的頭資訊寫進新照片
 fwrite(&head,sizeof(BITMAPFILEHEADER),1,fpw2);
 fwrite(&info,sizeof(BITMAPINFOHEADER),1,fpw2);
 
 int i=0,j=0;
 unsigned long dwsrcX,dwsrcY;
 unsigned char *pucDest;
 unsigned char *pucSrc;
 unsigned char *dest_data=malloc(new_Width*new_Height*3);
 for(i=0;i<new_Height;i++)
 {
  dwsrcY=i*old_height/new_Height;
  pucDest=dest_data+i*new_Width*3;
  pucSrc=src_data+dwsrcY*old_width*3;
  for(j=0;j<new_Width;j++)
  {
   dwsrcX=j*old_width/new_Width;
   memcpy(pucDest+j*3,pucSrc+dwsrcX*3,3);//資料拷貝
  }
 }
 fseek(fpw2,54,SEEK_SET);
 fwrite(dest_data,new_Width*new_Height*3,1,fpw2);
 printf("生成新圖片成功!\n");

 //釋放堆空間
 free(dest_data);
 free(src_data);

 //關閉檔案
 fclose(fpr1);
 fclose(fpw2);
}

/*
 函式名稱:main
 函式功能:主函式
 引數:void
 返回值:int
 */
int main()
{
 //定義原照片資訊結構體
 BITMAPFILEHEADER old_head;
 BITMAPINFOHEADER old_info;
 
 //將結構體清空
 memset(&old_head,0,sizeof(BITMAPFILEHEADER));
 memset(&old_info,0,sizeof(BITMAPINFOHEADER));
 

 Bmp_Bigger_And_Smaller(old_head,old_info);
 return 0; 
}


小結:還在上大學,第一次寫部落格,沒什麼經驗,可能有些地方描述的不是很清楚,還望諒解!



相關文章