当前位置: 首页 > news >正文

C/C++实现bmp文件读写

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

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

  • 实验输入图片864046-20170516093343291-1944922455.png

实验一


#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才对啊存图不对,有错位
    864046-20170516093723869-98222720.png

实验二


#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();
}

相关文章:

  • 后台开发:核心技术与应用实践3.4.1 map是什么
  • 二分法:从一个只包含数字的list中查找某个数
  • 直方图中最大矩形面积
  • 百度有道雅虎的实习面试经历
  • ubuntu下spring环境搭建
  • Java教程收集
  • Xmemcached vs Spymemcached 3th(linux下测试结果和多节点下表现)
  • Linux以GB显示内存大小
  • install ubuntu on Android mobile phone
  • python3学习之练习题
  • 查询缓存和执行流程
  • POJ-3984-迷宫问题-BFS(广搜)-手写队列
  • rowid去重(删除表的重复记录)
  • 完整的solr java api操作代码块
  • scala 学习笔记--闭了个包
  • [case10]使用RSQL实现端到端的动态查询
  • [Vue CLI 3] 配置解析之 css.extract
  • 《剑指offer》分解让复杂问题更简单
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • Druid 在有赞的实践
  • Hibernate【inverse和cascade属性】知识要点
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • Python - 闭包Closure
  • QQ浏览器x5内核的兼容性问题
  • 初识 webpack
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 基于webpack 的 vue 多页架构
  • 面试遇到的一些题
  • 前端面试之CSS3新特性
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 使用权重正则化较少模型过拟合
  • 线性表及其算法(java实现)
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • #define与typedef区别
  • #stm32整理(一)flash读写
  • (10)STL算法之搜索(二) 二分查找
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (读书笔记)Javascript高级程序设计---ECMAScript基础
  • (二)JAVA使用POI操作excel
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (利用IDEA+Maven)定制属于自己的jar包
  • (转)一些感悟
  • .bat批处理出现中文乱码的情况
  • .gitignore文件---让git自动忽略指定文件
  • .net core 依赖注入的基本用发
  • .NET Project Open Day(2011.11.13)
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .NET企业级应用架构设计系列之结尾篇
  • [20170705]lsnrctl status LISTENER_SCAN1
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [C#]winform使用引导APSF和梯度自适应卷积增强夜间雾图像的可见性算法实现夜间雾霾图像的可见度增强