#include #include #include #include typedef unsigned char uch; // 檔案結構 #pragma pack(2) struct BmpFileHeader { uint16_t bfTybe; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; }; struct BmpInfoHeader { uint32_t biSize; uint32_t biWidth; uint32_t biHeight; uint16_t biPlanes; // 1=defeaul, 0=custom uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; uint32_t biXPelsPerMeter; // 72dpi=2835, 96dpi=3780 uint32_t biYPelsPerMeter; // 120dpi=4724, 300dpi=11811 uint32_t biClrUsed; uint32_t biClrImportant; }; #pragma pack() //辅助计算函数 float linear_single(float x, float x1, float x2, float f1, float f2){ return floor(f1 * (x2 - x) / (x2 - x1) + f2 * (x - x1) / (x2 - x1)); } // 双线性插值函数 // 参考 https://zh.wikipedia.org/wiki/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC char linear_insert(uch** old_pixels, uint32_t row, uint32_t col, uint32_t old_width, uint32_t old_height, float radio_w, float radio_h){ float x = row / radio_h; float y = col / radio_w; // 如果整数格点就直接返回 int x1 = floor(x); int x2 = ceil(x); int y1 = floor(y); int y2 = ceil(y); if (x2 >= old_height){x2 = x1;} if (y2 >= old_width){y2 = y1;} if (x1 == x2 && y1 == y2){return old_pixels[x1][y1];} if (x1 == x2){ int x = x1; uint32_t idx1 = x*old_width+y; uint32_t idx2 = x*old_width+y; float r = linear_single(y, y1, y2, old_pixels[x][idx1 + 0], old_pixels[x][idx2 + 0]); float g = linear_single(y, y1, y2, old_pixels[x][idx1 + 1], old_pixels[x][idx2 + 1]); float b = linear_single(y, y1, y2, old_pixels[x][idx1 + 2], old_pixels[x][idx2 + 2]); return (char)r, (char)g, (char)b; } if (y1 == y2){ int y = y1; uint32_t idx = x*old_width+y; float r = linear_single(x, x1, x2, old_pixels[x1][idx + 0], old_pixels[x2][idx + 0]); float g = linear_single(x, x1, x2, old_pixels[x1][idx + 1], old_pixels[x2][idx + 1]); float b = linear_single(x, x1, x2, old_pixels[x1][idx + 2], old_pixels[x2][idx + 2]); return (char)r, (char)g, (char)b; } uint32_t idx1 = x*old_width+y; uint32_t idx2 = x*old_width+y; float fy1_r = linear_single(x, x1, x2, old_pixels[x1][idx1 + 0], old_pixels[x2][idx1 + 0]); float fy1_g = linear_single(x, x1, x2, old_pixels[x1][idx1 + 1], old_pixels[x2][idx1 + 1]); float fy1_b = linear_single(x, x1, x2, old_pixels[x1][idx1 + 2], old_pixels[x2][idx1 + 2]); float fy2_r = linear_single(x, x1, x2, old_pixels[x1][idx2 + 0], old_pixels[x2][idx2 + 0]); float fy2_g = linear_single(x, x1, x2, old_pixels[x1][idx2 + 1], old_pixels[x2][idx2 + 1]); float fy2_b = linear_single(x, x1, x2, old_pixels[x1][idx2 + 2], old_pixels[x2][idx2 + 2]); float r = linear_single(y, y1, y2, fy1_r, fy2_r); float g = linear_single(y, y1, y2, fy1_g, fy2_g); float b = linear_single(y, y1, y2, fy1_b, fy2_b); return (char)r, (char)g, (char)b; } void bmpWrite(const char* name, const uch* raw_img, uint32_t width, uint32_t height, uint32_t bits, float radio_w, float radio_h){ if(!(name && raw_img)){ perror("Error bmpWrite."); return; } // 檔案資訊 struct BmpFileHeader file_h = { .bfTybe=0x4d42, .bfReserved1=0, .bfReserved2=0, .bfOffBits=54, }; uint32_t new_width = floor(width*radio_w); uint32_t new_height = floor(height*radio_h); file_h.bfSize = file_h.bfOffBits + new_width*new_height * bits/8; if(bits==8) {file_h.bfSize+= 1024, file_h.bfOffBits+= 1024;} // 圖片資訊 struct BmpInfoHeader info_h = { .biSize=40, .biPlanes=1, .biCompression=0, .biXPelsPerMeter=0, .biYPelsPerMeter=0, .biClrUsed=0, .biClrImportant=0, }; info_h.biWidth = new_width; info_h.biHeight = new_height; info_h.biBitCount = bits;// 多少位的圖 info_h.biSizeImage = new_width*new_height * bits/8; if(bits == 8) {info_h.biClrUsed=256;} // 寫入檔頭 FILE *pFile = NULL; // pFile = fopen(name,"wb+"); fopen_s(&pFile, name,"wb+"); if(!pFile) { perror("Error opening file."); return; } fwrite((char*)&file_h, sizeof(char), sizeof(file_h), pFile); fwrite((char*)&info_h, sizeof(char), sizeof(info_h), pFile); // 寫調色盤 if(bits == 8) { for(unsigned i = 0; i < 256; ++i) { uch c = i; fwrite((char*)&c, sizeof(char), sizeof(uch), pFile); fwrite((char*)&c, sizeof(char), sizeof(uch), pFile); fwrite((char*)&c, sizeof(char), sizeof(uch), pFile); fwrite("", sizeof(char), sizeof(uch), pFile); } } // char newpixels[new_width*new_height]; unsigned char **newpixels=(unsigned char**)malloc(new_width*new_height*3);// 沒用到 // 寫入圖片資訊 size_t alig = ((new_width*bits/8)*3) % 4; // for(int j = new_height-1; j >= 0; --j) { // for(unsigned i = 0; i < new_width; ++i) { // uint32_t idx = j*new_width +i; // if(bits == 24) { // RGB圖片 // fwrite((char*)&raw_img[idx*3 +2], sizeof(char), sizeof(uch), pFile); // fwrite((char*)&raw_img[idx*3 +1], sizeof(char), sizeof(uch), pFile); // fwrite((char*)&raw_img[idx*3 +0], sizeof(char), sizeof(uch), pFile); // } else if(bits == 8) { // 灰階圖 // fwrite((char*)&raw_img[idx], sizeof(char), sizeof(uch), pFile); // } // } for(int j = new_height-1; j >= 0; --j) { for(unsigned i = 0; i < new_width; ++i) { uint32_t idx = j*new_width +i; if(bits == 24) { // RGB圖片 char* r, g, b = linear_insert(&raw_img, j, i, width, height, radio_w, radio_h); fwrite(b, sizeof(char), sizeof(uch), pFile); fwrite(g, sizeof(char), sizeof(uch), pFile); fwrite(r, sizeof(char), sizeof(uch), pFile); } else if(bits == 8) { // 灰階圖 fwrite((char*)&raw_img[idx], sizeof(char), sizeof(uch), pFile); } } //# 计算新像素 // 對齊4byte for(size_t i = 0; i < alig; ++i) { fwrite("", sizeof(char), sizeof(uch), pFile); } } fclose(pFile); free(newpixels); //記得釋放空間 } void bmpRead(const char* name, uch** oldpixels, uint32_t* width, uint32_t* height, uint16_t* bits) { if(!(name && oldpixels && width && height && bits)) { perror("Error bmpRead."); return; } // 檔案資訊 struct BmpFileHeader file_h; // 圖片資訊 struct BmpInfoHeader info_h; // 讀取檔頭 FILE *pFile = NULL; // pFile = fopen(name, "rb+"); fopen_s(&pFile, name, "rb+"); if(!pFile) { perror("Error opening file."); return; } fread((char*)&file_h, sizeof(char), sizeof(file_h), pFile); fread((char*)&info_h, sizeof(char), sizeof(info_h), pFile); // 讀取長寬 *width = info_h.biWidth; *height = info_h.biHeight; *bits = info_h.biBitCount; unsigned char **oldpixels=(unsigned char**)malloc((*width)*(*height)*3); // size_t ImgSize = ((size_t)*width) * ((size_t)*height) * 3; // *raw_img = (uch*)calloc(ImgSize, sizeof(uch)); // 讀取讀片資訊轉RAW檔資訊 fseek(pFile, file_h.bfOffBits, SEEK_SET); size_t alig = ((info_h.biWidth*info_h.biBitCount/8)*3) % 4; for(int j = *height-1; j >= 0; --j) { for(unsigned i = 0; i < *width; ++i) { uint32_t idx = j*(*width)+i; if(*bits == 24) { // RGB圖片 fread((char*)&(*oldpixels)[idx*3 +2], sizeof(char), sizeof(uch), pFile); fread((char*)&(*oldpixels)[idx*3 +1], sizeof(char), sizeof(uch), pFile); fread((char*)&(*oldpixels)[idx*3 +0], sizeof(char), sizeof(uch), pFile); } else if(*bits == 8) { // 灰階圖 fread((char*)&(*oldpixels)[idx], sizeof(char), sizeof(uch), pFile); } } fseek(pFile , (long)alig , SEEK_CUR); } fclose(pFile); //--------------------------------------------------------------------------- // size_t ImgSize = ((size_t)*width) * ((size_t)*height) * 3; // *raw_img = (uch*)calloc(ImgSize, sizeof(uch)); // // 讀取讀片資訊轉RAW檔資訊 // fseek(pFile, file_h.bfOffBits, SEEK_SET); // size_t alig = ((info_h.biWidth*info_h.biBitCount/8)*3) % 4; // for(int j = *height-1; j >= 0; --j) { // for(unsigned i = 0; i < *width; ++i) { // uint32_t idx = j*(*width)+i; // if(*bits == 24) { // RGB圖片 // fread((char*)&(*raw_img)[idx*3 +2], sizeof(char), sizeof(uch), pFile); // fread((char*)&(*raw_img)[idx*3 +1], sizeof(char), sizeof(uch), pFile); // fread((char*)&(*raw_img)[idx*3 +0], sizeof(char), sizeof(uch), pFile); // } else if(*bits == 8) { // 灰階圖 // fread((char*)&(*raw_img)[idx], sizeof(char), sizeof(uch), pFile); // } // } // fseek(pFile , (long)alig , SEEK_CUR); // } // fclose(pFile); //---------------------------------------------------------------------------- // for(int j = *height-1; j >= 0; --j) { // for(unsigned i = 0; i < *width; ++i) { // uint32_t idx = j*(*width)+i; // for(int k = 0; k < 3; k++){ // printf((char*)&(*raw_img)[idx*3 + k]); // printf("\t"); // } // printf("\t done \t"); // } // printf("\n"); // } } // 圖像結構 typedef struct Imgraw { uint32_t width, height; uint16_t bits; uch* data; } Imgraw; void Imgraw_Read(const Imgraw* _this, const char* name) { const Imgraw* p = _this; bmpRead(name, &p->data, &p->width, &p->height, &p->bits); } void Imgraw_Writ(const Imgraw* _this, const char* name, float radio_w, float radio_h) { const Imgraw* p = _this; bmpWrite(name, p->data, p->width, p->height, p->bits, radio_w, radio_h); } /*==============================================================*/ int main(int argc, char const *argv[]) { float radio_w, radio_h; printf("Enter a radio of width :") ; scanf("%f", &radio_w); printf("Enter a radio of height :") ; scanf("%f", &radio_h); printf("%f :: %f\n", radio_w, radio_h); // 建構 Imgraw img = {0, 0, 0, NULL}; // 讀圖 Imgraw_Read(&img, "./input/bw2x1.bmp"); // 寫圖 Imgraw_Writ(&img, "./output/bw2x1(output).bmp", radio_w, radio_h); return 0; } /*==============================================================*/