在读取BMP图像的时候,主要处理了24位和32位图像,在处理24位BMP图像的时候,BMP图像的数据已经被修改以便4字节自动对齐,
对于24位BMP图像而言,最需要注意的一点是,规定了每条行扫描线的数据大小必须是4的整数倍,如果不是4的整数倍,那么需要在行末端进行补0,否则数据读取将出现偏移,直接导致的结果:会加载出一张倾斜的图像。这个补0的操作叫做数据宽度对齐。
很抽象?举个例子,对于400×400的24位BMP图像而言,行扫描是400px,是4的整数倍,那么无需进行补0操作。如果是30×38(本篇每张麻将牌素材的尺寸),那么行扫描显然不是4的整数倍。对于24位BMP而言,一个像素由RGB三字节组成,那么一个行扫描的total字节是30 × 3 = 90字节,进行数据宽度对齐之后,行扫描的实际total字节是30 × 3 + 2 = 92字节。如此,才能被4整除。换句话说,每一行多出2个无用的字节。这在编程中,需要进行处理丢弃,否则图像再次变形
int channel= 0;
if ( texture->bpp == 24 ){
channel = 3;
texture->imageType = GL_RGB;
}else{
channel = 4;
texture->imageType = GL_RGBA;
}
int biWidth = 0; //每行补齐字节数,如果是24位的话需要补齐成4字节的倍数
if ( (texture->width*channel) % 4 != 0 )
biWidth = 4 - ( (texture->width*channel) % 4 );
我们求出每行自动填充的字节数,先读取数据,然后跳过自动添加的字节数,再接着读取下一行数据
for( int i = 0; i < height; i++ ){
GLubyte* pdest = texture->imageData + i * width * channel;
fread( pdest, 1, width * channel,file );
for( int j = 0; j < width* channel; j+=channel ){
pdest[ j ] ^= pdest[j+2] ^= pdest[j] ^= pdest[j+2]; //将BGR转为RGB,BMP数据从左下角到右上角的方式存储
}
fseek( file, biWidth, SEEK_CUR ); //丢弃补足字节,开始填充下一行
}
读取数据完毕,可以打印检验一下,用WINHEX打开看下,NoPropblem
因为我读取的图片不全是512*512,256*256,.......,所以我用OPENGL生成纹理的时候用了个gluBuild2DMipmaps
BOOL bRes = gluBuild2DMipmaps( GL_TEXTURE_2D, texture->bpp/8, texture->width,texture->height, texture->imageType, GL_UNSIGNED_BYTE, texture->imageData );
画出来后又成斜着的图像了,数据也没问题,只能说是生成MipMap 的时候读取数据跨度有问题,但是我传递的是32位图像的时候,生成的MIPMAP没任何问题,即使图像大小不能被2整除,即非512*512,256*256,.......
所以我做了个比较恶心的做法
if ( bMipmap ){
if ( texture->imageType == GL_RGB ){
GLubyte* data = new GLubyte[texture->width*texture->height*4 ];
int counter = 0;
for( int i = 0; i < texture->width*texture->height*3; i+=3 ){
data[i+counter] = texture->imageData[i];
data[i+1+counter] = texture->imageData[i+1];
data[i+2+counter] = texture->imageData[i+2];
data[i+3+counter] = 1.f;
counter++;
}
BOOL bRes = gluBuild2DMipmaps( GL_TEXTURE_2D, 4, texture->width,texture->height, GL_RGBA, GL_UNSIGNED_BYTE, data );
delete[] data;
}else{
BOOL bRes = gluBuild2DMipmaps( GL_TEXTURE_2D, texture->bpp/8, texture->width,texture->height, texture->imageType, GL_UNSIGNED_BYTE, texture->imageData );
}
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
将24位的图像生成纹理的时候,我把数据转换为32位的就没问题了,一直没更好的办法,请大家不吝指导
题外文章:
BMP文件的结构,从大的分类来看,可以分成2部分:头部信息区和图像数据区。其中头部信息区中,保存了图像的各种属性,如文件格式,图片宽度,调色板等等。过了头部信息区之后,就是用来呈现图像的真正的数据区了。BMP文件属于像素文件,也就是说,数据区中的数据,其实就是记录了图像中每一个像素的颜色,以32位BMP图片来说,每一个像素由ARGB四个字节保存其颜色,其中A是透明度。那么,一副400×400的32位BMP图像,就由160000个像素组成,则,数据区大小=160000×4byte = 640000byte = 640kb,所以也不难怪,BMP图像文件给人的印象就是文件非常大。
那么将BMP文件中的像素逐个读入数据缓冲再显示,是否就能正常显示了呢?显然不是的。前面说了,在文件开头有一块头部信息区,如果把这些数据也一起读进缓冲,那么图像是无法最终显示的。因此,通常载入BMP图像的首要任务是要知道这块头部信息区的大小,也就是数据区的偏移量offset,再利用fseek寻址到这个位置,再进行逐个像素的解析。而头部信息区的大小值貌似在头部信息区的某个字节中有的,只需要读取该字节,便可知道。对于24位和32位的BMP图像而言,这个offset值为0x36,也就是头部信息区的大小是54个字节。
如果你要把加载图像的函数做的通用一些的话,那么图片的宽度和高度也是需要获取的,对于24位BMP图像,这两个值可以分别在0x12和0x16进行寻址得到,注意fread需要读双字,即4字节,否则会出错。
对于24位BMP图像而言,最需要注意的一点是,规定了每条行扫描线的数据大小必须是4的整数倍,如果不是4的整数倍,那么需要在行末端进行补0,否则数据读取将出现偏移,直接导致的结果:会加载出一张倾斜的图像。这个补0的操作叫做数据宽度对齐。
很抽象?举个例子,对于400×400的24位BMP图像而言,行扫描是400px,是4的整数倍,那么无需进行补0操作。如果是30×38(本篇每张麻将牌素材的尺寸),那么行扫描显然不是4的整数倍。对于24位BMP而言,一个像素由RGB三字节组成,那么一个行扫描的total字节是30 × 3 = 90字节,进行数据宽度对齐之后,行扫描的实际total字节是30 × 3 + 2 = 92字节。如此,才能被4整除。换句话说,每一行多出2个无用的字节。这在编程中,需要进行处理丢弃,否则图像再次变形。
最后一个需要注意的小细节是,BMP图像的原点坐标,都是以左下角为基准,向右、向上增加。所以,在编程时,需要对y轴数据做一些小变换。否则将会得到一幅颠倒的图像,此外,BMP的三原色顺序是BGR,注意编程中的处理。
原文地址:BMP文件的结构,从大的分类来看,可以分成2部分:头部信息区和图像数据区。其中头部信息区中,保存了图像的各种属性,如文件格式,图片宽度,调色板等等。过了头部信息区之后,就是用来呈现图像的真正的数据区了。BMP文件属于像素文件,也就是说,数据区中的数据,其实就是记录了图像中每一个像素的颜色,以32位BMP图片来说,每一个像素由ARGB四个字节保存其颜色,其中A是透明度。那么,一副400×400的32位BMP图像,就由160000个像素组成,则,数据区大小=160000×4byte = 640000byte = 640kb,所以也不难怪,BMP图像文件给人的印象就是文件非常大。
那么将BMP文件中的像素逐个读入数据缓冲再显示,是否就能正常显示了呢?显然不是的。前面说了,在文件开头有一块头部信息区,如果把这些数据也一起读进缓冲,那么图像是无法最终显示的。因此,通常载入BMP图像的首要任务是要知道这块头部信息区的大小,也就是数据区的偏移量offset,再利用fseek寻址到这个位置,再进行逐个像素的解析。而头部信息区的大小值貌似在头部信息区的某个字节中有的,只需要读取该字节,便可知道。对于24位和32位的BMP图像而言,这个offset值为0x36,也就是头部信息区的大小是54个字节。
如果你要把加载图像的函数做的通用一些的话,那么图片的宽度和高度也是需要获取的,对于24位BMP图像,这两个值可以分别在0x12和0x16进行寻址得到,注意fread需要读双字,即4字节,否则会出错。
对于24位BMP图像而言,最需要注意的一点是,规定了每条行扫描线的数据大小必须是4的整数倍,如果不是4的整数倍,那么需要在行末端进行补0,否则数据读取将出现偏移,直接导致的结果:会加载出一张倾斜的图像。这个补0的操作叫做数据宽度对齐。
很抽象?举个例子,对于400×400的24位BMP图像而言,行扫描是400px,是4的整数倍,那么无需进行补0操作。如果是30×38(本篇每张麻将牌素材的尺寸),那么行扫描显然不是4的整数倍。对于24位BMP而言,一个像素由RGB三字节组成,那么一个行扫描的total字节是30 × 3 = 90字节,进行数据宽度对齐之后,行扫描的实际total字节是30 × 3 + 2 = 92字节。如此,才能被4整除。换句话说,每一行多出2个无用的字节。这在编程中,需要进行处理丢弃,否则图像再次变形。
最后一个需要注意的小细节是,BMP图像的原点坐标,都是以左下角为基准,向右、向上增加。所以,在编程时,需要对y轴数据做一些小变换。否则将会得到一幅颠倒的图像,此外,BMP的三原色顺序是BGR,注意编程中的处理。
原文地址:
http://naozifangde.blog.163.com/blog/static/1280042642009101614938531/
posted on 2010-05-29 11:22
风轻云淡 阅读(2622)
评论(0) 编辑 收藏 引用 所属分类:
图像读取