前段时间一朋友要为女朋友写个七夕礼物,感觉字符模式太单调了,但是汇编对图形的支持不是不够方便,就写了个位图到点阵的转换工具,这样就可以用汇编做出"丰富多彩"的界面了.虽然dos下的东西有点过时了,或许有朋友需要也说不一定,就发上来了.Win-tc下通过.代码如下:
#include <io.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#ifndef __STDIO_DEF_/*区分VC和TC,因为是在VC上调试的*/
typedef short bit16;
typedef unsigned int bit32 ;
#else
typedef int bit16 ;
typedef unsigned long bit32 ;
#endif
char *formatstring;
int file;
int bitget(char *bit,int i,int j)
{
bit32 num;
bit32 num2=0xffffffff;
*(&num)=*(bit32 *)bit;/*不使用指针来赋值的话,*/
/*vc使用movzx来把字节扩展到32位,那么在24位真彩模式下会有问题*/
num>>=i%8;/*把数组当做一个bitset对象*/
num2>>=(32-j);/*只对比这么多位*/
num&=num2;
return num==num2?0:1;/*白色为0*/
}
void bmptochars(char *chars,char *dots,int count,int bitofdot)
{
int i,j,k=(8/bitofdot)?(8/bitofdot-1):0;/*区分位图是1,4,8,24模式*/
int l,num=(count-1)/8+1;/*num是需要多少字节来存放转换后的数据*/
char Buffer[100];/*字符串缓冲区*/
memset(dots,0,num+1);/*清零*/
for(i=0,j=k;i<count;++i,--j)
{
if(j<0)j=k;
if(bitget(chars+i*bitofdot/8,j*bitofdot,bitofdot))
dots[i/8]|=(unsigned char)1<<i%8;
}/*一次性把这一行都转换掉*/
for(l=0;l<num;++l)
{
if(dots[l]==0)write(file,"0,",2);
else
write(file,Buffer,sprintf(Buffer,formatstring,dots[l]&255));
}/*写入文件*/
return ;
}
int main(int argc,char *argv[])
{
bit32 Width,Height,bitoff;/*宽,高,位图文件的位图数据偏移*/
bit16 fp,i,j,m,bitofdot,cflag=0;
/*fp 位图文件句柄,bitofdot 位图中多少个位表示一个点,cflag 是否翻译成c格式*/
char Buffer[200];/*文件名等缓冲区*/
char *bit,*dots;/*用于保存从位图文件中读取的数据和转换后的数据,后面会为其分配内存*/
printf("\t\t\t www.asmedu.net\n\t\t\tCopyright (C) 2012-2012.\n");
switch(argc)
{
case 1:printf("Input the file name:\n");
scanf("%s",Buffer);
break;
case 2:
if(!memicmp(argv[1],"/?",2))
{
printf("bmptodot [/c] filename.bmp\n[/c] use the c language format\n%s%s",
"use the default assembly langusge format\n",
"the bitmap must height=width,background must white\n");
return 0;
}
else
strcpy(Buffer,argv[1]);
break;
case 3:
{
if(!memicmp(argv[1],"/c",2))cflag=i=2;
else if(!memicmp(argv[2],"/c",2))cflag=i=1;
else {printf("error cmdline!\n");return -1;}
strcpy(Buffer,argv[i]);
break;
}
default:return -1;
}/*处理命令行参数*/
if(cflag)formatstring="%#x,";
else formatstring="0%xh,";/*指定翻译格式*/
if ((fp = open(Buffer, O_RDONLY|O_BINARY)) == -1) /* 打开文件 */
{
printf("Can't open the file!\n");
return -1;
}/*文件打开失败的处理*/
lseek(fp,10L,SEEK_SET);
read(fp,&bitoff,4);/*得到数据区相对与BMP文件的开始位置偏移*/
lseek(fp,18L,SEEK_SET); /* 读取文件宽高 */
read(fp,&Width,4);/*宽(X)*/
read(fp,&Height,4);/*高(Y)*/
lseek(fp,0x1CL,SEEK_SET);
read(fp,&bitofdot,2);/*每个像素需要多少位来存储*/
Width*=bitofdot;/*得到图像每行需要的位数*/
m=j=(Width-1)/8+1;/*得到字节数*/
j=j%4?(j+4-j%4):j;/*补充为4字节倍数*/
m=j-m;/*得到填补字节数*/
bit=(char *)malloc(j+4);
dots=(char*)malloc((Height-1)/8+2);/*分配内存*/
if(!bit||!dots)exit(-1);
memset(bit,0,j+4);
strcpy(strrchr(Buffer,'.'),".txt");
file=creat(Buffer,S_IWRITE);/*生成转换后的文件和位图文件同名*/
if(file == -1)
{
printf("Can't create file!\n");
return -1;
}
bitoff+=Height*j;/*得到文件的位图数据区最后偏移*/
*strrchr(Buffer,'.')='\0';
Buffer[7]='\0';/*如果文件名超出7个字符就截断,主要是想把一个缓冲区当两个用*/
if(cflag)
write(file,Buffer+8,sprintf(Buffer+8,"char bmp%s%d[]={ \n",Buffer,Height));
else
write(file,Buffer+8,sprintf(Buffer+8,"bmp%s%d \n",Buffer,Height));
for (i = 1; i <=Height; ++i)
{
lseek(fp,bitoff-(bit32)i*j, SEEK_SET); /*需要倒着读 */
read(fp, bit,j); /* 一次读取一行*/
if(cflag)/*判断翻译格式*/
bmptochars(bit,dots,Height,bitofdot);
else
{
write(file,"db ",3);
bmptochars(bit,dots,Height,bitofdot);
lseek(file,-1,SEEK_CUR);
}
write(file,"\n",1);/*换行*/
}
if(cflag)write(file,"};\n",4);
close(fp);
close(file);/*关闭文件*/
return 0;
}
它有个/c参数,可以生成c格式的数组.
c的显示函数(改自Win-tc的 点阵字模工具编程辅助效果示例):
void drawmat(char *mat,int matsize,int x,int y,int color)
/*依次:字模指针、点阵大小、起始坐标(x,y)、颜色*/
{
int i, j, k, n;
n = (matsize - 1) / 8 + 1;
for(j = 0; j < matsize; j++)
for(i = 0; i < n; i++)
for(k = 0;k < 8; k++)
if(mat[j * n + i] & (1<<k)) /*测试为1的位则显示*/
putpixel(x + i * 8 + k, y + j, color);
}
汇编版的显示子程序,由Me.song先生所写:
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;按位写像素子程序(单图显示)
;
;参数:ds=DG ds:bp=指定行数 ds:di=指定列数
; al=颜色 cx=图像长度
;
;返回参数:si=下一图的首字节 bp=下一图行数 di=下一图列数
;
;
;功能:根据单色位图翻译工具生成的数据。来计算坐标并写像素。
;
tim :push cx
push dx
push ax
mov bx,ds:[bp]
mov ax,640
mul bx
add ax,word ptr ds:[di]
adc dx,0 ;计算结果DX为页数,ax为偏移地址
mov di,ax
xor bx,bx
mov ax,4f05h
int 10h ;设置页数
add bp,2
add di,2 ;指向下一图行列
mov ax,cx
mov cl,8
div cl
xor ah,ah
mov bx,ax
pop ax ;计算字节数
tim1 :push cx
mov cx,bx
push bx
xor bx,bx ;初始化辅助偏移
tim2 :push cx
mov cx,8 ;位数
mov ah,[si] ;取字节
tim3 :rcl ah,1
jnc zero ;检测每位
mov es:[bx+di],al ;当为1时,送入字节
zero :inc bx ;指向下一像素点
loop tim3
inc si ;指向下一字节
pop cx
loop tim2
pop bx
add di,640 ;指向下一行
pop cx
loop tim1
pop dx
pop cx
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
希望对大家有用.