cook-c100/src/app/Module/wjh_BMP.c

274 lines
9.0 KiB
C
Raw Normal View History

2024-08-20 19:34:19 +08:00
/*
* wjh_BMP.c
*
* Created on: 2024<EFBFBD><EFBFBD>7<EFBFBD><EFBFBD>25<EFBFBD><EFBFBD>
* Author: wu
*/
#include "wjh_BMP.h"
// BMP ͷ<>ļ<EFBFBD>
typedef struct {
unsigned char header[100];
unsigned int width;
unsigned int height;
unsigned short bits_per_pixel;
unsigned int data_offset;
unsigned int data_size;
} BMPHeader;
// <20><> BMP <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡͷ<C8A1><CDB7>Ϣ
static void parse_bmp_header(unsigned char *bmp_data, BMPHeader *header) {
u32 offset = bmp_data[13];
offset = offset * 256 + bmp_data[12];
offset = offset * 256 + bmp_data[11];
offset = offset * 256 + bmp_data[10];
memcpy(header->header, bmp_data, offset);
header->width = bmp_data[21];
header->width = header->width * 256 + bmp_data[20];
header->width = header->width * 256 + bmp_data[19];
header->width = header->width * 256 + bmp_data[18];
header->height = bmp_data[25];
header->height = header->height * 256 + bmp_data[24];
header->height = header->height * 256 + bmp_data[23];
header->height = header->height * 256 + bmp_data[22];
header->bits_per_pixel = bmp_data[29];
header->bits_per_pixel = header->bits_per_pixel * 256 + bmp_data[28];
header->data_offset = offset;
header->data_size = bmp_data[37];
header->data_size = header->data_size * 256 + bmp_data[36];
header->data_size = header->data_size * 256 + bmp_data[35];
header->data_size = header->data_size * 256 + bmp_data[34];
}
// <20><> BMP <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡͷ<C8A1><CDB7>Ϣ
static void Set_bmp_header(u8 *scaled_data,u32 new_width,u32 new_height,u32 total) {
scaled_data[18] = new_width % 256;
new_width /= 256;
scaled_data[19] = new_width % 256;
new_width /= 256;
scaled_data[20] = new_width % 256;
new_width /= 256;
scaled_data[21] = new_width % 256;
scaled_data[22] = new_height % 256;
new_height /= 256;
scaled_data[23] = new_height % 256;
new_height /= 256;
scaled_data[24] = new_height % 256;
new_height /= 256;
scaled_data[25] = new_height % 256;
scaled_data[34] = total % 256;
total /= 256;
scaled_data[35] = total % 256;
total /= 256;
scaled_data[36] = total % 256;
total /= 256;
scaled_data[37] = total % 256;
}
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static unsigned short get_pixel(unsigned char *data, int x, int y, int width,int bits_per_pixel) {
int index = y * width + x;
if (bits_per_pixel == 24) {
// 24λBMP
return ((unsigned short *)data)[index];
} else if (bits_per_pixel == 16) {
// 16λR5G6B5 BMP
unsigned short color;
color = data[index * 2]; // <20><>ɫ
color |= (data[index * 2 + 1] << 8); // <20><>ɫ
return color;
} else {
// δ֪λ<D6AA><CEBB>
return 0;
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static void set_pixel(unsigned char *data, int x, int y, int width, int bits_per_pixel, unsigned short color) {
int index = y * width + x;
if (bits_per_pixel == 24) {
// 24λBMP
((unsigned short *)data)[index] = color;
} else if (bits_per_pixel == 16) {
// 16λR5G6B5 BMP
data[index * 2] = color; // <20><>ɫ
data[index * 2 + 1] = color >> 8; // <20><>ɫ
} else {
// δ֪λ<D6AA><CEBB>
return;
}
}
// <20><><EFBFBD>Բ<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>
static unsigned short interpolate(unsigned short a, unsigned short b, float t) {
unsigned short red = ((a >> 11) & 0x1F) * (1 - t) + ((b >> 11) & 0x1F) * t;
unsigned short green = ((a >> 5) & 0x3F) * (1 - t) + ((b >> 5) & 0x3F) * t;
unsigned short blue = (a & 0x1F) * (1 - t) + (b & 0x1F) * t;
return (red << 11) | (green << 5) | blue;
}
// ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static void scale_image_ByEqualRatio(unsigned char *src, unsigned char *dst, BMPHeader *header, float scale) {
int new_width = header->width * scale;
int new_height = header->height * scale;
int y;
for (y = 0; y < new_height; y++) {
int x;
for (x = 0; x < new_width; x++) {
float src_x = x / scale;
float src_y = y / scale;
int x0 = (int)src_x;
int y0 = (int)src_y;
int x1 = x0 + 1;
int y1 = y0 + 1;
if (x1 >= header->width) x1 = header->width - 1;
if (y1 >= header->height) y1 = header->height - 1;
unsigned short p0 = get_pixel(src, x0, y0, header->width,header->bits_per_pixel);
unsigned short p1 = get_pixel(src, x1, y0, header->width,header->bits_per_pixel);
unsigned short p2 = get_pixel(src, x0, y1, header->width,header->bits_per_pixel);
unsigned short p3 = get_pixel(src, x1, y1, header->width,header->bits_per_pixel);
float tx = src_x - x0;
float ty = src_y - y0;
unsigned short interpolated_pixel = interpolate(
interpolate(p0, p1, tx),
interpolate(p2, p3, tx),
ty
);
set_pixel(dst, x, y, new_width,header->bits_per_pixel, interpolated_pixel);
}
}
}
u8* BMP_Scale_Change_ByEqualRatio(u8 *bmp_data,float scale) {
BMPHeader header;
parse_bmp_header(bmp_data, &header);
int new_width = header.width * scale;
int new_height = header.height * scale;
return BMP_Scale_Change(bmp_data,new_width,new_height);
// unsigned char *scaled_data = (unsigned char *)malloc(new_width * new_height * 2 + 54);
//
// for(u32 i = 0;i < 54;i ++){
// scaled_data[i] = header.header[i];
// }
//
// scale_image_ByEqualRatio(bmp_data + header.data_offset, scaled_data + 54, &header, scale);
//
// // <20><><EFBFBD><EFBFBD> BMP ͷ<><CDB7>Ϣ
// Set_bmp_header(scaled_data,new_width,new_height,new_width * new_height * 2);
//
// return scaled_data;
}
// ͼ<><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
static void scale_image(unsigned char *src, unsigned char *dst, BMPHeader *header, int new_width, int new_height) {
int y;
for (y = 0; y < new_height; y++) {
int x;
for (x = 0; x < new_width; x++) {
//<2F><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫӦ<C9AB><D3A6>ͨ<EFBFBD><CDA8>ԭͼ<D4AD>ĸ<EFBFBD>λ<EFBFBD>õ<EFBFBD><C3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD>м<EFBFBD><D0BC><EFBFBD>
float src_x = (float)x * header->width / new_width;
float src_y = (float)y * header->height / new_height;
int x0 = (int)src_x;//ԭͼ<D4AD><CDBC>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>x<EFBFBD><78>
int y0 = (int)src_y;//ԭͼ<D4AD><CDBC>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>y<EFBFBD><79>
int x1 = x0 + 1;//<2F><><EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD><EFBFBD><EFBFBD><E3B7A8><EFBFBD>ţ<EFBFBD><C5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int y1 = y0 + 1;
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3>˷<EFBFBD>Χ<EFBFBD><CEA7><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
if (x1 >= header->width) x1 = header->width - 1;
if (y1 >= header->height) y1 = header->height - 1;
//<2F><>ȡ<EFBFBD>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD>ӵ<EFBFBD>RGBֵ
unsigned short p0 = get_pixel(src, x0, y0, header->width,header->bits_per_pixel);
unsigned short p1 = get_pixel(src, x1, y0, header->width,header->bits_per_pixel);
unsigned short p2 = get_pixel(src, x0, y1, header->width,header->bits_per_pixel);
unsigned short p3 = get_pixel(src, x1, y1, header->width,header->bits_per_pixel);
//<2F>
float tx = src_x - x0;
float ty = src_y - y0;
unsigned short interpolated_pixel = interpolate(
interpolate(p0, p1, tx),//<2F><><EFBFBD><EFBFBD>x<EFBFBD><78><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><D3B5>м<EFBFBD>ֵ
interpolate(p2, p3, tx),//<2F><><EFBFBD><EFBFBD>x<EFBFBD><78><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><D3B5>м<EFBFBD>ֵ
ty
);//<2F><><EFBFBD><EFBFBD>y<EFBFBD><79><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><D3B5>м<EFBFBD>ֵ
set_pixel(dst, x, y, new_width,header->bits_per_pixel, interpolated_pixel);
}
}
}
// <20><><EFBFBD><EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD><EFBFBD>ݵ<EFBFBD>4<EFBFBD>ֽڱ߽<DAB1>
void align_row(unsigned char *row, int width, int bytes_per_pixel) {
int padding = (4 - (width % 4)) % 4;
for (int i = 0; i < padding; ++i) {
row[width + i] = row[width + i - 2];
}
}
//----BMPͼ<50><CDBC><EFBFBD>ݿ<EFBFBD><DDBF>߽<EFBFBD><DFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С-------------------------------------------------------------
//<2F><><EFBFBD><EFBFBD>: <20><>Ŀ<EFBFBD><C4BF>bmp_data<74><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>width<74><68>heigh<67><68>С
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>bmp_data<74><61>ͼƬ<CDBC><C6AC><EFBFBD><EFBFBD> new_width<74><68>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD> new_height<68><74>Ŀ<EFBFBD><C4BF><EFBFBD>߶<EFBFBD>
//<2F><><EFBFBD>أ<EFBFBD><D8A3>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD>ź<EFBFBD><C5BA><EFBFBD>bmpͼƬ<CDBC><C6AC><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>ͷţ<CDB7><C5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//------------------------------------------------------------------------------
u8* BMP_Scale_Change(u8 *bmp_data,u32 new_width,u32 new_height){
BMPHeader header;
parse_bmp_header(bmp_data, &header);
// <20><><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
int stride = header.width * 2; // ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD>ֽ<EFBFBD>
int padding = (4 - (stride % 4)) % 4; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
stride += padding; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
header.width = stride / 2;
unsigned char *aligned_data = NULL;
if(padding != 0){
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µ<EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E9A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
aligned_data = (unsigned char *)malloc(header.height * (header.width + stride) * 2);
for (int y = 0; y < header.height; ++y) {
memcpy(aligned_data + y * stride, bmp_data + header.data_offset + y * header.width * 2, header.width * 2);
align_row(aligned_data + y * stride, stride - padding, 2);
}
}
unsigned char *scaled_data = (unsigned char *)malloc(new_width * new_height * 2 + header.data_offset);
for(u32 i = 0;i < header.data_offset;i ++){
scaled_data[i] = header.header[i];
}
scale_image(padding?aligned_data:(bmp_data + header.data_offset), scaled_data + header.data_offset, &header, new_width, new_height);
if(aligned_data != NULL){
free(aligned_data);
}
// <20><><EFBFBD><EFBFBD> BMP ͷ<><CDB7>Ϣ
Set_bmp_header(scaled_data,new_width,new_height,new_width * new_height * 2);
return scaled_data;
}