按字母查成语词典:A|B|C|D|E F G|H|J|K|L|M|N|O|P|Q|R|S|T|W|X|Y|Z
在线新华字典:按偏旁部首查询汉字 | 按汉字拼音查询汉字 | 五笔字根查询
工商管理论文 | 工学工业论文 | 社会艺术论文 | 理学医学论文 | 语言教育论文 | 计算机论文
大屏幕图像的快速保存和恢复
摘 要 该文介绍了一种在图形状态下能快速保存和恢复任意大小,任意数目的屏幕区域的新算法及其C实现,该算法可代替Turbo C 2.0, Borland C++ 3.1中的imagesize, getimage, putimage位图函数,屏蔽内部实现细节。适合于需要保存和恢复大屏幕图象区域的工程软件及使用多级菜单窗口软件系统中。
一、Turbo C Borland C++中的三个位图操作函数
unsigned far imagesize (int left, int top, int right, int bottom);
void far getimage (int left, int top, int right, int bottom, void far *bitmap);
void far putimage (int left, int top, void far *bitmap);
原型在graphics.h中,这三个函数用于把屏幕上的一个位图拷贝到主存储区(640K内),然后把它放回屏幕。getimage将屏幕上的一个矩形区域的位图拷贝到主存储区(640K内)中,left、top、right、bottom四个参数用于定义屏幕上的矩形。bitmap指向主存储区中存放位图的区域。该区域前两个Bytes用于存放矩形的宽和高。其余部分存放位图本身。imagesize决定getimage用于保存指定矩形所需的字节数。它返回的位图大小包括用于记录矩形的宽和高的空间。putimage将以前用getimage保存的位图重新送回屏幕。位图左上角位于(left, top),bitmap指向主存储区中存放位图的区域。
以目前最通用的VGA 640*480*16色方式为例,当需要保存整个屏幕区域时约需640*480/2=153,600 Bytes,约合150 KB左右。而imagesize计算存储指定目标区域所需字节数,若指定区域要求字节数> = 64K-1则返回0xFFFF (-1),使程序无法存储。另外,getimage所需的缓冲区是从Heap中申请的或是静态申请的。因此要占用宝贵的640K常规内存。如果有>=640KB/150KB=5幅的大屏幕图像需要保存和恢复,则内存将会用尽而出错。在大型工程软件项目及各种GUI中,快速保存及恢复屏幕图像已成为一种良好的界面设计方法,因此本文介绍了一种简便,易行的新算法用于替换上述标准的位图操作函数。
二、三个新的位图函数
void NewGetImage (int left, int top, int right, int bottom, int win-id);
void NewPutImage (int left, int top, int right, int bottom, int win-id);
int NewImageSize (int left, int top, int right, int bottom, int *height, int*block-num);
首先,将需要保存的指定目标区域(left, top,right, bottom)等分成若干个存储面积小于64KB-1的小矩形块B1,B2,B3,..., Bn,然后利用标准的imagesize和getimage函数分n次将各块保存到同一个位图文件中。文件名形式为"WINXXX. SAV", "XXX"是该区域(或称为窗口)的标志号,它应是000-999之间的一个值,且是唯一的。如WIN666.SAV.分块算法如下:
(i)单块高度=单块的最大块长*每字节点数/块宽度
(ii)分块总数=指定目标区域高度/单块高度
(iii)实际分块总数=分块总数,如果指定目标区域高度%单块高度=0
分块总数+1,如果指定目标区域高度%单块高度!=0
注:
(a):单块的最大块长越大,则单块高度越大,分块总数越小,显示速度越快,但应小于64KB-1,一般取63KB以下。
(b):每字节点数由当前显示器的图形方式确定。如当前一个点能够显示的最大颜色数为MaxColor,则每字节可存储的点数为:log2 MaxColor。如对VGA 640 * 480 * 16方式每字节点数=2。用户需要在初始化图形方式后,给定每字节点数,本文以如下方式实现:
switch ((getmaxcolor ()+1))
{
case 2 :DotPerByte=8; break;
case 4 :DotPerByte=4; break;
case 16 :DotPerByte=2; break;
default :DotPerByte=1;
};
(c):根据实际分块数在保存和恢复位图时由NewGetImage, NewPutImage自动作一调整。NewImageSize函数算法计算代码如下:
*height = (int) (MaxLength0fBlock * DotPerByte / (right - left + 1));
*block-num = (bottom - top +1) / *height;
NewGetImage函数根据NewImageSize函数计算的小块的数目和单块高度对指定区域进行分块保存,代码如下:
void NewGetImage (int left, int top, int right, int bottom, int win-id)
{
FILE *fp;
char filename [20];
char temp [4];
unsigned int size=0;
void *image-buf;
int ya,yb;
int height,block-num;
int i;
strcpy(filename,"WIN");
strncat(filename, itoa(win-id, temp, 10), 3);
strncat(filename, ".SAV", 4);
if((fp=fopen(filename,"wb"))==NULL)
{
printf("\nError open file in NewGetImage !")'
exit(0);
};
if(NewImageSize(left, top, right, bottom, &height, &block-num))
{
printf("\nInvalid coordinate !");
}
else
{
ya=top;yb=top+height-1;
size = imagesize(left, ya, right, yb);
image-buf = UserMalloc(size);
for(i=0;i<block-num;i++)
{
getimage(left, ya, right, yb, image-buf);
if(fwrite(image-buf, size, 1, fp) != 1 )
{
printf("\nError write file in NewGetImage !");
exit(0);
};
ya = yb+1;yb = ya+height-1;
};
if(image-buf) free(image-buf);
if( ya < bottom )
{
size = imagesize(left, ya, right, bottom);
image-buf = UserMalloc(size);
getimage(left, ya, right, bottom, image-buf);
if(fwrite(image-buf, size, 1, fp) != 1) /* write struct s to file */
{
printf("\nError write file in NewGetImage !");
exit(0);
};
free(image-buf);
};
};
fclose(fp);
}
NewGetImage独特之处在于该函数使用磁盘文件作为屏幕暂存区域,而不是使用常规内存。因此在调用NewGetImage前后常规内存并没有减少!它需要一个窗口编号win-id用于形成该文件的文件名:WINXXX.SAV。
NewPutImage函数是NewGetImage函数的逆过程。由用户传入的窗口编号win-id找到对应的先前保存的位图文件,使用同样的分块算法进行分块,然后依次读入并显示各块到对应位置。在调用NewGetImage前后常规内存并没有增加,也没有减少。代码如下:
void NewPutImage(int left,int top,int right,int bottom, int win-id)
{
FILE *fp;
char filename[20];
char temp[4];
unsigned int size=0;
void *image-buf;
int ya,yb;
int height,block-num;
int i;
strcpy(filename,"WIN");
strncat(filename, itoa(win-id, temp, 10), 3);
strncat(filename, ".SAV", 4);
if((fp = fopen(filename,"rb")) == NULL)
{
printf("\nError open file in NewPutImage !");
exit(0);
};
if(NewImageSize(left, top, right, bottom, &height, &block-num))
{
printf("\nInvalid coordinate !");
}
else
{
ya=top;yb=top+height-1;
size = imagesize(left, ya, right, yb);
image-buf = UserMalloc(size);
for(i = 0;i< block-num;i++)
{
if(fread(image-buf, size, 1, fp) != 1) /* write struct s to file */
{
printf("\nError read file in NewPutImage !");
exit(0);
}
putimage(left, ya, image-buf, COPY-PUT);
ya = yb+1;yb = ya+height-1;
};
if(image-buf) free(image-buf);
if( ya < bottom)
{
size = imagesize(left, ya, right, bottom);
image-buf = UserMalloc(size);
if(fread(image-buf, size, 1, fp) != 1) /* write struct s to file */
{
printf("\nError read file in NewPutImage !");
exit(0);
};
putimage(left, ya, image-buf, COPY-PUT);
free(image-buf);
};
};
fclose(fp);
remove(filename);
}
三、算法分析
使用该算法的最大优点是它可以保存和恢复无限个(仅受磁盘空间限制)任意尺寸大小的屏幕区域,包括1024*768*256在内的大屏幕。
用户只须给定(left, top, right, bottom)和一个窗口编号,至于保存和恢复的内部实现细节不用关心。
该算法对于大型工程项目软件及GUI系统的用户来说,可以节约大量宝贵的常规内存空间,无须担心内存不够等问题。把640KB尽可能多地留给真正需要它的地方。
该算法也同时提供了一种截取屏幕图像的极好方法。只需在NewPutImage函数去掉如下语句:
remove (filename);
则任一时刻任一区域的图像将留给用户的磁盘上,调入时使用相应的NewPutImage即可。
该算法的不足之处在于恢复大于64K屏幕时在每两个连续的小块显示之间有微小的停顿感,因为此时NewPutImage在作读入下一块的工作。使用smartdrv.sys和vdisk.sys可以改善上述现象。如将虚盘开在扩充或扩展内存中,那么就可以直接利用这三个函数使用它们。并不需要了解和遵守繁琐的规范,显示速度可大为改观。
本算法使用Turbo C 2.0编写,也有相应的Borland C++ 3.1版本。经过笔者的多个大型软件使用证明,效果很好。用户使用时需要在源程序中加入下面语句:
#include "newimage.h"
本文附有一个简单的演示程序,它将一个需要82KB存储空间的矩形窗口显示出来,并快速移动它,据此可以观察本文所述算法的实际运行速度及效果。
/************************/
/* */
/*File Name:DEMO.C*/
/* */
/************************/#include <graphics.h>
#include "newimage.h"
long int MaxLengthOfBlock;
int DotPerByte;
void main(void)
{
int x=0,y=0,Wide=0,Height=0;
int i=0;
int gdriver = DETECT, gmode, errorcode;
int midx,midy;
/*initialize graphics and local variables*/
initgraph(&gdriver,&gmode,"");
/*read result of initialization*/
errorcode = graphresult();
if(errorcode !=grOk) /*an error occurred*/
{
printf("Graphics error:%s\n",grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
exit(1); /*terminate with an error code*/
};
MaxLengthOfBlock=631*1024;
switch((getmaxcolor()+1))
{
case 2:DotPerByte=8;break;
case 4:DotPerByte=4;break;
case 16:DotPerByte=2;break;
default:DotPerByte=1;
};
Wide=getmaxx()/2+100;
Height=getmaxy()/2+150;
setfillstyle(11,EGA-LIGHTGRAY);
bar(0,0,getmaxx(),getmaxy());
NewGetImage(0,0,Wide,Height,1);
setfillseyle(1,EGA-GREEN);
bar(0,0,Wide,Height);
setcolor(1);
rectangle(0,0,Wide,Height);
rectangle(0+2,0+2,Wide-2,Height-2);
setcolor(EGA-RED);
for(i=0;i<Height/textheight("w");i++)
outtextxy(4,i*textheight("w")+3,"Hello ! Computer World !");
setfillstyle(1,EGA-BLUE);
fillellipse(Wide/2+50,Height/2,50,80);
NewGetImage(0,0,Wide,Height,2);
getch();
NewPutImage(0,0,Wide,Height,1);
for(y=16,x=16;y<getmaxy()-Height-16;y+=16,x+=16)
{
NewGetImage(x,y,x+Wide,y+Height,1);
NewPutImage(x,y,x+Wide,y+Height,2);
NewGetImage(x,y,x+Wide,y+Height,2);
getch();
NewPutImage(x,y,x+Wide,y+Height,1);
};
NewPutImage(x,y,x+Wide,y+Height,2);
}
/************************/
/*File Name:NEWIMAGE.H*/
/************************/
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#include<conio.h>
void NewGetImage(int left,int top,int right,int bottom,int win-id);
void NewPutImage(int left,int top,int right,int bottom,int win-id);
int NewImageSize(int left,int top,int right,int bottom,
int *height,int *block-num);
void *UserMalloc(unsigned int);
extern long MaxLengthOfBlock;
extern int DotPerByte;
/*------------------------------------*/
void NewGetImage(int left,int top,int right,int bottom,int win-id);
{
FILE *fp;
char filename[20];
char temp[4];
unsigned int size=0;
void *image-buf;
int ya,yb;
int height,block-num;
int i;
strcpy(filename,"WIN");
strncat(filename,itoa(win-id,temp,10),3);
strncat(filename,".SAV",4);
if((fp=fopen(filename,"wb"))==NULL)
{
printf("\nError open file in NewGetImage !");
exit(0);
}
if(NewImageSize(left, top, right, bottom, &height, &block-num))
{
printf("\nInvalid coordinate !");
}
else
{
ya=top;yb=top+height-1;
size=imagesize(left, ya, right, yb);
image-buf=UserMalloc(size);
for(i=0;i<block-num;i++)
{
getimage(left, ya, right, yb, image-buf);
if(fwri
te(image-buf, size, 1, fp) !=1 )
{
printf("\nError write file in NewGetImage !");
exit(0);
}
ya=yb+1;yb=ya+height-1;
};
if(image-buf)free(image-buf);
if(ya<bottom)
{
size=imagesize(left, ya, right, bottom);
image-buf=UserMalloc(size);
getimage(left, ya, right, bottom, image-buf);
if(fwrite(image-buf, size, 1, fp) !=1) /* write struct s to file */
{
printf("\nError write file in NewGetImage !");
exit(0);
};
free(image-buf);
};
};
fclose(fp);
}
/*------------------------------------*/
void NewPutImage(int left,int top,int right,int bottom,int win-id)
{
FILE *fp;
char filename[20];
char temp[4];
unsigned int size=0;
void *image-buf;
int ya,yb;
int height,block-num;
int i;
strcpy(filename,"WIN");
strncat(filename,itoa(win-id, temp, 10), 3);
strncat(filename,".SAV", 4);
if((fp=fopen(filename,"rb"))==NULL)
{
printf("\nError open file in NewPutImage !");
exit(0);
};
if(NewImageSize(left, top, right, bottom, &height, &block-num))
{
printf("\nInvalid coordinate !");
}
else
{
ya=top;yb=top+height-1;
size=imagesize(left, ya, right, yb);
image-buf=UserMalloc(size);
for(i=0;i<block-num;i++)
{
if(fread(image-buf, size, 1, fp) !=1) /* write struct s to file */
{
printf("\nError read file in NewPutImage !");
exit(0);
};
putimage(left, ya, image-buf, COPY-PUT);
ya=yb+1;yb=ya+height-1;
};
if(image-buf) free(image-buf);
if(ya<bottom)
{
size=imagesize(left,ya,right,bottom);
image-buf=UserMalloc(size);
if(fread(image-buf,size,1,fp) !=1) /* write struct s to file */
{
printf("\nError read file in NewPutImage !");
exit(0);
};
putimage(left,ya,image-buf,COPY-PUT);
free(image-buf);
};
};
fclose(fp);
remove(filename);
};
/*------------------------------------*/
int NewImageSize(int left,int top,int right,int bottom,
int *height,int *block-num)
{
if(left<0 ||right>getmaxx()||left>=right||
top<0||bottom>getmaxy()||top>=bottom)
return 1;
*height=(int)(MaxLengthOfBlock*DotPerByte/(right-left+1));
*block-num=(bottom-top+1)/ *height;
return 0;
};
/*------------------------------------*/
void *UserMalloc(size-t size)
{
void *p;
if((p=malloc(size))==NULL)
{
printf("\nNot enough memory !");
exit(1);
};
return(p);
}
本文摘录自互联网络,在此刊登仅为传递更多信息,版权归作者所有.

