位图的读取与保存 C语言 源文件+头文件
有关位图的一些知识:
1、关于颜色表:一般是针对16位以下的图像而设置的,对于16位和16位以上的图像,由于其位图像素数据中直接对对应像素的RGB(A)颜色经行描述,因而省却了调色板。而对于16位以下的图像,由于其位图像素数据中记录的只是调色板索引值,因而需要根据这个索引到调色板去取得相应的RGB(A)颜色,颜色表的作用就是创建调色板。
2、位图的分类:
0,用在JPEG格式中。
1,单色图,调色板中含有两种颜色,也就是黑白图片。
4,16色图
8,256色图,通常说的灰度图。
16,64k图,一般没有调色板,图像数据中每两个字节表示一个像素,5个或6个位表示一个RGB分量。
24,16M真彩色图,无调色板,图像数据中每3个字节表示一个像素,每个字节表示一个RGB分量。
32,4G真彩色,无调色板,每4个字节表示一个像素,相对于24位真彩色图而言,加入了一个透明度,即RGBA模式。
3、关于位图中的字节对其方法:
a、灰度图像:stepWidth = (width + 3)& ~3;
b、16位彩色图:stepWidth = ( width * 3 + 3)& ~3;
4、关于位图的两种形式:底到上型DIB,和顶到下型DIB。底到上型DIB的原点在图像的左下角,而顶到下型DIB的原点在图像的左上角。如果DIB的高度biHeight是一个正值,那么就表示这个DIB是一个底到上型,反之就是顶到下型。(注意:顶到下型DIB位图不能压缩)
.c 源文件
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
void readBmp(const char* fileName, unsigned char** raw, int* width, int* height, int* bitCount, int* stepWidth)
{
BitmapHeader head;
FILE *ffp;
int lineByte, size;
ffp = fopen(fileName, "rb");
if(ffp == 0) return;
fseek(ffp, sizeof(BitmapFileHeader),0);
fread(&head, sizeof(BitmapHeader), 1, ffp);
*width = head.biWidth;
*height = head.biHeight;
*bitCount = head.biBitCount;
*stepWidth = lineByte = (((*width * *bitCount >> 3) + 3) >> 2) << 2;
size = lineByte * *height;
if(*bitCount == 8)
fseek(ffp, 256*sizeof(RGBQUAD1), SEEK_CUR);
*raw = (unsigned char *)malloc(size);
size = fread(*raw, 1, size, ffp);
fclose(ffp);
}
void saveBmp(const char* fileName,unsigned char* raw, int width, int height, int bitCount)
{
BitmapFileHeader fileHead;
BitmapHeader head;
RGBQUAD1 quad[256];
int colorTablesize;
int i;
FILE *file;
int lineBytes;
file = fopen(fileName, "wb");
if(!file) return;
if(!raw) return;
lineBytes = (((width * bitCount >> 3) + 3) >> 2) << 2;
if(bitCount == 8) colorTablesize = 1024;
else colorTablesize = 0;
//申请位图文件头结构变量,填写文件头信息
fileHead.bfType = 0x4D42;//bmp类型
fileHead.bfSize= sizeof(BitmapFileHeader) + sizeof(BitmapHeader)+ colorTablesize + lineBytes* height;
fileHead.bfReserved1 = 0;
fileHead.bfReserved2 = 0;
fileHead.bfOffBits=54+colorTablesize;
fwrite(&fileHead, sizeof(BitmapFileHeader),1, file);
//申请位图信息头结构变量,填写信息头信息
head.biBitCount= bitCount;
head.biClrImportant=0;
head.biClrUsed=0;
head.biCompression=0;
head.biHeight= height;
head.biPlanes=1;
head.biSize=40;
head.biSizeImage= lineBytes * height;
head.biWidth= width;
head.biXPelsPerMeter=0;
head.biYPelsPerMeter=0;
//写位图信息头进内存
fwrite(&head, sizeof(BitmapHeader),1, file);
//如果灰度图像,有颜色表,写入文件
if (head.biBitCount == 8)
{
for (i=0; i<256; i++)
{
quad[i].rgbBlue = i;
quad[i].rgbGreen = i;
quad[i].rgbRed = i;
quad[i].rgbReserved = 0;
fwrite(&quad[i], sizeof(RGBQUAD1), 1, file);
}
}
fwrite(raw, lineBytes * head.biHeight, 1 , file);
fclose(file);
return;
}
.h 头文件
#ifndef __Bmp__H
#define __Bmp__H
#pragma pack(push)
#pragma pack(1)
typedef struct tagBitmapFileHeader
{
short bfType; // 位图文件的类型,必须为BM
int bfSize; // 位图文件的大小,以字节为单位
short bfReserved1; // 位图文件保留字,必须为0
short bfReserved2; // 位图文件保留字,必须为0
int bfOffBits; // 位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位
} BitmapFileHeader, *pBitmapFileHeader;
typedef struct tagRGBQUAD1
{ // rgbq
unsigned char rgbBlue; // 该颜色的蓝色分量
unsigned char rgbGreen; // 该颜色的绿色分量
unsigned char rgbRed; // 该颜色的红色分量
unsigned char rgbReserved; // 保留字节,暂不用
} RGBQUAD1;
//位图信息头
typedef struct tagBitmapInfor
{
int biSize; // 本结构所占用字节数,即sizeof(BITMAPINFOHEADER)
int biWidth; // 位图的宽度,以像素为单位
int biHeight; // 位图的高度,以像素为单位
short biPlanes; // 目标设备的级别,必须为1
short biBitCount; // 每个像素所需的位数,必须是1(双色),4(16色),8(256色)或24(真彩色)之一
int biCompression; // 位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
int biSizeImage; // 位图的大小,以字节为单位
int biXPelsPerMeter; // 位图水平分辨率,每米像素数
int biYPelsPerMeter; // 位图垂直分辨率,每米像素数
int biClrUsed; // 位图实际使用的颜色表中的颜色数
int biClrImportant; // 位图显示过程中重要的颜色数
} BitmapHeader, *pBitmapHeader;
#pragma pack(pop)
void readBmp(const char* fileName, unsigned char** raw, int* width, int* height,int* bitCount, int* stepWidth);
void saveBmp(const char* fileName,unsigned char* raw, int width, int height, int bitCount);
#endif