网站公告列表

  没有公告

加入收藏
设为首页
联系站长
您现在的位置: 61IC中国电子在线 >> 技术文库 >> 嵌入式 >> 文章正文
  BMP文件读写程序       ★★★ 【字体:
BMP文件读写程序
作者:61IC录入    文章来源:本站原创    点击数:    更新时间:2006-4-15    

bmpTest.h   : 介绍BMP文件的格式及结构定义

bmpTest.cpp : 24bitBMP颜色数据到256色位图颜色数据的转换函数实现,具体算法可参考以 前的一个帖子

bmpTransfer.cpp  :  读入一个24bitBMP文件,转换成一个256BMP文件的程序

 

编译完成后得到的程序,如bmpTransfer.exe

执行  bmpTransfer file1 file2

file124bitBMP位图源文件名,file2是新生成的256色位图文件名

 

可以用windows画板程序查看结果,似乎比直接用画板程序将24bitBMP存成256BMP文件的转换效果要好哦。

 

/*************

   bmpTest.h

**************/

#ifndef __BMPTEST_H_

#define __BMPTEST_H_

 

#include <stdio.h>

 

typedef unsigned char  BYTE;

typedef unsigned short WORD;

 

 

// BMP图像各部分说明如下

 

/***********

    第一部分    位图文件头

该结构的长度是固定的,为14个字节,各个域的依次如下:

    2byte   :文件类型,必须是0x4d42,即字符串"BM"

    4byte   :整个文件大小

    4byte   :保留字,为0

    4byte   :从文件头到实际的位图图像数据的偏移字节数。

*************/

 

typedef struct

{

    long imageSize;

    long blank;

    long startPosition;

    void show(void)

    {

        printf("BMP Head:\n");

        printf("Image Size:%d\n",imageSize);

        printf("Image Data Start Position : %d\n",startPosition);

    }

}BmpHead;

 

/*********************

 

/*********************

    第二部分    位图信息头

该结构的长度也是固定的,为40个字节,各个域的依次说明如下:

    4byte   :本结构的长度,值为40

    4byte   :图像的宽度是多少象素。

    4byte   :图像的高度是多少象素。

    2Byte   :必须是1

    2Byte   :表示颜色时用到的位数,常用的值为1(黑白二色图)4(16色图)8(256色图)24(真彩色图)

    4byte   :指定位图是否压缩,有效值为BI_RGBBI_RLE8BI_RLE4BI_BITFIELDSWindows位图可采用RLE4RLE8的压缩格式,BI_RGB表示不压缩。

    4byte   :指定实际的位图图像数据占用的字节数,可用以下的公式计算出来:

              图像数据 = Width' * Height * 表示每个象素颜色占用的byte(即颜色位数/8,24bit图为3256色为1

              要注意的是:上述公式中的biWidth'必须是4的整数倍(不是biWidth,而是大于或等于biWidth的最小4的整数倍)

              如果biCompressionBI_RGB,则该项可能为0

    4byte   :目标设备的水平分辨率。

    4byte   :目标设备的垂直分辨率。

    4byte   :本图像实际用到的颜色数,如果该值为0,则用到的颜色数为2(颜色位数)次幂,如颜色位数为82^8=256,256色的位图

    4byte   :指定本图像中重要的颜色数,如果该值为0,则认为所有的颜色都是重要的。

***********************************/

typedef struct

{

    long    Length;

    long    width;

    long    height;

    WORD    colorPlane;

    WORD    bitColor;

    long    zipFormat;

    long    realSize;

    long    xPels;

    long    yPels;

    long    colorUse;

    long    colorImportant;

    void show(void)

    {     

        printf("infoHead Length:%d\n",Length);

        printf("width&height:%d*%d\n",width,height); 

        printf("colorPlane:%d\n",colorPlane);

        printf("bitColor:%d\n",bitColor);

        printf("Compression Format:%d\n",zipFormat);

        printf("Image Real Size:%d\n",realSize);

        printf("Pels(X,Y):(%d,%d)\n",xPels,yPels);

        printf("colorUse:%d\n",colorUse);     

        printf("Important Color:%d\n",colorImportant);

    }

}InfoHead;

 

/***************************

/***************************

    第三部分    调色盘结构

    对于256BMP位图,颜色位数为8,需要2^8 = 256个调色盘;

    对于24bitBMP位图,各象素RGB值直接保存在图像数据区,不需要调色盘,不存在调色盘区

    rgbBlue   该颜色的蓝色分量。

    rgbGreen  该颜色的绿色分量。

    rgbRed    该颜色的红色分量。

    rgbReserved:保留值。

************************/

typedef struct

{

         BYTE   rgbBlue;

         BYTE   rgbGreen;

         BYTE   rgbRed;

         BYTE   rgbReserved;

         void show(void)

         {

            printf("Mix Plate B,G,R:%d %d %d\n",rgbBlue,rgbGreen,rgbRed);

         }

}RGBMixPlate;

 

