• 关于结构体字对齐—BMP文件图像处理程序


    最近用C写了个关于BMP文件图像处理的简单程序,结果算法写了不用1个小时搞定,而次要的文件输入输出搞了我半天才搞定。

    主要问题有两点:

    第一,在读取BMP文件的文件头信息放入结构体时,发现中间会漏了2个字节,原因是结构体字对齐,结果导致整体的错位,一个输入66K的图片,输出有178MB。

    解决办法:不将结构体整个一起read、write,而是将其中的每个成员一个一个地read、write。当然,牺牲了效率。

    第二,之前以为BMP灰度图的颜色表信息是没用的,后来查了资料才发现,只有24位深的BMP图才没有颜色表项,对于其他的1、4、8位深还是有用的。

    解决办法:将颜色表项读入内存,然后再写入新图像文件中。对于8bit的BMP灰度图,颜色表就是0 0 0 0 ~ 255 255 255 0的灰度值

    /*********************************以下是关于BMP文件图像处理程序源代码***************************/

    //*********************image.h****************

    #ifndef IMAGE_H
    #define IMAGE_H
    void image_info(FILE* file);
    void image_save(FILE *file);
    void image_smooth(); //图像平滑
    void image_Roberts_sharpen(); //Roberts算法的图像锐化
    void image_Roberts_enhance(); //Roberts算法的图像增强
    void image_median_filter(); //中值滤波
    typedef struct BMP //其实BMP文件头、位图信息头、颜色信息的结构体在<windows.h>头文件中有
    {
    unsigned short bfType; //文件标识 2字节 必须为BM
    unsigned int bfSize; //文件大小 4字节
    unsigned short bfReserved1; //保留,每字节以"00"填写 2字节
    unsigned short bfReserved2; //同上 2字节
    unsigned int bfOffBits; //记录图像数据区的起始位置(图象数据相对于文件头字节的偏移量)。 4字节

    //40字节
    unsigned int biSize; //表示本结构的大小 4字节
    int biWidth; //位图的宽度 4字节
    int biHeight; //位图的高度 4字节
    unsigned short biPlanes; //永远为1 , 2字节
    unsigned short biBitCount; //位图的位数 分为1 4 8 16 24 32 2字节
    unsigned int biCompression; //压缩说明 4字节
    unsigned int biSizeImage; //表示位图数据区域的大小以字节为单位 4字节
    int biXPelsPerMeter; //用象素/米表示的水平分辨率 4字节
    int biYPelsPerMeter; //用象素/米表示的垂直分辨率 4字节
    unsigned int biClrUsed; //位图使用的颜色索引数 4字节
    unsigned int biClrImportant; //对图象显示有重要影响的颜色索引的数目 4字节

    } BMP;

    int color_table_length; //颜色表项数
    int line_byte;
    unsigned char *imagedata;
    unsigned char *temp;
    extern BMP bmp;
    unsigned char *pColorTable;//颜色表指针
    extern unsigned char *pColorTable;//颜色表指针
    extern int line_byte;
    extern int color_table_length;
    extern unsigned char *imagedata;
    extern unsigned char *temp;
    #endif

    //****************image_rw***************

    #include<stdio.h>
    #include<stdlib.h>
    //#include<windows.h>
    #include"image.h"
    void image_info(FILE *file)
    {


    //int times=3; //输入文件名次数。
    char bmp_name[10]; //文件名

    printf("\nplease enter a file name for reading:");
    do
    {
    fflush(stdin);
    gets(bmp_name);
    file=fopen(bmp_name,"rb+"); //打开一个文件进行读写操作。
    if (file==NULL)
    {
    printf("\nerror opening %s for reading! ",bmp_name);
    }
    else
    {
    break;
    }
    }
    while(1);


    //读取图像信息

    fseek(file,0L,0); //读取图像文件类型
    //fread(&bmp,sizeof(struct BMP),1,file);
    fseek(file,0L,0); //图像文件类型
    fread(&(bmp.bfType),sizeof(short),1,file);

    fseek(file,2L,0); //图像文件大小
    fread(&(bmp.bfSize),sizeof(int),1,file);

    fseek(file,6L,0); //图像文件保留字1
    fread(&(bmp.bfReserved1),sizeof(short),1,file);

    fseek(file,8L,0); //图像文件保留字2
    fread(&(bmp.bfReserved2),sizeof(short),1,file);

    fseek(file,10L,0);//数据区的偏移量
    fread(&(bmp.bfOffBits),sizeof(short),1,file);


    fseek(file,14L,0);//文件头结构大小
    fread(&(bmp.biSize),sizeof(int),1,file);


    fseek(file,18L,0);//图像的宽度
    fread(&(bmp.biWidth),sizeof(int),1,file);

    fseek(file,22L,0);//图像的高度
    fread(&(bmp.biHeight),sizeof(int),1,file);


    fseek(file,26L,0);//图像的面数
    fread(&(bmp.biPlanes),sizeof(short),1,file);

    fseek(file,28L,0);//图像一个像素的字节数
    fread(&(bmp.biBitCount),sizeof(short),1,file);

    fseek(file,30L,0);//图像压缩信息
    fread(&(bmp.biCompression),sizeof(short),1,file);

    fseek(file,34L,0);//图像数据区的大小
    fread(&(bmp.biSizeImage),sizeof(int),1,file);

    fseek(file,38L,0);//水平分辨率
    fread(&(bmp.biXPelsPerMeter),sizeof(int),1,file);

    fseek(file,42L,0);//垂直分辨率
    fread(&(bmp.biYPelsPerMeter),sizeof(int),1,file);

    fseek(file,46L,0);//颜色索引数
    fread(&(bmp.biClrUsed),sizeof(int),1,file);

    fseek(file,50L,0);//重要颜色索引数
    fread(&(bmp.biClrImportant),sizeof(int),1,file);

    printf("\n bmp tpye: %x",bmp.bfType);
    printf("\n bmp size: %u",bmp.bfSize);
    printf("\n bmp reserved1: %u",bmp.bfReserved1);
    printf("\n bmp reserved2: %u",bmp.bfReserved2);
    printf("\n bmp offBits: %u",bmp.bfOffBits);

    printf("\n bmp bisize: %u",bmp.biSize);
    printf("\n bmp biWidth: %d",bmp.biWidth);
    printf("\n bmp biHeight: %d",bmp.biHeight);
    printf("\n bmp biplans: %u",bmp.biPlanes);
    printf("\n bmp biBitCount: %u",bmp.biBitCount);
    printf("\n bmp biCompression: %u",bmp.biCompression);
    printf("\n bmp biSizeImage: %u",bmp.biSizeImage);
    printf("\n bmp biXPelsPerMeter: %d",bmp.biXPelsPerMeter);
    printf("\n bmp biYPelsPerMeter: %d",bmp.biYPelsPerMeter);
    printf("\n bmp biClrUsed: %u",bmp.biClrUsed);
    printf("\n bmp biClrImportant: %u\n",bmp.biClrImportant);

    switch(bmp.biBitCount)
    {
    case 1:
    color_table_length = 2;
    break;
    case 4:
    color_table_length = 16;
    break;
    case 8:
    color_table_length = 256;
    break;
    case 24:
    color_table_length = 0;
    break;
    default:
    color_table_length = 0;
    printf("\n wrong biBitCount!");
    }

    line_byte=(( bmp.biWidth*bmp.biBitCount + 31) / 8);//获得图像数据每行的数据个数,Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,

    imagedata=( unsigned char* )malloc( bmp.biSizeImage );
    temp=( unsigned char* )malloc( bmp.biSizeImage );
    pColorTable=(unsigned char*)malloc( color_table_length * 4 );
    fseek(file, 54L, 0);
    fread(pColorTable, sizeof(unsigned char), color_table_length * 4, file);
    fseek(file, (long)bmp.bfOffBits, 0);
    fread(imagedata, sizeof(unsigned char), bmp.biSizeImage, file);
    fseek(file, (long)bmp.bfOffBits, 0);
    fread(temp, sizeof(unsigned char), bmp.biSizeImage, file);

    fclose(file);
    }

    //保存图像
    void image_save(FILE *file)
    {
    //int times=3; //输入文件名次数。
    char bmp_name[10]; //文件名
    //int i; //记录数据区个数

    printf("\nplease enter a file name for writeing:");
    do
    {
    fflush(stdin);
    gets(bmp_name);
    file=fopen(bmp_name,"wb+"); //打开一个文件进行读写操作。
    if (file==NULL)
    {
    printf("\nerror opening %s for writing",bmp_name);
    }
    else
    {
    break;
    }
    }
    while(1);

    //写文件头
    printf("\n%s",bmp_name);
    fseek(file,0L,0); //图像文件类型
    fwrite(&(bmp.bfType),sizeof(short),1,file);
    printf("\n bmp tpye: %x",bmp.bfType);

    fseek(file,2L,0); //图像文件大小
    fwrite(&(bmp.bfSize),sizeof(int),1,file);
    printf("\n bmp size: %d",bmp.bfSize);

    fseek(file,6L,0); //图像文件保留字1
    fwrite(&(bmp.bfReserved1),sizeof(short),1,file);
    printf("\n bmp reserved1: %d",bmp.bfReserved1);

    fseek(file,8L,0); //图像文件保留字2
    fwrite(&(bmp.bfReserved2),sizeof(short),1,file);
    printf("\n bmp reserved2: %d",bmp.bfReserved2);

    fseek(file,10L,0);//数据区的偏移量
    fwrite(&(bmp.bfOffBits),sizeof(short),1,file);
    printf("\n bmp offBits: %d",bmp.bfOffBits);


    fseek(file,14L,0);//文件头结构大小
    fwrite(&(bmp.biSize),sizeof(int),1,file);
    printf("\n bmp bisize: %d",bmp.biSize);


    fseek(file,18L,0);//图像的宽度
    fwrite(&(bmp.biWidth),sizeof(int),1,file);
    printf("\n bmp biWidth: %d",bmp.biWidth);

    fseek(file,22L,0);//图像的高度
    fwrite(&(bmp.biHeight),sizeof(int),1,file);
    printf("\n bmp biHeight: %d",bmp.biHeight);


    fseek(file,26L,0);//图像的面数
    fwrite(&(bmp.biPlanes),sizeof(short),1,file);
    printf("\n bmp biplans: %d",bmp.biPlanes);

    fseek(file,28L,0);//图像一个像素的字节数
    fwrite(&(bmp.biBitCount),sizeof(short),1,file);
    printf("\n bmp biBitCount: %d",bmp.biBitCount);

    fseek(file,30L,0);//图像压缩信息
    fwrite(&(bmp.biCompression),sizeof(short),1,file);
    printf("\n bmp biCompression: %d",bmp.biCompression);

    fseek(file,34L,0);//图像数据区的大小
    fwrite(&(bmp.biSizeImage),sizeof(int),1,file);
    printf("\n bmp biSizeImage: %d",bmp.biSizeImage);

    fseek(file,38L,0);//水平分辨率
    fwrite(&(bmp.biXPelsPerMeter),sizeof(int),1,file);
    printf("\n bmp biXPelsPerMeter: %d",bmp.biXPelsPerMeter);

    fseek(file,42L,0);//垂直分辨率
    fwrite(&(bmp.biYPelsPerMeter),sizeof(int),1,file);
    printf("\n bmp biYPelsPerMeter: %d",bmp.biYPelsPerMeter);

    fseek(file,46L,0);//颜色索引数
    fwrite(&(bmp.biClrUsed),sizeof(int),1,file);
    printf("\n bmp biClrUsed: %d",bmp.biClrUsed);

    fseek(file,50L,0);//重要颜色索引数
    fwrite(&(bmp.biClrImportant),sizeof(int),1,file);
    printf("\n bmp biClrImportant: %d\n",bmp.biClrImportant);

    fseek(file, 54L, 0);
    fwrite(pColorTable, sizeof(unsigned char), color_table_length * 4, file);

    fseek(file,(long)(bmp.bfOffBits),0);
    fwrite(imagedata,sizeof(unsigned char),bmp.biSizeImage,file);

    fclose(file);
    }

    //*****************pixprocess.c***************

    #include<stdio.h>
    #include<stdlib.h>
    #include<math.h>
    #include"image.h"


    //************************homework**********************
    void image_smooth()
    {
    int i,j,tmp;
    for (i=1;i<bmp.biHeight-1;i++)
    {
    for (j=1;j<bmp.biWidth-1;j++)
    {
    tmp = 0;
    tmp += temp[(i-1)*bmp.biWidth + j-1];
    tmp += temp[(i-1)*bmp.biWidth + j];
    tmp += temp[(i-1)*bmp.biWidth + j+1];
    tmp += temp[ i*bmp.biWidth + j-1];
    tmp += temp[ i*bmp.biWidth + j+1];
    tmp += temp[(i+1)*bmp.biWidth + j-1];
    tmp += temp[(i+1)*bmp.biWidth + j];
    tmp += temp[(i+1)*bmp.biWidth + j+1];
    tmp = tmp/9;
    imagedata[ i*bmp.biWidth + j ] =tmp;
    }
    }
    }


    void image_Roberts_sharpen()
    {
    int i,j,tmp;
    for (i=1;i<bmp.biHeight-1;i++)
    {
    for (j=1;j<bmp.biWidth-1;j++)
    {
    tmp = 0;
    tmp += abs( temp[(i+1)*bmp.biWidth + j-1] + 2*temp[(i+1)*bmp.biWidth + j] + temp[(i+1)*bmp.biWidth + j+1] - temp[(i-1)*bmp.biWidth + j-1] - 2*temp[(i-1)*bmp.biWidth + j] - temp[(i-1)*bmp.biWidth + j+1] );
    tmp += abs( temp[(i-1)*bmp.biWidth + j+1] + 2*temp[ i*bmp.biWidth + j+1] + temp[(i+1)*bmp.biWidth + j+1] - temp[(i-1)*bmp.biWidth + j-1] - 2*temp[ i*bmp.biWidth + j-1] - temp[(i+1)*bmp.biWidth + j-1] );
    imagedata[ i*bmp.biWidth + j ] =tmp;
    }
    }
    }

    void image_Roberts_enhance()
    {
    int i,j,tmp;
    for (i=1;i<bmp.biHeight-1;i++)
    {
    for (j=1;j<bmp.biWidth-1;j++)
    {
    tmp = 0;
    tmp += abs( temp[(i+1)*bmp.biWidth + j-1] + 2*temp[(i+1)*bmp.biWidth + j] + temp[(i+1)*bmp.biWidth + j+1] - temp[(i-1)*bmp.biWidth + j-1] - 2*temp[(i-1)*bmp.biWidth + j] - temp[(i-1)*bmp.biWidth + j+1] );
    tmp += abs( temp[(i-1)*bmp.biWidth + j+1] + 2*temp[ i*bmp.biWidth + j+1] + temp[(i+1)*bmp.biWidth + j+1] - temp[(i-1)*bmp.biWidth + j-1] - 2*temp[ i*bmp.biWidth + j-1] - temp[(i+1)*bmp.biWidth + j-1] );
    imagedata[ i*bmp.biWidth + j ] +=tmp;
    }
    }
    }

    void image_median_filter()
    {
    int i,j,k,m;
    unsigned char tmp[9];
    unsigned char change;
    for (i=1;i<bmp.biHeight-1;i++)
    {
    for (j=1;j<bmp.biWidth-1;j++)
    {
    tmp[0] = temp[(i-1)*bmp.biWidth + j-1];
    tmp[1] = temp[(i-1)*bmp.biWidth + j];
    tmp[2] = temp[(i-1)*bmp.biWidth + j+1];
    tmp[3] = temp[ i*bmp.biWidth + j-1];
    tmp[4] = temp[ i*bmp.biWidth + j+1];
    tmp[5] = temp[(i+1)*bmp.biWidth + j-1];
    tmp[6] = temp[(i+1)*bmp.biWidth + j];
    tmp[7] = temp[(i+1)*bmp.biWidth + j+1];
    tmp[8] = temp[ i *bmp.biWidth + j];
    for(k=0; k<9; k++)
    {
    for(m=k; m<9; m++)
    {
    if(tmp[k] > tmp[m])
    {
    change = tmp[k];
    tmp[k] = tmp[m];
    tmp[m] =change;
    }
    }
    }
    imagedata[ i*bmp.biWidth + j ] = tmp[4];
    }
    }
    }

    //***************main.c******************

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<conio.h>
    //#include<windows.h>
    #include"image.h"


    //RGBQUADUAD *pColorTable;//颜色表指针
    BMP bmp;

    int main()
    {
    FILE *file=NULL;
    int choose;
    char go_on;
    do
    {
    image_info(file); //imagedata已经分配了动态内存,但是没有释放

    printf("\n 1.image_smooth");
    printf("\n 2.image_Roberts_sharpen");
    printf("\n 3.image_Roberts_enhance");
    printf("\n 4.image_median_filter");
    printf("\n 5.do nothing");
    //printf("7.image_opposite");

    printf("\nchoose your options:");
    fflush(stdin);
    scanf("%d",&choose);
    switch(choose)
    {
    case 1:
    image_smooth();
    image_save(file);
    case 2:
    image_Roberts_sharpen();
    image_save(file);
    break;
    case 3:
    image_Roberts_enhance();
    image_save(file);
    break;
    case 4:
    image_median_filter();
    image_save(file);
    case 5:
    image_save(file);
    break;
    default:
    printf("\n wrong choose!");

    }
    free(imagedata);
    free(temp);
    free(pColorTable);
    printf("\nlet's go on?(y/n):");
    fflush(stdin);
    scanf("%c",&go_on);
    if (go_on=='n')
    {
    printf("\nbye bye!");
    break;
    }
    }
    while(1);

    return 0;
    }

    /*********************************以下是关于BMP文件结构的内容【百度百科来的】***************************/

    组成

     

      典型的BMP图像文件由四部分组成:

     

      1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;

     

      2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;

     

      3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;

     

      4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

    对应的数据结构

      1:BMP文件组成

     

      BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

     

      2:BMP文件头(14字节)

     

      BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

     

      其结构定义如下:

     

      typedef struct tagBITMAPFILEHEADER

     

      {

     

      WORD bfType; // 位图文件的类型,必须为BM(0-1字节)

     

      DWORD bfSize; // 位图文件的大小,以字节为单位(2-5字节)

     

      WORD bfReserved1; // 位图文件保留字,必须为0(6-7字节)

     

      WORD bfReserved2; // 位图文件保留字,必须为0(8-9字节)

     

      DWORD bfOffBits; // 位图数据的起始位置,以相对于位图(10-13字节)

     

      // 文件头的偏移量表示,以字节为单位

     

      } BITMAPFILEHEADER;

     

      3:位图信息头(40字节)

     

      BMP位图信息头数据用于说明位图的尺寸等信息。

     

      typedef struct tagBITMAPINFOHEADER{

     

      DWORD biSize; // 本结构所占用字节数(14-17字节)

     

      LONG biWidth; // 位图的宽度,以像素为单位(18-21字节)

     

      LONG biHeight; // 位图的高度,以像素为单位(22-25字节)

     

      WORD biPlanes; // 目标设备的级别,必须为1(26-27字节)

     

      WORD biBitCount;// 每个像素所需的位数,必须是1(双色),(28-29字节)

     

      // 4(16色),8(256色)或24(真彩色)之一

     

      DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),(30-33字节)

     

      // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

     

      DWORD biSizeImage; // 位图的大小,以字节为单位(34-37字节)

     

      LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数(38-41字节)

     

      LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数(42-45字节)

     

      DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数(46-49字节)

     

      DWORD biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)

     

      } BITMAPINFOHEADER;

     

      4:颜色表

     

      颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

     

      typedef struct tagRGBQUAD {

     

      BYTE rgbBlue;// 蓝色的亮度(值范围为0-255)

     

      BYTE rgbGreen; // 绿色的亮度(值范围为0-255)

     

      BYTE rgbRed; // 红色的亮度(值范围为0-255)

     

      BYTE rgbReserved;// 保留,必须为0

     

      } RGBQUAD;

     

      颜色表中RGBQUAD结构数据的个数有biBitCount来确定:

     

      当biBitCount=1,4,8时,分别有2,16,256个表项;

     

      当biBitCount=24时,没有颜色表项。

     

      位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:

     

      typedef struct tagBITMAPINFO {

     

      BITMAPINFOHEADER bmiHeader; // 位图信息头

     

      RGBQUAD bmiColors[1]; // 颜色表

     

      } BITMAPINFO;

     

      5:位图数据

     

      位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

     

      当biBitCount=1时,8个像素占1个字节;

     

      当biBitCount=4时,2个像素占1个字节;

     

      当biBitCount=8时,1个像素占1个字节;

     

      当biBitCount=24时,1个像素占3个字节;

     

      Windows规定一个扫描行所占的字节数必须是

     

      4的倍数(即以long为单位),不足的以0填充,

     

      biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

     

      具体数据举例:

     

      如某BMP文件开头:

     

      424D 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 E007 1F00 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....

     

      BMP文件可分为四个部分:位图文件头、位图信息头、彩色板、图像数据阵列,在上图中已用*分隔。

    图像文件头

      1)1:(这里的数字代表的是"字",即两个字节,下同)图像文件头。0x424D=’BM’,表示是Windows支持的BMP格式。

     

      2)2-3:整个文件大小。4690 0000,为00009046h=36934。

     

      3)4-5:保留,必须设置为0。

     

      4)6-7:从文件开始到位图数据之间的偏移量。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。

    位图信息头

      5)8-9:位图图信息头长度。

     

      6)10-11:位图宽度,以像素为单位。8000 0000,为00000080h=128。

     

      7)12-13:位图高度,以像素为单位。9000 0000,为00000090h=144。

     

      8)14:位图的位面数,该值总是1。0100,为0001h=1。

     

      9)15:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。

     

      10)16-17:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3。

     

      11)18-19:用字节数表示的位图数据的大小,该数必须是4的倍数,数值上等于(≥位图宽度的最小的4的倍数)×位图高度×每个像素位数。0090 0000为00009000h=80×90×2h=36864。

     

      12)20-21:用象素/米表示的水平分辨率。A00F 0000为0000 0FA0h=4000。

     

      13)22-23:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。

     

      14)24-25:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。

     

      15)26-27:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。

    彩色板

      16)28-....(不确定):彩色板规范。对于调色板中的每个表项,用下述方法来描述RGB的值:

     

      1字节用于蓝色分量

     

      1字节用于绿色分量

     

      1字节用于红色分量

     

      1字节用于填充符(设置为0)

     

      对于24-位真彩色图像就不使用彩色板,因为位图中的RGB值就代表了每个象素的颜色。

    /**********************************以下是关于结构体对齐的内容【转载来的】*******************************/

    (1)什么是字节对齐

      一个变量占用 n 个字节,则该变量的起始地址必须能够被 n 整除,即: 存放起始地址 % n = 0, 对于结构体而言,这个 n 取其成员种的数据类型占空间的值最大的那个。

    (2)为什么要字节对齐

      内存空间是按照字节来划分的,从理论上说对内存空间的访问可以从任何地址开始,但是在实际上不同架构的CPU为了提高访问内存的速度,就规定了对于某些类型的数据只能从特定的起始位置开始访问。这样就决定了各种数据类型只能按照相应的规则在内存空间中存放,而不能一个接一个的顺序排列。

      举个例子,比如有些平台访问内存地址都从偶数地址开始,对于一个int型(假设32位系统),如果从偶数地址开始的地方存放,这样一个读周期就可以读出这个int数据,但是如果从奇数地址开始的地址存放,就需要两个读周期,并对两次读出的结果的高低字节进行拼凑才能得到这个int数据,这样明显降低了读取的效率。

    (3)如何进行字节对齐

      每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(不指定则取默认值)中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。

      这个规则有点苦涩,可以把这个规则分解一下,前半句的意思先获得对齐值后与指定对齐值进行比较,其中对齐值获得方式如下:

      1. 数据类型的自身对齐值为:对于char型数据,其自身对齐值为1,对于short型为2,对于int, long, float类型,其自身对齐值为4,对于 double 类型其自身对齐值为8,单位为字节。

      2.结构体自身对齐值:其成员中自身对齐值最大的那个值。

      其中指定对齐值获得方式如下:

      #pragma pack (value)时的指定对齐值value。

      未指定则取默认值。

      后半句的意思是主要是针对于结构体的长度而言,因为针对数据类型的成员,它仅有一个对齐参数,其本身的长度、于这个对齐参数,即1倍。对于结构体而言,它可能使用了多种数据类型,那么这句话翻译成对齐规则: 每个成员的起始地址 % 自身对齐值 = 0,如果不等于 0 则先补空字节直至这个表达式成立。

    换句话说,对于结构体而言,结构体在在内存的存放顺序用如下规则即可映射出来:

      (一)每个成员的起始地址 % 每个成员的自身对齐值 = 0,如果不等于 0 则先补空字节直至这个表达式成立;

      (二)结构体的长度必须为结构体的自身对齐值的整数倍,不够就补空字节。

     

      举个例子:

    #pragmapack(8)
    structA{
      chara;
      longb;
    };
    structB{
      chara;
      structAb;
      longc;
    };

      对于 struct A 来说,对于char型数据,其自身对齐值为1,对于long类型,其自身对齐值为4, 结构体的自身对齐值取其成员最大的对齐值,即大小4。那么struct A 在内存中的顺序步骤为:

      (1) char a, 地址范围为0x0000~0x0000,起始地址为0x0000,满足 0x0000 % 1 = 0,这个成员字节对齐了。

      (2) long b, 地址起始位置不能从0x00001开始,因为 0x0001 % 4 != 0, 所以先补空字节,直到0x00003结束,即补3个字节的空字节,从0x00004开始存放b,其地址范围为0x00004~0x0007.

      (3)此时成员都存放结束,结构体长度为8,为结构体自身对齐值的2倍,符合条件(二).

      此时满足条件(一)和条件(二),struct A 中各成员在内存中的位置为:a*** b ,sizeof(struct A) = 8。(每个星号代表一位,成员各自代表自己所占的位,比如a占一位,b占四位)

      对于struct B,里面有个类型为struct A的成员b自身对齐值为4,对于long类型,其自身对齐值为4. 故struct B的自身对齐值为4。那么structB 在内存中的顺序步骤为:

      (1) char a, 地址范围为0x0000~0x0000,起始地址为0x0000,满足 0x0000 % 1 = 0,这个成员字节对齐了。

      (2) struct A b, 地址起始位置不能从0x00001开始,因为 0x0001 % 4 != 0, 所以先补空字节,直到0x00003结束,即补3个字节的空字节,从0x00004开始存放b,其地址范围为0x00004~0x00011.

      (3) long c,地址起始位置从0x000012开始, 因为 0x0012 % 4 = 0,其地址范围为0x00012~0x0015.

      (4)此时成员都存放结束,结构体长度为16,为结构体自身对齐值的4倍,符合条件(二).

      此时满足条件(一)和条件(二),struct B 中各成员在内存中的位置为:a*** b c ,sizeof(struct C) = 24。(每个星号代表一位,成员各自代表自己所占的位,比如a占一位,b占八位,c占四位)

  • 相关阅读:
    【html】【21】高级篇--搜索框
    【html】【20】高级篇--轮播图[聚焦]
    【html】【19】高级篇--大事件时间轴
    【html】【18】高级篇--下拉列表[竖向手风琴]
    【html】【17】高级篇--loading加载
    【html】【16】高级篇--毛玻璃效果[模糊]
    【html】【15】特效篇--分页
    【html】【14】特效篇--侧边栏客服
    【mysql】【分组】后取每组的top2
    【html】【13】特效篇--下拉导航
  • 原文地址:https://www.cnblogs.com/maliqian/p/2416194.html
Copyright © 2020-2023  润新知