您当前的位置:首页 > 计算机论文>计算机应用论文

DOS真彩色模式下真彩色图像显示技术解析

2015-05-30 09:17 来源:学术参考网 作者:未知

  一、高、真彩色显示卡

  近年来,顺应cad、cg及多媒体技术进步的要求,许多彩色适配器板卡厂商先后推出性能价格比较高的一系列高彩色(high color)和真彩色(true color)supervga显示卡。如trident microsystems公司的tgui94xx、tgui96xx,cirrus logic的gd543x、gd544x,tseng laboratories的et4000, ark logic的ark1000,、ark2000,s3 incorporated的 s3 86cxxx等等。它们除了继续支持标准vga模式外,都支持16色、256色、32k高彩色、64k高彩色及16.7m真彩色vesa bios 扩展模式,版本大多为vesa 1.2, 卡上具有32k、64k及16.7m dac,有16位isa、32位vesa、32位 pci总线等多种接口,显示vram配置一般有1m、2m、4m,一般都带有硬件加速的32位或64位图形加速引擎(graphics engine),满足了当今386~586各种档次的pc机对更多色彩、更高分辨率的要求。

  表1整理了市场上常见的gd5434(64位gui)、tgui9440agi(32位gui)和ark2000pv(64位gui)三种pci总线高、真彩色显示卡的oem bios调用模式号、色彩数、分辨率、vesa模式对照及其相应的vram占用等数据。WwW.11665.CoM其他支持 vesa 1.2的显示卡只要查阅卡附手册得到oem(原始设备制造商)自定义的高、真彩色模式号或其对应的vesa模式号。有些配4m vram的显示卡甚至可支持1280×1024 16m色(vesa 1.2 11bh模式)。

  表1

  二、高、真彩色编程与256色编程的异同

  高、真彩色模式编程在写视频缓冲区端口索引号、页切换方式、置模式号等方面类同扩展256色编程,例如,trident的高、真彩色显示卡,写视频缓冲区端口索引号仍是(0x3c4, 0xe)和(0x3c5, page^2),视频窗口页粒度仍是64, 页切换方式仍是64k 页、128k页任选。不同点在于:高、真彩色模式已经不再使用256组dac寄存器索引号及调色板概念,而使用像素字长的rgb 分量数据直接描述色彩及饱和度,写视频缓冲区映射到vram后由新的64k dac或16m dac将色彩数据转为模拟信号送多频彩色显示器,256 色编程中有关调色板的bios中断全部失去作用;其次,由于用多个字节表示一个像素,高、真彩色dac 转换的时间成倍增加,显示速度过分依赖卡上图形引擎(graphics engine)的效率,再加上数据成倍占用ram或vram,所以显示速度明显慢于256色图像显示。

  另外,不同厂商自定义的访问端口寄存器索引号的方式均各不相同,直接根据硬件特性的编程必然缺乏通用性。若按照这些显示适配卡都支持的 vesa ( videoelectronics standards association)标准扩展bios功能调用接口编程,从而实现软件接口层次上的兼容性,所编程序便可在众多的super vga卡上运行,有关 vesa编程的详细资料请查阅有关书刊。

  表2是高、真彩色像素的分量结构示意,是理解高、真彩色图像编程的关键。

  表2

  三、24位pcx图像格式简介

  24位pcx图像的文件头同16色、256色的一样,共128字节, 其中每个像素所用的彩色位数(bit-perpixel)值为8,彩色平面数(color-planes)值为3, 不再使用调色板。24位pcx图像数据的存储仍采用有限行程压缩法,但却是把单个的rgb行作为三个位平面数据分别进行压缩存放,第一个位平面由该行所有红色像素组成;第二个位平面由该行所有绿色像素组成;第三个位平面由该行所有蓝色像素组成,因为行程编码方法并不是总能减小24位复杂图像的大小,所以对24位pcx 文件进行解码得到的结果图像比原来的小也属正常。本文所用24 位pcx 文件格式符合pcpaintbrush version 5标准,是从photo styler 1.0的tif图例转换的。

  将上述解压缩的数据用于显示时,需按显示卡硬件高、真彩色dac送色彩信号的顺序--红绿蓝红绿蓝......--重新组织,才能正确地显示24位真彩色图像。这一点是最不同于其他用三字节行程编码的24位rgb真彩色图像(如24位tga)。其它格式24位的真彩色图像文件只是图像头处理及解压数据的方式不同,显示的原理则完全相同。文后所附例程作适当改变,就可用于24位tif、24位bmp、24位tga 等图像文件的显示。

  下面就640x480分辨率介绍32k、64k高彩色、16m真彩色模式显示24位pcx图像。

  四、32k、64k高彩色仿真16m真彩色编程

  现成的64k色图像很少,彩色扫描仪扫出的多为256色或24位真彩色, 许多图像处理软件包的图例也是同样情形。这里只好用24位真彩色图像经下述图示过程的位移合并,做成16位的64k高彩色像素字。这种取24位rgb分量高位的方法仿真显示真彩色图像,明亮部分的色彩层次能较好还原,低暗部分的色彩层次有微小损失,仿真效果很好。读者也可根据需要作其他位的取舍(如舍两头留中间),以使色彩还原最小失真。

  图

  图示中的空格为零。32k 高彩色仿真与此类似,只需将绿色分量也右移3位,与红色、蓝色分量一道做成最高位为零,低15位有效的一个字,送视频缓冲区便可。

  具体编程要点如下:

  1.调用vesa bios 4f02h 号功能置高彩色图形模式,成功后调用vesa bios4f01h号功能返回每线字节数line-bytes及窗口页粒度wingran等重要参数;

  2.读图像头后直接读图像数据,按上述方法转换为一16位字后送视频缓冲区始址a000:0000,每一像素一个字,每送一个字到视频缓冲区,地址偏移量加2;

  3.640×480分辨率下每根扫描线需1280字节,为提高显示速度,由line-bytes预先算出每根扫描线始址存于addr数组备查,由于满屏需600k字节,故编程上仍需考虑切换vram页的情况。例程根据各种卡不同模式的窗口页粒度wingran值,调用vesa bios 4f05h号功能访问硬件分页寄存器实现64k页模式切换(此时仍有一根扫描线跨两页的情形);

  4.显示完毕,调用vesa bios 4f02h 号功能置模式03h恢复原文本模式。

  五、16m真彩色编程

  真彩色编程的关键是要了解图像数据的存放顺序及解压方法,其次注意读图像数据后按顺序要求作转换,否则图像色彩失真。其余过程同高彩色模式。

  具体编程要点如下:

  1.调用vesa bios 4f02h号中断置真彩色图形模式;成功后调用vesa bios4f01h号功能,返回每线字节数line-bytes及窗口页粒度wingran等重要参数;

  2.读图像文件头后直接读图像数据,解压缩后按红绿蓝顺序送视频缓冲区始址a000:0000,每一像素三字节,每送一像素到视频缓冲区,地址偏移量加3;

  3.在vesa 112h模式(640×480 16.7m color)下,不同显示适配卡的每线字节数是不一样的, 如ark2000pv 为1920, gd5434及tgui9440为2048,s3 86c868为2560, 但由于使用vesa编程, 4f01h号功能能准确返回每线字节line-bytes 值, 并预先算出每条扫描线始址存于addr数组,可提高显示速度,由于满屏需900k以上字节,故编程上仍需考虑切换vram页的情况,换页机制同64k色情形;

  4.有些装2m vram的适配卡, 可在640×480 16.7m色情况下使用32位快速格式,如s3 86c868的112h模式及gd5434的76h模式, 每线字节为2560, 此时解压缩后按红绿蓝及一零字节顺序送视频缓冲区始址 a000:0000,每一像素4字节,每送一像素到视频缓冲区,地址偏移量加4,类似特殊情况,例程照此稍作修改便可;

  5.显示完毕,调用vesa bios 4f02h号功能置模式03h,恢复原文本模式。

  六、示范程序

  以上两种编程实现见所附例程,程序在有isa/vesa/pci三种总线插槽的 octekhippo12型主板、amd dx4/100 cpu、8m ram、emc1024×768、28隔行扫描彩色显示器、cirrus gd5434(2m vram)显示卡、borland c++ 3.1 small 模式下编译通过。但执行程序并不依赖所编译的硬件环境, 曾经在装有 1m vram 的tgui9440、tgui9680、ark2000pv、s3 86c868 等vesa局部总线、pci局部总线、甚至isa总线的tvga8900d(也支持vesa 1.2标准, 1m以下的oem模式号同tgui9440)显示卡的486~586各档pc机的dos环境下均获通过。

  示例程序对super vga卡vesa bios高、真彩色扩展模式编程具有一般性。对本文未提到的其它高、真彩色显示卡,只要其支持vesa标准(version>1.1),不加修改或稍作修改便可使用;对更高分辨率,只要显示适配卡配2m vram, 便可作115h、116h、117h模式的编程, 例程中只要修改highcolor()、truecolor()两函数中n、m的宽高界值和addr的上界。但更重要的是: 程序运行以前用显示适配卡所配调整dram像素时钟或调整彩色显示器扫描频率的实用程序, 将像素时钟和扫描频率调整到该卡现行分辨率所要求的值上, 例如, cirrus gd5434卡(2m vram)要在117h模式下顺利仿真显示16.7m真彩色, 须在dos下先执行 clmode.exe t640=60 t800=60t1024=60 t1280=0, 程序便可顺利显示高彩色图像。

  // 24位pcx高、真彩色图像显示例程

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  unsigned long dataoffset,line-bytes;

  unsigned long addr;

  unsigned int curpage,wingran,y-res,width,height;

  file *fp;

  typedef struct { // pcx图像文件头格式

  char manufacturer;

  char version;

  char encoding;

  char bits-perpixel;

  int xmin, ymin;

  int xmax, ymax;

  int hres;

  int vres;

  char palette;

  char reserved;

  char color-planes;

  int bytes-perline;

  int palettetype;

  char filler;

  } pcxhead;

  struct mode infoblock {

  unsigned int modeattr;

  unsigned char winaattr;

  unsigned char winbattr;

  unsigned int wingran;

  unsigned int winsize;

  unsigned int winaseg;

  unsigned int winbseg;

  unsigned char *pagefunc;

  unsigned int bytesperscanline;

  unsigned int xres,yres;

  unsigned char charx,chary;

  unsigned char numberofplanes;

  unsigned char bitperpixel;

  unsigned char numberofbanks;

  unsigned char memorymodel;

  unsigned char banksize;

  unsigned char numberofimagepages;

  unsigned char reserved;

  unsigned char x;

  } modeinfo;

  void setvesamode(unsigned int mode);

  void vesainfo(unsigned int mode);

  void map(void);

  void selectpage(unsigned int page);

  void highcolor(void);

  void truecolor(void);

  main() // 主函数

  { pcxhead header;

  char *filename,c;

  printf("please enter the 640x480 24bit rgb mode pcx fil

  ename: ");

  gets(filename);

  if((fp=fopen(filename, "rb"))==null)

  {

  setvesamode(0x03);

  puts("file reading error");

  exit(1);

  }

  fread( (char *) &header, 1, sizeof(pcxhead), fp);

  width = header.bytes-perline;

  height = header.ymax - header.ymin + 1;

  printf("image information: width=%d, height=%d",width,h

  eight);

  if ((header.bits-perpixel==8)&&(header.color-planes==3)

  ) {

  printf("

  type : 24bits rgb true colors");

  printf("1...emulating display 16m true color image with

  64k high color");

  printf("2...display of 16m true color image");

  printf("press select 1 or 2 : ");

  if ((c=getch())=='1') {

  highcolor();

  setvesamode(0x03);

  }

  else if (c=='2') {

  truecolor();

  setvesamode(0x03);

  }

  else {

  printf("this is not high-color & true-color image !")

  ;

  exit(1);

  }

  }

  fclose(fp);

  return 0;

  }

  // 设置vesa bios扩展模式函数

  void setvesamode(unsigned int mode)

  { union regs r;

  unsigned int setmode=1;

  r.x.ax=0x4f02;

  r.x.bx=mode;

  int86(0x10,&r,&r);

  if (r.x.ax!=0x4f)

  setmode=0;

  else vesainfo(mode);

  curpage=0xffff;

  return(setmode);

  }

  // 返回vesa编程信息函数

  void vesainfo(unsigned int mode)

  { union regs r;

  struct sregs sr;

  r.x.cx=mode;

  r.x.ax=0x4f01;

  sr.es =fp-seg(&modeinfo);

  r.x.di=fp-off(&modeinfo);

  int86x(0x10,&r,&r,&sr);

  wingran =modeinfo.wingran;

  line-bytes=modeinfo.bytesperscanline;

  y-res

  =modeinfo.yres;

  }

  // 计算扫描线始址函数

  void map(void)

  { register int i,j;

  for(i=0; i

  addr =(unsigned long)(i)*line-bytes;

  }

  // 选择视频窗口对准页函数

  void selectpage(unsigned int page)

  { union regs r;

  if (page!=curpage) {

  r.x.bx=0;

  r.x.dx=page*64l/wingran;

  r.x.ax=0x4f05;

  int86(0x10,&r,&r);

  curpage=page;

  }

  }

  // 16位高彩色仿真24位pcx真彩色图像显示函数

  void highcolor(void)

  { register int i, j;

  unsigned int red, green, blue;

  unsigned int *word, *wordptr;

  int n, m, k, cnt, total;

  unsigned long segmet;

  unsigned char *pic, *p0,*p1,*p2;

  unsigned char page, picdata;

  setvesamode(0x111);

  map();

  selectpage(0);

  n=min(480,height);

  m=min(640,width);

  word =(unsigned int *)malloc(2*m);

  wordptr=word;

  for (k=0; k<3; k++)

  pic=(unsigned char *)malloc(m);

  p0=pic; p1=pic; p2=pic;

  fseek(fp,0x80l,seek-set);

  for(i=0; i

  pic=p0; pic=p1; pic=p2;

  word=wordptr;

  for (j=0;j<3;j++) {

  total = 0;

  while(total < m) {

  cnt = 1;

  picdata = fgetc(fp);

  if(0xc0==(0xc0 & picdata)) {

  cnt = 0x3f & picdata;

  picdata = fgetc(fp);

  for (k=0; k

  *pic++ =picdata;

  }

  else

  *pic++ =picdata;

  total+=cnt;

  }

  }

  pic=p0; pic=p1; pic=p2;

  for (j=0; j

  red = *pic++ >>3;

  green= *pic++ >>2;

  blue = *pic++ >>3;

  red=red<<11; green=green<<5;

  *word++ =red|green|blue;

  }

  word=wordptr;

  for (j=0;j<2*(m-1);j+=2) {

  segmet=addr+j;

  page=segmet>>16;

  if (segmet <= 65535l) {

  poke(0xa000, addr+j, *word++ );

  }

  else {

  selectpage(page);

  poke(0xa000, addr+j, *word++ );

  }

  }

  }

  getch();

  free(wordptr); free(pic);

  free(pic) ; free(pic);

  }

  // 24位pcx真彩色图像全息显示函数

  void truecolor(void)

  { register int i, j;

  unsigned char *pic, *p0,*p1,*p2;

  unsigned char page, picdata;

  int n,m,k,cnt,total;

  unsigned long segmet;

  setvesamode(0x112);

  map();

  selectpage(0);

  n=min(480,height);

  m=min(640,width);

  for (k=0; k<3; k++)

  pic=(unsigned char *)malloc(m);

  p0=pic; p1=pic; p2=pic;

  fseek(fp,0x80l,seek-set);

  for(i=0; i

  pic=p0; pic=p1; pic=p2;

  for (j=0;j<3;j++) {

  total = 0;

  while(total < m) {

  cnt = 1;

  picdata = fgetc(fp);

  if(0xc0==(0xc0 & picdata)) {

  cnt = 0x3f & picdata;

  picdata = fgetc(fp);

  for (k=0; k

  *pic++ =picdata;

  }

  else

  *pic++ =picdata;

  total+=cnt;

  }

  }

  pic=p0; pic=p1; pic=p2;

  for (j=0;j<3*(m-1);j+=3) {

  segmet=addr+j;

  page=segmet>>16;

  if (segmet <= 65535l) {

  for (k=0; k<3; k++)

  pokeb(0xa000, addr+j+k, *pic++);

  }

  else {

  selectpage(page);

  for (k=0; k<3; k++)

  pokeb(0xa000, addr+j+k, *pic++);

  }

  }

  }

  getch();

  for (k=0; k<3; k++) free(pic);

  }

  参考文献

  1.张一波.super vga与vesa编程指南.北京:海洋出版社,1993.8

  2.张益明.微机图像文件格式大全(续篇).北京:学苑出版社,1994.7

相关文章
学术参考网 · 手机版
https://m.lw881.com/
首页