/****************************

 

/****************************

    第四部分    图像数据区

    对于用到调色板的位图,图像数据就是该象素颜色在调色板中的索引值;

    对于真彩色图,图像数据就是实际的RGB值。

        2色图,用1位就可以表示该象素的颜色,所以1个字节可以表示8个象素。

        16色图,用4位可以表示一个象素的颜色,所以1个字节可以表示2个象素。

        256色图,1个字节刚好可以表示1个象素。

        真彩色图,3个字节才能表示1个象素。       

****************************/

 

 

//24bit的象素颜色数据转换为256色图的图像数据(即索引值)

int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor);

 

#endif

 

/***************

    bmpTest.cpp

****************/

#include "bmpTest.h"

#include <string.h>

#include <assert.h>

 

//计算平方差的函数

int PFC(int color1, int color2)

{

    int x,y,z;

    x = (color1 & 0xf) - (color2 & 0xf);

    y = ((color1>>4) & 0xf) - ((color2>>4) & 0xf);

    z = ((color1>>8) & 0xf) - ((color2>>8) & 0xf);

    return (x*x + y*y + z*z);

};

 

//直接插入排序

int Sort1(int *src, int *attach, int n)

{

    int cur, cur1;

    int i,j,k=0;

    for (i = 1; i < n; i++)

    {

        cur     = src;

        cur1 = attach;

        for (j = i - 1; j >= 0; j--)

        {

            if (cur > src[j])

            {

                src[j+1]    = src[j];

                attach[j+1] = attach[j];

            }

            else

                break;

        }

        src[j+1]  = cur;

        attach[j+1] = cur1;

    }

    return 0;

}

 

//快速排序

int Sort2(int *src, int *attach, int n)

{

    if (n <= 12)

        return Sort1(src, attach, n);

    int low = 1, high = n - 1;

    int tmp;

    while (low <= high)

    {

        while (src[low] >= src[0])

        {

            if (++low > n - 1)

                break;

        }

        while (src[high] < src[0])

        {

            if (--high < 1)

                break;

        }

        if (low > high)

            break;

        {

            tmp                = src[low];

            src[low]        = src[high];

            src[high]        = tmp;

            tmp                = attach[low];

            attach[low]        = attach[high];

            attach[high]    = tmp;

        }

        low++;

        high--;

    }

 

    

    {

        tmp                = src[low - 1];

        src[low - 1]    = src[0];

        src[0]            = tmp;

        tmp                = attach[low - 1];

        attach[low - 1]    = attach[0];

        attach[0]        = tmp;

    }

    if (low > 1)

        Sort2(src, attach, low - 1);

    if (low < n)

        Sort2(&src[low], &attach[low], n - low);

    return 0;

}

 

//24bit的象素颜色数据转换为256色图的图像数据(即索引值)

int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor)

{

    int usedTimes[4096] = {0};

    int miniColor[4096];

    for (int i = 0; i < 4096; i++)

        miniColor = i;

    i = 0;

    for (i = 0; i < len; i++)

    {

        assert(color24bit < 4096);

        usedTimes[color24bit]++;

    }

 

    int numberOfColors = 0;

    for (i = 0; i < 4096; i++)

    {

        if (usedTimes > 0)

            numberOfColors++;

    }

 

    //usedTimes进行排序,排序过程中minColor数组(保存了颜色值)也作与useTimes

    //数组相似的交换

    Sort2(usedTimes, miniColor, 4096);

 

    //usedTimes数组中是各颜色使用频率,从高到低排列,显然第numberOfColor个之后的都为0

    //miniColor数组中是相应的颜色数据

    //将前256个颜色数据保存到256色位图的调色盘中

    for (i = 0; i < 256; i++)

    {

        mainColor.rgbBlue    = (BYTE)((miniColor>>8)<<4);

        mainColor.rgbGreen    = (BYTE)(((miniColor>>4) & 0xf)<<4);

        mainColor.rgbRed        = (BYTE)((miniColor & 0xf)<<4);

        mainColor.rgbReserved = 0;

    }

 

    int *colorIndex = usedTimes;//用原来的useTimes数组来保存索引值

    memset(colorIndex, 0, sizeof(int) * 4096);

   

    if (numberOfColors <= 256)

    {

        for (i = 0; i < numberOfColors; i++)

            colorIndex[miniColor] = i;

    }

    else//为第256之后的颜色在前256种颜色中找一个最接近的

    {

        for (i = 0; i < 256; i++)

            colorIndex[miniColor] = i;

       

        int index, tmp, tmp1;

        for (i = 256; i < numberOfColors; i++)

        {

            tmp      = PFC(miniColor[0], miniColor);

            index = 0;

            for (int j = 1; j < 256; j++)

            {

                tmp1 = PFC(miniColor[j], miniColor);

                if (tmp > tmp1)

                {

                    tmp = tmp1;

                    index = j;

                }

            }

            colorIndex[miniColor] = index;