回 帖 发 新 帖 刷新版面

主题:[讨论]TC下实现真24位色彩 (转贴)

[color=FF0000]以下内容为转贴,希望大家讨论讨论[/color]



在TC下显示24位真彩色
在TC下显示24位真彩色
  本文纯属抛砖引玉之作,如果各路高手对此文有什么不同或者更加准确的看法,请畅所欲言。
虽然在TC显示24位图像上的速度远远比不上256色的速度快,但是真彩色色彩带给我们的视觉上的冲击是256色远远不能达到的。很多人都认为 640x480 256色是TC显示的最终极限。其实不然。我今天就来仔细描述下我对TC下24位位图的理解。
我们以显示24位BMP位图为例子
1. 24位BMP文件结构
24位BMP文件结构和256色BMP文件结构很大部分都是一样的。这里为了简单
就只介绍其中一些最常用的部分,具体的结构大家可以参考一下256色BMP文件结构。
   0012—0015 ::图像宽度
   0016—0019 :图像高度
   001c—001d :图像的颜色数(24位图的值是24,256色图的值是8)
   0036—???? :所有点的RGB颜色值(重点,因为只有这里和256色图的结构不一样)

图像的宽度和高度以及颜色数都很好理解,现在我想重点讲的是0036的部分。
在24位图像中,没有‘DAC色表’,也没有‘图像数据区’。唯一留给我们的只有图像上所有点的颜色值。因为每个颜色都用BGR三种颜色来表示,而每个颜色占用1个字节,所以在24位图像中,每1个点就占用了3个字节。3*8=24 这就是24位图名称的由来。
那没有‘DAC’色表,也没有‘数据图像区’我们怎么来显示图像呢?很简单,24位图给我们提供了个更加简单的方法:‘所有点的颜色值’。既然是所有点,那么只要把这些点按照他们的颜色重新画出来就是该图像完整的信息了。

2. 修正宽度值(难点)
读取一行所有点的颜色:

fread(buffer,width*sizeof(ColorBGR),1,fp);  /*读取该行像素的所有点的颜色*/

吴进说过:为了显示的方便,除了真彩色外,其他的每中颜色模式的行字节数要用数据“00”补齐为4的整数倍。

其实他说错了,起码在24位真彩色图像上,他是错误的。真彩色每行的字节数如果不够4的整数倍同样也需要“00”来补齐。

If(width%4)   fseek(fp,(4-width%4),SEEK_CUR);
/*当宽度不是4的整数倍的时候,把文件指针fp跳过用来补齐的那几个“00”*/

3. 画点
画点的过程也就是图像显示出来的过程。每一个点都有自己的颜色,这样才能展现出绚丽的色彩。所以我们在画每一个点之前,都必须为该点重新调整调色板。

    setrgbpalette(1026,buffer[i].r>>3,buffer[i].g>>2,buffer[i].b>>3); /*重设该点的颜色*/
    putpixel(i,j,0);  /*画点*/

经过以上的几个步骤,绚丽的真彩色图像就显现出来了。以下是我整理的代码,BGI驱动我采用了Jordan Hargraphix 编写的SVGA64K.BGI  请大家编译的时候务必要把该文件与源代码文件放在同一个目录下。大家在输入文件名的时候请注意用大写,后缀名BMP也要大写。


#include "graphics.h"
#include "stdio.h"

int huge return_SVGA64K_mode(void)
{
        return(3); /*把分辨率设置为640x480。4是800x600模式;5是1024x768*/
}

typedef struct    /*ColorBGR像素类型*/
{
        unsigned char b;
        unsigned char g;
        unsigned char r;
}ColorBGR;


