///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////BMP接口: 基于8位,16位位图的显示及贴图文件处理
/////版本: 3.0
/////程序: 沈华
/////日期: 2004.12.26
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __ZBMP_CPP
#define __ZBMP_CPP
//文件头14字节结构(不常用)
struct
{
int type; //2
long filesize; //4
int reserved1; //2
int reserved2; //2
long imageoffset; //4
}BMPHEAD; //14bytes
//信息头结构40字节(同ICONINFO)
struct
{
long size; //4
long width; //4
long height; //4
int planes; //2
int bitcount; //2
long compress; //4
long imagesize; //4
long xpelspermeter; //4
long ypelspermeter; //4
long clrused; //4
long clrimportant; //4
}BMPINFO; //40bytes
//自定义的256色图片格式,主要用于3D引擎纹理贴图
struct
{
long width; //图片宽度
long height; //图片高度
unsigned char colornum[256][3]; //已规格化(直接调色板接口排列顺序)
}PICINFO;
//图片高宽及色深全局变量
unsigned long BMPWIDTH;
unsigned long BMPHEIGHT;
unsigned long BITDEPTH;
//设置全局量和返回备用调色板号(打开成功返回大于零值)
int G_OPENBMP(unsigned char far * filename,unsigned int tsbnum=0,char lookinfo=0);
int G_SHOWBMP256(unsigned char far * filename,int sx=0,int sy=0,unsigned int tsbnum=0);
int G_SHOWBMP565(unsigned char far * filename,int sx=0,int sy=0);
//显示BMP图片的通用版本
int G_SHOWBMP(unsigned char far * filename,int sx=0,int sy=0,unsigned int tsbnum=0);
//显示PIC格式文件
int G_SHOWPIC(unsigned char far * filename,int sx=0,int sy=0);
//BMP格式转换为PIC格式
int G_BMP2PIC(unsigned char far * bmpname,unsigned char far * picname);
int G_OPENBMP(unsigned char far * filename,unsigned int tsbnum,char lookinfo)
{
unsigned char colornum[256][4];
FILE *fp;
if( (fp=fopen(filename,"rb"))==NULL)
{fclose(fp);return 0;}
if(lookinfo!=-1)
{fread(&BMPHEAD,1,sizeof(BMPHEAD),fp);}
//定位信息结构
fseek(fp,14,SEEK_SET);
//读取信息结构数据
fread(&BMPINFO,1,sizeof(BMPINFO),fp);
if(lookinfo)
{
G_CLS(0);
G_PUTS("位图文件的格式信息",32,0);
G_PUTS("按任意键退出",200,0);
G_PRINTEN(0,20,"BMPHEAD:");
G_PRINTEN(0,35," filesize=%ldKb",BMPHEAD.filesize/1000);
G_PRINTEN(0,50," reserved1=%d",BMPHEAD.reserved1);
G_PRINTEN(0,65," reserved2=%d",BMPHEAD.reserved2);
G_PRINTEN(0,80,"imageoffset=%ld",BMPHEAD.imageoffset);
G_PRINTEN(160,20,"BMPINFO:");
G_PRINTEN(160,35," size=%ld",BMPINFO.size);
G_PRINTEN(160,50," width=%ld",BMPINFO.width);
G_PRINTEN(160,65," height=%ld",BMPINFO.height);
G_PRINTEN(160,80," planes=%d",BMPINFO.planes);
G_PRINTEN(160,95," bitcount=%d",BMPINFO.bitcount);
G_PRINTEN(160,110," compress=%ld",BMPINFO.compress);
G_PRINTEN(160,130," imagesize=%ldKb",BMPINFO.imagesize/1000);
G_PRINTEN(160,145," xpelspermeter=%ld",BMPINFO.xpelspermeter);
G_PRINTEN(160,160," ypelspermeter=%ld",BMPINFO.ypelspermeter);
G_PRINTEN(160,175," clrused=%ld",BMPINFO.clrused);
G_PRINTEN(160,190," clrimportant=%ld",BMPINFO.clrimportant);
getch();
G_CLS(0);
}
//向全局变量赋值
BMPWIDTH=BMPINFO.width;
BMPHEIGHT=BMPINFO.height;
//确定是否压缩及256色格式
switch(BMPINFO.bitcount)
{
case 4:
BITDEPTH=4;break;
case 8:
BITDEPTH=8;break;
case 24:
BITDEPTH=24;break;
}
//不支持压缩或16色格式
if(BMPINFO.compress==1 || BITDEPTH==4)
{fclose(fp);return 0;}
//不支持在256色模式下显示真彩格式图片即不支持抖动显示
if(G_BITWIDTH==1 && BITDEPTH==24)
{fclose(fp);return 0;}
//256色格式设置调色板索引
if(BITDEPTH==8)
{
fseek(fp,54,SEEK_SET);
fread(colornum,1,1024,fp);
for(unsigned int i=0;i<256;i++)
{
G_TSB[tsbnum][i][0]=(colornum[i][2])>>2;
G_TSB[tsbnum][i][1]=(colornum[i][1])>>2;
G_TSB[tsbnum][i][2]=(colornum[i][0])>>2;
}
}
fclose(fp);
return tsbnum;
}
int G_SHOWBMP256(unsigned char far * filename,int sx,int sy,unsigned int tsbnum)
{
FILE *fp;
if( (fp=fopen(filename,"rb"))==NULL)
{fclose(fp);return 3;}
unsigned char colorn[1024];//显示宽度支持至1024象素
long width=BMPWIDTH,height=BMPHEIGHT;
long gy=height,gx=width,zy=0L,offn;
long xoff=0L,yoff=0L;
unsigned int bz8,bz565;
sx+=G_VMINX;
sy+=G_VMINY;
//left clip
if(sx<G_VMINX) //超出左边界
{
xoff=abs(-sx);//扫描线缓存起始地址
gx=abs(width-xoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gx>(G_VMAXX-G_VMINX)){xoff=0;gx=(G_VMAXX-G_VMINX);}
if(sx<-width){xoff=width;gx=0;}
//图片显示到屏幕的X坐标
sx=0;
}
//right clip case
if(sx>=G_VMAXX-width)
{
xoff=0;
gx=abs(G_VMAXX-sx);
if(sx>G_VMAXX){xoff=width;gx=0;}
sx=sx;
}
//no clip case
else
{
xoff=0;
gx=width;
sx=sx;
}
//up clip case
if(sy<G_VMINY) //超出上边界
{
yoff=abs(-sy);
gy=abs(height-yoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gy>(G_VMAXY-G_VMINY)){gy=(G_VMAXY-G_VMINY);}
if(sy<-height){yoff=height;gy=0;}
//图片显示到屏幕的X坐标
sy=0;
}
//down clip case
if(sy>G_VMAXY-height)
{
yoff=0;
gy=abs(G_VMAXY-sy);
if(sy>G_VMAXY){yoff=height;gy=0;}
sy=sy;
}
else
{
yoff=0;
gy=height;
sy=sy;
}
sx-=G_VMINX;
sy-=G_VMINY;
width=(width+3)/4*4;
offn=1078L+(height-yoff-1L)*(width);
for(zy=0;zy<gy;zy++)
{
fseek(fp,(offn-zy*width+xoff),SEEK_SET);
fread(colorn,1,gx,fp);
switch(G_BITWIDTH)//测试扫描线内是否有换页
{
case 1: bz8=G_GETXY_YESC8(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz8){G_SETPAGE(G_PAGE[bz8-100]);}
break;
case 2: bz565=G_GETXY_YESC565(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz565){G_SETPAGE(G_PAGE[bz565-100]);}
break;
}
for(unsigned int x=0;x<gx;x++)
{
unsigned char c=colorn[x];
if(G_BITWIDTH==1)//256色模式显示256色文件
{
if(bz8) //无换页版本写点
{G_PUTPIXEL_NOC(x+sx,zy+sy,c);}
else //有换页版本写点
{G_PUTPIXEL(x+sx,zy+sy,c);}
}
if(G_BITWIDTH==2)//增强色模式显示256色文件
{
unsigned char r=(G_TSB[tsbnum][c][0])>>1;
unsigned char g=(G_TSB[tsbnum][c][1]);
unsigned char b=(G_TSB[tsbnum][c][2])>>1;
if(bz565)
{G_PUTPIXEL_NOC(x+sx,zy+sy,RGB565(r,g,b));}
else
{G_PUTPIXEL(x+sx,zy+sy,RGB565(r,g,b));}
}
}
}
fclose(fp);
return 0;
}
int G_SHOWBMP565(unsigned char far * filename,int sx,int sy)
{
if(G_BITWIDTH==1)return 0;
FILE *fp;
if( (fp=fopen(filename,"rb"))==NULL)
{fclose(fp);return 3;}
RGB24 colorn[1024];//显示宽度支持至1024象素
long width=BMPWIDTH,height=BMPHEIGHT;
long gx=width;
long gy=height;
long zy=0L;
int xoff=0,yoff=0;
long offn;
unsigned char r,g,b;
unsigned int bz565;
sx=sx+G_VMINX;
sy=sy+G_VMINY;
//left clip
if(sx<G_VMINX) //超出左边界
{
xoff=abs(-sx);//扫描线缓存起始地址
gx=abs(width-xoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gx>(G_VMAXX-G_VMINX)){xoff=0;gx=(G_VMAXX-G_VMINX);}
if(sx<-width){xoff=width;gx=0;}
//图片显示到屏幕的X坐标
sx=0;
}
//right clip case
if(sx>=G_VMAXX-width)
{
xoff=0;
gx=abs(G_VMAXX-sx);
if(sx>G_VMAXX){xoff=width;gx=0;}
sx=sx;
}
//no clip case
else
{
xoff=0;
gx=width;
sx=sx;
}
//up clip case
if(sy<G_VMINY) //超出上边界
{
yoff=abs(-sy);
gy=abs(height-yoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gy>(G_VMAXY-G_VMINY)){gy=(G_VMAXY-G_VMINY);}
if(sy<-height){yoff=height;gy=0;}
//图片显示到屏幕的X坐标
sy=0;
}
//down clip case
if(sy>G_VMAXY-height)
{
yoff=0;
gy=abs(G_VMAXY-sy);
if(sy>G_VMAXY){yoff=height;gy=0;}
sy=sy;
}
else
{
yoff=0;
gy=height;
sy=sy;
}
sx-=G_VMINX;
sy-=G_VMINY;
width=((width*3)/4)*4+(width*3)%4+width%4;
offn=54L+(height-yoff-1)*width;
for(zy=0;zy<gy;zy++)
{
fseek(fp,(offn-zy*width+xoff*G_BITWIDTH),SEEK_SET);
fread(colorn,1,gx*3L,fp);
bz565=G_GETXY_YESC565(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz565){G_SETPAGE(G_PAGE[bz565-100]);}
for(unsigned int x=0;x<gx;x++)
{
unsigned char b=((colorn[x].red)>>3)&0x1f;
unsigned char g=((colorn[x].green)>>2)&0x3f;
unsigned char r=((colorn[x].blue>>3))&0x1f;
if(bz565)
{G_PUTPIXEL_NOC(x+sx,zy+sy,RGB565(r,g,b));}
else
{G_PUTPIXEL(x+sx,zy+sy,RGB565(r,g,b));}
}
}
fclose(fp);
return 0;
}
int G_SHOWPIC(unsigned char far * filename,int sx,int sy)
{
FILE *fp;
if( (fp=fopen(filename,"rb"))==NULL)
{fclose(fp);return 3;}
//读取信息头
fread((char *)&PICINFO,1,sizeof(PICINFO),fp);
long width=PICINFO.width,height=PICINFO.height;
unsigned char colorn[1024];
unsigned char colornum[256][3];
long gx=width;
long gy=height;
long zy=0L;
int xoff=0,yoff=0;
long offn=776L;
unsigned char r,g,b;
unsigned int bz8,bz565;
//读取调色板
fseek(fp,8,SEEK_SET);
fread(colornum,1,768,fp);
GDX=FP_OFF(colornum);GES=FP_SEG(colornum);
GCX=256;GBX=0;GAX=0x1012;
int86x(0x10,®s,®s,&sregs);
sx=sx+G_VMINX;
sy=sy+G_VMINY;
//left clip
if(sx<G_VMINX) //超出左边界
{
xoff=abs(-sx);//扫描线缓存起始地址
gx=abs(width-xoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gx>(G_VMAXX-G_VMINX)){xoff=0;gx=(G_VMAXX-G_VMINX);}
if(sx<-width){xoff=width;gx=0;}
//图片显示到屏幕的X坐标
sx=0;
}
//right clip case
if(sx>=G_VMAXX-width)
{
xoff=0;
gx=abs(G_VMAXX-sx);
if(sx>G_VMAXX){xoff=width;gx=0;}
sx=sx;
}
//no clip case
else
{
xoff=0;
gx=width;
sx=sx;
}
//up clip case
if(sy<G_VMINY) //超出上边界
{
yoff=abs(-sy);
gy=abs(height-yoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gy>(G_VMAXY-G_VMINY)){gy=(G_VMAXY-G_VMINY);}
if(sy<-height){yoff=height;gy=0;}
//图片显示到屏幕的X坐标
sy=0;
}
//down clip case
if(sy>G_VMAXY-height)
{
yoff=0;
gy=abs(G_VMAXY-sy);
if(sy>G_VMAXY){yoff=height;gy=0;}
sy=sy;
}
else
{
yoff=0;
gy=height;
sy=sy;
}
sx-=G_VMINX;
sy-=G_VMINY;
width=(width+3)/4*4;
for(zy=0;zy<gy;zy++)
{
fseek(fp,(offn+(zy+yoff)*width),SEEK_SET);
fread(colorn,1,gx+xoff,fp);
switch(G_BITWIDTH)
{
case 1: bz8=G_GETXY_YESC8(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz8){G_SETPAGE(G_PAGE[bz8-100]);}
break;
case 2: bz565=G_GETXY_YESC565(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz565){G_SETPAGE(G_PAGE[bz565-100]);}
break;
}
for(unsigned int x=0;x<gx;x++)
{
unsigned char c=colorn[x+xoff];
if(G_BITWIDTH==1)
{
if(bz8)
{G_PUTPIXEL_NOC(x+sx,zy+sy,c);}
else
{G_PUTPIXEL(x+sx,zy+sy,c);}
}
if(G_BITWIDTH==2)
{
r=colornum[c][0]>>1;
g=colornum[c][1];
b=colornum[c][2]>>1;
if(bz565)
{G_PUTPIXEL_NOC(x+sx,zy+sy,RGB565(r,g,b));}
else
{G_PUTPIXEL(x+sx,zy+sy,RGB565(r,g,b));}
}
}
}
fclose(fp);
return 0;
}
int G_SHOWBMP(unsigned char far * filename,int sx,int sy,unsigned int tsbnum)
{
if(G_BITWIDTH==1 && BITDEPTH==24){return 4;}
FILE *fp;
if( (fp=fopen(filename,"rb"))==NULL)
{fclose(fp);return 3;}
long width=BMPWIDTH,height=BMPHEIGHT;
long gy=height,gx=width,zy=0L,offn;
long xoff=0L,yoff=0L;
unsigned int bz8,bz565;
sx+=G_VMINX;
sy+=G_VMINY;
//left clip
if(sx<G_VMINX) //超出左边界
{
xoff=abs(-sx);//扫描线缓存起始地址
gx=abs(width-xoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gx>(G_VMAXX-G_VMINX)){xoff=0;gx=(G_VMAXX-G_VMINX);}
if(sx<-width){xoff=width;gx=0;}
//图片显示到屏幕的X坐标
sx=0;
}
//right clip case
if(sx>=G_VMAXX-width)
{
xoff=0;
gx=abs(G_VMAXX-sx);
if(sx>G_VMAXX){xoff=width;gx=0;}
sx=sx;
}
//no clip case
else
{
xoff=0;
gx=width;
sx=sx;
}
//up clip case
if(sy<G_VMINY) //超出上边界
{
yoff=abs(-sy);
gy=abs(height-yoff);//裁剪后图片宽度
//如裁剪后图片宽度>屏幕取屏幕尺寸
if(gy>(G_VMAXY-G_VMINY)){gy=(G_VMAXY-G_VMINY);}
if(sy<-height){yoff=height;gy=0;}
//图片显示到屏幕的X坐标
sy=0;
}
//down clip case
if(sy>G_VMAXY-height)
{
yoff=0;
gy=abs(G_VMAXY-sy);
if(sy>G_VMAXY){yoff=height;gy=0;}
sy=sy;
}
else
{
yoff=0;
gy=height;
sy=sy;
}
sx-=G_VMINX;
sy-=G_VMINY;
switch(BITDEPTH)
{
case 4: break;//不支持16色格式
case 8: unsigned char colorn8[1024];
width=(width+3)/4*4;
offn=1078L+(height-yoff-1L)*(width);
for(zy=0;zy<gy;zy++)
{
fseek(fp,(offn-zy*width+xoff),SEEK_SET);
fread(colorn8,1,gx,fp);
switch(G_BITWIDTH)
{
case 1: bz8=G_GETXY_YESC8(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz8){G_SETPAGE(G_PAGE[bz8-100]);}
break;
case 2: bz565=G_GETXY_YESC565(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz565){G_SETPAGE(G_PAGE[bz565-100]);}
break;
}
for(unsigned int x=0;x<gx;x++)
{
unsigned char c=colorn8[x];
if(G_BITWIDTH==1)
{
if(bz8)
{G_PUTPIXEL_NOC(x+sx,zy+sy,c);}
else
{G_PUTPIXEL(x+sx,zy+sy,c);}
}
if(G_BITWIDTH==2)
{
unsigned char r=(G_TSB[tsbnum][c][0])>>1;
unsigned char g=(G_TSB[tsbnum][c][1]);
unsigned char b=(G_TSB[tsbnum][c][2])>>1;
if(bz565)
{G_PUTPIXEL_NOC(x+sx,zy+sy,RGB565(r,g,b));}
else
{G_PUTPIXEL(x+sx,zy+sy,RGB565(r,g,b));}
}
}
}
break;
case 24:
RGB24 colorn[1024];
width=((width*3)/4)*4+(width*3)%4+width%4;
offn=54L+(height-yoff-1)*width;
for(zy=0;zy<gy;zy++)
{
fseek(fp,(offn-zy*width+xoff*G_BITWIDTH),SEEK_SET);
fread(colorn,1,gx*3L,fp);
bz565=G_GETXY_YESC565(G_VMINX,G_VMINX+gx+sx,(unsigned int)zy+sy+G_VMINY);
if(bz565){G_SETPAGE(G_PAGE[bz565-100]);}
for(unsigned int x=0;x<gx;x++)
{
unsigned char b=((colorn[x].red)>>3)&0x1f;
unsigned char g=((colorn[x].green)>>2)&0x3f;
unsigned char r=((colorn[x].blue>>3))&0x1f;
if(bz565)
{G_PUTPIXEL_NOC(x+sx,zy+sy,RGB565(r,g,b));}
else
{G_PUTPIXEL(x+sx,zy+sy,RGB565(r,g,b));}
}
}
break;
}
fclose(fp);
return 0;
}
int G_BMP2PIC(unsigned char far * bmpname,unsigned char far * picname)
{
//读取BMP格式文件
FILE * bmpfp;
if( (bmpfp=fopen(bmpname,"rb"))==NULL)
{fclose(bmpfp);return 3;}
//跳过读取文件头
fseek(bmpfp,14,SEEK_SET);
//读取信息头
fread(&BMPINFO,1,sizeof(BMPINFO),bmpfp);
//确定是否压缩及256色格式
if (BMPINFO.compress!=0)
{fclose(bmpfp);return 3;}
if(BMPINFO.bitcount!=8)
{fclose(bmpfp);return 3;}
unsigned char far * databuf=(unsigned char far *)farmalloc(BMPINFO.width);
if(databuf==NULL)
{fclose(bmpfp);return 2;}
//BMP格式第一行数据在文件中的指针
long offn=1078+(BMPINFO.height-1)*BMPINFO.width;
//创建PIC格式文件
FILE * picfp;
if( (picfp=fopen(picname,"wb"))==NULL)
{farfree(databuf);fclose(bmpfp);fclose(picfp);return 3;}
long wd[2];
unsigned char colorpal1[256][4];
unsigned char colorpal2[256][3];
//从BMP格式文件读尺寸数据
wd[0]=(BMPINFO.width+3)/4*4;
wd[1]=BMPINFO.height;
//从BMP格式文件读调色板数据
fseek(bmpfp,54,SEEK_SET);
fread(colorpal1,1,1024,bmpfp);
for(unsigned int i=0;i<256;i++)
{
colorpal2[i][0]=(colorpal1[i][2])>>2;
colorpal2[i][1]=(colorpal1[i][1])>>2;
colorpal2[i][2]=(colorpal1[i][0])>>2;
}
//写尺寸数据到PIC文件
fwrite(wd,4,2,picfp);
//写调色板数据到PIC文件
fseek(picfp,8,SEEK_SET);
fwrite(colorpal2,1,768,picfp);
//写颜色数据到文件
for(unsigned int zy=0;zy<BMPINFO.height;zy++)
{
unsigned long cap=zy*BMPINFO.width;
fseek(bmpfp,(offn-cap),SEEK_SET);
fread(databuf,1,BMPINFO.width,bmpfp);
fseek(picfp,776+cap,SEEK_SET);
fwrite(databuf,1,BMPINFO.width,picfp);
}
farfree(databuf);
fclose(bmpfp);
fclose(picfp);
return 0;
}
#endif
评论