• 之前知道点bmp图的格式,然后对8位操作过,然后今天弄了一下24位真彩色的。
  • C++读取、旋转和保存bmp图像文件编程实现
  • 主要是理解bmp文件的格式8/24位的区别
  • 8位图有调色板,24位在文件头和信息头之后就是图像数据区,但是保存24位图的时候,直接在文件头和信息头之后写图像数据,会有图像错位,查看bfOffBits=138 不等于54!

BMP文件格式详解(BMP file format)

  • 实验输入图片

实验一


#include <stdio.h>
#include <stdlib.h> typedef struct
{
//unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} ClBitMapFileHeader; typedef struct
{
unsigned long biSize;
long biWidth;
long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
long biXPelsPerMeter;
long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} ClBitMapInfoHeader; typedef struct
{
unsigned char rgbBlue; //该颜色的蓝色分量
unsigned char rgbGreen; //该颜色的绿色分量
unsigned char rgbRed; //该颜色的红色分量
unsigned char rgbReserved; //保留值
} ClRgbQuad; typedef struct
{
int width;
int height;
int channels;
unsigned char* imageData;
}ClImage; ClImage* clLoadImage(char* path);
bool clSaveImage(char* path, ClImage* bmpImg); ClImage* clLoadImage(char* path)
{
ClImage* bmpImg;
FILE* pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int channels = 1;
int width = 0;
int height = 0;
int step = 0;
int offset = 0;
unsigned char pixVal;
ClRgbQuad* quad;
int i, j, k; bmpImg = (ClImage*)malloc(sizeof(ClImage));
pFile = fopen(path, "rb");
if (!pFile)
{
free(bmpImg);
return NULL;
} fread(&fileType, sizeof(unsigned short), 1, pFile);
if (fileType == 0x4D42) //string "BM"
{
//printf("bmp file! \n"); fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件头信息:\n");
printf("文件大小:%d \n", bmpFileHeader.bfSize);
printf("保留字:%d \n", bmpFileHeader.bfReserved1);
printf("保留字:%d \n", bmpFileHeader.bfReserved2);
printf("位图数据偏移字节数:%d \n", bmpFileHeader.bfOffBits);*/ fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile);
/*printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");
printf("bmp文件信息头\n");
printf("结构体长度:%d \n", bmpInfoHeader.biSize);
printf("位图宽度:%d \n", bmpInfoHeader.biWidth);
printf("位图高度:%d \n", bmpInfoHeader.biHeight);
printf("位图平面数:%d \n", bmpInfoHeader.biPlanes);
printf("颜色位数:%d \n", bmpInfoHeader.biBitCount);
printf("压缩方式:%d \n", bmpInfoHeader.biCompression);
printf("实际位图数据占用的字节数:%d \n", bmpInfoHeader.biSizeImage);
printf("X方向分辨率:%d \n", bmpInfoHeader.biXPelsPerMeter);
printf("Y方向分辨率:%d \n", bmpInfoHeader.biYPelsPerMeter);
printf("使用的颜色数:%d \n", bmpInfoHeader.biClrUsed);
printf("重要颜色数:%d \n", bmpInfoHeader.biClrImportant);
printf("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n");*/ if (bmpInfoHeader.biBitCount == 8)
{
//printf("该文件有调色板,即该位图为非真彩色\n\n");
channels = 1;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight;
offset = (channels*width) % 4;
if (offset != 0)
{
offset = 4 - offset;
}
//bmpImg->mat = kzCreateMat(height, width, 1, 0);
bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 1;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height);
step = channels*width; quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
fread(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad); for (i = 0; i<height; i++)
{
for (j = 0; j<width; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height - 1 - i)*step + j] = pixVal; //每次一个像素处理
}
if (offset != 0)
{
for (j = 0; j<offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpInfoHeader.biBitCount == 24)
{
//printf("该位图为位真彩色\n\n");
channels = 3;
width = bmpInfoHeader.biWidth;
height = bmpInfoHeader.biHeight; bmpImg->width = width;
bmpImg->height = height;
bmpImg->channels = 3;
bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width * 3 * height);
step = channels*width; offset = (channels*width) % 4;
if (offset != 0)
{
offset = 4 - offset;
} fseek(pFile, bmpFileHeader.bfOffBits - sizeof(bmpInfoHeader) - sizeof(bmpFileHeader), SEEK_CUR); //138-54?感觉应该没有138才对啊 for (i = 0; i<height; i++)
{
for (j = 0; j<width; j++)
{
for (k = 0; k<3; k++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
bmpImg->imageData[(height - 1 - i)*step + j * 3 + k] = pixVal; //
}
//kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2]));
}
if (offset != 0)
{
for (j = 0; j<offset; j++)
{
fread(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
} return bmpImg;
} bool clSaveImage(char* path, ClImage* bmpImg)
{
FILE *pFile;
unsigned short fileType;
ClBitMapFileHeader bmpFileHeader;
ClBitMapInfoHeader bmpInfoHeader;
int step;
int offset;
unsigned char pixVal = '\0';
int i, j;
ClRgbQuad* quad; pFile = fopen(path, "wb");
if (!pFile)
{
return false;
} fileType = 0x4D42;
fwrite(&fileType, sizeof(unsigned short), 1, pFile); if (bmpImg->channels == 3)//24位,通道,彩图
{
step = bmpImg->channels*bmpImg->width;
offset = step % 4;
if (offset != 4)
{
step += 4 - offset;
} bmpFileHeader.bfSize = bmpImg->height*step + 54;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile); bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 24;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height*step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile); for (i = bmpImg->height - 1; i>-1; i--)
{
for (j = 0; j<bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3 + 1];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
pixVal = bmpImg->imageData[i*bmpImg->width * 3 + j * 3 + 2];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset != 0)
{
for (j = 0; j<offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
else if (bmpImg->channels == 1)//8位,单通道,灰度图
{
step = bmpImg->width;
offset = step % 4;
if (offset != 4)
{
step += 4 - offset;
} bmpFileHeader.bfSize = 54 + 256 * 4 + bmpImg->width;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = 54 + 256 * 4;
fwrite(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile); bmpInfoHeader.biSize = 40;
bmpInfoHeader.biWidth = bmpImg->width;
bmpInfoHeader.biHeight = bmpImg->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 8;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biSizeImage = bmpImg->height*step;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 256;
bmpInfoHeader.biClrImportant = 256;
fwrite(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile); quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad) * 256);
for (i = 0; i<256; i++)
{
quad[i].rgbBlue = i;
quad[i].rgbGreen = i;
quad[i].rgbRed = i;
quad[i].rgbReserved = 0;
}
fwrite(quad, sizeof(ClRgbQuad), 256, pFile);
free(quad); for (i = bmpImg->height - 1; i>-1; i--)
{
for (j = 0; j<bmpImg->width; j++)
{
pixVal = bmpImg->imageData[i*bmpImg->width + j];
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
if (offset != 0)
{
for (j = 0; j<offset; j++)
{
pixVal = 0;
fwrite(&pixVal, sizeof(unsigned char), 1, pFile);
}
}
}
}
fclose(pFile); return true;
} int main(int argc, char* argv[])
{
ClImage* img = clLoadImage("F:\\RANJIEWEN\\CLQ_C_code\\HOG_SVM_master\\000001.bmp");
bool flag = clSaveImage("E:/result.bmp", img);
if (flag)
{
printf("save ok... \n");
} while (1);
return 0;
}
  • 在存24w位图的时候没有加fseek(pFile, bmpFileHeader.bfOffBits - sizeof(bmpInfoHeader) - sizeof(bmpFileHeader), SEEK_CUR); //138-54?感觉应该没有138才对啊存图不对,有错位

实验二


#include<iostream>
#include <stdlib.h>
#include <windows.h>
#include <fstream>
using namespace std; //---------------------------------------------------------------------------------------
//以下该模块是完成BMP图像(彩色图像是24bit RGB各8bit)的像素获取,并存在文件名为xiang_su_zhi.txt中
unsigned char *pBmpBuf;//读入图像数据的指针 int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD *pColorTable;//颜色表指针 int biBitCount;//图像类型,每像素位数 //-------------------------------------------------------------------------------------------
//读图像的位图数据、宽、高、颜色表及每像素位数等数据进内存,存放在相应的全局变量中
bool readBmp(char *bmpName)
{
FILE *fp = fopen(bmpName, "rb");//二进制读方式打开指定的图像文件 if (fp == 0)
return 0; //跳过位图文件头结构BITMAPFILEHEADER fseek(fp, sizeof(BITMAPFILEHEADER), 0); //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中 BITMAPINFOHEADER head; fread(&head, sizeof(BITMAPINFOHEADER), 1, fp); //获取图像宽、高、每像素所占位数等信息 bmpWidth = head.biWidth; bmpHeight = head.biHeight; biBitCount = head.biBitCount;//定义变量,计算图像每行像素所占的字节数(必须是4的倍数) int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;//灰度图像有颜色表,且颜色表表项为256 if (biBitCount == 8)
{ //申请颜色表所需要的空间,读颜色表进内存 pColorTable = new RGBQUAD[256]; fread(pColorTable, sizeof(RGBQUAD), 256, fp); } //申请位图数据所需要的空间,读位图数据进内存 pBmpBuf = new unsigned char[lineByte * bmpHeight]; fread(pBmpBuf, 1, lineByte * bmpHeight, fp); fclose(fp);//关闭文件 return 1;//读取文件成功
} //-----------------------------------------------------------------------------------------
//给定一个图像位图数据、宽、高、颜色表指针及每像素所占的位数等信息,将其写到指定文件中
bool saveBmp(char *bmpName, unsigned char *imgBuf, int width, int height, int biBitCount, RGBQUAD *pColorTable)
{ //如果位图数据指针为0,则没有数据传入,函数返回 if (!imgBuf)
return 0; //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0 int colorTablesize = 0; if (biBitCount == 8)
colorTablesize = 1024; //待存储图像数据每行字节数为4的倍数 int lineByte = (width * biBitCount / 8 + 3) / 4 * 4; //以二进制写的方式打开文件 FILE *fp = fopen(bmpName, "wb"); if (fp == 0)
return 0; //申请位图文件头结构变量,填写文件头信息 BITMAPFILEHEADER fileHead; fileHead.bfType = 0x4D42;//bmp类型 //bfSize是图像文件4个组成部分之和 fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + colorTablesize + lineByte*height; fileHead.bfReserved1 = 0; fileHead.bfReserved2 = 0; //bfOffBits是图像文件前3个部分所需空间之和 fileHead.bfOffBits = 54 + colorTablesize; //写文件头进文件 fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp); //申请位图信息头结构变量,填写信息头信息 BITMAPINFOHEADER head; head.biBitCount = biBitCount; head.biClrImportant = 0; head.biClrUsed = 0; head.biCompression = 0; head.biHeight = height; head.biPlanes = 1; head.biSize = 40; head.biSizeImage = lineByte*height; head.biWidth = width; head.biXPelsPerMeter = 0; head.biYPelsPerMeter = 0; //写位图信息头进内存 fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp); //如果灰度图像,有颜色表,写入文件 if (biBitCount == 8)
fwrite(pColorTable, sizeof(RGBQUAD), 256, fp); //写位图数据进文件 fwrite(imgBuf, height*lineByte, 1, fp); //关闭文件 fclose(fp); return 1; } //----------------------------------------------------------------------------------------
//以下为像素的读取函数
void doIt()
{ //读入指定BMP文件进内存 char readPath[] = "F:\\RANJIEWEN\\CLQ_C_code\\HOG_SVM_master\\000001.bmp"; readBmp(readPath); //输出图像的信息 cout << "width=" << bmpWidth << " height=" << bmpHeight << " biBitCount=" << biBitCount << endl; //循环变量,图像的坐标 //每行字节数 int lineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4; //循环变量,针对彩色图像,遍历每像素的三个分量 int m = 0, n = 0, count_xiang_su = 0; //将图像左下角1/4部分置成黑色 ofstream outfile("图像像素.txt", ios::in | ios::trunc); if (biBitCount == 8) //对于灰度图像
{
//------------------------------------------------------------------------------------
//以下完成图像的分割成8*8小单元,并把像素值存储到指定文本中。由于BMP图像的像素数据是从
//左下角:由左往右,由上往下逐行扫描的
int L1 = 0;
int hang = 63;
int lie = 0;
//int L2=0;
//int fen_ge=8;
for (int fen_ge_hang = 0; fen_ge_hang<8; fen_ge_hang++)//64*64矩阵行循环
{
for (int fen_ge_lie = 0; fen_ge_lie<8; fen_ge_lie++)//64*64列矩阵循环
{
//--------------------------------------------
for (L1 = hang; L1>hang - 8; L1--)//8*8矩阵行
{
for (int L2 = lie; L2<lie + 8; L2++)//8*8矩阵列
{
m = *(pBmpBuf + L1*lineByte + L2);
outfile << m << " ";
count_xiang_su++;
if (count_xiang_su % 8 == 0)//每8*8矩阵读入文本文件
{
outfile << endl;
}
}
}
//---------------------------------------------
hang = 63 - fen_ge_hang * 8;//64*64矩阵行变换
lie += 8;//64*64矩阵列变换
//该一行(64)由8个8*8矩阵的行组成
}
hang -= 8;//64*64矩阵的列变换
lie = 0;//64*64juzhen
}
} //double xiang_su[2048];
//ofstream outfile("xiang_su_zhi.txt",ios::in|ios::trunc);
if (!outfile)
{
cout << "open error!" << endl;
exit(1);
}
else if (biBitCount == 24)
{//彩色图像
for (int i = 0; i<bmpHeight; i++)
{
for (int j = 0; j<bmpWidth; j++)
{
for (int k = 0; k<3; k++)//每像素RGB三个分量分别置0才变成黑色
{
//*(pBmpBuf+i*lineByte+j*3+k)-=40;
m = *(pBmpBuf + i*lineByte + j * 3 + k);
outfile << m << " ";
count_xiang_su++;
if (count_xiang_su % 8 == 0)
{
outfile << endl;
}
//n++;
}
n++;
} }
cout << "总的像素个素为:" << n << endl;
cout << "----------------------------------------------------" << endl;
} //将图像数据存盘 char writePath[] = "E://nvcpy.BMP";//图片处理后再存储 saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable); //清除缓冲区,pBmpBuf和pColorTable是全局变量,在文件读入时申请的空间 delete[]pBmpBuf; if (biBitCount == 8)
delete[]pColorTable;
} void main()
{
doIt();
}
  • 没有fseek,24位图错位

实验三

  • 我自己使用的8/24分别写成函数的

#include "readbmp.h"
#include "stdio.h"
#include "string.h"
#include "malloc.h" //typedef unsigned short WORD;
//typedef unsigned int DWORD;
//typedef int LONG;
//typedef struct tagBITMAPFILEHEADER {
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
//} BITMAPFILEHEADER;
//typedef struct tagBITMAPINFOHEADER{
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount;
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
//} BITMAPINFOHEADER; #include "windows.h" //BITMAPFILEHEADER包含文件 myMat *loadBitmapFromFile24(const char *filePath, U8 **bits) //24
{
myMat *img;
img = (myMat*)malloc(sizeof(myMat));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
} FILE *fp = fopen(filePath, "rb");
if (fp == NULL) {
exit(-1);
}
BITMAPFILEHEADER bfh;
if (fread(&bfh, sizeof(bfh), 1, fp) != 1) {
fclose(fp);
exit(-1);
}
BITMAPINFOHEADER bih;
if (fread(&bih, sizeof(bih), 1, fp) != 1) {
fclose(fp);
exit(-1);
}
if (bih.biBitCount != 24) {
fclose(fp);
printf("unsupported bitmap format.\n");
exit(-1);
}
int imageSize = (bih.biWidth*3 + 3) / 4 * 4 * bih.biHeight; img->width = bih.biWidth;
img->height = bih.biHeight;
img->type = myCV_8U;
img->dims = 2;
img->channels = 3;
img->step = imageSize / bih.biHeight;
img->totalsize = imageSize;
img->data = (uchar*)malloc(img->totalsize);
img->dataend = img->datalimit = (uchar*)img->data + img->totalsize; fseek(fp, bfh.bfOffBits - sizeof(bfh) - sizeof(bih), SEEK_CUR); //138-54?感觉应该没有138才对啊 if (fread(img->data, 1, imageSize, fp) != imageSize) {
fclose(fp);
exit(-1);
}
fclose(fp); U8 *buffer = (U8 *)malloc(imageSize);
buffer = img->data;
*bits = buffer; return img;
} myMat *loadBitmapFromFile8(const char *filePath, U8 **bits) //----8
{
myMat *img;
img = (myMat*)malloc(sizeof(myMat));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);
} FILE *fp = fopen(filePath, "rb");
if (fp == NULL) {
exit(-1);
}
BITMAPFILEHEADER bfh;
if (fread(&bfh, sizeof(bfh), 1, fp) != 1) {
fclose(fp);
exit(-1);
}
BITMAPINFOHEADER bih;
if (fread(&bih, sizeof(bih), 1, fp) != 1) {
fclose(fp);
exit(-1);
}
if (bih.biBitCount != 8) {
fclose(fp);
printf("unsupported bitmap format.\n");
exit(-1);
}
int imageSize = (bih.biWidth + 3) / 4 * 4 * bih.biHeight; img->width = bih.biWidth;
img->height = bih.biHeight;
img->type = myCV_8U;
img->dims = 2;
img->channels = 1;
img->step = imageSize / bih.biHeight;
img->totalsize = imageSize ;
img->data = (uchar*)malloc(img->totalsize);
img->dataend = img->datalimit = (uchar*)img->data + img->totalsize; fseek(fp, bfh.bfOffBits - sizeof(bfh) - sizeof(bih), SEEK_CUR); U8 *buffer = (U8 *)malloc(imageSize ); if (fread(img->data, 1, imageSize, fp) != imageSize) {
fclose(fp);
exit(-1);
} fclose(fp); *bits = buffer; return img;
} int CreateImage(IplImage_ *_img, int _width, int _height, U8 *_image_data)
{
if (_img->valid)
{
return -1; //这个图像结构体已经有用了
}
if (_width & 3) //是否是4的整数倍
{
_img->width_step = (_width & (~3)) + 4;
}
else
{
_img->width_step = _width;
}
_img->width = _width;
_img->height = _height;
_img->image_data = _image_data;
_img->valid = 1;
return 0;
} void ReleaseImage(IplImage_ *_img)
{
_img->width_step = 0;
_img->width = 0;
_img->height = 0;
_img->image_data = 0;
_img->valid = 0;
} void SaveGrayBitmap24(const char *fileName, const U8 *imageData, int width, int height)
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
DWORD palette[256];
int i, imageSize;
FILE *fp = fopen(fileName, "wb");
int widthS = (width*3 + 3) / 4 * 4;
imageSize = widthS* height; if (fp == NULL)
{
return;
} memset(&bfh, 0, sizeof(bfh));
bfh.bfType = 0x4d42;
bfh.bfSize = imageSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
fwrite(&bfh, sizeof(bfh), 1, fp); memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = 0;
bih.biSizeImage = imageSize;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
fwrite(&bih, sizeof(bih), 1, fp); for (i = 0; i < height; i++)
{
fwrite(imageData + (height - i - 1)*widthS, 1, widthS, fp);
} fclose(fp);
} void SaveGrayBitmap8(const char *fileName, const U8 *imageData, int width, int height) //8
{
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
DWORD palette[256];
int i, imageSize; FILE *fp = fopen(fileName, "wb");
int widthS = (width + 3) / 4 * 4;
imageSize = widthS* height; if (fp == NULL)
{
return;
} memset(&bfh, 0, sizeof(bfh));
bfh.bfType = 0x4d42;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * 4 + imageSize;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * 4;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
fwrite(&bfh, sizeof(bfh), 1, fp); memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = width;
bih.biHeight = height;
bih.biPlanes = 1;
bih.biBitCount = 8;
bih.biCompression = 0;
bih.biSizeImage = imageSize;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
fwrite(&bih, sizeof(bih), 1, fp); for (i = 0; i < 256; i++)
{
palette[i] = (i << 16) | (i << 8) | i;
}
fwrite(palette, sizeof(palette), 1, fp); for (i = 0; i < height; i++)
{
fwrite(imageData + (height - i - 1)*widthS, 1, widthS, fp);
} fclose(fp);
}

实验四

  • C++类实现
void SaveToBmpGray::save(const unsigned char* src, int height, int width, std::string path, std::string name)
{
int imagDataSize = height*width; // imag data size //位图第三部分,调色板
RGBQUAD rgbQuad[256];
for (int i = 0; i < 256; ++i)
{
rgbQuad[i].rgbBlue = (BYTE)i;
rgbQuad[i].rgbGreen = (BYTE)i;
rgbQuad[i].rgbRed = (BYTE)i;
rgbQuad[i].rgbReserved = i;
} //位图第一部分,位图文件头
BITMAPFILEHEADER *bfHeader{ new BITMAPFILEHEADER };
bfHeader->bfType = (WORD)0x4d42; // string"BM"
bfHeader->bfSize = (DWORD)(imagDataSize + sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgbQuad)); // file size
bfHeader->bfReserved1 = 0; // reserved
bfHeader->bfReserved2 = 0; // reserved
bfHeader->bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(rgbQuad)); // real data 位置 //位图第二部分,位图信息头
BITMAPINFOHEADER *biHeader{ new BITMAPINFOHEADER };
biHeader->biSize = sizeof(BITMAPINFOHEADER);
biHeader->biWidth = width;
biHeader->biHeight = -height;//BMP图片从最后一个点开始扫描,显示时图片是倒着的,所以用-height,这样图片就正了
biHeader->biPlanes = 1;//为1,不用改
biHeader->biBitCount = 8; // 每个像素占用的bit
biHeader->biCompression = BI_RGB;//不压缩
biHeader->biSizeImage = imagDataSize;
biHeader->biXPelsPerMeter = 0;//像素每米
biHeader->biYPelsPerMeter = 0;
biHeader->biClrUsed = 0;//已用过的颜色,24位的为0
biHeader->biClrImportant = 0;//每个像素都重要 //打开文件并保存
//文件路径
std::string fpath;
fpath += path;
if (name.empty())
fpath += "IMG_";
else
fpath += name + "_";
SYSTEMTIME st;
GetLocalTime(&st);
char time[20];
sprintf_s(time, sizeof(st), "%4d%2d%2d_%2d%2d%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
for (int i = 0; time[i]; ++i)
{
if (time[i] == ' ') time[i] = '0';
}
fpath += time;
fpath += ".bmp";
std::fstream file(fpath, std::ios::out | std::ios::binary);
file.write((char*)bfHeader, sizeof(BITMAPFILEHEADER));
file.write((char*)biHeader, sizeof(BITMAPINFOHEADER));
file.write((char*)rgbQuad, sizeof(rgbQuad));
file.write((char*)src, imagDataSize);
file.close();
} void SaveToBmp24::save(const unsigned char* src, int height, int width, std::string path, std::string name)
{
int imagDataSize = height*width * 3; // imag data size //位图第一部分,位图文件头
BITMAPFILEHEADER *bfHeader{ new BITMAPFILEHEADER };
bfHeader->bfType = 0x4d42; // string"BM"
bfHeader->bfSize = imagDataSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); // file size
bfHeader->bfReserved1 = 0; // reserved
bfHeader->bfReserved2 = 0; // reserved
bfHeader->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); // real data 位置 //位图第二部分,位图信息头
BITMAPINFOHEADER *biHeader{ new BITMAPINFOHEADER };
biHeader->biSize = sizeof(BITMAPINFOHEADER);
biHeader->biWidth = width;
biHeader->biHeight = height;//BMP图片从最后一个点开始扫描,显示时图片是倒着的,所以用-height,这样图片就正了
biHeader->biPlanes = 1;//为1,不用改
biHeader->biBitCount = 24; // 每个像素占用的bit
biHeader->biCompression = BI_RGB;//不压缩
biHeader->biSizeImage = imagDataSize;
biHeader->biXPelsPerMeter = 0;//像素每米
biHeader->biYPelsPerMeter = 0;
biHeader->biClrUsed = 0;//已用过的颜色,24位的为0
biHeader->biClrImportant = 0;//每个像素都重要 //打开文件并保存
//文件路径
std::string fpath;
fpath += path;
if (name.empty())
fpath += "IMG_";
else
fpath += name + "_";
SYSTEMTIME st;
GetLocalTime(&st);
char time[20];
sprintf_s(time, sizeof(st), "%4d%2d%2d_%2d%2d%2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
for (int i = 0; time[i]; ++i)
{
if (time[i] == ' ') time[i] = '0';
}
fpath += time;
fpath += ".bmp";
std::fstream file(fpath, std::ios::out | std::ios::binary);
file.write((char*)bfHeader, sizeof(BITMAPFILEHEADER));
file.write((char*)biHeader, sizeof(BITMAPINFOHEADER));
file.write((char*)src, imagDataSize);
file.close();
}

