8位与24位图像的相互转换
原文链接:
http://hi.baidu.com/mayadong7349/blog/item/1b7e2b445f8e9e1c6a63e53a.html
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
FILE *fpSrcBmpfile;
FILE *fpDestBmpfile;
void GetBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER);
void ChangeBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER, WORD);
void SetBmpHeader(const PBITMAPFILEHEADER, const PBITMAPINFOHEADER);
void SetRGBQUAD();
void RgbToGrade(); // 24位真彩色转8位灰度
void GradeToRgb(); // 8位灰度位图转24位真彩色
int main(int argc, char *argv[])
{
BITMAPFILEHEADER bfheader; // bmp文件头
BITMAPINFOHEADER biheader; // 位图信息头
memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
if(argc != 2)
{
puts("\n\t***Error : I need two parameters.");
puts("\t Example: RgbToQuad.exe D:\\flower.bmp");
system("pause>nul");
exit(EXIT_SUCCESS);
}
if((fpSrcBmpfile = fopen(argv[1], "rb")) == NULL) {
perror("\t***Open file failed:(read)");
system("pause>nul");
exit(EXIT_FAILURE);
}
GetBmpHeader(&bfheader, &biheader);
if(bfheader.bfType != 0x4D42) {
puts("\t *End: This file is not bitmap file.");
system("pause>nul");
exit(EXIT_SUCCESS);
}
if(biheader.biBitCount != 24 && biheader.biBitCount != 8) {
puts("\n *End: This bmp file is neither a 24bit nor a 8bit bitmap.");
system("pause>nul");
exit(EXIT_SUCCESS);
}
// 对于采用了游程长度编码方法进行压缩的8位位图 不能按照本算法转为24位位图
if(biheader.biBitCount == 8 && biheader.biCompression != BI_RGB) {
puts("\n *End: This 8bit bmp file is not BI_RGB type");
system("pause>nul");
exit(EXIT_SUCCESS);
}
if((fpDestBmpfile = fopen("D:\\_Done_.bmp", "wb")) == NULL) {
perror("fopen failed :(write)");
system("pause>nul");
exit(EXIT_FAILURE);
}
switch(biheader.biBitCount) {
case 8 : GradeToRgb(); break;
case 24: RgbToGrade(); break;
default: break;
}
fclose(fpDestBmpfile);
fclose(fpSrcBmpfile);
system("pause>nul");
return 0;
}
void GetBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader)
{
fread(pbfheader, sizeof(BITMAPFILEHEADER), 1,fpSrcBmpfile);
fread(pbiheader, sizeof(BITMAPINFOHEADER), 1,fpSrcBmpfile);
}
void ChangeBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader, WORD wType)
{
pbiheader->biBitCount = wType; // 24 或者 8
pbiheader->biClrUsed = (wType == 24) ? 0 : 256;
pbfheader->bfOffBits = 54 + pbiheader->biClrUsed * sizeof(RGBQUAD);
pbiheader->biSizeImage = ((((pbiheader->biWidth * pbiheader->biBitCount) + 31) & ~31) / 8) * pbiheader->biHeight;
pbfheader->bfSize = pbfheader->bfOffBits + pbiheader->biSizeImage;
}
void SetBmpHeader(const PBITMAPFILEHEADER pbfheader, const PBITMAPINFOHEADER pbiheader)
{
fwrite(pbfheader, sizeof(BITMAPFILEHEADER), 1, fpDestBmpfile);
fwrite(pbiheader, sizeof(BITMAPINFOHEADER), 1, fpDestBmpfile);
}
void SetRGBQUAD()
{
int i;
RGBQUAD rgbquad[256];
for(i=0;i<256;i++) {
rgbquad[i].rgbBlue = i;
rgbquad[i].rgbGreen = i;
rgbquad[i].rgbRed = i;
rgbquad[i].rgbReserved = 0;
}
fwrite(rgbquad, 256 * sizeof(RGBQUAD), 1, fpDestBmpfile);
}
void RgbToGrade() {
LONG w, h;
COLORREF rgb;
BYTE r, g, b;
BYTE gray;
BYTE count24, count8;
BYTE Bmpnul = 0;
BITMAPFILEHEADER bfheader; // bmp文件头
BITMAPINFOHEADER biheader; // 位图信息头
memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
rewind(fpSrcBmpfile);
GetBmpHeader(&bfheader, &biheader);
ChangeBmpHeader(&bfheader, &biheader, 8);
SetBmpHeader(&bfheader, &biheader);
SetRGBQUAD();
count24 = ( 4 - ( biheader.biWidth * 3 ) % 4 ) % 4;
count8 = ( 4 - ( biheader.biWidth ) % 4 ) % 4;
for(h=biheader.biHeight-1; h>=0; h--) {
for(w=0; w<biheader.biWidth; w++) {
fread(&rgb, 3, 1, fpSrcBmpfile);
if(feof(fpSrcBmpfile)) {
break;
}
// rgb: 0x00bbggrr
r = GetBValue(rgb);
g = GetGValue(rgb);
b = GetRValue(rgb);
// 参见: http://zhidao.baidu.com/question/152910968.html
gray = (BYTE)( ( 77 * r + 151 * g + 28 * b) >> 8 ); // 24位转8位核心算法
fwrite(&gray, sizeof(gray), 1, fpDestBmpfile);
} // for(w
fseek(fpSrcBmpfile, count24, SEEK_CUR);
fwrite(&Bmpnul, 1, count8, fpDestBmpfile);
} // for(h=...
}
void GradeToRgb()
{
LONG w, h;
COLORREF rgb;
BYTE gray;
BYTE count24, count8; // 24位位图、8位位图每个扫描行需要填充的0的个数
BYTE Bmpnul = 0;
BITMAPFILEHEADER bfheader; // bmp文件头
BITMAPINFOHEADER biheader; // 位图信息头
memset(&bfheader, 0, sizeof(BITMAPFILEHEADER));
memset(&biheader, 0, sizeof(BITMAPINFOHEADER));
rewind(fpSrcBmpfile);
GetBmpHeader(&bfheader, &biheader);
ChangeBmpHeader(&bfheader, &biheader, 24);
SetBmpHeader(&bfheader, &biheader);
fseek(fpSrcBmpfile, 256 * sizeof(RGBQUAD), SEEK_CUR); // 跳过颜色表部分 因为24位位图不需要颜色表
count24 = ( 4 - ( biheader.biWidth * 3 ) % 4 ) % 4;
count8 = ( 4 - ( biheader.biWidth ) % 4 ) % 4;
for(h=biheader.biHeight-1; h>=0; h--) {
for(w=0; w<biheader.biWidth; w++) {
fread(&gray, 1, 1, fpSrcBmpfile);
if(feof(fpSrcBmpfile)) {
break;
}
rgb = RGB(gray, gray, gray); //
8位转24位核心算法
fwrite(&rgb, 3, 1, fpDestBmpfile);
} // for(w
fseek(fpSrcBmpfile, count8, SEEK_CUR);
fwrite(&Bmpnul, 1, count24, fpDestBmpfile);
} // for(h
}