编程实现根据指定文本生成电子印章(hnust)
题目描述 题目1:先为自己的名字制作一个汉字点阵txt文件,然后编程,通过程序读取汉字点阵txt文件中的信息,根据点阵信息决定向BMP文件中写入红点或白点数据,从而制作出自己的一枚电子印章。
编程前准备:利用隶书56点阵汉字字库文本文件LiShu56.txt(在老师提供的软件包中)制作印章字库文本文件XXX.txt(用记事本软件即可制作完成),要求与印章的摆放顺序一致。其中XXX指自定义的任意名称。如图2所示,是编者自己制作的字库文件文件xds.txt。
编程时的注意事项:
- 建立存储印章的文件XXX.bmp,然后按照BMP文件的格式往XXX.bmp文件中写入文件头、信息头。
- 然后根据XXX.txt文件中的内容确定颜色数据写入XXX.bmp文件中。XXX.txt文件中的一个字符对应于XXX.bmp文件中一个彩色点的数据(包括蓝、绿、红三个字节数据,若是红色点,一般置B=0、G=0,R=255)。构成字形的数据对应写入红色点数据,未构成字形的数据对应写入白色点数据。
- 检查文件头、信息头、彩色数据是否符合BMP文件的格式规范,若规范,则在windows环境下可以正常浏览和使用该电子印章图片了。
- 印章字库文本文件XXX.txt和生成的印章文件XXX.bmp通过命令行参数给定。假如程序编译连接后生成的可执行文件名为mySeal.exe,则用xds.txt制作印章xds.bmp的命令为:mySeal xds.txt xds.bmp。由图2生成的印章如图3所示。 4.5 关键问题释疑 4.5.1 彩色图像的显示原理
对于彩色图像,它的显示必须从三原色RGB概念说起。众所周知,自然界中的所有颜色都可以由红(R)、绿(G)、蓝(B)三原色组合而成。有的颜色含有红色成分多一些,其它成分少一些。针对含有红色成分的多少,可以人为地分成0到255共256个等级,0级表示不含红色成分,255级表示含有100%的红色成分。同样,绿色和蓝色也可以被分成256级。这样,根据红、绿、蓝各种不同的组合我们就能表示出256×256×256(约1600万)种颜色。表1是常见的一些颜色的RGB组合值。当一幅图中每个像素被赋予不同的RGB值时,就能呈现出五彩缤纷的颜色了,这就形成了彩色图像。
真彩色图像(又称24位色图像)的颜色种类高达256×256×256=224=16777216种,也就是包含上述提到的R、G、B颜色表示方法中所有的颜色。真彩色图像是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。通常,在表示真彩色图时,每个像素直接用R、G、B这3个分量字节来表示,而不采用调色板技术。原因很简单:如果使用调色板,表示一个像素颜色在调色板中的索引要用24位(因为共有224种颜色,即调色板有224行),这和直接用R、G、B这3个分量表示用的字节数一样,不但没有节省任何空间,还要加上一个256×256×256×3=3×224字节的大调色板。所以真彩色图直接用R、G、B这3个分量表示。
表1 常见颜色的RGB组合 4.5.2 BMP彩色图像的文件格式
BMP图像文件格式,是微软公司为其WINDOWS环境设置的标准图像格式,并且内含了一套图像处理的API函数。随着WINDOWS在世界范围内的普及,BMP文件格式越来越多地被各种应用软件所支持。BMP图像文件是位图文件,位图表示的是将一幅图像分割成栅格,栅格的每一点称为像素,每一个像素具有自己的RGB值,即一幅位图是由一系列像素点构成的点阵。一个BMP文件包括位图文件头BITMAPFILEHEADER、位图信息头BITMAPINFOHEADER、调色板PALETTE和位图像素数据4个部分,如图5所示。其中,前面3部分的结构在windows.h中进行了定义。下面对它们进行详细说明。 一、位图文件头
位图文件头结构BITMAPFILEHEADER包含位图文件的类型大小信息和版面信息。结构如下:
typedef struct tagBITMAPFILEHEADER // bmfh
{ WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER;
这个结构的长度是固定的,为14个字节,各个域的说明如下:
bfType:指定文件类型,必须是0x4D42,即字符串"BM"。也就是说所有BMP文件的头两个字节都是"BM"。 bfSize:指定整个文件的大小(以字节为单位)。 bfReserved1:保留,一般为0。 bfReserved2:保留,一般为0。 bfOffBits:指定从文件头到实际的位图像素数据首部的字节偏移量。即图5中前3个部分的长度之和。
二、位图信息头
位图信息头结构BITMAPINFOHEADER包含图像本身的属性。其定义如下:
typedef struct tagBITMAPINFOHEADER // bmih { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER;
这个结构的长度是固定的,为40个字节,各个域的说明如下:
biSize:指定 BITMAPINFOHEADER 结构的长度,为40个字节。 biWidth:指定位图的宽度(以象素为单位)。 biHeight:指定位图的高度(以象素为单位)。 biPlanes:指定目标设备的位面数。这个成员变量的值必须为1。 biBitCount:指定每个象素的位数。常用的值为1(黑白二色图)、4(16色图)、8(256色图)、24(真彩色图)。 biCompression:指定压缩位图的压缩类型。有效的值为BI_RGB(0), BI_RLE8(1), BI_RLE4(2), BI_BITFIELDS(3)。用得不多,在24位格式中,该变量被设置为0。 biSizeImage:指定图像的大小(以字节为单位)。如果位图的格式是BI_RGB,则将此成员变量设置为0是有效的。该值可以根据biWidth’和biHeight的乘积计算出来。要注意的是:上述公式中的biWidth’必须是4的整倍数(所以计算乘积时写的是biWidth’,表示大于或等于biWidth的、离4最近的整倍数。例如,若biWidth=240,则biWidth’=240;若biWidth=241,则biWidth’=244)。 biXPelsPerMeter:为位图指定目标设备的水平分辨率(以"象素/米"为单位)。 biYPelsPerMeter:为位图指定目标设备的垂直分辨率(以"象素/米"为单位)。 biClrUsed:指定位图实际用到的颜色数。如果该值为0,则用到的颜色数为2的biBitCount次方。 biClrImportant:指定对位图的显示有重要影响的颜色数。如果此值为0,则所有颜色都很重要。
三、调色板(注意:印章要求采用24位色,不需要调色板)
对于2色、16色和256色位图,需要调色板。调色板中的各个元素规定了第4部分(实际位图数据)对应的颜色值。对于24位色的真彩色图,不需要调色板,第2部分(信息头BITMAPINFOHEADER)后直接是位图数据。
调色板实际上是一个数组,共有biClrUsed个元素(如果此值为0,则有2的biBitCount次方个元素)。数组中每个元素的类型是一个RGBQUAD结构(4个字节),定义如下:
typedef struct tagRGBQUAD
{ BYTE rgbBlue; //该颜色的蓝色分量 BYTE rgbGreen; //该颜色的绿色分量 BYTE rgbRed; //该颜色的红色分量 BYTE rgbReserved; //保留值 } RGBQUAD;
四、图像数据
对于用到调色板的位图,图像数据就是该像素值在调色板中的索引值,对于24位色的真彩色图,图像数据就是实际的R、G、B值。下面对2色、16色、256色位图和真彩色位图分别加以介绍。
对于2色位图,用1位就可以表示该像素的颜色(一般0表示黑,1表示白),所以1个字节可以表示8个像素。 对于16色位图,用4位表示1个像素的颜色,所以1个字节可以表示2个像素。 对于256色位图,1个字节刚好可以表示1个像素。 对于24位色真彩色图(无调色板),3个字节才表示1个像素。 注意:
(1) BMP文件按从下到上,从左到右的顺序存储图像数据。即从文件中最先读到的是图像最下面一行的左边第一个像素,然后是左边第二个像素……接下来是倒数第二行左边第一个像素,左边第二个像素……依次类推,最后得到的是最上面一行的最右一个像素。
(2) 对于24位色真彩色位图而言,数据的排列顺序以图像的左下角为起点,从左到右、从下到上,每连续3个字节便描述图像一个像素点的颜色信息,这三个字节分别代表蓝、绿、红三基色在此像素中的亮度,若某连续三个字节为:00H,00H,FFH,则表示该像素的颜色为红色。24位真彩色位图中每个像素的RGB数据可以定义成如下结构:
typedef struct tagRGBDATA{ BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; } RGBDATA;
五、BMP文件示例
24位色真彩色位图文件组成。用编辑软件(HEdit,老师的软件包中也会提供)查看24位色真彩色位图文件Lena.bmp的组成,有如下3部分:
1.24位色真彩色位图的文件头。如图6深色部分所示,从文件存放首地址0x0000开始,共14个字节。 2.24位色真彩色位图的信息头。如图7深色部分所示,从文件存放地址0x000E开始,共40个字节。 3.24位色真彩色位图的实际像素数据。如图8深色部分所示,从文件存放地址0x0036开始,共512×512×3=786432个字节。 通过以上实例,我们熟悉了BMP彩色图像的格式,然后我们按格式创建BMP文件,并将印章点阵数据写入,则可制作出自己的印章BMP图像。
4.5.3 如何制作BMP文件
制作一个可在windows中正常浏览和使用的BMP文件,主要包括如下四个步骤:
第一步:用命令行中给出的文件名新建一BMP文件,此时还是一个空文件;
第二步:置文件头数据并写入BMP文件;
第三步:置信息头数据并写入BMP文件;
第四步:置图像RGB数据并写入BMP文件。
/****************************************************************************
**** FileName: demo.c
**** Function: 真彩色bmp图片文件的创建
**** Usage: demo xxxx.bmp
*****************************************************************************/
#include <CONIO.H>
#include <STDLIB.H>
#include <STDIO.H>
#include <MATH.H>
#include <MALLOC.H>
#include <string.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
/**** The file header of bmp file 文件头*****/
#include <pshpack2.h> //This file turns 2 byte packing of structures on, then sizeof(BITMAPFILEHEADER)=14, otherwise sizeof(BITMAPFILEHEADER)=16
typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfoffBits; } BITMAPFILEHEADER;
#include <poppack.h> //This file turns packing of structures off /**** The information header of bmp file 信息头*****/ typedef struct tagBITMAPINFOHEADER { DWORD biSize; DWORD biWidth; DWORD biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompress; DWORD biSizeImage; DWORD biXPeIsPerMeter; DWORD biYPeIsPerMeter; DWORD biCIrUsed; DWORD biClrImprotant; } BITMAPINFOHEADER;
/**** The RGB data of bmp file 图像RGB数据*****/ typedef struct tagRGBDATA{ BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; } RGBDATA;
//第三步:置信息头数据并写入BMP文件 bmiHeader.biSize=40; bmiHeader.biWidth=width; bmiHeader.biHeight=height; bmiHeader.biPlanes=1; bmiHeader.biBitCount=24; bmiHeader.biCompress=0; bmiHeader.biSizeImage=widthheight3; bmiHeader.biXPeIsPerMeter=0; bmiHeader.biYPeIsPerMeter=0; bmiHeader.biCIrUsed=0; bmiHeader.biClrImprotant=0; fwrite(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp);
//第四步:置图像数据并写入BMP文件 //分配足够内存,让bmpData指向这块内存,用于存放图像各象素点的RGB分量值 if((bmpData=(RGBDATA*)malloc(widthheight3))==NULL) { printf(“bmpData memory malloc error!”); }
//先在bmpData所指内存中置图像RGB数据,然后将所有数据写入BMP文件 for(i=0;i<height;i++) { for(j=0;j<width;j++) { k=(height-i-1)*width + j;//计算第i行第j列图像数据在bmpData[]数组中的位置 if(i<100)//上100行只置红色分量值,显示为红色 { bmpData[k].rgbBlue=0; bmpData[k].rgbGreen=0; bmpData[k].rgbRed=255;//红色分量值为:255 } else if(i<200)//中100行只置绿色分量值,显示为绿色 { bmpData[k].rgbBlue=0; bmpData[k].rgbGreen=255;//绿色分量值为:255 bmpData[k].rgbRed=0; } else if(i<300)//下100行只置蓝色分量值,显示为蓝色 { bmpData[k].rgbBlue=255;//蓝色分量值为:255 bmpData[k].rgbGreen=0; bmpData[k].rgbRed=0; } } } fwrite(bmpData,sizeof(RGBDATA),dataSize,fp);//将bmpData所指的RGB数据一次性写入BMP文件 printf(" 恭喜您!BMP文件已经成功生成! "); printf(" 请在当前目录下查看生成的BMP文件%s ",argv[1]); free(bmpData); //释放bmpData所指的内存空间 bmpData=NULL; //置bmpData为空指针 fclose(fp); //关闭fp所指文件 }
该程序生成的大小为300×300的BMP图片,可在运行本程序的目录下查看。 重要提示:任务2的编程与本示例编程的不同主要是在第四步。
4.5.4 如何根据输入的汉字确定其编码
我们看到屏幕上显示的汉字的字型有两种表达方式:一种称为矢量方式,一种称为点阵方式。其中的点阵方式较为简单,其原理就是好比:铺地砖。有的铺为白色,有的铺为黑色,只要精心安排,就会组成我们希望的图案,当然也可以是汉字。
瓷砖越多,铺出的图案效果越细腻,这就是点阵的规模。56点阵汉字用56 x 56 = 3136个像素点来描绘。
当我们需要记录一个汉字信息的时候,当然不是存储汉字的字型,而是存储它的编码。汉字可以有多种编码的规则,其中GB2312的编码规则是:一个汉字用两个字节表示,前一个字节表示区号,后一个表示区中的偏移序号。
每个区有94个汉字。区号和序号的编码都是从 0xA1开始(为了避免和西文冲突)。已知某个汉字的GB2312编码,就可以计算出它在二进制字模文件中所在的绝对位置。我们在本次课程设计中,不用二进制字模文件。而是用文本文件LiShu56.txt,因为其中的点阵信息非常形象直观,适合我们这些C的初学者。
下面程序能从键盘获得一个或多个汉字的编码,如输入“向”,则其编码为CF F2,有了这个编码,我们就可以在LiShu56.txt文件中查找其点阵信息。
#include<stdio.h> int main(void) { int i, len; unsigned char BM[100]; printf(“请输入一个或多个汉字:”); scanf("%s",BM); for(len=0;BM[len]!=’’;len++); for(i=0;i<len;i++) printf(“BM[%d]=%x ”,i,BM[i]); //输入"向",则其编码为CF F2 return 0; }
4.5.5 如何将编码变成字符串?
我们知道,“向”的编码为2个字节,分别是CF和 F2,如何将其变成字符串(包括字符’C’、’F’、’F’、’2’,占4个字节)存入字符数组中,以便于在LiShu56.txt文件中查找其点阵信息。 #include<stdio.h> int main(void) { int i, len; unsigned char BM[100]; char str[200]; printf(“请输入一个或多个汉字:”); scanf("%s",BM); for(len=0;BM[len]!=’’;len++); for(i=0;i<len;i++) printf(“BM[%d]=%x ”,i,BM[i]); //输入"向",则其编码为CF F2 printf(“将编码转换成字符并显示:”); for(i=0;i<len;i++) sprintf(str+2i,"%x",BM[i]); //编码->字符,并存入str数组 for(i=0;i<2len;i++) printf("%c ",str[i]); return 0; }
例如,我想制作自己的印章,先输入4个印章上显示的汉字“向德生印”,通过上面的程序就可以得到相应的编码(十六进制表示)。其中,“向”字的编码为cff2,“德”字的编码为b5c2,“生”字的编码为c9fa,“印”字的编码为“d3a1”。然后将这4个汉字的十六进制编码转换成对应的字符“c f f 2”、“b 5 c 2”、“c 9 f a”、“d 3 a 1”。执行效果如下图所示。 当我们输入要生成印章的汉字后,首先将编码转换成“字符”,然后就可以利用这些字符在LiShu56.txt文件中查找匹配其点阵信息。原理就是:利用这些字符,在文本文件LiShu56.txt中搜索,有匹配的编码,就将其后的点阵信息读出并写入图像文件,则可生成印章图片。
注意:4个汉字处在图片的不同位置,在将各个汉字的点阵信息写入图像文件中时,要通过适当的算法对各汉字的位置进行调整。
解题过程如下:
1.在desktop(桌面)上开了一个名为bmp的文件夹, 2. 然后把代码所生成的exe文件与含有名字的txt文件放进了这个文件夹(文件在软件包内找) 3. 利用cmd指令(win+R)先输入cd desktop(桌面)回车 再输入cd bmp(找你桌面叫bmp的文件)回车 再输入demo xxx. bmp(给bmp图片命名) 输入所给的图片名(01.bmp)查看代码所生成的图片 理解之后接下来修改第四步代码,找到你所制作的txt文件,放入建立的桌面bmp文件中,(可直接放老师的文件xds2.txt),那四个字是由“X”和“_”组成的,只要把是X的上红色,上白色就可以达到题意,然后还有一个问题怎么让你的程序知道哪里是x哪里是 :读入文件,定义一个二维数组,将文件内容写入二维数组。
解题代码如下:
在cmd中运行得到图片如下: 完成任务,科大学子加油噢!!!
以下是在同学那里要到的编码,可以生成自己的名字,完成任务三的题目二
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; /**** The file header of bmp file 文件头*****/ #pragma pack(push) #pragma pack(2) //避免结构体内存对齐,按2b对齐 typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; /**** The information header of bmp file 信息头*****/ #pragma pack(pop)//使上一个失效 typedef struct tagBITMAPINFOHEADER { DWORD biSize; DWORD biWidth; DWORD biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompress; DWORD biSizeImage; DWORD biXPeIsPerMeter; DWORD biYPeIsPerMeter; DWORD biCIrUsed; DWORD biClrImprotant; } BITMAPINFOHEADER; /**** The RGB data of bmp file 图像 RGB 数据*****/ typedef struct tagRGBDATA { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; } RGBDATA; long position(int x,int y) { x = x-0xb0, y = y-0xa1; int k = 715+x * 94 + y; if(k>=4475) k -= 5; return 68 + 17 + 4 + 15 + 11 + k * (15 + 11 + 4 + 56 * 65); } void indata(FILE *fpp,char data[160][160] ) //从字库中导入数据 { char input[100]; //要打印的汉字 int judge = 0,len; while(!judge) { judge = 1; printf(" 请输入印章上的4个汉字: "); gets(input); len = strlen(input); for (int i = 0; input[i]; i++) if(input[i]>=0&&input[i]<=127) //判断是否有非汉字字符 { judge = 0; printf(" 您输入了非汉字字符,请重新输入: "); break; } } for (int i = 0; i < len;i=i+2) { long k = position(input[i]&0xff, input[i + 1]&0xff); //找到该汉字在文件中的位置 fseek(fpp, k, SEEK_SET); //将文件指针跳转到汉字所在位置 int row, end, column; if(i==0)row = 0, end = 56, column = 56; //右上角 if(i==2)row = 56, end = 113, column = 56;//右下角 if(i==4)row = 0, end = 56, column = 0;//左上角 if(i==6)row = 56, end = 113, column = 0;//左下角 for (; row < end;row++) { char ch=fgetc(fpp); int _column = column; while (ch != ) { if(ch!=,)data[row][_column++] = ch; //去除汉字点库中的逗号 ch = fgetc(fpp); } } } } int main(int argc, char *argv[]) { RGBDATA *bmpData = NULL; //图像数据指针 FILE *fp, *fpp; //fp为BMP文件指针,fpp为汉字点阵指针; long i, j, k; long width = 112+16; //图像宽度 long height =113+16; //图像高度 long dataSize = width * height; BITMAPFILEHEADER bmfHeader; BITMAPINFOHEADER bmiHeader; if (argc < 3) { printf(" ******************************************************************** "); printf(" 欢迎您使用电子印章制作软件 "); printf(" 命令格式:mySeal ls.txt xxxx.bmp "); printf(" 主要功能: 实现根据点阵信息文件"ls.txt"制作对应的电子印章文件"xxxx.bmp" "); printf(" 使用说明: "); printf(" 1:请按上面的格式输入命令,其中xxxx.bmp为您自定义的名称, 扩展名为.bmp "); printf(" 2:执行本命令后会提示您输入4个汉字,用于生成方形印章bmp文件,然后程序 "); printf(" 会根据您提供的汉字自动从隶书56点阵字形文本文件LiShu56.txt中提取相 "); printf(" 应的点阵信息,并生成印章bmp文件! "); printf(" 3:如果想生成行楷字体的印章,请将上面命令中的ls.txt换成xk.txt即可! "); } //第一步:用命令行中给出的文件名新建一 BMP 文件,此时还是一个空文件 if ((fpp = fopen(argv[1], "r")) == NULL) { printf("Cannot open txt file!"); exit(0); } if ((fp = fopen(argv[2], "wb+")) == NULL) { printf("Cannot open bmp file!"); exit(0); } //第二步:置文件头数据并写入 BMP 文件 bmfHeader.bfType = 0x4d42; bmfHeader.bfSize = 14 + 40 + width * height * 3; bmfHeader.bfReserved1 = 0; bmfHeader.bfReserved2 = 0; bmfHeader.bfOffBits = 0x36; fwrite(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, fp); //第三步:置信息头数据并写入 BMP 文件 bmiHeader.biSize = 40; bmiHeader.biWidth = width; bmiHeader.biHeight = height; bmiHeader.biPlanes = 1; bmiHeader.biBitCount = 24; bmiHeader.biCompress = 0; bmiHeader.biSizeImage = width * height * 3; bmiHeader.biXPeIsPerMeter = 0; bmiHeader.biYPeIsPerMeter = 0; bmiHeader.biCIrUsed = 0; bmiHeader.biClrImprotant = 0; fwrite(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp); //第四步:置图像数据并写入 BMP 文件 //分配足够内存,让 bmpData 指向这块内存,用于存放图像各象素点的 RGB 分量值 if ((bmpData = (RGBDATA *)malloc(width * height * 3)) == NULL) { printf("bmpData memory malloc error! "); exit(0); } //先在 bmpData 所指内存中置图像 RGB 数据,然后将所有数据写入 BMP 文件 char data [160][160]; indata(fpp, data); //根据输入从汉字点阵中寻找数据 for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { k = (height - i - 1) * width + j; //计算第 i 行第 j 列图像数据在 bmpData[]数组中的位置 if(i<8||j<8||i>=height-8||j>=width-8) //加边框,并设置为红色边框。 { bmpData[k].rgbBlue = 0; bmpData[k].rgbGreen = 0; bmpData[k].rgbRed = 255; continue; } if (data[i-8][j-8] == X) //构成字体的字符为红色 { bmpData[k].rgbBlue = 0; bmpData[k].rgbGreen = 0; bmpData[k].rgbRed = 255; } else //不构成字体的字符为白色 { bmpData[k].rgbBlue = 255; bmpData[k].rgbGreen = 255; bmpData[k].rgbRed = 255; } } } fwrite(bmpData, sizeof(RGBDATA), dataSize, fp); //将 bmpData 所指的 RGB 数据一次性写入 BMP 文件 printf(" 恭喜您!BMP 文件已经成功生成! "); printf(" 请在当前目录下查看生成的 BMP 文件%s ", argv[2]); free(bmpData); //释放 bmpData 所指的内存空间 bmpData = NULL; //置 bmpData 为空指针 fclose(fp); //关闭 fp 所指文件 fclose(fpp); //关闭fpp所指文件 }
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/290642.html