#define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include "image_proc.h" #include "user_proc.h" #pragma pack(push,1) typedef struct { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; } BMPFILEHEADER; #pragma pack(pop) static uint8_t* g_pixels = NULL; static BITMAPINFO* g_bmi = NULL; static int g_w=0, g_h=0, g_bpp=0; static const char* g_title = "BMP Viewer"; static void FreeImage() { free(g_pixels); g_pixels = NULL; free(g_bmi); g_bmi = NULL; g_w = g_h = g_bpp = 0; } static int LoadBMP(const char* path) { FreeImage(); FILE* fp = fopen(path, "rb"); if(!fp){ fprintf(stderr,"无法打开: %s\n", path); return 0; } BMPFILEHEADER fh; BITMAPINFOHEADER ih; if(fread(&fh,sizeof(fh),1,fp)!=1){ fclose(fp); return 0; } if(fh.bfType != 0x4D42){ fclose(fp); fprintf(stderr,"非BMP\n"); return 0; } if(fread(&ih,sizeof(ih),1,fp)!=1){ fclose(fp); return 0; } if(ih.biCompression != BI_RGB){ fclose(fp); fprintf(stderr,"仅支持未压缩 BI_RGB\n"); return 0; } if(!(ih.biBitCount==8 || ih.biBitCount==24 || ih.biBitCount==32)){ fclose(fp); fprintf(stderr,"不支持位数: %u\n", ih.biBitCount); return 0; } g_w = ih.biWidth; g_h = ih.biHeight; g_bpp = ih.biBitCount; int bytesPerPixel = g_bpp / 8; int stride = ((g_w * bytesPerPixel + 3) / 4) * 4; size_t imgSize = (size_t)stride * g_h; uint32_t colors = 0; if(g_bpp == 8){ colors = ih.biClrUsed ? ih.biClrUsed : 256; if(colors > 256) colors = 256; } size_t bmiSize = sizeof(BITMAPINFOHEADER) + colors * sizeof(RGBQUAD); g_bmi = (BITMAPINFO*)calloc(1, bmiSize); if(!g_bmi){ fclose(fp); return 0; } g_bmi->bmiHeader = ih; if(g_bpp == 8){ if(colors){ size_t readPaletteBytes = colors * sizeof(RGBQUAD); if(fread(g_bmi->bmiColors, 1, readPaletteBytes, fp) != readPaletteBytes){ for(uint32_t i=0;ibmiColors[i].rgbRed = g_bmi->bmiColors[i].rgbGreen = g_bmi->bmiColors[i].rgbBlue = (BYTE)i; } } } else { } } g_pixels = (uint8_t*)malloc(imgSize); if(!g_pixels){ fclose(fp); FreeImage(); return 0; } if(fseek(fp, (long)fh.bfOffBits, SEEK_SET)!=0){ fclose(fp); FreeImage(); return 0; } if(fread(g_pixels,1,imgSize,fp)!=imgSize){ fclose(fp); FreeImage(); fprintf(stderr,"像素读取失败\n"); return 0; } fclose(fp); if(g_bpp == 8){ int isGray = 1; for(uint32_t i=0;ibmiColors[i].rgbRed; BYTE g=g_bmi->bmiColors[i].rgbGreen; BYTE b=g_bmi->bmiColors[i].rgbBlue; if(!(r==g && g==b)){ isGray=0; break; } } if(!isGray){ for(uint32_t i=0;ibmiColors[i].rgbRed = g_bmi->bmiColors[i].rgbGreen = g_bmi->bmiColors[i].rgbBlue = (BYTE)i; } } } return 1; } static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg){ case WM_ERASEBKGND: return 1; case WM_PAINT:{ PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd,&ps); if(g_pixels && g_bmi){ int dstW = g_w * IMAGE_SCALE; int dstH = g_h * IMAGE_SCALE; SetStretchBltMode(hdc, COLORONCOLOR); StretchDIBits( hdc, 0,0,dstW,dstH, 0,0,g_w,g_h, g_pixels, g_bmi, DIB_RGB_COLORS, SRCCOPY ); } else { TextOutA(hdc,10,10,"未加载BMP",12); } EndPaint(hWnd,&ps); } break; case WM_DESTROY: FreeImage(); PostQuitMessage(0); break; default: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPSTR lpCmdLine,int nShow){ (void)hPrev; (void)lpCmdLine; if(!LoadBMP(BMP_PATH)){ char msg[256]; snprintf(msg,sizeof(msg),"加载失败: %s", BMP_PATH); MessageBoxA(NULL,msg,"错误",MB_OK|MB_ICONERROR); } else { g_title = BMP_PATH; GrayImage gray = {0}; if(ExtractGray(g_pixels, g_w, g_h, g_bpp, &gray)){ img_proc(&gray);//这里调用了图像处理函数 BITMAPINFO *newBMI = NULL; uint8_t *newPixels = NULL; if(Build8BitDIB(&gray, &newBMI, &newPixels)){ free(g_pixels); free(g_bmi); g_pixels = newPixels; g_bmi = newBMI; g_bpp = 8; } } FreeGray(&gray); } const char* cls = "BMP_VIEWER_CLASS"; WNDCLASSA wc = (WNDCLASSA){0}; wc.lpfnWndProc = WndProc; wc.hInstance = hInst; wc.lpszClassName = cls; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); if(!RegisterClassA(&wc)) return 0; int winW = g_w ? g_w * IMAGE_SCALE : 640; int winH = g_h ? g_h * IMAGE_SCALE : 480; RECT rc = {0,0, winW, winH}; DWORD style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; AdjustWindowRect(&rc, style, FALSE); HWND hWnd = CreateWindowExA( 0, cls, g_title, style, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL,NULL,hInst,NULL); if(!hWnd) return 0; ShowWindow(hWnd,nShow); UpdateWindow(hWnd); MSG msg; while(GetMessage(&msg,NULL,0,0)>0){ TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }