注册 登录
编程论坛 C图形专区

[求助]怎么获取64K色图形模式下的某点颜色值

cdmalcl 发布于 2006-07-29 13:57, 3726 次点击

256 还是 16色图形模式下的某点颜色值用getpixel获取就行
可是在64K色的图形模式下这种方法肯定是不行的
那用什么方法能获取呢?

37 回复
#2
jig2006-07-29 19:40
你要读取颜色值,也只是直接读显存就可以了,LZ可以去看看NEO中的 get_dot() 函数,你马上就能明白到底是怎么做的
#3
cdmalcl2006-09-01 17:09

最近才有时间弄这个~~


NEO里的那个我没弄明白!
我做了个程序,在没用NEO库下做的获取颜色,BZ看一下:
#include <dos.h>
#include <graphics.h>

typedef struct
{
unsigned char b;
unsigned char g;
unsigned char r;
}
rgb16M;

int huge Return_SVGA64K(void)
{
return(3);
}

void putpoint(int x, int y, rgb16M color)
{
setrgbpalette(1026, color.r >> 3, color.g >> 2, color.b >> 3);
putpixel(x, y, 0);
}

void init64k()
{
int gd=DETECT,gm=0;
installuserdriver("Svga64K", Return_SVGA64K);
initgraph(&gd, &gm, "");
}

main()
{
int x,y;
int page,get;
long addr;
rgb16M color;
int far *videoptr = (int far *)MK_FP(0xa000, 0);

init64k();
for(x=0;x<getmaxx();x++)
for(y=0;y<getmaxy();y++)
{
color.r=8;
color.g=3;
color.b=8;
putpoint(x,y,color);
}
x=123;
y=45;
page = (int)((addr = ((long)y + 0) * 640 + x) >> 15);

_BX = 0;
_DX =page;
_AX = 0x4f05;
__int__(0x10);

get=*(videoptr + (unsigned)(addr & 0xffff));

getch();
closegraph();
printf("%d",get);
getch();
}

好象的确获取了颜色值!
但是怎么把获取的那个颜色值转化回去啊?
怎么我改了好几个color值后获取的get值都是一样的?
例如:
color.r=1 把这个1改为0或者2~7 get都是0?
color.b=0
color.g=0

#4
一笔苍穹2006-09-02 11:14
因为color.r &gt;&gt; 3将分量压缩了,造成了几个原本不同的颜色值在实际运用中读出来的值却一样的情况。
#5
cdmalcl2006-09-02 17:15

那就是说其实颜色种类并不是64K种拉!

#6
一笔苍穹2006-09-04 15:58
是啊,共65536种颜色:
color.r >> 3将颜色压缩了3个位,还剩下5位,能用来表示2的5次方级数的红色分量,共32级;
同样的color.g >> 2压缩了2位,还剩6位,就能表示2的6次方即64级绿色;
color.b >> 3可表示32级兰色。
三原色组合起来就是32 * 64 * 32 = 65536
这是具体的计算方法,其实两个字节的int型无符号变量本来就能表示2的16次方也就是65536个数嘛。
#7
一笔苍穹2006-09-04 16:03

所以这个压缩是指将颜色从24位(真彩,R:G:B=8:8:8,共16777216色)转换成16位(高彩,R:G:B=5:6:5,共65536色),很明显这两个总数相差太大,所以最后每个高彩值都会和好几个真彩值相对应,也就是在真彩模式下能表现出来的颜色过渡细节在高彩下会丢失一些,因为每相邻接近的几级颜色都被压缩成了高彩中的一个,缺失掉了。

#8
cdmalcl2006-09-04 17:07

多谢多谢!

但是这个问题也体现我的学习态度还是不好!
这个问题自己仔细算一下应该明白!

#9
cdmalcl2006-09-06 21:02

郁闷
怎么在显示图片后获取的值是负值?!
#10
cdmalcl2006-09-06 21:26

#include <dos.h>
#include <graphics.h>

typedef struct
{
unsigned char b;
unsigned char g;
unsigned char r;
}
rgb16M;

int huge Return_SVGA64K(void)
{
return(3);
}

void putpoint(int x, int y, rgb16M color)
{
setrgbpalette(1026, color.r >> 3, color.g >> 2, color.b >> 3);
putpixel(x, y, 0);
}

void init64k()
{
int gd=DETECT,gm=0;
installuserdriver("Svga64K", Return_SVGA64K);
initgraph(&gd, &gm, "");
}

main()
{
int x,y;
unsigned int page,get;
long addr;
rgb16M color;
unsigned int far *videoptr = (int far *)MK_FP(0xa000, 0);

init64k();
for(x=0;x<getmaxx();x++)
for(y=0;y<getmaxy();y++)
{
color.r=31<<3;
color.g=63<<2;
color.b=0;
putpoint(x,y,color);
}
x=123;
y=45;
page = (int)((addr = ((long)y + 0) * 640 + x) >> 15);

_BX = 0;
_DX =page;
_AX = 0x4f05;
__int__(0x10);

get=*(videoptr + (unsigned)(addr & 0xffff));

getch();
closegraph();
printf("%u",get);
getch();
}

改进了一下

#11
一笔苍穹2006-09-08 10:00
我曾经想过但并未尝试过用扩展BGI在64K色下读取颜色值,但隐隐记得以前在老外的网站里看到过关于这方面的东西:好像是先置一下某个环境变量,然后用getpixel()连续读两次,就分别能得到高、低各8字节的信息,组合在一起就可以了。不过又好像是调用getpixel()后不用它返回的值,而是立即读寄存器_AX(也可能是_BX)的值,这里面保存有真正的16位颜色值。
第二种方法从逻辑上说的可能性大些,因为我实在记不清了,只能从逻辑上猜测了,因为程序运行离不开寄存器,graphics的内核应该会读到完整的颜色值放进里面,只是返回时迫于函数原型将值截断了。
楼主有时间可以试试,不过先申明我只是凭稀薄的印象回忆的,所以很可能只是我梦到的而没有任何的依据,所以没成功可别骂我哦。
#12
一笔苍穹2006-09-08 10:04
当然,你也可以从
setrgbpalette(1026, color.r >> 3, color.g >> 2, color.b >> 3);
putpixel(x, y, 0);
着手推断读颜色值的方法,上面说的第一个方法中可能是我将getrgbpalette()之类的函数错记成环境变量了也说不定,加油吧
#13
cdmalcl2006-09-08 13:46

