如果你想用TC对BMP文件进行操作,首先应该清楚BMP的文件格式。
<TC读取BMP文件>
在TC的graphic模式下是可以对BMP文件进行读入的,但是因为我们使用的模式是EGAVGA,只能显示16种颜色,所以也就要求BMP文件的属性为16色(位深度4),对BMP文件格式熟悉的朋友都应该知道,除了真彩色中“位图数据区”中存储的就是它的RGB值之外,其他的颜色模式,比如256色,16色 2色,在它们的“位图数据区”中存储的只是“颜色表”的索引值,而颜色表中才是存储着某像素的RGB值。这就给我们在TC的graphic模式下读取BMP文件信息造成了很大障碍,首先,我们不能简单的只读取“位图数据区”中的数据直接当成“颜色值”,因为那只是“颜色表”的“索引值”,比如属性为16色的BMP文件,“位图数据区”中的一个字节为0x00ff,在16色模式中,它并不代表黑色和白色,而是代表在“颜色表”的第0个表和第15个表中的颜色。再者,你通过“索引值”取得的“颜色表”中的是一个RGB值,这个值如何转换成EGAVGA所能表示的16色呢?我曾想过使用近似值的方法,也就是将RGB值归类成EGAVGA所能表示的16种颜色,但这是不可能办到的,因为RGB的取值是256×256×256种颜色(3Byte)。所以最后也只能将“索引值”当成“颜色值”在屏幕上显示了,所幸的是用WINDOWS自带的绘图软件所转换的16色BMP图片的“索引值”基本都等于“颜色值”,当然也有部分的“颜色值”需要我们手动转换,但这样的转换就简单多了(这里我要感谢我的朋友阿华在这方面做的测试,我用的“调色板”是他颜色转换实验的成果),还有,WINDOWS自带的绘图软件所转换后的BMP16色图片中使用的颜色是最接近EGAVGA所能表示的16种颜色(所以看起来失真度也就非常大,当然,我们也可以使用photoshop等等工具来制作16色的BMP图片,但因为这类软件想保证图片的最大真实度,所以它们所转换的16色BMP图片对“颜色表”做了修改,它所表示的16色是RGB中最接近图片本色的16色,所以用photoshop等等工具所转换的16色BMP图片看起来都和原图区别不是很大,但通过这类工具转换的16色BMP图片在我的程序中显示的颜色都是错乱的)。
<TC写入BMP文件>
有时候,我们很想将TC在graphic模式下所显示的图像“截取”下来,但因为TC是DOS程序,所以我们无法使用WINDOWS的“截图”功能来办到(这里只以XP系统做说明,因为似乎WIN98和WIN2000可以通过按ALT+TAB 将TC的graphic模式窗口化来达到“截图”的目的),但我们可以通过将TC的graphic模式下的图像保存成一份BMP文件以达到“截图”的目的。具体的做法就是编写你的“颜色表”,在这里,我使用的是EGAVGA的颜色常量值作为“颜色表”的索引值,这样就可以将屏幕上像素的“颜色值”直接保存到BMP文件的中“位图数据区”而无需再做转换,而“颜色表”中的RGB值我将尽可能找到最接近EGAVGA所能表示的16色值的颜色。这样保存的BMP图片无法再用我的BMP读取代码读取出来,因为这个“颜色表”是我自定的,性质如同photoshop对颜色表的优化处理,所以,再用我的BMP读取代码显示在屏幕上的图片颜色将是错乱的。
void screen_save_bmp16(char *savefile,unsigned x1,unsigned y1,unsigned x2,unsigned y2)为BMP文件的写入函数,你可以将它放入你的程序中看效果。
void display_bmp16(char *bmpfile,unsigned x,unsigned y)为BMP文件的读入函数,你可以用WINDOWS自带的绘图软件处理一张16色的BMP图片看效果。
以下是代码,按F1键进行截图:
/*------------------------------------>>> Game: DOS Intercept Image Author: Cifry Create Date: 2007.09.03 New Amend: 2007.09.04 SAY: 该程序可以将DOS屏幕上任意位置的图像输出保存为BMP文件 添加了截图进度条 有些DOS上的图像输出后的BMP文件存在变形,已诊断并非程 序问题,此情况多发生在屏幕有大字体输出上 BUG: 图片小于52×52将不能显示,目前还未找到原因 <<<------------------------------------*/ #ifndef BYTE typedef unsigned char BYTE; #endif #ifndef WORD typedef int WORD; #endif #ifndef UINT typedef unsigned UINT; #endif #ifndef LONG typedef long LONG; #endif #ifndef DWORD typedef long DWORD; #endif /*位图文件头*/ typedef struct tagBITMAPFILEHEADER { UINT bfType; /*位图文件的类型,必须为BM*/ DWORD bfSize; /*位图文件的大小,以字节为单位*/ UINT bfReserved1; /*位图文件保留字,必须为0*/ UINT bfReserved2; /*位图文件保留字,必须为0*/ DWORD bfOffBits; /*位图数据的起始位置,以相对于位图文件头的偏移量表示,以字节为单位*/ } BITMAPFILEHEADER; /*位图信息头*/ typedef struct tagBITMAPINFOHEADER { DWORD biSize; /*本结构所占用字节数*/ LONG biWidth; /*位图的宽度,以像素为单位*/ LONG biHeight; /*位图的高度,以像素为单位*/ WORD biPlanes; /*目标设备的级别,必须为1*/ WORD biBitCount; /*每个像素所需的位数,必须是1(双色),4(16色),8(256色)或24(真彩色)之一*/ DWORD biCompression; /*位图压缩类型,必须是 0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一*/ DWORD biSizeImage; /*位图的大小,以字节为单位*/ LONG biXPelsPerMeter; /*位图水平分辨率,每米像素数*/ LONG biYPelsPerMeter; /*位图垂直分辨率,每米像素数*/ DWORD biClrUsed; /*位图实际使用的颜色表中的颜色数*/ DWORD biClrImportant; /*位图显示过程中重要的颜色数*/ } BITMAPINFOHEADER; /*颜色表*/ typedef struct tagRGBQUAD { BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/ BYTE rgbGreen; /*绿色的亮度(值范围为0-255)*/ BYTE rgbRed; /*红色的亮度(值范围为0-255)*/ BYTE rgbReserved; /*保留,必须为0*/ } RGBQUAD; #include<stdio.h> #include<alloc.h> #include<fcntl.h> #include<io.h> #include<graphics.h> /*EGAVGA16色转换RGB值 呵呵,大家可要喝水不忘挖井人哟*/ void setRGBQUAD(RGBQUAD *rgbquad) { /*黑色0*/ rgbquad->rgbRed=0x00; rgbquad->rgbGreen=0x00; rgbquad->rgbBlue=0x00; rgbquad++; /*蓝色1*/ rgbquad->rgbRed=0x00; rgbquad->rgbGreen=0x00; rgbquad->rgbBlue=0xFF; rgbquad++; /*绿色2*/ rgbquad->rgbRed=0x80; rgbquad->rgbGreen=0x80; rgbquad->rgbBlue=0x00; rgbquad++; /*青色3*/ rgbquad->rgbRed=0x00; rgbquad->rgbGreen=0xFF; rgbquad->rgbBlue=0xFF; rgbquad++; /*红色4*/ rgbquad->rgbRed=0xFF; rgbquad->rgbGreen=0x00; rgbquad->rgbBlue=0x00; rgbquad++; /*洋红5*/ rgbquad->rgbRed=0xFF; rgbquad->rgbGreen=0x00; rgbquad->rgbBlue=0xFF; rgbquad++; /*棕色6*/ rgbquad->rgbBlue=0x2A; rgbquad->rgbRed=0xA5; rgbquad->rgbGreen=0x2A; rgbquad++; /*淡灰7*/ rgbquad->rgbRed=0x77; rgbquad->rgbGreen=0x88; rgbquad->rgbBlue=0x99; rgbquad++; /*深灰8*/ rgbquad->rgbRed=0xA9; rgbquad->rgbGreen=0xA9; rgbquad->rgbBlue=0xA9; rgbquad++; /*深蓝9*/ rgbquad->rgbRed=0xAD; rgbquad->rgbGreen=0xD8; rgbquad->rgbBlue=0xE6; rgbquad++; /*淡绿10*/ rgbquad->rgbRed=0x90; rgbquad->rgbGreen=0xEE; rgbquad->rgbBlue=0x90; rgbquad++; /*淡青11*/ rgbquad->rgbRed=0xE0; rgbquad->rgbGreen=0xFF; rgbquad->rgbBlue=0xFF; rgbquad++; /*淡红12*/ rgbquad->rgbRed=0xCD; rgbquad->rgbGreen=0x5C; rgbquad->rgbBlue=0x5C; rgbquad++; /*淡洋红13*/ rgbquad->rgbRed=0xDB; rgbquad->rgbGreen=0x70; rgbquad->rgbBlue=0x93; rgbquad++; /*黄色14*/ rgbquad->rgbRed=0xFF; rgbquad->rgbGreen=0xFF; rgbquad->rgbBlue=0x00; rgbquad++; /*白色15*/ rgbquad->rgbRed=0xFF; rgbquad->rgbGreen=0xFF; rgbquad->rgbBlue=0xFF; } /*截图进度显示*/ int guage(int plan) { static unsigned _x; static unsigned _y; static void *image; static int initialize=1; static float percent; static float buff; static unsigned tally; int displayhow; unsigned print; if(plan==0)return 1; if(initialize==1) { unsigned size; _x=getmaxx(); _y=getmaxy(); _x=(_x-100)/2; _y=(_y-9); percent=(float)100/plan; buff=0.49; tally=0; size=imagesize(_x,_y,_x+100,_y+4); image=malloc(size); getimage(_x,_y,_x+100,_y+4,image); setfillstyle(SOLID_FILL,WHITE); bar(_x,_y,_x+100,_y+4); initialize=0; } buff+=percent; displayhow=(int)buff; if(displayhow!=0) { buff=buff-displayhow; setfillstyle(SOLID_FILL,RED); bar(_x+tally,_y,_x+tally+displayhow,_y+4); tally+=displayhow; } if(tally==100) { putimage(_x,_y,image,COPY_PUT); free(image); initialize=1; return 1; } return 0; } /*16色屏幕图像保存为BMP图片*/ void screen_save_bmp16(char *savefile,unsigned x1,unsigned y1,unsigned x2,unsigned y2) { BITMAPFILEHEADER *bmphard;/*位图文件头*/ BITMAPINFOHEADER *bmpinfo;/*位图信息头*/ RGBQUAD *rgbquad;/*颜色表*/ unsigned widthpixel =x2-x1+1;/*宽像素值*/ unsigned heightpixel=y2-y1+1;/*高像素值*/ unsigned widthbyte;/*宽字节值*/ unsigned heightbyte;/*高字节值*/ int handpf;/*文件句柄*/ BYTE *buff; if((handpf=open(savefile,O_WRONLY|O_CREAT))==-1) { printf("/n not save %s/n",savefile); getch(); exit(1); } widthbyte=(x2-x1+1+1)/2; if(widthbyte%4!=0)/*处理补零情况*/ { widthbyte=widthbyte+(4-widthbyte%4); } heightbyte=y2-y1+1; bmphard=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER));/*申请位图文件头所需空间*/ bmpinfo=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER));/*申请位图信息头所需空间*/ bmphard->bfType=0x4D42; bmphard->bfSize=sizeof(BITMAPFILEHEADER)/*位图文件的大小*/ +sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD)*16 +((DWORD)widthbyte*heightbyte); bmphard->bfReserved1=0; bmphard->bfReserved2=0; bmphard->bfOffBits=sizeof(BITMAPFILEHEADER) +sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD)*16; bmpinfo->biSize=sizeof(BITMAPINFOHEADER); bmpinfo->biWidth=widthpixel; bmpinfo->biHeight=heightpixel; bmpinfo->biPlanes=1; bmpinfo->biBitCount=4; bmpinfo->biCompression=0; bmpinfo->biSizeImage=((DWORD)widthbyte*heightbyte); bmpinfo->biXPelsPerMeter=0; bmpinfo->biYPelsPerMeter=0; bmpinfo->biClrUsed=0; bmpinfo->biClrImportant=0; rgbquad=(RGBQUAD *)malloc(sizeof(RGBQUAD)*16); setRGBQUAD(rgbquad);/*设置颜色表*/ write(handpf,bmphard,sizeof(BITMAPFILEHEADER));/*写入位图文件头*/ write(handpf,bmpinfo,sizeof(BITMAPINFOHEADER));/*写入位图信息头*/ write(handpf,rgbquad,sizeof(RGBQUAD)*16);/*写入颜色表*/ buff=(BYTE *)malloc(widthbyte);/*设置缓冲区,提高写速度*/ while(heightpixel--)/*从下至上写入数据*/ { unsigned _x; BYTE *poinbuff=buff; for(_x=0;_x<(widthpixel+1)/2;_x++) { BYTE pixelbyte=0; unsigned color; color=getpixel(_x*2+x1,heightpixel+y1); color<<=4; color+=getpixel(_x*2+1+x1,heightpixel+y1)&0x000f; pixelbyte=(BYTE)color; *poinbuff=pixelbyte; poinbuff++; } write(handpf,buff,widthbyte); if(heightpixel+y1 < (getmaxy()-9)) { guage(heightpixel); } } free(buff); close(handpf); free(rgbquad); /*内存释放*/ free(bmphard); /*内存释放*/ free(bmpinfo); /*内存释放*/ } /*------------------------------------>>> Game: BMP Load DOS Author: Cifry Create Date: 2007.09.02 New Amend: 2007.09.04 SAY: 和DOS Intercept Image函数模块的功能正好相反,该 函数是将16色BMP图片导入到DOS图形模式下 <<<------------------------------------*/ /*该调色板取自阿华的调色实验成果*/ unsigned Palette(int color) { switch(color) { case 1: return RED; case 4: return BLUE; case 3: return BROWN; case 6: return CYAN; case 9: return LIGHTRED; case 12: return LIGHTBLUE; case 11: return YELLOW; case 14: return LIGHTCYAN; default: return color; } } /*16色BMP图片导入*/ void display_bmp16(char *bmpfile,unsigned x,unsigned y) { BITMAPFILEHEADER *bmphard;/*位图文件头*/ BITMAPINFOHEADER *bmpinfo;/*位图信息头*/ RGBQUAD *rgbquad;/*颜色表*/ unsigned widthpixel;/*宽像素值*/ unsigned heightpixel;/*高像素值*/ unsigned widthbyte;/*宽字节值*/ int handpf;/*文件句柄*/ BYTE *buff; if((handpf=open(bmpfile,O_RDONLY))==-1) { printf("/n not open //%s/n",bmpfile); getch(); exit(1); } bmphard=(BITMAPFILEHEADER *)malloc(sizeof(BITMAPFILEHEADER));/*申请位图文件头所需空间*/ bmpinfo=(BITMAPINFOHEADER *)malloc(sizeof(BITMAPINFOHEADER));/*申请位图信息头所需空间*/ read(handpf,bmphard,sizeof(BITMAPFILEHEADER));/*读取位图文件头*/ read(handpf,bmpinfo,sizeof(BITMAPINFOHEADER));/*读取位图信息头*/ if(bmpinfo->biBitCount!=4)/*16色图片*/ { printf("/nNot Sustain BMP Color Amount!/n"); getch(); exit(1); } if(bmphard->bfType!=0x4D42) { printf("/nThis's Not BMP File!/n"); getch(); exit(1); } widthpixel =bmpinfo->biWidth; heightpixel=bmpinfo->biHeight; widthbyte=(bmpinfo->biWidth+1)/2; if(widthbyte%4!=0)/*处理补零情况*/ { widthbyte=widthbyte+(4-widthbyte%4); } lseek(handpf,(long)bmphard->bfOffBits,SEEK_SET); /*文件指针指向位图数据区*/ buff=(BYTE *)malloc(widthbyte);/*设置缓冲区,提高读速度*/ while(heightpixel--)/*从下至上读入数据*/ { BYTE *poinbuff=buff; unsigned _x; static BYTE flag; flag=0; read(handpf,buff,widthbyte);/*得到每一行的像素*/ for(_x=0;_x<widthpixel;_x++) { if(flag==0) { int color=(*poinbuff>>4)&0x0f; color&=0x00FF; putpixel(x+_x,y+heightpixel,Palette(color)); } if(flag==1) { int color=*poinbuff&0x0f; color&=0x00FF; putpixel(x+_x,y+heightpixel,Palette(color)); poinbuff++; } if(flag==0)flag=1; else flag=0; } } free(buff);/*内存释放*/ close(handpf); free(bmphard); /*内存释放*/ free(bmpinfo); /*内存释放*/ } /*------------------------------------>>> Game: MOUSE MAGNIFIER Author: Cifry Create Date: 2007.06 SAY: 早期写的鼠标程序,现用于测试DOS Intercept Image程序 <<<------------------------------------*/ #include<dos.h> #include<conio.h> #include<graphics.h> #include<bios.h> getmouse() { union REGS inregs,outregs; inregs.x.ax=3; int86(0x33,&inregs,&outregs); /*gotoxy(2,6);printf("%-3d,%-3d",outregs.x.cx,outregs.x.dx);*/ mouse_pointer(outregs.x.cx,outregs.x.dx); } mouse_pointer(int mouse_x,int mouse_y) { int pixi,pixj; static int revert_x,revert_y; int _x,_y; static int savimage[16][16]; static int flag=1; int mose_pot[16]={ 0x0003,0x000D,0x0032,0x00C2, 0x0304,0x0C04,0x3008,0xC008, 0x4010,0x2010,0x1020,0x0820, 0x0440,0x0240,0x0180,0x0080, }; if(flag==1) { revert_x=mouse_x; revert_y=mouse_y; for(pixi=0,_y=mouse_y;pixi<16;pixi++,_y++) for(pixj=0,_x=mouse_x;pixj<16;pixj++,_x++) savimage[pixi][pixj]=getpixel(_x,_y); for(pixi=0;pixi<16;pixi++) { int test=0x0001; for(pixj=0;pixj<16;pixj++) { if((mose_pot[pixi]&test)!=0) putpixel(mouse_x+pixj,mouse_y+pixi,15); test<<=1; } } flag=0; } if((mouse_x!=revert_x)||(mouse_y!=revert_y)) { for(pixi=0;pixi<16;pixi++) { int test=0x0001; for(pixj=0;pixj<16;pixj++) { if((mose_pot[pixi]&test)!=0) putpixel(revert_x+pixj,revert_y+pixi,savimage[pixi][pixj]); test<<=1; } } revert_x=mouse_x; revert_y=mouse_y; for(pixi=0,_y=mouse_y;pixi<16;pixi++,_y++) for(pixj=0,_x=mouse_x;pixj<16;pixj++,_x++) savimage[pixi][pixj]=getpixel(_x,_y); for(pixi=0;pixi<16;pixi++) { int test=0x0001; for(pixj=0;pixj<16;pixj++) { if((mose_pot[pixi]&test)!=0) putpixel(mouse_x+pixj,mouse_y+pixi,~savimage[pixi][pixj]&0x00FF); test<<=1; } } } } void userinigraph(int gdriver,int gmode,char *say)/*自定义图形检测*/ { int errorcode; initgraph(&gdriver,&gmode,""); errorcode = graphresult(); if (errorcode !=0) { printf("%s/n",say); printf("/n/terror:/t%s/n", grapherrormsg(errorcode)); getch(); exit(1); } } word() { int x=100,y=150; char *author="Author : Cifry"; char *qq= "OICQ : 442044866"; char *email= "Email : [email protected]"; settextstyle(0,0,4); setcolor(BLUE); outtextxy(x,y,"M"); setcolor(GREEN); outtextxy(x+=32,y,"0"); setcolor(CYAN); outtextxy(x+=32,y,"U"); setcolor(RED); outtextxy(x+=32,y,"S"); setcolor(MAGENTA); outtextxy(x+=32,y,"E"); setcolor(BLACK); outtextxy(x+=32,y," "); setcolor(BROWN); outtextxy(x+=32,y,"M"); setcolor(LIGHTGREEN); outtextxy(x+=32,y,"a"); setcolor(LIGHTCYAN); outtextxy(x+=32,y,"g"); setcolor(LIGHTRED); outtextxy(x+=32,y,"n"); setcolor(LIGHTMAGENTA); outtextxy(x+=32,y,"i"); setcolor(YELLOW); outtextxy(x+=32,y,"f"); setcolor(WHITE); outtextxy(x+=32,y,"i"); setcolor(BLUE); outtextxy(x+=32,y,"e"); setcolor(RED); outtextxy(x+=32,y,"r"); x=400;y=250; settextstyle(0,0,0); setcolor(WHITE); outtextxy(x,y,author); outtextxy(x,y+=20,qq); outtextxy(x,y+=20,email); } main() { userinigraph(VGA,VGAHI, "/n/t/t/tGame : DOS Intercept Image/n/t/t/tAuthor : Cifry/n"); /*display_bmp16("****.bmp",0,0);*//*在这里读入你张你处理好的16色BMP图片*/ word(); while(1) { if(bioskey(1)) { char filename[20]={0}; struct time t;/*以时间命名截图文件*/ gettime(&t); sprintf(filename,"%d",t.ti_hour); sprintf(filename+strlen(filename),"%d",t.ti_min); sprintf(filename+strlen(filename),"%d",t.ti_sec); sprintf(filename+strlen(filename),"%d",t.ti_hund); strcat(filename,".bmp"); if(bioskey(0)==0x3B00)/*F1键进入截图*/ screen_save_bmp16(filename,0,0,639,479); else break; } getmouse(); } }