void main()
{
char fname[30]; /*文件名*/
int width,height,gd=DETECT,gm,i,j;
FILE *fp;
ColorBGR *buffer;

        printf("Please input the 64K BMP filename: "); /*输入24位位图的文件名*/
        gets(fname);

        if((fp=fopen(fname,"rb"))==NULL)    /*打开文件,并且判断文件是否存在*/
        {
                printf("Can't find file %s",fname);
                getch();
                exit(1);
        }

        installuserdriver("Svga64k",return_SVGA64K_mode);/*对于svga64k必需执行该函数以安装BGI驱动*/
        initgraph(&gd,&gm,"");/* 执行TC默认的BGI初始化函数 */

        fseek(fp,18,SEEK_SET);
        fread(&width,4,1,fp);      /*图像宽度*/
        fread(&height,4,1,fp);     /*图像长度*/

        buffer=(ColorBGR *)malloc(width*sizeof(ColorBGR));/*为一行所有的像素的颜色开创空间,用来保存同一个宽度上的每个点的RGB三种颜色值*/

        fseek(fp,54,SEEK_SET);     /*定位文件指针指向颜色存储区*/

        for(j=height-1;j>=0;j--)
        {
                fread(buffer,width*sizeof(ColorBGR),1,fp); /*读取该行像素的所有点的颜色*/

                if(width%4)   fseek(fp,(4-width%4),SEEK_CUR); /*宽度修正*/

                for(i=0;i<width;i++)
                {
                        setrgbpalette(1026,buffer[i].r>>3,buffer[i].g>>2,buffer[i].b>>3); /*重设每个点的颜色*/
                        putpixel(i,j,0);  /*画点*/
                }
        }

        free(buffer);
        fclose(fp);
        getch();
        closegraph();
}
大家不要看到这么多的代码就害怕,其实用心去看是很容易就理解的。

补记:
也许有人会问:为什么256色图片显示的时候我们必须要换页,而真彩色24位的图片显示的时候却不用呢?
我的回答是:因为显示256色的时候用的是直接改写VRAM的技术,所以要换页。而我们这里用的显示24位真彩色的时候用的是画点的方法,所以跳过了换页的问题(交给putpixel去解决啦)。因此速度上肯定比不过直接改写VRAM来得快。所以大家如果有了自己的想法,不妨自己改写一下程序,说不定你能让真彩色图像显示得更快哦~(那是肯定的,因为我的这个方法是最最笨的法子)

小提示:如果你正在为你的程序不能达到800x600或者更加高的分辨率而苦恼的话,你不妨换个编程环境试试。个人极力推荐纯DOS编程。在纯DOS环境下,很容易就能达到1024x768的高分辨率。具体原因:去问‘比尔该死’,我也不知道。

纯DOS的环境需要:  
一张DOS系统启动盘(软盘)
mouse.com(如果你找不到,在我的压缩包里面有)

mouse.com是鼠标驱动程序。如果不先执行它,那么你软件中的鼠标部分将不可用(因为你已经不在WINDOWS环境下了)

回复列表 (共11个回复)

沙发

数学系的兄弟果然厉害呀
谢谢贴子了

板凳

to 1 楼;

       看明白了就讨论讨论吧! 好多内容我没学过,能讲讲吗??
       明白多少说多少,谢谢,大家一起提高

3 楼

国际惯例,自己顶

4 楼

我也顶

5 楼

国际惯例,自己顶  

6 楼

帮你顶一下

7 楼

按楼主的思路,是分析BMP的格式然后自己将BMP图片自己画到屏幕上。但我听过一个前辈说过,现在的显卡是直接支持BMP的显示的。换句话说,楼主的显示方法是‘软方法’,但后者是‘硬方法’。而后者由于有硬件的支持,速度肯定比楼主写的要快,但是具体如何操作我也不清楚,毕竟这有一定的技术性,我也不方便向那位前辈请教(人家是要靠它来吃饭的,不会轻易将饭碗借给你用)。

8 楼

to 只在乎你:
   你说的硬方法是怎么样的呢?具体介绍一下吧.

9 楼

say somethings about this,ok?

10 楼

好象可以用直接写视频缓冲区的方法实现

我来回复

您尚未登录,请登录后再回复。点此登录或注册