Files
template/main.c
2026-09-13 20:57:03 +08:00

205 lines
5.8 KiB
C

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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;i<colors;i++){
g_bmi->bmiColors[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;i<colors;i++){
BYTE r=g_bmi->bmiColors[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;i<colors;i++){
g_bmi->bmiColors[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;
}