为取用方便,代码包含:
(1)路径斜杠替换 => 方便文件读取
(2)图片像素数据用文件保存
(3)遍历文件夹下所有文件名
(4)分块文件数据的组合
(5)套接字面向连接的 TCP 数据传输
(6)多线程
(7)字符串数据的分割
(8)字符串与整数的相互转换
(9)字符串相关操作 => string.h
(10)图像打印与保存 => EGE图形库
(11)文件大小获取、文件读取
(12)字符串格式规范 => sprintf
实验答辩 PPT
附:
(1)服务器代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <pthread.h>
4 // Winsock是一个基于Socket模型的API
5 #include <winsock2.h>
6 #include <windows.h>
7 #include "graphics.h"
8
9 // 要包含头文件 Winsock2.h,就需要调用库 ws2_32.lib
10 #pragma comment( lib, "ws2_32.lib" )
11
12
13
14 /* Winsock启动测试,检查系统协议栈安装情况 */
15 void TestWinsockStartup();
16
17
18 // 分块大小固定为100KB
19
20
21 /* 定义全局变量 */
22 // 待获取的文件名后缀 (除序号外的信息)
23 char getFileName[] = "_28#1440_665.myt";
24 // 用来存储图像数据
25 int width=1440, height=665; // 也可通过填写的待获取文件名后缀获取图片宽高信息
26 // 待维护的要获取文件数组 (数组大小也可通过上面方法获得)
27 const int block_num = 28 + 1;
28 // block该由哪个序号的 peer上传 (上传名额被谁抢到了)
29 int blocks[block_num];
30 // 每个分块的数据
31 char block_data[block_num][100*1024]; // 每个分块为 100KB
32
33
34
35 /* 要经常检查分块是否已全部收到 */
36 bool isReceiveAll() {
37 bool flag = true;
38 for(int i=0; i<block_num; i++) {
39 if( blocks[i] == -1 ) {
40 flag = false;
41 }
42 }
43 return flag;
44 }
45
46
47
48 /* 保存连接的 client信息 */
49 struct SocketInfo {
50 SOCKADDR_IN cli; // 其实只有 accept()时才用到 cli,连接后几乎可以不用
51 SOCKET sAccept;
52 } sAccepts[20]; // 最多 20个client连接
53 int peer_id = 0; // peer序号计数
54
55
56 // 每个 client拥有的文件
57 // 下标就是 client的序号
58 struct ClientFiles {
59 int len; // 拥有总文件数
60 char file_name[50][50]; // 文件名
61 int idx[50]; // 文件序号
62 bool getFile[50]; // 文件是否要索要
63 } clientFiles[20]; // 最多 20个client连接
64
65
66
67 // 获取文件名列表
68 void *AskFilesName( void *arg ) {
69 int id = *(int *)(arg);
70 // printf("id: %d\n", id);
71
72 SOCKET *sAccept = &sAccepts[id].sAccept;
73 char command[] = "AskFilesName";
74
75 // 1. 索要所有文件名
76 int iSend = send( *sAccept, command, sizeof(command), 0 );
77 if( iSend == SOCKET_ERROR ) {
78 printf("send() Failed: %d\n", WSAGetLastError());
79 } else if( iSend == 0) {
80 printf("发送失败!\n");
81 } else {
82 printf(">>> peer%d所有文件名给我看看!\n", id);
83 }
84
85 // 2. 接收所有文件名
86 char str[1024*3];
87 int iLen = recv( *sAccept, str, sizeof(str), 0 );
88 if( iLen == SOCKET_ERROR ) {
89 printf("recv() Failed: %d\n", WSAGetLastError());
90 } else if( iLen == 0 ) {
91 printf("接收失败!\n");
92 } else {
93 printf("%s\n", str);
94 }
95
96 // 3. 将收到的字符串分割成文件名存放在结构体中
97 char num_str[10];
98 int i, j;
99 for(i=0; str[i]!='&'; i++) {
100 num_str[i] = str[i];
101 }
102 num_str[i++] = '\0';
103 clientFiles[peer_id].len = atoi(num_str);
104 // 分割
105 char file_name[50];
106 int index=0, cnt=0;
107 for( ; str[i]!='\0'; i++) {
108 if( str[i]=='&' ) {
109 file_name[index] = '\0';
110 // printf("%s\n", file_name);
111 // 得到序号
112 char ttmp[10];
113 for(j=0; file_name[j]!='_'; j++) {
114 ttmp[j] = file_name[j];
115 }
116 ttmp[j] = '\0';
117 // 添加上序号
118 clientFiles[peer_id].idx[cnt] = atoi(ttmp);
119 // 添加上文件名
120 strcpy( clientFiles[peer_id].file_name[cnt], file_name );
121 index = 0;
122 cnt++;
123 } else {
124 file_name[index++] = str[i];
125 }
126 }
127 // 文件总数目
128 clientFiles[peer_id].len = cnt;
129 // 索要文件初始化
130 for(i=0; i<50; i++) {
131 clientFiles[peer_id].getFile[i] = false;
132 }
133
134 // 4. 打印看看有没有错误
135 // printf("peer%d:\nlen: %d\n", peer_id, clientFiles[peer_id].len);
136 // for(i=0; i<clientFiles[peer_id].len; i++) {
137 // printf("file index: %d\n", clientFiles[peer_id].idx[i]);
138 // printf("file name: %s\n", clientFiles[peer_id].file_name[i]);
139 // }
140
141 // 5. 为该 peer抢分块上传名额
142 char send_str[1024] = "";
143 int count = 0; // 要传输的文件计数
144 for(i=0; i<clientFiles[peer_id].len; i++) {
145 // peer拥有的第 i个文件的分块序号
146 int idx = clientFiles[peer_id].idx[i];
147 // 这个分块还没被抢
148 if( blocks[idx] == -1 ) {
149 blocks[idx] = peer_id; // 这个分块被 peer_id抢了
150 clientFiles[peer_id].getFile[idx] = true; // 待上传文件
151 count++; // 该 peer将要传的文件数量
152 // 待索要的文件名 加入待传输字符串中
153 char tmp[10];
154 itoa(idx, tmp, 10); // 十进制
155 strcat(send_str, tmp);
156 strcat(send_str, getFileName); // 文件后缀 (除序号外的信息)
157 strcat(send_str, "&");
158 }
159 strcat(send_str, "\0");
160 }
161 // for(i=0; i<block_num; i++) printf("%d: %d\n", i, blocks[i]);
162
163 // 6. 接收文件
164 // 发出所有需要的文件的文件名
165 iSend = send( *sAccept, send_str, sizeof(send_str), 0 );
166 if( iSend == SOCKET_ERROR ) {
167 printf("send() Failed: %d\n", WSAGetLastError());
168 } else if( iSend == 0 ) {
169 printf("发送失败!\n");
170 } else {
171 printf(">>> 文件传输列表:%s\n", send_str);
172 }
173 short *img_mx = (short *)malloc(width*height*3*sizeof(short));
174 // 接收所有 getFile = true的文件
175 for(i=0; i<clientFiles[peer_id].len; i++) {
176 int index = clientFiles[peer_id].idx[i];
177 // 索要的文件
178 if( clientFiles[peer_id].getFile[index] ) {
179 iLen = recv( *sAccept, block_data[index], sizeof(block_data[index]), 0 );
180 if( iLen == SOCKET_ERROR ) {
181 printf("recv() Failed: %d\n", WSAGetLastError());
182 } else if( iLen == 0 ) {
183 printf("第%d个分块丢失了\n", index);
184 } else {
185 printf("第%d个分块已接收\n", index);
186 }
187 }
188 }
189
190 if( isReceiveAll() ) {
191 printf(">>> 所有分块均已收到!\n");
192
193 // 7. 将所有分块数据转化成图像数据
194 // 分块拼接起来
195 char *total = (char *)malloc(width*height*3*sizeof(char));
196 int tcnt = 0;
197 for(i=0; i<block_num; i++) {
198 for(j=0; j<100*1024; j++) {
199 if( i*100*1024+j >= width*height*3 ) {
200 break;
201 }
202 *(img_mx+tcnt) = (unsigned char)block_data[i][j];
203 tcnt++;
204 // printf("%hd ", *(img_mx+tcnt));
205 }
206 // printf("j:%d\n", j);
207 }
208 // printf("tcnt: %d", tcnt);
209
210 // 8. 打印图像矩阵
211 short red, green, blue;
212 for(i=0; i<width; i++) {
213 for(j=0; j<height; j++) {
214 red = *(img_mx+3*(height*i+j)+0);
215 green = *(img_mx+3*(height*i+j)+1);
216 blue = *(img_mx+3*(height*i+j)+2);
217 putpixel(i, j, EGERGB(red, green, blue));
218 }
219 }
220 // 保存图像
221 PIMAGE pimg = newimage();
222 getimage(pimg, 0, 0, getwidth(), getheight());
223 saveimage(pimg, "receive.jpg");
224
225 // 在此关闭连接
226 closesocket( *sAccept );
227 free(img_mx);
228 delimage(pimg);
229 return NULL;
230 }
231
232 // 在此关闭连接
233 closesocket( *sAccept );
234 return NULL;
235 }
236
237
238
239 int main() {
240 initgraph(width, height, 0);
241 setcaption("ByHansel");
242
243 // Winsock启动测试
244 TestWinsockStartup();
245
246 // 分块初始化
247 for(int i=0; i<block_num; i++) blocks[i]=-1; // -1代表还没人抢到
248
249 SOCKET sListen;
250 struct sockaddr_in ser;
251
252 // 1. 创建服务器端通信套接字
253 sListen = socket( AF_INET, SOCK_STREAM, 0 );
254 if( sListen == INVALID_SOCKET ) {
255 printf("socket() Failed: %d\n", WSAGetLastError());
256 return -1;
257 }
258
259 // 2. 将创建的套接字与服务器地址进行绑定
260 ser.sin_family = AF_INET;
261 ser.sin_port = htons( 44965 ); // 端口号
262 ser.sin_addr.s_addr = htonl( INADDR_ANY );
263 if( bind(sListen, (LPSOCKADDR)&ser, sizeof(ser)) == SOCKET_ERROR ){
264 printf("bind() Failed: %d\n", WSAGetLastError());
265 return -1;
266 }
267
268 // 3. 进入监听状态
269 if( listen(sListen, 5) == SOCKET_ERROR ) {
270 printf("lisiten() Failed: %d\n", WSAGetLastError());
271 return -1;
272 }
273
274
275 // 4. 获取所有文件列表
276 peer_id = 0;
277 printf(">>> 等待peer接入!\n");
278 while(1) {
279 // 4.1. 接收到客户连接请求
280 SOCKET *sAccept = &sAccepts[peer_id].sAccept;
281 SOCKADDR_IN *cli = &sAccepts[peer_id].cli;
282 int iLen = sizeof(*cli);
283 *sAccept = accept( sListen, (struct sockaddr *)cli, &iLen );
284 if( *sAccept == INVALID_SOCKET ) {
285 printf("accept() Failed: %d\n", WSAGetLastError());
286 return -1;
287 }
288 // 输出客户 IP地址和端口号
289 printf("Accepted client IP:[%s], port:[%d]\n", inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
290
291 // 4.2. 创建新进程处理连接请求
292 pthread_t tid;
293 // 接收分块 0的文件名和数据
294 int id = peer_id; // 不能直接传 peer_id的地址
295 pthread_create(&tid, NULL, AskFilesName, &id);
296 // 主线程与子线程分离,子线程结束后,资源自动回收
297 pthread_detach(tid);
298 peer_id++;
299 }
300
301 getch();
302 closegraph();
303 closesocket(sListen);
304 WSACleanup();
305 return 0;
306 }
307
308
309
310 /* Winsock启动测试,检查系统协议栈安装情况 */
311 void TestWinsockStartup() {
312 WORD wVersionRequested;
313 WSADATA wsaData;
314 wVersionRequested = MAKEWORD(2, 2);
315
316 if( WSAStartup(wVersionRequested, &wsaData) != 0 ) {
317 printf("Winsock初始化错误!\n");
318 return ;
319 }
320 if( wsaData.wVersion != wVersionRequested ) {
321 printf("Winsock版本不匹配!\n");
322 WSACleanup();
323 return ;
324 }
325 // printf("WinsockDLL正确加载!\n");
326 }
(2)客户端代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <io.h>
4 // Winsock是一个基于Socket模型的API
5 #include <winsock2.h>
6
7 // 要包含头文件 Winsock2.h,就需要调用库 ws2_32.lib
8 #pragma comment( lib, "ws2_32.lib" )
9
10
11
12 /* Winsock启动测试,检查系统协议栈安装情况 */
13 void TestWinsockStartup();
14
15
16
17 char IPaddr[] = "127.0.0.1";
18 int main() {
19 // Winsock启动测试
20 TestWinsockStartup();
21
22 SOCKET sClient;
23 // 从服务器端接收的数据长度
24 int iLen;
25 // 接收数据的缓冲区
26 char buf[50];
27 //接收缓冲区初始化
28 memset( buf, 0, sizeof(buf) );
29 // 服务器端地址
30 struct sockaddr_in ser;
31
32
33 // 1. 填写要连接的服务器地址信息
34 ser.sin_family = AF_INET;
35 ser.sin_port = htons( 44965 );
36 ser.sin_addr.s_addr = inet_addr( IPaddr );
37
38 // 2. 建立客户端流式套接字
39 sClient = socket( AF_INET,SOCK_STREAM, 0 );
40 if( sClient == INVALID_SOCKET ) {
41 printf("socket() Failed: %d\n", WSAGetLastError());
42 return -1;
43 }
44
45 // 3. 请求与服务器端建立 TCP连接
46 if( connect(sClient, (struct sockaddr *)&ser, sizeof(ser)) == INVALID_SOCKET ) {
47 printf("connect() Failed: %d\n", WSAGetLastError());
48 return -1;
49 } else {
50 // 从服务器端接收命令
51 iLen = recv( sClient, buf, sizeof(buf), 0 );
52 if( iLen == SOCKET_ERROR ) {
53 printf("recv() Failed: %d\n", WSAGetLastError());
54 return -1;
55 } else if( iLen == 0) {
56 printf("接收失败!\n");
57 } else {
58 // 4. 交出所有文件名
59 if( strcmp(buf, "AskFilesName") == 0 ) {
60 /* 拥有的所有文件名发过去 */
61 char str[1024] = ""; // 要发送的字符串
62 // 遍历文件夹
63 _finddata_t fileDir;
64 long lfDir;
65 int len = 0; // 文件总数量
66 // _findfirst():如果查找成功的话,将返回一个 long型的唯一的查找用的句柄
67 if( ( lfDir=_findfirst("upload//*.myt", &fileDir) ) == -1l ) {
68 printf("No file is found\n");
69 } else {
70 // _findnext():若成功返回0,否则返回-1
71 do {
72 len++;
73 // &为每个文件名的分隔符
74 strcat(str, "&");
75 strcat(str, fileDir.name);
76 } while( !_findnext( lfDir, &fileDir ) );
77 }
78 // 末尾加上
79 strcat(str, "&\0");
80 _findclose(lfDir);
81
82 // 将文件总数量放在最前面
83 char tmp[1024];
84 itoa(len, tmp, 10); // 十进制
85 strcat(tmp, str);
86 // 将包含所有文件名的字符串传过去
87 int iSend = send( sClient, tmp, sizeof(str), 0 );
88 if( iSend == SOCKET_ERROR ) {
89 printf("send() Failed: %d\n", WSAGetLastError());
90 } else if( iSend == 0 ) {
91 printf("发送失败!\n");
92 } else {
93 printf(">>> 我全上报了!\n");
94 }
95 }
96 }
97 // 5. 接收文件传输列表
98 char recv_str[1024];
99 iLen = recv( sClient, recv_str, sizeof(recv_str), 0 );
100 if( iLen == SOCKET_ERROR ) {
101 printf("recv() Failed: %d\n", WSAGetLastError());
102 return -1;
103 } else if( iLen == 0 ) {
104 printf("接收失败!\n");
105 } else {
106 printf("待传输文件:%s\n", recv_str);
107 }
108
109 // 6. 传输给定文件
110 // 分割文件名
111 char file_name[50][50];
112 int count=0, index=0;
113 for(int i=0; recv_str[i]!='\0'; i++) {
114 if( recv_str[i] == '&' ) {
115 file_name[count][index] = '\0';
116 // printf("%s\n", file_name[count]);
117 count++;
118 index = 0;
119 } else {
120 file_name[count][index++] = recv_str[i];
121 }
122 }
123 // 传输文件
124 for(int i=0; i<count; i++) {
125 // 读取文件
126 char read_data[100*1024]; // 一次最多读 100KB数据
127 char PATH[50];
128 sprintf(PATH, "%s%s", "upload/", file_name[i]);
129 FILE *fp;
130 fp = fopen(PATH, "rb");
131 printf("%s\n", PATH);
132 // 读取文件
133 fseek( fp, 0, SEEK_END );
134 int file_size = ftell( fp );
135 fseek( fp, 0, SEEK_SET );
136 fread( read_data, sizeof(char), file_size, fp );
137 fclose(fp);
138 // 发送文件流
139 int iSend = send( sClient, read_data, sizeof(read_data), 0 );
140 if( iSend == SOCKET_ERROR ) {
141 printf("send() Failed: %d\n", WSAGetLastError());
142 } else if( iSend == 0 ) {
143 printf("发送失败!\n");
144 } else {
145 printf("%s已成功发送!\n", file_name[count]);
146 }
147 Sleep(1);
148 }
149 }
150
151 closesocket(sClient);
152 WSACleanup();
153 system("pause");
154 return 0;
155 }
156
157
158
159 /* Winsock启动测试,检查系统协议栈安装情况 */
160 void TestWinsockStartup() {
161 WORD wVersionRequested;
162 WSADATA wsaData;
163 wVersionRequested = MAKEWORD(2, 2);
164
165 if( WSAStartup(wVersionRequested, &wsaData) != 0 ) {
166 printf("Winsock初始化错误!\n");
167 return ;
168 }
169 if( wsaData.wVersion != wVersionRequested ) {
170 printf("Winsock版本不匹配!\n");
171 WSACleanup();
172 return ;
173 }
174 // printf("WinsockDLL正确加载!\n");
175 }
(3)图片分块代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include "graphics.h"
5
6 char PATH[] = "building.jpg";
7 int size = 100; // KB
8
9 int main() {
10 color_t color;
11 int i, j;
12 short width, height, red, green, blue;
13
14 for(i=0; i<strlen(PATH); i++) {
15 if(PATH[i] == '\\') {
16 PATH[i] = '/';
17 }
18 }
19
20 PIMAGE pimg = newimage();
21 getimage(pimg, PATH);
22 width = getwidth(pimg);
23 height = getheight(pimg);
24 short *img_mx = (short *)malloc(width*height*3*sizeof(short));
25
26 for(i=0; i<width; i++) {
27 for(j=0; j<height; j++) {
28 color = getpixel(i, j, pimg);
29 red = EGEGET_R(color);
30 green = EGEGET_G(color);
31 blue = EGEGET_B(color);
32 *(img_mx+3*(height*i+j)+0) = red;
33 *(img_mx+3*(height*i+j)+1) = green;
34 *(img_mx+3*(height*i+j)+2) = blue;
35 }
36 }
37
38
39
40
41 // 待保存数据
42 char *save = (char *)malloc(width*height*3*sizeof(char));
43 for(i=0; i<width*height*3; i++) {
44 // 用 char保存图像灰度值数据
45 *(save+i) = (char)*(img_mx+i);
46 }
47
48 // 文件分块数量
49 int num_block = ceil(width*height*3.0/size/1024.0);
50 char file_name[50];
51 for(i=0; i<num_block; i++) {
52 // 文件取名
53 sprintf(file_name, "%d_%d#%d_%d", i, num_block-1, width, height);
54 strcat(file_name, ".myt");
55 printf("%s\n", file_name);
56 FILE *fp;
57 fp = fopen(file_name, "wb");
58
59 for(j=0; j<size*1024; j++) {
60 if( i*size*1024+j < width*height*3 ) {
61 fprintf(fp, "%c", *(save+i*size*1024+j));
62 } else {
63 break;
64 }
65 }
66
67 fclose(fp);
68 }
69
70
71 free(img_mx);
72 free(save);
73 delimage(pimg);
74 return 0;
75 }
(4)图片组合代码:
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include <io.h>
5 #include "graphics.h"
6
7 int width=1440, height=665;
8 int size = 100; // KB
9
10
11 void SortByIndex(char files[][50], int n) {
12 int i, j;
13 char tmp[n][50], ch[50];
14
15 int index[n];
16
17 // 数组复制
18 for(i=0; i<n; i++) {
19 strcpy(tmp[i], files[i]);
20 for(j=0; tmp[i][j]!='_'; j++) {
21 ch[j] = tmp[i][j];
22 }
23 ch[j] = '\0';
24 index[i] = atoi(ch);
25 }
26
27 // 排序
28 for(i=0; i<n-1; i++) {
29 for(j=i+1; j<n; j++) {
30 if( index[i] > index[j] ) {
31 int tt = index[i];
32 index[i] = index[j];
33 index[j] = tt;
34 strcpy(ch, files[i]);
35 strcpy(files[i], files[j]);
36 strcpy(files[j], ch);
37 }
38 }
39 }
40 }
41
42
43 int main() {
44 initgraph(width, height, 0);
45 setcaption("ByHansel");
46
47 char ch;
48 int i, j;
49 short red, green, blue;
50 short *img_mx = (short *)malloc(width*height*3*sizeof(short));
51
52 char files[50][50];
53 int idx = 0;
54
55 // 遍历 upload文件夹内所有文件
56 _finddata_t fileDir;
57 long lfDir;
58 // _findfirst():如果查找成功的话,将返回一个long型的唯一的查找用的句柄
59 if( ( lfDir=_findfirst("download//*.myt", &fileDir) ) == -1l ) {
60 printf("No file is found\n");
61 } else {
62 // printf("file list:\n");
63 // _findnext():若成功返回0,否则返回-1
64 do {
65 strcpy(files[idx++], fileDir.name);
66 } while( !_findnext( lfDir, &fileDir ) );
67 }
68 _findclose(lfDir);
69
70
71 // 根据文件序号将文件在数组中排序
72 SortByIndex(files, idx);
73
74
75
76 char PATH[50];
77 int num_block = ceil(width*height*3.0/size/1024.0);
78
79 // 组合分块
80 for(i=0; i<num_block; i++) {
81 sprintf(PATH, "%s%s", "download/", files[i]);
82 FILE *fp;
83 fp = fopen(PATH, "rb");
84 printf("%s\n", PATH);
85
86 for(j=0; j<size*1024; j++) {
87 if( i*size*1024+j < width*height*3 ) {
88 // 可以在此将分块数据进行发送
89 fscanf(fp, "%c", &ch);
90 *(img_mx+i*size*1024+j) = (unsigned char)ch;
91 } else {
92 break;
93 }
94 }
95 fclose(fp);
96 }
97
98
99 // 打印图像矩阵
100 for(i=0; i<width; i++) {
101 for(j=0; j<height; j++) {
102 red = *(img_mx+3*(height*i+j)+0);
103 green = *(img_mx+3*(height*i+j)+1);
104 blue = *(img_mx+3*(height*i+j)+2);
105 putpixel(i, j, EGERGB(red, green, blue));
106 }
107 }
108
109 // 保存图像
110 PIMAGE pimg = newimage();
111 getimage(pimg, 0, 0, getwidth(), getheight());
112 saveimage(pimg, "receive.jpg");
113
114 // 图像移动功能
115 int x=0, y=0, num=50;
116 for (; is_run(); delay_fps(20)) {
117 key_msg keyMsg = {0};
118 while(kbhit()) {
119 keyMsg = getkey();
120 if(keyMsg.key == key_left) {
121 x -= num;
122 } else if(keyMsg.key == key_up) {
123 y -= num;
124 } else if(keyMsg.key == key_right) {
125 x += num;
126 } else if(keyMsg.key == key_down) {
127 y += num;
128 }
129 cleardevice();
130 for(i=0; x+i<width && i<width; i++) {
131 for(j=0; y+j<height && j<height; j++) {
132 if(x+i>=0 && y+j>=0) {
133 red = *(img_mx+3*(height*i+j)+0);
134 green = *(img_mx+3*(height*i+j)+1);
135 blue = *(img_mx+3*(height*i+j)+2);
136 putpixel(x+i, y+j, EGERGB(red,green, blue));
137 }
138 }
139 }
140 }
141 }
142
143 getch();
144 free(img_mx);
145 delimage(pimg);
146 closegraph();
147 return 0;
148 }