generated from bob/template
Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
*.exe
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "image_proc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
|
||||
int ExtractGray(const uint8_t *srcPixels, int w, int h, int bpp, GrayImage *outImg){
|
||||
if(!srcPixels || w<=0 || h<=0) return 0;
|
||||
int srcBytesPerPixel = bpp / 8;
|
||||
int srcStride = ((w * srcBytesPerPixel + 3) / 4) * 4;
|
||||
outImg->width = w;
|
||||
outImg->height = h;
|
||||
outImg->stride = w;
|
||||
size_t total = (size_t)w * h;
|
||||
outImg->data = (uint8_t*)malloc(total);
|
||||
if(!outImg->data) return 0;
|
||||
outImg->rows = (uint8_t**)malloc(sizeof(uint8_t*) * h);
|
||||
if(!outImg->rows){
|
||||
free(outImg->data);
|
||||
outImg->data = NULL;
|
||||
return 0;
|
||||
}
|
||||
for(int y=0; y<h; ++y){
|
||||
outImg->rows[y] = outImg->data + (size_t)y * w;
|
||||
}
|
||||
|
||||
for(int y=0; y<h; ++y){
|
||||
const uint8_t *srcLine = srcPixels + (size_t)(h - 1 - y) * srcStride;
|
||||
uint8_t *dstLine = outImg->rows[y];
|
||||
if(bpp == 8){
|
||||
memcpy(dstLine, srcLine, (size_t)w);
|
||||
} else if(bpp == 24 || bpp == 32){
|
||||
for(int x=0; x<w; ++x){
|
||||
const uint8_t *p = srcLine + x * srcBytesPerPixel;
|
||||
uint8_t B = p[0], G = p[1], R = p[2];
|
||||
uint8_t Y = (uint8_t)((R*77 + G*150 + B*29) >> 8);
|
||||
dstLine[x] = Y;
|
||||
}
|
||||
} else {
|
||||
free(outImg->rows); free(outImg->data);
|
||||
memset(outImg,0,sizeof(*outImg));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void FreeGray(GrayImage *img){
|
||||
if(!img) return;
|
||||
free(img->rows);
|
||||
free(img->data);
|
||||
memset(img,0,sizeof(*img));
|
||||
}
|
||||
|
||||
int Build8BitDIB(const GrayImage *img, BITMAPINFO **outBMI, uint8_t **outPixels){
|
||||
if(!img || !img->data) return 0;
|
||||
int w = img->width;
|
||||
int h = img->height;
|
||||
int bpp = 8;
|
||||
int dstStride = ((w * (bpp/8) + 3)/4)*4;
|
||||
size_t pixelBytes = (size_t)dstStride * h;
|
||||
|
||||
size_t bmiSize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
|
||||
BITMAPINFO *bmi = (BITMAPINFO*)calloc(1, bmiSize);
|
||||
if(!bmi) return 0;
|
||||
|
||||
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi->bmiHeader.biWidth = w;
|
||||
bmi->bmiHeader.biHeight = h;
|
||||
bmi->bmiHeader.biPlanes = 1;
|
||||
bmi->bmiHeader.biBitCount = 8;
|
||||
bmi->bmiHeader.biCompression = BI_RGB;
|
||||
bmi->bmiHeader.biSizeImage = (DWORD)pixelBytes;
|
||||
bmi->bmiHeader.biClrUsed = 256;
|
||||
|
||||
for(int i=0;i<256;i++){
|
||||
bmi->bmiColors[i].rgbBlue = (BYTE)i;
|
||||
bmi->bmiColors[i].rgbGreen = (BYTE)i;
|
||||
bmi->bmiColors[i].rgbRed = (BYTE)i;
|
||||
bmi->bmiColors[i].rgbReserved = 0;
|
||||
}
|
||||
|
||||
uint8_t *pixels = (uint8_t*)malloc(pixelBytes);
|
||||
if(!pixels){
|
||||
free(bmi);
|
||||
return 0;
|
||||
}
|
||||
for(int y=0; y<h; ++y){
|
||||
uint8_t *dstLine = pixels + (size_t)(h - 1 - y) * dstStride;
|
||||
const uint8_t *srcLine = img->rows[y];
|
||||
memcpy(dstLine, srcLine, (size_t)w);
|
||||
if(dstStride > w){
|
||||
memset(dstLine + w, 0, dstStride - w);
|
||||
}
|
||||
}
|
||||
|
||||
*outBMI = bmi;
|
||||
*outPixels = pixels;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef IMAGE_PROC_H
|
||||
#define IMAGE_PROC_H
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int stride; // 连续灰度数据每行字节数 (无 4 字节对齐,= width)
|
||||
uint8_t *data; // 连续内存 (height * width)
|
||||
uint8_t **rows; // 行指针 (rows[0] 顶行)
|
||||
} GrayImage;
|
||||
|
||||
// 从已加载的 BMP 像素提取灰度 (支持 8/24/32 bpp),源为 bottom-up DIB,输出 top-down
|
||||
// srcPixels: 原始像素 (bottom-up)
|
||||
// bpp: 8 / 24 / 32
|
||||
// 返回 1 成功 0 失败
|
||||
int ExtractGray(const uint8_t *srcPixels, int w, int h, int bpp, GrayImage *outImg);
|
||||
|
||||
|
||||
// 释放
|
||||
void FreeGray(GrayImage *img);
|
||||
|
||||
// 把灰度图转换成可直接 StretchDIBits 的 8 位 DIB (bottom-up + 调色板)
|
||||
// 返回 1 成功
|
||||
int Build8BitDIB(const GrayImage *img, BITMAPINFO **outBMI, uint8_t **outPixels);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,205 @@
|
||||
#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;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#include <stdint.h>
|
||||
#include "user_proc.h"
|
||||
//绘制十字交叉线
|
||||
void draw_cross(GrayImage *img, int x, int y, int size, uint8_t color){
|
||||
if(!img || !img->data) return;
|
||||
//获取图像宽度和高度
|
||||
int w = img->width;
|
||||
int h = img->height;
|
||||
if(x<0 || x>=w || y<0 || y>=h) return;
|
||||
//定义一个二维数组指针方便访问像素
|
||||
uint8_t **image = img->rows;
|
||||
for(int dx=-size;dx<=size;dx++){
|
||||
int nx = x + dx;
|
||||
if(nx>=0 && nx<w){
|
||||
image[y][nx] = color;
|
||||
}
|
||||
}
|
||||
for(int dy=-size;dy<=size;dy++){
|
||||
int ny = y + dy;
|
||||
if(ny>=0 && ny<h){
|
||||
image[ny][x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
void img_proc(GrayImage *img){
|
||||
draw_cross(img, img->width/2, img->height/2, 20, 0);
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#ifndef USER_PROC_H
|
||||
#define USER_PROC_H
|
||||
|
||||
#include "image_proc.h"
|
||||
|
||||
#define BMP_PATH ".\\img_files\\0.bmp" // 更改这里即可切换要加载的 BMP
|
||||
#define IMAGE_SCALE 3 // 放大倍数,可改成 1 / 2 / 3 等
|
||||
|
||||
void img_proc(GrayImage *img);
|
||||
#endif
|
||||
Reference in New Issue
Block a user