如果你想用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键进行截图:
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 : cifry@163.com";
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();
}
}