274 lines
9.0 KiB
C
274 lines
9.0 KiB
C
|
/*
|
|||
|
* 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;
|
|||
|
}
|