用C语言将bmp 8位灰度图的灰度值缩小16倍,由0-255变成0-16,调色板中数值由255行变成16行,同时调色板rgbBlue rgbRed rgbGreen数值范围由0-255变成0-1。我用c语言实现后,为什么图片不再是灰度图,有了其他颜色???
```#pragma once
#ifndef BMP_H_INCLUDED
#define BMP_H_INCLUDED
#include
#include
#include
#include
#include
#include
typedef unsigned short WORD;//2字节
typedef unsigned long DWORD;//4字节
typedef long LONG;
typedef unsigned char BYTE;
#define pi 3.1415926535
/* 位图文件头结构 14字节 */
typedef struct tagBITMAPFILEHEADER
{ // bmfh
WORD bfType;//位图文件类型,必须为BMP(0-1字节)
DWORD bfSize;//位图文件大小,以字节为单位(2-5字节)
WORD bfReserved1;//位图文件保留字,必须为0(6-7字节)
WORD bfReserved2;//位图文件保留字,必须为0(8-9字节)
DWORD bfOffBits;//位图数据的起始位置,以相对于位图文件头的偏移量表示(10-13字节)
}BITMAPFILEHEADER;
/* 位图信息头结构 40字节 */
typedef struct tagBITMAPINFOHEADER
{ // bmih
DWORD biSize; // 本结构占得字节数(14-17字节),结构长度 40B
LONG biWidth;//位图的宽度,以像素为单位(18-21字节)
LONG biHeight;//位图的高度,以像素为单位(22-25字节)
WORD biPlanes;//颜色面板值必须为1(26-27字节)
WORD biBitCount;// 表示颜色要用到的位数,颜色位值可以是1(双色),(28-29字节)
//4(16色),8(256色),16(64K色,高彩色),24(16M,真彩色),32(4096M增强型真彩色)中的一个
DWORD biCompression;// 压缩格式,必须是0(不压缩)(30-33字节)
//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)或3(Bitfields,位域存放)
DWORD biSizeImage;// 位图的大小,位图占用字节数=biWidth(4的整倍数)*biHeight
LONG biXPelsPerMeter;// 水平分辨率,每米像素数(38-41字节)
LONG biYPelsPerMeter;// 垂直分辨率,每米像素数(42-45字节)
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数,(46-49字节)
DWORD biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)
}BITMAPINFOHEADER;
/* 调色板 4字节 */
//颜色表中RGBQUAD结构数据的个数由biBitCount来确定
//颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
// 当biBitCount=1,4,8时,分别有2,16,256个表项;????????????
// 当biBitCount=24时,没有颜色表项
typedef struct tagRGBQUAD
{ // rgbq
double rgbBlue;//蓝色的亮度(值得范围0-255)
double rgbGreen;//绿色的亮度
double rgbRed;//红色的亮度
double rgbReserved;//保留,必须为0
}RGBQUAD;
//位图数据
//位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,
//扫描行之间是从下到上。位图的一个像素值所占的字节数:
/* 当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;*/
//Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,
/* 定义图像信息 */
typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;//位图信息头
RGBQUAD bmiColors[1];//颜色表
}BITMAPINFO;
/* 定义位图图像 /
typedef struct _Bitmap
{
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
int width;
int height;
int bitCount; // 8 或者24
int imageSize; // 图像数据大小(imageSize=height*widthStep)字节
BYTE imageData; //排列的图像数据,指向存储空间第一个单元的
int widthStep; //排列的图像行大小,不够4的整数倍的就补0
}Bitmap;
/**
- 位图创建函数 创建一个Bitmap结构,并为图像数据分配空间 *
- 使用方法:
- Bitmap bmp=(Bitmap)malloc(sizeof(Bitmap));
-
ret=CreateBitmap(bmp,50,50,3);
/
int CreateBitmap(Bitmap bmp, int width, int height, int bitCount)
{
bmp->width = width;
bmp->height = height;
bmp->bmih.biWidth = width;
bmp->bmih.biHeight = height;bmp->widthStep = (int)((width*bitCount + 31) / 32) * 4; //可是为什么这样计算????????????
//eg:5*5的灰度图像,bitcount=8,则计算出来,widthstep=8,一行的像素个数不够4的倍数的补0
bmp->imageSize = bmp->height*bmp->widthStep*sizeof(BYTE);//计算排列的图像大小sizeof(BYTE)=1if (bitCount == 8)
{
bmp->bitCount = 8;
bmp->bmfh.bfType = 0x4d42; //注意是4d42 这个地方折磨我一下午啊
bmp->bmfh.bfReserved1 = 0;
bmp->bmfh.bfReserved2 = 0;
bmp->bmih.biBitCount = 8;
bmp->bmih.biSize = 40;
bmp->bmih.biPlanes = 1;
bmp->bmfh.bfSize = 54 + 256 * 4 + height*bmp->widthStep;
bmp->bmfh.bfOffBits = 1078;
bmp->bmih.biBitCount = 8;
bmp->bmih.biCompression = 0;
bmp->bmih.biSizeImage = bmp->imageSize;
bmp->bmih.biClrUsed = 0;
bmp->bmih.biClrImportant = 0;
bmp->bmih.biXPelsPerMeter = 0;
bmp->bmih.biYPelsPerMeter = 0;
}
else if (bitCount == 24)
{
bmp->bitCount = 24;
bmp->bmfh.bfType = 0x4d42;
bmp->bmih.biBitCount = 24;
bmp->bmfh.bfReserved1 = 0;
bmp->bmfh.bfReserved2 = 0;
bmp->bmih.biSize = 40;
bmp->bmih.biPlanes = 1;
bmp->bmfh.bfSize = 54 + height*bmp->widthStep;
bmp->bmfh.bfOffBits = 54;
bmp->bmih.biBitCount = 24;
bmp->bmih.biSizeImage = bmp->imageSize;
bmp->bmih.biClrUsed = 0;
bmp->bmih.biCompression = 0;
bmp->bmih.biClrImportant = 0;
bmp->bmih.biXPelsPerMeter = 0;
bmp->bmih.biYPelsPerMeter = 0;
}
else
{
printf("Error(CreateBitmap): only supported 8 or 24 bits bitmap.\n");
return -1;
}bmp->imageData = (BYTE*)malloc(bmp->imageSize); //分配数据空间
if (!(bmp->imageData))
{
printf("Error(CreateBitmap): can not allocate bitmap memory.\n");
return -1;
}
return 0;
}
/**
- 位图指针释放函数 释放位图数据空间 *
- 使用方法:
- ReleaseBitmap(bmp); / void ReleaseBitmap(Bitmap bmp) { free(bmp->imageData); bmp->imageData = NULL; free(bmp); bmp = NULL; }
/**
- 路径检查函数:是否为BMP文件,是否可读
- 正确返回0,错误返回-1 *
- 使用方法
-
ret=CheckPath(path);
*/
int CheckPath(char *path)
{
FILE *fd;
int len = strlen(path) / sizeof(char);
char ext[3];
//check whether the path include the characters "bmp" at end
strncpy(ext, &path[len - 3], 3);
if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p')) {
printf("Error(CheckPath): the extension of the file is not bmp.\n");
return -1;
}//check whether the file can be read or not
fd = fopen(path, "r");
if (!fd)
{
printf("Error(CheckPath): can not open the file.\n");
return -1;
}
fclose(fd);return 0;
}
void ShowImage(char * filepath)
{
char cmd[266];
strcpy(cmd, "start ");
strcat(cmd, filepath);
printf("%s\n", cmd);
system(cmd);
}
/**
- 从文件中读取位图函数
- 正确返回0,错误返回-1 *
- 使用方法:
- bmp=(Bitmap*)malloc(sizeof(Bitmap));
-
ret=ReadBitmap(path, bmp);
/
int ReadBitmap(char path, Bitmap* bmp)
{
int ret;
FILE *fd;//检查路径是否可读
ret = CheckPath(path);
if (ret == -1)
{
printf("Error(ReadRGBBitmap): the path of the image is invalid.\n");
return -1;
}ShowImage(path);
//打开文件
fd = fopen(path, "rb");
if (fd == 0)
{
printf("Error(ReadRGBBitmap): can not open the image.\n");
return -1;
}
//读取文件信息头14字节
fread(&(bmp->bmfh.bfType), sizeof(WORD), 1, fd);
fread(&(bmp->bmfh.bfSize), sizeof(DWORD), 1, fd);
fread(&(bmp->bmfh.bfReserved1), sizeof(WORD), 1, fd);
fread(&(bmp->bmfh.bfReserved2), sizeof(WORD), 1, fd);
fread(&(bmp->bmfh.bfOffBits), sizeof(DWORD), 1, fd);//读取位图信息头40字节
fread(&(bmp->bmih.biSize), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biWidth), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biHeight), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biPlanes), sizeof(WORD), 1, fd);
fread(&(bmp->bmih.biBitCount), sizeof(WORD), 1, fd);
fread(&(bmp->bmih.biCompression), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biSizeImage), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biXPelsPerMeter), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biYPelsPerMeter), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biClrUsed), sizeof(DWORD), 1, fd);
fread(&(bmp->bmih.biClrImportant), sizeof(DWORD), 1, fd);//创建位图结构
ret = CreateBitmap(bmp, bmp->bmih.biWidth, bmp->bmih.biHeight, bmp->bmih.biBitCount);
if (ret == -1)
{
printf("Error(CreateBitmap): can not CreateBitmap.\n");
return -1;
}
//读取图像数据
//由于4字节对齐格式
fseek(fd, bmp->bmfh.bfOffBits, SEEK_SET); //定位到图像数据区
ret = fread(bmp->imageData, bmp->imageSize, 1, fd);
if (ret == 0)
{
if (feof(fd)) //if the file pointer point to the end of the file
{
}
if (ferror(fd)) //if error happened while read the pixel data
{
printf("Error(ReadBitmap): can not read the pixel data.\n");
fclose(fd);
return -1;
}
}
//关闭文件
fclose(fd);
return 0;
}
/**
- 保存位图到文件中去
- 正确返回0,错误返回-1 *
- 使用方法:
- bmp=(Bitmap*)malloc(sizeof(Bitmap));
-
ret=SaveBitmap(path, bmp);
/
int SaveBitmap(char path, Bitmap* bmp, RGBQUAD *map = 0)
{
int ret = 0;
FILE *fd;//检查路径是否正确
int len = strlen(path) / sizeof(char);
char ext[3];
//check whether the path include the characters "bmp" at end
strncpy(ext, &path[len - 3], 3);
if (!(ext[0] == 'b' && ext[1] == 'm' && ext[2] == 'p'))
{
printf("Error(SaveBitmap): the extension of the file is not bmp.\n");
return -1;
}//打开文件
fd = fopen(path, "wb");
if (fd == 0)
{
printf("Error(SaveBitmap): can not open the image.\n");
return -1;
}//保存文件信息头 14字节
fwrite(&(bmp->bmfh.bfType), sizeof(WORD), 1, fd);
fwrite(&(bmp->bmfh.bfSize), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmfh.bfReserved1), sizeof(WORD), 1, fd);
fwrite(&(bmp->bmfh.bfReserved2), sizeof(WORD), 1, fd);
fwrite(&(bmp->bmfh.bfOffBits), sizeof(DWORD), 1, fd);//保存位图信息头 40字节
fwrite(&(bmp->bmih.biSize), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biWidth), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biHeight), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biPlanes), sizeof(WORD), 1, fd);
fwrite(&(bmp->bmih.biBitCount), sizeof(WORD), 1, fd);
fwrite(&(bmp->bmih.biCompression), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biSizeImage), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biXPelsPerMeter), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biYPelsPerMeter), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biClrUsed), sizeof(DWORD), 1, fd);
fwrite(&(bmp->bmih.biClrImportant), sizeof(DWORD), 1, fd);//保存颜色表
if (bmp->bmih.biBitCount == 8)
{
ret = fwrite(map, sizeof(RGBQUAD) , 256, fd);
}
if (ret == -1)
{
printf("Error(SaveBitmap): can not save Color Palette.\n");
return -1;
}//保存图像数据
ret = fwrite(bmp->imageData, bmp->imageSize, 1, fd);
if (ret != 1)
{
printf("Error(SaveBitmap): can not save the pixel data.\n");
return -1;
}//关闭文件
fclose(fd);
return 0;
}
int gray2ind(Bitmap* src, RGBQUAD map, Bitmap dst)
{
int r ,m;
CreateBitmap(dst, src->width, src->height, 8);
//灰度数据缩放
for (int i = 0; i<dst->height; i++)
{
for (int j = 0; j<dst->width; j++)
{
r = *(src->imageData + src->widthStep*(src->height - 1 - i) + j);
m = r / 16;
*(dst->imageData + dst->widthStep*(dst->height - 1 - i) + j) = m;
}
}
for (int i = 0; i<16; ++i) //调色板转换为0-1的小数
{
double gray = 0;
gray = i*0.0667;
(map + i)->rgbBlue = gray;
(map + i)->rgbRed = gray;
(map + i)->rgbGreen = gray;
(map + i)->rgbReserved = 0;
}
return 0;
}
#endif // BMP_H_INCLUDED