C/C++实现bmp文件读写的更多相关文章

  1. 【Win 10 应用开发】文件读写的三种方案

    本文老周就跟伙伴们探讨一下关于文件读写的方法.总得来说嘛,有三种方案可以用,而且每种方案都各有特色,也说不上哪种较好.反正你得记住老祖宗留给我们的大智慧——事无定法,灵活运用者为上. OK,咱们开始吧 ...

  2. Matlab 读取文件夹中所有的bmp文件

    将srcimg文件下的bmp文件转为jpg图像,存放在dstimg文件夹下 str = 'srcimg'; dst = 'dstimg'; file=dir([str,'\*.bmp']); :len ...

  3. c语言文件读写操作总结

    C语言文件读写操作总结 C语言文件操作 一.标准文件的读写 1.文件的打开 fopen() 文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程 ...

  4. ActionScript 3.0入门:Hello World、文件读写、数据存储(SharedObject)、与JS互调

    近期项目中可能要用到Flash存取数据,并与JS互调,所以就看了一下ActionScript 3.0,现把学习结果分享一下,希望对新手有帮助. 目录 ActionScript 3.0简介 Hello ...

  5. Android 文件读写

    一.分类 文件读写作为Android四大数据存储方式之一,又分为内部存储和外部存储两种: (1)内部存储(Internal storage): 总是可用. 文件默认情况存储在/data/data/包名 ...

  6. python基础之文件读写

    python基础之文件读写 本节内容 os模块中文件以及目录的一些方法 文件的操作 目录的操作 1.os模块中文件以及目录的一些方法 python操作文件以及目录可以使用os模块的一些方法如下: 得到 ...

  7. 【Python】[IO编程]文件读写,StringIO和BytesIO,操作文件和目录,序列化

    IO在计算机中指Input/Output,也就是输入和输出. 1.文件读写,1,读文件[使用Python内置函数,open,传入文件名标示符] >>> f = open('/User ...

  8. [转]Android - 文件读写操作 总结

     转自:http://blog.csdn.net/ztp800201/article/details/7322110 Android - 文件读写操作 总结 分类: Android2012-03-05 ...

  9. Windows Phone 八、文件读写IO

    文件存储的类型 •本地应用文件: •ApplicationData.Current.LocalFolder: •漫游应用文件: •ApplicationData.Current.RoamingFold ...

随机推荐

  1. 看云&gitbook 写帮助文档 | 专注于文档在线创作、协作和托管

    看云 写帮助文档 | 专注于文档在线创作.协作和托管 https://www.kancloud.cn/manual/thinkphp/1678 https://www.gitbook.com/

  2. C++静态全局变量和全局变量的区别

      静态全局变量 非静态全局变量 存储方式 静态存储 静态存储 作用域 定义该变量的源文件内 所有源文件 解释: 共同点:全局变量(外部变量)的说明之前再冠以static 就构 成了静态的全局变量.全 ...

  3. java 数据库(二)

    1.SQL概述 1.什么是SQL(了解): 结构化查询语言,是一种功能齐全的数据库语言.在使用它时,只需要发出“做什么”的命令,“怎么做”是不用使用者考虑的 SQL被美国国家标准局(ANSI)确定为关 ...

  4. Gym-101615C-Fear Factoring(数论)

    分析 题意是求 L - R之间的数的因数和 我们知道如果对于一个数 i ( i < k = sqrt(R)),那么一定有一个数 R/i 也是R的因数 遍历 i = 2 - k,然后对于每一个 i ...

  5. [LOJ] 分块九题 7

    区间加法,区间乘法,单点查询. 洛谷线段树2 屡清加法乘法的关系,定义答案为 a*mut+add 对于整块: 新的乘w,mut和add都要乘w 新的加w,add加w //Stay foolish,st ...

  6. 关键css

    参考: 掘金-JS和CSS的位置对资源加载顺序的影响 起舞-什么是关键CSS 有兴趣也可以看看这里一篇关于页面加载的文章.以上掘金那篇文章说css的加载不会影响其他资源的下载,但是我测试了一下,发现是 ...

  7. cetos7 安装telnet

    先执行命令 rpm -qa | grep telnet rpm -qa | grep telnet-server rpm -qa | grep xinetd 如果返回空白就是没有安装 yum inst ...

  8. pwntools各使用模块简介

    pwntools pwntools 是一款专门用于CTF Exploit的python库,能够很方便的进行本地与远程利用的切换,并且里面包含多个模块,使利用变得简单.可以在github上直接搜索pwn ...

  9. Nowcoder 106 C.Professional Manager(统计并查集的个数)

    题意: 给出四种操作: 1. 合并u,v两棵树 2. 从u所在的集合中删除u 3. 询问u所在集合有多少颗树 4. 询问 u,v是否在同一个集合 分析: 对于删除操作, 只要新开一个点代替原来的点即可 ...

  10. 大数据学习——linux常用命令(四)

    四 查到命令 1 查找可执行的命令所在的路径 which ls 查ls命令所在的路径 2 查找可执行的命令和帮助的位置 whereiis ls 3 从某个文件夹开始查找文件 find / -name ...