將任意bmp圖片大小重新設定後生成新的bmp圖片

藍桉未遇釋槐鳥發表於2024-05-13
#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;
#pragma pack()
// 取消位元組對齊
/*
 函式名稱:Bmp_Smaller
 函式功能:圖片放大縮小
 引數:BITMAPFILEHEADER head,BITMAPINFOHEADER info-原照片頭資訊
 返回值:void
 */
void Bmp_Bigger_And_Smaller(char *path)
{
	FILE *fpr1 = fopen(path, "rb");
	FILE *fpw2 = fopen("new.bmp", "wb");
	if (fpr1 == NULL || fpw2 == NULL)
	{
		printf("圖片開啟失敗!\n");
		return;
	}
	// 讀取原照片的頭資訊
	struct tagBITMAPFILEHEADER head;
	struct tagBITMAPINFOHEADER info;

	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);

	int ret = (4 - new_Width * 3 % 4) % 4;
	head.bfSize = new_Width * new_Height * 3 + 54 + ret * new_Width;
	info.biSizeImage = new_Width * new_Height * 3 + ret * new_Width;
	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;													 // 新bmp畫素點對應的原bmp畫素點位置
	unsigned char *pucDest;															 // 新bmp行數對應的起始畫素點
	unsigned char *pucSrc;															 // 原bmp畫素點
	unsigned char *dest_data = malloc(new_Width * new_Height * 3 + ret * new_Width); // 新bmp畫素空間大小
	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 + ret * i, 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(int argc, char const *argv[])
{
	Bmp_Bigger_And_Smaller(argv[1]);
	return 0;
}

測試結果

image
image

相關文章