颜色的表示和mrp的加密bmp图

在开始之前,我们需要了解:在计算机中我们怎样表示颜色。 
我们知道,色光的三原色是红绿蓝。 
如果你用放大镜观察你的手机屏幕,你会发现它的每一个像素都是由紧挨着的红色、绿色和蓝色的小点组成。如果你的放大倍数足够高,你甚至还能够明显地看到显示不同颜色的像素三点发光的亮度是不一样的。比如,显示红色的像素绿色和蓝色明显很暗,而白色则是红绿蓝都很亮。 
于是我们得到了颜色的通用表示方法:红绿蓝亮度,简称RGB。R,Red,三原色中的红色。G,Green,绿色。B,Blue,蓝色,每种原色都分为从0到255共256个亮度级,用十六进制表示就是00到FF。于是,我们便可以用这种方法表示的颜色多达255*255*255=16777216种!这也就是我们通常说的16万色了。 
RGB的10进制写法: 
rgb(0,255,0) 
在显示时,像素中红和蓝点都不发光,只绿色发光,所以我们看到满屏幕刺眼的绿。 
你也可以用十六进制表示: 
#00FF00 
其中第一个00是红,紧接着FF是绿,后面的00是蓝。F=15,所以FF=15*16+15=255。 

在bmp中,如果我们分别用1个字节存储红绿蓝(1个字节就是十进制0到255,十六进制00到FF,二进制00000000到11111111),这样一个像素就是3字节,也就是24位(一字节八位,上面的八个1)。所以这就是24位bmp图。
24位bmp的效果很好,很清晰。可是,它太大了。即使一张铺满屏幕的240*320背景图,也会用掉240*320*3B=230400B=225KB的内存!而mrp中可给软件自行分配的内存也就300KB左右,显示一张背景图就内存不足了,软件还怎么运行??所以,我们得压缩!于是,bmp565出现了。
bmp565中的565,即R5G6B5,也就是红和蓝用5位存储,而绿色用6位存储(据说人眼对绿色最敏感)。5+6+5=16位,这就是所谓的16位bmp图啦。二进制11111(5位二进制的最大值)=31,111111=63,所以我们要把R5G6B5还原成RGB颜色值,只要用R*8,G*4,B*8就可以了。这样做会导致颜色失真(R5G6B5存储时就已经失真了),因为31*8=248,63*4=252,而达不到255了。
mrp的bmp565没有文件头,它的前两个字节就是图片左上角的R5G6B5值(注意是以Little Endian(LE,小尾)存储的,如果你在十六进制里看到BF 73,得倒过来变成73 BF,然后才能继续计算),从左至右,从上到下依次存储,而且没有填充用的多余字节。
逐像素显示这种bmp时,我们每次读取两字节,换算出真实RGB后画在屏幕上。如果到达宽度限制(这个宽度是你在显示时决定的,一般就是图片处理前的宽度),就换下一行继续画,直到画完所有字节。
可是,麻烦又来了,看下面两个字节:
00000111 11100000
其中六个1是绿色,其他0是红和蓝。我们悲剧地发现,绿色的值居然分布在了两个字节之间,该怎么把它们分离出来呢?通过常规的+-*/似乎难以做到。所以我们要使用新的操作符,使用那些起初令你费解的“位运算符”就可以实现了。
$fp=fopen('test.bmp','r'); //打开文件
$rgb=fread($fp,2); //读两字节
$rgb=unpack('v',$rgb); //转换成整数。悲剧的是该函数返回一个数组
$rgb=$rgb[0]; //把值从数组中取回来
$b=$rgb & 0x1F; //取得蓝色的亮度
  &  按位与
A=11100110
B=00001111
C=00000110
A与B是位与的操作数,C便是结果。
位于的过程如下:
取A的倒数第一位(0)和B的倒数第一位(1),判断。如果两个都是1,那么结果的倒数第一位就是1,否则结果的倒数第一位是0。然后再判断倒数第二位,倒数第三位……
位与的作用,就是保留字节集中自己需要的部分,把其他部分置为0(去除)。比如,任何东东与B进行位与的结果都是只保留后4位。
而在程序中,$rgb & 0x1F的结果就是保留后5位,因为0x1F=00000000 00011111。于是我们得到了蓝色的值。
现在我们来取得绿色。
$g=$rgb >>> 5 & 0x3F;
<<<和>>>是位移操作符(左移和右移),上例子:
A=10011110
A=A>>>5
(A=100,右边的5位没了)
A=A<<<3
(A=100000,右边补3个0)
所以$rgb右移5位之后蓝色就被移没啦(00000111111),再位与0x3F(111111)是为了去掉红色的值。当然这里红色就是0,没位与也一样,不过若是红色不为0,那位与就很重要了。
现在取红色,相信你已经会了,
$r=$rgb >>> 11;
5+6=11,现在只剩红色了,不需要掩码了。
把R5G6B5颜色转换成RGB颜色,可以
$r*=8;$g*=4;$b*=8;//$r*=8即$r=$r*8;
或者用位移:
$r=$r<<<3; $g=$g<<<2; $b=$b<<<3;//效果是一样一样的
好了,现在你就可以把点画在你需要的位置上了。
然后,$rgb=fread($fp,2);(文件指针会自己移动),继续。
可以用这种方式把bmp565画在GD图形库的画布上,然后转成jpg/gif/png。也可以把jpg/gif/png载入到画布,得到rgb后再反向处理(左移改成右移,unpack改成pack。注意pack不返回数组)得到字节按顺序写入bmp文件,便得到了mrp可用的bmp565现在取红色,相信你已经会了,
$r=$rgb >>> 11;
5+6=11,现在只剩红色了,不需要掩码了。
把R5G6B5颜色转换成RGB颜色,可以
$r*=8;$g*=4;$b*=8;//$r*=8即$r=$r*8;
或者用位移:
$r=$r<<<3; $g=$g<<<2; $b=$b<<<3;//效果是一样一样的
好了,现在你就可以把点画在你需要的位置上了。
然后,$rgb=fread($fp,2);(文件指针会自己移动),继续。
可以用这种方式把bmp565画在GD图形库的画布上,然后转成jpg/gif/png。也可以把jpg/gif/png载入到画布,得到rgb后再反向处理(左移改成右移,unpack改成pack。注意pack不返回数组)得到字节按顺序写入bmp文件,便得到了mrp可用的bmp565

Q浏一不注意就发重
回复列表(6|隐藏机器人聊天)
  • @Ta / 2011-06-15 / /
    能不能把帖子下载下来?你写的都很好,可有时帖子要用了难得找到,甚至丢失
  • @Ta / 2011-06-15 / /
    在别处复制的。
    老虎会自己写吗?
  • @Ta / 2011-06-15 / /
    那好吧,我不复制了,剩下的部分由二楼来补完:)
  • @Ta / 2011-06-15 / /
    那好吧,我不复制了,剩下的部分由二楼来补完:)
  • @Ta / 2011-06-15 / /
    老虎别啊,别理他啊,他有本事他自己写!老虎你继续啊!我很需要啊!求你了!
  • @Ta / 2011-06-15 / /
    你还没说怎样把
    00000111 11100000
    位与成绿色值啊?
添加新回复
回复需要登录