用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;
/**
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)=1
if (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;
}
/**
/**
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);
}
/**
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;
}
/**
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
問題是,調色板 r g b三值相等啊,還有怎麼會變三通道呢