随笔 - 132  文章 - 51  trackbacks - 0
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(7)

随笔分类

随笔档案

文章分类

文章档案

cocos2d-x

OGRE

OPenGL

搜索

  •  

最新评论

阅读排行榜

评论排行榜

      在读取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 );
            
我们求出每行自动填充的字节数,先读取数据,然后跳过自动添加的字节数,再接着读取下一行数据
            forint i = 0; i < height; i++ ){
                GLubyte
* pdest = texture->imageData + i * width * channel;
                fread( pdest, 
1, width * channel,file );

                
forint 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;
            
forint 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 风轻云淡 阅读(2584) 评论(0)  编辑 收藏 引用 所属分类: 图像读取

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理