(一)吴进的《TC的16色BMP闪电显示 》
Turbo C2.0图形模式下显示BMP位图的高速方法,不同于一般的putpixel和line绘制的方法,速度之快令你感觉不到显示的过程,而且绝对能在TC的initgraph()初始化的BGI模式下使用。
/*程序设计:吴进*/
/*注意:编译程序时内存模式必需为 Large 以上模式*/
#include "stdio.h"
#include "dir.h"
#include "dos.h"
#include "graphics.h"
char *malloc();/*malloc转换*/
char bmp_to_dat(char *bmp,char *dat)
/*将16色BMP文件转换为可以用putimage输出的格式,bmp为原BMP文件,dat为转化文件*/
{unsigned char c[8],scan_times,scan_pixs;
unsigned char workpos;int i,j,k,n,nowpos,iw,ih;
static int color[16]={0,4,2,6,1,5,3,7,8,12,10,14,9,13,11,15};
unsigned char workline[640],scanline[640];
FILE *fp,*targetfp;
union
{unsigned char value;
struct
{unsigned cl:4;
unsigned ch:4;
}color;
}mycolor;
if((fp=fopen(bmp,"rb"))==NULL)return(0);
targetfp=fopen(dat,"wb");
fseek(fp,18,SEEK_SET);
iw=0;ih=0;
fread(&iw,4,1,fp); /*读图像宽度*/
fread(&ih,4,1,fp); /*读图像高度*/
if(iw==0&&ih==0&&iw>640&&ih>480)
{fclose(fp);fclose(targetfp);return(0);}
iw--;ih--; /*∵putimage中的长宽比实际数值少1*/
scan_times=iw/8+1; /*行处理单位数*/
scan_pixs=scan_times*4; /*行像素字节数∵1单位=4字节*/
fputc(iw%256,targetfp); /*填充信息头:长、宽部分*/
fputc(iw/256,targetfp);
fputc(ih%256,targetfp);
fputc(ih/256,targetfp);
fseek(fp,-scan_pixs,SEEK_END);
for(j=0;j<=ih;j++)
{nowpos=0;
fread(scanline,scan_pixs,1,fp);
fseek(fp,-scan_pixs*2,SEEK_CUR);
for(n=3;n>=0;n--) /*解码4个位面*/
{for(i=0;i<scan_times;i++) /*解码各编码单位*/
{workpos=0;
for(k=0;k<4;k++) /*分离出8个像素*/
{mycolor.value=scanline[i*4+k];
c[k*2]=color[mycolor.color.ch];
c[k*2+1]=color[mycolor.color.cl];
}
for(k=0;k<8;k++)workpos+=(c[k]>>n&1)<<(7-k);
workline[nowpos]=workpos;nowpos++;
}}
fwrite(workline,scan_pixs,1,targetfp);
}
fclose(fp);fclose(targetfp);
return(1);
}
main()
{int gd=VGA,gm=VGAHI,n;
char *buffer,bmpfile[13],_16file[13]={0};
FILE *fp;
struct ffblk *ff;
initgraph(&gd,&gm,"");
puts("(c)2001 BY Wu Jin");
printf("Now begin showing 16 colors BMP...\n\n");
puts("Select 16 color BMP file to put:");
printf("0. Exit\n1. zx.bmp\n2. mm.bmp\n3.Other bmp file(*.bmp In this directory)\n");
while(1)
{n=getch();
switch(n)
{case 0 :continue;
case '0':exit(0);
case '1':strcpy(bmpfile,"zx.bmp");goto OUT;
case '2':strcpy(bmpfile,"mm.bmp");goto OUT;
case '3':{printf("Input filename(*.bmp):");
gets(bmpfile);goto OUT;
}
}
}
OUT:
strncpy(_16file,bmpfile,strlen(bmpfile)-3);
strcat(_16file,"dat");
if(!bmp_to_dat(bmpfile,_16file))
{puts("File Error!");closegraph();exit(0);}
fp=fopen(_16file,"rb");
findfirst(_16file,ff,FA_ARCH);
if((buffer=malloc(ff->ff_fsize))==NULL)exit(0);
n=0;
while(!feof(fp))
{buffer[n]=fgetc(fp);
n++;
}
for(n=0;n<100;n++)
{putimage(350-n,n/2,buffer,COPY_PUT);
}
getch();
closegraph();
free(buffer);
fclose(fp);
}
上面的程序没有点基本工也看不懂。我来解释一下。先调用bmp_to_dat()把BMP转换成TC可以直接putimage输出的格式的文件,宽展名DAT。至于MAIN函数不用管太多,有价值的就一句putimage(350-n,n/2,buffer,COPY_PUT);输出而已。
(二)改进
由于吴进的程序是在输出图片前进行格式转换,因此时间都耗在转换中了。而我使用转换程序把BMP先转换完毕。而随程序发布的就只有中间文件了(暂时命为PIC文件)。
下面是转换程序。(其实就是照搬吴进的程序,捎做改进)
/*程序设计:luckylai*/
/*文件名:bmp2pic.c */
#include "stdio.h"
#include "dir.h"
#include "dos.h"
char bmp_to_dat(char *bmp,char *dat)
/*将16色BMP文件转换为可以用putimage输出的格式,bmp为原BMP文件,dat为转化文件*/
{unsigned char c[8],scan_times,scan_pixs;
unsigned char workpos;int i,j,k,n,nowpos,iw,ih;
static int color[16]={0,4,2,6,1,5,3,7,8,12,10,14,9,13,11,15};
unsigned char workline[640],scanline[640];
FILE *fp,*targetfp;
union
{unsigned char value;
struct
{unsigned cl:4;
unsigned ch:4;
}color;
}mycolor;
if((fp=fopen(bmp,"rb"))==NULL)return(0);
targetfp=fopen(dat,"wb");
fseek(fp,18,SEEK_SET);
iw=0;ih=0;
fread(&iw,4,1,fp); /*读图像宽度*/
fread(&ih,4,1,fp); /*读图像高度*/
if(iw==0&&ih==0&&iw>640&&ih>480)
{fclose(fp);fclose(targetfp);return(0);}
iw--;ih--; /*∵putimage中的长宽比实际数值少1*/
scan_times=iw/8+1; /*行处理单位数*/
scan_pixs=scan_times*4; /*行像素字节数∵1单位=4字节*/
fputc(iw%256,targetfp); /*填充信息头:长、宽部分*/
fputc(iw/256,targetfp);
fputc(ih%256,targetfp);
fputc(ih/256,targetfp);
fseek(fp,-scan_pixs,SEEK_END);
for(j=0;j<=ih;j++)
{nowpos=0;
fread(scanline,scan_pixs,1,fp);
fseek(fp,-scan_pixs*2,SEEK_CUR);
for(n=3;n>=0;n--) /*解码4个位面*/
{for(i=0;i<scan_times;i++) /*解码各编码单位*/
{workpos=0;
for(k=0;k<4;k++) /*分离出8个像素*/
{mycolor.value=scanline[i*4+k];
c[k*2]=color[mycolor.color.ch];
c[k*2+1]=color[mycolor.color.cl];
}
for(k=0;k<8;k++)workpos+=(c[k]>>n&1)<<(7-k);
workline[nowpos]=workpos;nowpos++;
}}
fwrite(workline,scan_pixs,1,targetfp);
}
fclose(fp);fclose(targetfp);
return(1);
}
void main(int argc,char *aaaa[])
{
int i;char a1[30],a2[30];
printf("\n\nUsage: Bmp2pic -inputfile [*.bmp] -outputfile[*.pic]\ncopy right (C) 1989-2002 CENTER COMPUTER CO, LTD.\n");
if(aaaa[1]==NULL)
{ printf("\nInput Filename:");
gets(a1);
aaaa[1]=a1;
// if(aaaa[2]==NULL)
printf("\nOutput Filename:");
gets(a2);
aaaa[2]=a2;
}
i=bmp_to_dat(aaaa[1],aaaa[2]);
if(i==0) printf("Fail");
}
之后的事情就很简单了。
输出函数
#include "stdio.h"
#include "dir.h"
#include "dos.h"
int Pic_Putout(int x,int y,char *filenames)
{int n;
char *buffer;
FILE *fp;
struct ffblk *ff;
fp=fopen(filenames,"rb"); //打开PIC文件
findfirst(filenames,ff,FA_ARCH);//获得文件信息,主要是大小
if((buffer=malloc(ff->ff_fsize))==NULL)exit(0);
putimage(x,y,buffer,COPY_PUT); //输出
free(buffer);
fclose(fp);
}
如果你要频繁使用这张图片,那么就只在初始化时打开一次文件,内存不要释放,请读者自己写好了。
(四)图片处理的问题
16色图片由于颜色信息少,因此处理上就得很讲究了。使用xnview114gb.exe这个免费软件吧(本站可以下载),功能强大。另外的他的抖动处理,可以使16色图片显示更多信息。
另外一个要点就是调色板的问题。使用ACDSEE等软件转换出来的16色,并不是标准的16色。他们使用了调色板。为了正确显示,建议使用WINDOWS自带的“画图”软件,进行处理。