我改了改变量类型 然后显示后重显测试成功了
至于你那个方法我还要多研究一段日子(发现技术上有点限制
我现在先用这个:
unsigned int far *videoptr = (int far *)MK_FP(0xa000, 0);
unsigned int get64kdot(int x,int y)
{
long addr;
int page;

page = (int)((addr = (long)y *GRPAH_MAXX +(long)x) >> 15);

_BX = 0;
_DX =page;
_AX = 0x4f05;
__int__(0x10);

return *(videoptr + (unsigned)(addr & 0xffff));

}
所以非常感谢斑竹的帮助

#14
一笔苍穹2006-09-08 13:56
恩,负值那个事我忘了说了,负值是正常的,改成无符号整型就行了,在实际应用中不改也不会有太大的问题,给人看的时候换成16进制就没事了。
#15
RockCarry2006-09-08 15:28
在Jordan Hargraphix Software提供的SVGA BGI中,对于16bit色、24bit色和32bit色视频模式下,获取某个像素点的颜色值的方法如下:
DWORD color = 0;
getpixel(x, y);
color = _EAX;
颜色值被存放在了EAX寄存器中,如果在TC2.0中,编译器不支持EAX寄存器,以上代码是无法正常编译的,在TC3.0下是可以的。所以,在TC2.0下,要取得24bit色和32bit色的像素颜色值,较为困难,但是取得16bit色的颜色值是没有问题的:
WORD color = 0;
getpixel(x, y);
color = _AX;
从道理上讲,C语言中函数的返回值都是被放到AX或EAX中,所以如下写法也是对的:
WORD color = 0;
color = getpixel(x, y);






[此贴子已经被作者于2006-9-8 15:32:40编辑过]

#16
RockCarry2006-09-08 15:29

原理是这样的,Jordan Hargraphix Software提供的BGI的getpixel函数的返回值实际上是32bit的,它将这个返回值放入了EAX寄存器,这也是C函数调用的通常做法,因此putpixel函数的正确的声明应该如下:
unsigned long far _Cdecl getpixel(int x, int y);
然而,在graphics.h中getpixel的函数原型为:
unsigned far _Cdecl getpixel(int x, int y);
其返回值是16bit的,所以编译器认为getpixel的返回值为16bit,并且放入了AX寄存器中。所以对于16bit色模式的返回值在TC2.0中是可以正常取得的,而对于24bit色和32bit色的颜色值,就只能取得其低16bit了,因为TC2.0中不支持EAX寄存器,并且graphics.h中getpixel函数声明的返回值也是16bit的。

在TC3.0种,可以访问EAX寄存器以下的写法对于16bit、24bit和32bit都是适用的:
DWORD color = 0;
getpixel(x, y);
color = _EAX;






[此贴子已经被作者于2006-9-8 15:33:24编辑过]

#17
RockCarry2006-09-08 15:29

如果在支持32bit寄存器的编译器中对于32bit的返回值,都是放在EAX中的,不知道TC3.0 对于32bit的返回值是否是这样处理的,如果是的话,就可以采用如下的办法:
首先将getpixel的原型改为:
unsigned long far _Cdecl getpixel(int x, int y);
然后:
DWORD color = 0;
color = getpixel(x, y);

以上的说法,有一部分是我从理论上进行的推测,我也没有具体写代码去测试。(自己去测吧:-)


[此贴子已经被作者于2006-9-8 15:33:48编辑过]

#18
RockCarry2006-09-08 15:29

结论:
TC2.0下不能取得24bit色和32bit色的像素值,可以取得16bit色的像素值,方法如下:
WORD color = 0;
getpixel(x, y);
color = _AX; // 绝对能行
或者:
WORD color = 0;
color = getpixel(x, y); // 理论上能行,我没有测试过

TC3.0下能够取得16bit色、24bit色、32bit色的像素值,方法如下:
DWORD color = 0;
getpixel(x, y);
color = _EAX; // 绝对能行
或者:
改getpixel函数原型为:unsigned long far _Cdecl getpixel(int x, int y);
然后如下:
DWORD color = 0;
color = getpixel(x, y); // 理论上能行,我没有测试



[此贴子已经被作者于2006-9-8 15:34:05编辑过]

#19
RockCarry2006-09-08 15:30

另外setrgbpalette可以用来设置颜色是对setcolor函数的功能扩充,如下:
#define SET_DRAW_COLOR 1024
#define SET_FILL_COLOR 1025
#define SET_PIXEL_COLOR 1026
setrgbpalette(SET_DRAW_COLOR, r, g ,b); // 设置画笔颜色
setrgbpalette(SET_FILL_COLOR, r, g ,b); // 设置填充颜色
setrgbpalette(SET_PIXEL_COLOR, r, g ,b); // 设置putpixel函数所使用的颜色
16bit色、24bit色和32bit色下的绘点方法:
setrgbpalette(SET_PIXEL_COLOR, r, g ,b);
putpixel(x, y, 0);

如有问题可以进一步参考Jordan Hargraphix Software BGI的相关文档,在上面讲的非常清楚。(不过这个原始版本的BGI很难搞到的,我这里有一份,可是没法给你;-)。





[此贴子已经被作者于2006-9-8 15:34:32编辑过]

#20
RockCarry2006-09-08 15:30
抱歉,公司的电脑发帖子存在字数限制,所以只有分多次发出了。

[此贴子已经被作者于2006-9-8 15:36:06编辑过]


#21
RockCarry2006-09-08 15:53
TC2.0中是将一个long型的返回值放在了dx和ax寄存器中,TC3.0中不知道是不是,我没有测试,因为没有TC3.0的编译器。
如果是的话,那个方法就不成立了,就只能color = _EAX。
#22
RockCarry2006-09-08 16:05

第三方BGI的种类很多,使用前都要认真阅读供应商的参考文档。不过现在这个已经不流行了,找不到资料也是自然。看国内流行的第三方BGI好像都是Jordan Hargraphix Software的,其实在国外还能找到很多,性能都很不错。
一般情况下使用了BGI,就最好使用其提供的接口函数,比如取像素颜色,而不要自己去直接访问显存,这样多少有点不规范。至于RGB分量的量化压缩的问题,理解了是很好的,这个思想可以运用到256色模式下的,自己去想吧。

[此贴子已经被作者于2006-9-8 16:07:32编辑过]

#23
cdmalcl2006-09-08 16:28

太感动了!!!
#24
一笔苍穹2006-09-08 16:49
呵呵,感谢RockCarry的及时出现,这下就印证在getpixel()之后读取寄存器_AX值是没错的了,希望cdmalcl的作品及早问世,记得发一份上来哦~
#25
RockCarry2006-09-08 16:52

TC3.0没有TC2.0好用,他没有能很好的支持32位DOS程序,不能使用大内存,仅仅是提供了对部分32bit指令和寄存器的支持,所以显得有点不伦不类。对于写16bit的DOS程序,推荐使用TC2.0,如果要想使用32bit的DOS编译器,推荐使用Djgpp。

不过Djgpp的入门可能要难一点,国内很少有人用,光是安装就要花去很多时间去研究,因为国内找不到资料。当时我就是搞了很久才把安装搞定。国内以前曾经流行过一个Djgpp的版本,是在Crazy Bugs(现在已经死了:-)上提供的,不过那个版本显得有点问题,几乎不能痛快地使用。可以自己去官方网站下载,然后尝试这安装,其实安装说明在网站上讲的很清楚了,要认真阅读。我当时就是没有认真阅读,浪费了一天多时间去研究。

#26
RockCarry2006-09-08 16:52

对于初学者,可以尝试使用RHIDE,其界面都和TC差不多,对于Linux老手来说,RHIDE就显得有点垃圾了。一般的项目管理方法都是使用MakeFile工具来进行,非常方便,真是得心应手。我现在使用TC2.0编译器也不用IDE和WinTC的IDE了,都是使用Make工具,极为方便。

如果想使用Djgpp编译Allegro还需要注意一些问题,就是GCC新版本的编译器对Allegro中的一些语法有点不支持,所以要下载比较老版本的Djgpp编译器来编译(新版本不一定就好哦:-)。

#27
RockCarry2006-09-08 17:09
通常情况下,很多人都很难理解16位DOS程序与32位DOS程序的区别,也就是实模式和保护模式的区别。其实实模式和保护模式最大的区别不是别的,而是寻址方式。
还有就是对编译器的理解,也是值得去研究的。理解编译、汇编、函数调用机理、什么是目标文件、什么是链接、什么是库文件。打通编译器这一层,你会觉得世界是如此的光明,世界又是如此的简单。正是因为编译器为我们做了太多的事情,使得我们不能深刻理解计算机了。
#28
RockCarry2006-09-08 17:09
要理解这些,也不是一两天能完成的。对于写应用程序来说,事情就相对简单,只需要理解自己的平台,工具,然后注重程序模块、逻辑和算法据可以了。
整个计算机世界都是层级形式的,正是这种形式使得我们可以在不同的层级上并行开发,而每一个层级的开发都不用去理解整个计算机世界,而只需要理解他的平台就可以了,也就是要理解其下一层提供的工具和调用接口。这种形式是优美的,最鲜明的例子就是网络协议栈的实现过程,清晰而生动。
不管你是做什么的,努力吧,继续!
RockCarry

[此贴子已经被作者于2006-9-8 17:10:56编辑过]

#29
RockCarry2006-09-08 17:46
模块之间的依赖关系应该是一个单向的依赖关系,就是说是一个无环有向图。正是这样的依赖关系形成了计算机世界的层级形式,也正是这样优美的形式奠定了计算机世界层级关系的基础。每一层级都要完成自己的事情,也无所谓难与易,最关键的还是对平台的理解,不理解平台会导致做无用功,曾经就有人在使用C语言编写应用程序的过程中,为了处理字符串去编写字符串处理函数,这是愚蠢的。首先要搞清楚自己的开发所处的层级,所使用的平台,需要深刻理解平台。使用C做应用开发,在C标准库中就提供了字符串处理的函数。理解平台的目的就是最大的使用平台所提供的功能,而不是自己去重新构建。
#30
cdmalcl2006-09-08 17:59
以下是引用一笔苍穹在2006-9-8 16:49:37的发言:
呵呵,感谢RockCarry的及时出现,这下就印证在getpixel()之后读取寄存器_AX值是没错的了,希望cdmalcl的作品及早问世,记得发一份上来哦~

一定一定
绝对不副众望

#31
RockCarry2006-09-08 18:01
层级或模块之间的通信或调用协议就称之为接口。个人认为整个计算机世界在大的范围内是层级式的、模块化的,对象化只是在模块的内部才得到体现。因此说,真正的代码重用不是面向对象的继承,而是层级和模块之间的接口。面向对象的继承机制重用的只是一个类而已,而接口实现的重用,则是重用了整个计算机世界。
对象其实只是对模块的另一种提法而已,它是设计得更好的模块。
#32
一笔苍穹2006-09-09 09:49
这要是能整理成一个学习纲要就好了,可惜发帖字数有限制
#33
RockCarry2006-09-09 10:47
只是随便扯一扯淡,说得也不一定正确。现在都没有太多机会写文章,其实除了上班时间,平时都很空闲的,可是呢,还没有电脑,所以周末基本上都跑到网吧去打游戏了,到网吧也只有打游戏,什么都干不了。
#34
一笔苍穹2006-09-09 10:49
加油,早些买个本本!
#35
cdmalcl2006-09-09 22:22

终于研究出来了
最近心情不是很好 事还多 所以一直没多弄 拖多了今天

int GRPAH_MAXX;

void init64k()/*图形初始化*/
{
int gd=DETECT,gm=0;
installuserdriver("Svga64K", Return_SVGA64K);
initgraph(&gd, &gm, "");
GRPAH_MAXX=getmaxx()+1;
}

int putpoint(int x, int y, rgb16M color)/*画点(x,y)*/
{
int page;

page = (int)((y*(long)GRPAH_MAXX +x) >> 15);
_BX = 0;
_DX =page;
_AX = 0x4f05;
__int__(0x10);

setrgbpalette(1026, color.r >> 3, color.g >> 2, color.b >> 3);
putpixel(x, y, 0);
}

unsigned int far *videoptr = (int far *)MK_FP(0xa000, 0);
unsigned int get64kdot(int x,int y)/*获取(x,y)的颜色值*/
{
long addr;
int page;

page = (int)((addr = (long)y *GRPAH_MAXX +(long)x) >> 15);

_BX = 0;
_DX =page;
_AX = 0x4f05;
__int__(0x10);

return *(videoptr + (unsigned)(addr & 0xffff));

}

rgb16M get_rgb_dot(int x,int y)/*获取颜色分量*/
{
rgb16M color_rgb;
unsigned int color;

color=get64kdot(x,y);
color_rgb.r=(color/2048)<<3;
color_rgb.g=((color%2048)/32)<<2;
color_rgb.b=((color%2048)%32)<<3;

return color_rgb;
}

#36
cdmalcl2006-09-09 22:24
#37
一笔苍穹2006-09-11 10:26
color_rgb.r=(color/2048)<<3;
color_rgb.g=((color%2048)/32)<<2;
color_rgb.b=((color%2048)%32)<<3;
把里面的除法和求余全部优化掉,用移位代替。
#38
cdmalcl2006-09-11 10:55
好的
1