1 // ----------------------------------------------------------------------------
2 // ifkppic.cxx -- ifkp image support functions
3 //
4 // Copyright (C) 2015
5 // Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi. Adapted from code contained in gifkp source code
8 // distribution.
9 //
10 // Fldigi is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Fldigi is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
22 // ----------------------------------------------------------------------------
23 #include <FL/Fl_Counter.H>
24 #include <FL/Fl_Choice.H>
25 #include <iostream>
26
27 #include "gettext.h"
28 #include "fileselect.h"
29 #include "timeops.h"
30
31 Fl_Double_Window *ifkppicRxWin = (Fl_Double_Window *)0;
32 picture *ifkppicRx = (picture *)0;
33 Fl_Button *btnifkpRxReset = (Fl_Button *)0;
34 Fl_Button *btnifkpRxSave = (Fl_Button *)0;
35 Fl_Button *btnifkpRxClose = (Fl_Button *)0;
36 Fl_Counter *ifkpcnt_phase = (Fl_Counter *)0;
37 Fl_Counter *ifkpcnt_slant = (Fl_Counter *)0;
38
39 Fl_Double_Window *ifkppicTxWin = (Fl_Double_Window *)0;
40 picture *ifkppicTx = (picture *)0;
41 Fl_Button *btnifkppicTransmit = (Fl_Button *)0;
42 Fl_Button *btnifkppicTxSendAbort = (Fl_Button *)0;
43 Fl_Button *btnifkppicTxLoad = (Fl_Button *)0;
44 Fl_Button *btnifkppicTxClose = (Fl_Button *)0;
45 Fl_Choice *selifkppicSize = (Fl_Choice *)0;
46 Fl_Check_Button *btnifkppicTxGrey = (Fl_Check_Button *)0;
47
48 void ifkp_showRxViewer(char c);
49 void ifkp_createRxViewer();
50
51 Fl_Shared_Image *ifkpTxImg = (Fl_Shared_Image *)0;
52 unsigned char *ifkpxmtimg = (unsigned char *)0;
53 unsigned char *ifkpxmtpicbuff = (unsigned char *)0;
54
55 #define RAWSIZE 640*(480 + 8)*3*ifkp::IMAGEspp
56
57 #define RAWSTART 640*4*3*ifkp::IMAGEspp
58
59 unsigned char *ifkp_rawvideo = 0;//[RAWSIZE + 1];
60
61 int ifkp_numpixels;
62 int ifkp_pixelptr;
63 int ifkp_rawcol;
64 int ifkp_rawrow;
65 int ifkp_rawrgb;
66 char ifkp_image_type = 'S';
67
68 char ifkp_txclr_tooltip[24];
69 char ifkp_txgry_tooltip[24];
70
71 static int translate = 0;
72 static bool enabled = false;
73
74 static string ifkp_fname;
75
76 std::string ifkp::imageheader;
77 std::string ifkp::avatarheader;
78
ifkp_correct_video()79 void ifkp_correct_video()
80 {
81 int W = ifkppicRx->w();
82 int H = ifkppicRx->h();
83 int slant = ifkpcnt_slant->value();
84 int vidsize = W * H;
85 int index, rowptr, colptr;
86 float ratio = (((float)vidsize - (float)slant)/(float)vidsize);
87 unsigned char vid[W * H * 3];
88 for (int row = 0; row < H; row++) {
89 rowptr = W * 3 * row * ifkp::IMAGEspp;
90 for (int col = 0; col < W; col++) {
91 colptr = ifkp::IMAGEspp*col;
92 for (int rgb = 0; rgb < 3; rgb++) {
93 index = ratio*(rowptr + colptr + ifkp::IMAGEspp*W*rgb);
94 index += RAWSTART - ifkp::IMAGEspp*ifkp_pixelptr;
95 if (index < 2) index = 2;
96 if (index > RAWSIZE - 2) index = RAWSIZE - 2;
97 vid[rgb + 3 * (col + row * W)] = ifkp_rawvideo[index];
98 }
99 }
100 }
101 ifkppicRx->video(vid, W*H*3);
102 }
103
ifkp_updateRxPic(unsigned char data,int pos)104 void ifkp_updateRxPic(unsigned char data, int pos)
105 {
106 if (!ifkppicRxWin->shown()) ifkppicRx->show();
107
108 ifkppicRx->pixel(data, pos);
109
110 int W = ifkppicRx->w();
111 if (ifkp_image_type == 'F' || ifkp_image_type == 'p' || ifkp_image_type == 'm' ||
112 ifkp_image_type == 'l' || ifkp_image_type == 's' || ifkp_image_type == 'v') {
113 int n = RAWSTART + ifkp::IMAGEspp*(ifkp_rawcol + W * (ifkp_rawrgb + 3 * ifkp_rawrow));
114 if (n < RAWSIZE)
115 for (int i = 0; i < ifkp::IMAGEspp; i++) ifkp_rawvideo[n + i] = data;
116 ifkp_rawrgb++;
117 if (ifkp_rawrgb == 3) {
118 ifkp_rawrgb = 0;
119 ifkp_rawcol++;
120 if (ifkp_rawcol == W) {
121 ifkp_rawcol = 0;
122 ifkp_rawrow++;
123 }
124 }
125 } else
126 for (int i = 0; i < ifkp::IMAGEspp; i++)
127 ifkp_rawvideo[RAWSTART + ifkp::IMAGEspp*ifkp_numpixels + i] = data;
128 ifkp_numpixels++;
129 if (ifkp_numpixels >= (RAWSIZE - RAWSTART - ifkp::IMAGEspp))
130 ifkp_numpixels = RAWSIZE - RAWSTART - ifkp::IMAGEspp;
131 }
132
cb_btnifkpRxReset(Fl_Widget *,void *)133 void cb_btnifkpRxReset(Fl_Widget *, void *)
134 {
135 progStatus.ifkp_rx_abort = true;
136 }
137
cb_btnifkpRxSave(Fl_Widget *,void *)138 void cb_btnifkpRxSave(Fl_Widget *, void *)
139 {
140 ifkppicRx->save_png(string(ifkp_fname).append(".png").c_str());
141 }
142
cb_btnifkpRxClose(Fl_Widget *,void *)143 void cb_btnifkpRxClose(Fl_Widget *, void *)
144 {
145 ifkppicRxWin->hide();
146 progStatus.ifkp_rx_abort = true;
147 }
148
ifkp_save_raw_video()149 void ifkp_save_raw_video()
150 {
151 time_t time_sec = time(0);
152 struct tm ztime;
153 (void)gmtime_r(&time_sec, &ztime);
154 char sztime[20];
155
156 strftime(sztime, sizeof(sztime), "%Y%m%d%H%M%Sz", &ztime);
157
158 ifkp_fname.assign(PicsDir).append("IFKP").append(sztime);
159
160 FILE *raw = fl_fopen(string(ifkp_fname).append(".raw").c_str(), "wb");
161 fwrite(&ifkp_image_type, 1, 1, raw);
162 fwrite(ifkp_rawvideo, 1, RAWSIZE, raw);
163 fclose(raw);
164 }
165
ifkp_load_raw_video()166 void ifkp_load_raw_video()
167 {
168 // abort & close any Rx video processing
169 int image_type = 0;
170 string image_types = "TtSsLlFVvPpMm";
171
172 if (!ifkppicRxWin)
173 ifkp_createRxViewer();
174 else
175 ifkppicRxWin->hide();
176
177 const char *p = FSEL::select(
178 _("Load raw image file"), "Image\t*.raw\n", PicsDir.c_str());
179
180 if (!p || !*p) return;
181
182 ifkp_fname.assign(p);
183 size_t p_raw = ifkp_fname.find(".raw");
184 if (p_raw != std::string::npos) ifkp_fname.erase(p_raw);
185
186 FILE *raw = fl_fopen(p, "rb");
187 int numread = fread(&image_type, 1, 1, raw);
188 if (numread != 1) {
189 fclose(raw);
190 return;
191 }
192
193 if (image_types.find(ifkp_image_type) != string::npos) {
194
195 ifkp_showRxViewer(image_type);
196
197 numread = fread(ifkp_rawvideo, 1, RAWSIZE, raw);
198
199 if (numread == RAWSIZE) {
200 ifkpcnt_phase->activate();
201 ifkpcnt_slant->activate();
202 btnifkpRxSave->activate();
203
204 ifkp_correct_video();
205 ifkppicRxWin->redraw();
206 }
207 }
208
209 fclose(raw);
210 }
211
cb_ifkp_cnt_phase(Fl_Widget *,void * data)212 void cb_ifkp_cnt_phase(Fl_Widget *, void *data)
213 {
214 ifkp_pixelptr = ifkpcnt_phase->value();
215 if (ifkp_pixelptr >= RAWSTART/ifkp::IMAGEspp) {
216 ifkp_pixelptr = RAWSTART/ifkp::IMAGEspp - 1;
217 ifkpcnt_phase->value(ifkp_pixelptr);
218 }
219 if (ifkp_pixelptr < -RAWSTART/ifkp::IMAGEspp) {
220 ifkp_pixelptr = -RAWSTART/ifkp::IMAGEspp;
221 ifkpcnt_phase->value(ifkp_pixelptr);
222 }
223 ifkp_correct_video();
224 }
225
cb_ifkp_cnt_slant(Fl_Widget *,void *)226 void cb_ifkp_cnt_slant(Fl_Widget *, void *)
227 {
228 ifkp_correct_video();
229 }
230
ifkp_disableshift()231 void ifkp_disableshift()
232 {
233 if (!ifkppicRxWin) return;
234 ifkpcnt_phase->deactivate();
235 ifkpcnt_slant->deactivate();
236 btnifkpRxSave->deactivate();
237 ifkppicRxWin->redraw();
238 }
239
ifkp_enableshift()240 void ifkp_enableshift()
241 {
242 if (!ifkppicRxWin) return;
243 ifkpcnt_phase->activate();
244 ifkpcnt_slant->activate();
245 btnifkpRxSave->activate();
246
247 ifkp_save_raw_video();
248
249 ifkppicRxWin->redraw();
250 }
251
ifkp_createRxViewer()252 void ifkp_createRxViewer()
253 {
254
255 ifkppicRxWin = new Fl_Double_Window(324, 274, _("IFKP Rx Image"));
256 ifkppicRxWin->xclass(PACKAGE_NAME);
257 ifkppicRxWin->begin();
258
259 ifkppicRx = new picture(2, 2, 320, 240);
260 ifkppicRx->noslant();
261
262 Fl_Group *buttons = new Fl_Group(0, ifkppicRxWin->h() - 26, ifkppicRxWin->w(), 26, "");
263 buttons->box(FL_FLAT_BOX);
264
265 btnifkpRxReset = new Fl_Button(2, ifkppicRxWin->h() - 26, 40, 24, "Reset");
266 btnifkpRxReset->callback(cb_btnifkpRxReset, 0);
267
268 ifkpcnt_phase = new Fl_Counter(46, ifkppicRxWin->h() - 24, 80, 20, "");
269 ifkpcnt_phase->step(1);
270 ifkpcnt_phase->lstep(10);
271 ifkpcnt_phase->minimum(-RAWSTART + 1);
272 ifkpcnt_phase->maximum(RAWSTART - 1);
273 ifkpcnt_phase->value(0);
274 ifkpcnt_phase->callback(cb_ifkp_cnt_phase, 0);
275 ifkpcnt_phase->tooltip(_("Phase correction"));
276
277 ifkpcnt_slant = new Fl_Counter(140, ifkppicRxWin->h() - 24, 80, 20, "");
278 ifkpcnt_slant->step(1);
279 ifkpcnt_slant->lstep(10);
280 ifkpcnt_slant->minimum(-200);
281 ifkpcnt_slant->maximum(200);
282 ifkpcnt_slant->value(0);
283 ifkpcnt_slant->callback(cb_ifkp_cnt_slant, 0);
284 ifkpcnt_slant->tooltip(_("Slant correction"));
285
286 btnifkpRxSave = new Fl_Button(226, ifkppicRxWin->h() - 26, 45, 24, _("Save"));
287 btnifkpRxSave->callback(cb_btnifkpRxSave, 0);
288
289 btnifkpRxClose = new Fl_Button(273, ifkppicRxWin->h() - 26, 45, 24, _("Close"));
290 btnifkpRxClose->callback(cb_btnifkpRxClose, 0);
291 buttons->end();
292
293 ifkppicRxWin->end();
294 ifkppicRxWin->resizable(ifkppicRx);
295
296 ifkp_numpixels = 0;
297 }
298
ifkp_showRxViewer(char itype)299 void ifkp_showRxViewer(char itype)
300 {
301 int W = 320;
302 int H = 240;
303 switch (itype) {
304 case 'L' : case 'l' : W = 320; H = 240; break;
305 case 'S' : case 's' : W = 160; H = 120; break;
306 case 'V' : case 'F' : W = 640; H = 480; break;
307 case 'P' : case 'p' : W = 240; H = 300; break;
308 case 'M' : case 'm' : W = 120; H = 150; break;
309 case 'T' : W = 59; H = 74; break;
310 }
311
312 if (!ifkppicRxWin) ifkp_createRxViewer();
313 int winW, winH;
314 int ifkppicX, ifkppicY;
315 winW = W < 320 ? 324 : W + 4;
316 winH = H < 240 ? 274 : H + 34;
317 ifkppicX = (winW - W) / 2;
318 ifkppicY = (winH - 30 - H) / 2;
319 ifkppicRxWin->size(winW, winH);
320 ifkppicRx->resize(ifkppicX, ifkppicY, W, H);
321 ifkppicRxWin->init_sizes();
322
323 ifkppicRx->clear();
324 ifkppicRxWin->show();
325 ifkp_disableshift();
326
327 if (ifkp_rawvideo == 0) ifkp_rawvideo = new unsigned char [RAWSIZE + 1];
328 memset(ifkp_rawvideo, 0, RAWSIZE);
329 ifkp_numpixels = 0;
330 ifkp_pixelptr = 0;
331 ifkp_rawrow = ifkp_rawrgb = ifkp_rawcol = 0;
332 ifkp_image_type = itype;
333 }
334
ifkp_clear_rximage()335 void ifkp_clear_rximage()
336 {
337 ifkppicRx->clear();
338 ifkp_disableshift();
339 translate = 0;
340 enabled = false;
341 ifkp_numpixels = 0;
342 ifkp_pixelptr = 0;
343 ifkpcnt_phase->value(0);
344 ifkpcnt_slant->value(0);
345 ifkp_rawrow = ifkp_rawrgb = ifkp_rawcol = 0;
346 }
347
348 //------------------------------------------------------------------------------
349 // image transmit functions
350 //------------------------------------------------------------------------------
351
ifkp_load_image(const char * n)352 int ifkp_load_image(const char *n) {
353
354 int D = 0;
355 unsigned char *img_data;
356 int W = 640;
357 int H = 480;
358
359 switch (selifkppicSize->value()) {
360 case 0 : W = 59; H = 74; break;
361 case 1 : W = 120; H = 150; break;
362 case 2 : W = 240; H = 300; break;
363 case 3 : W = 160; H = 120; break;
364 case 4 : W = 320; H = 240; break;
365 case 5 : W = 640; H = 480; break;
366 }
367
368 if (ifkpTxImg) {
369 ifkpTxImg->release();
370 ifkpTxImg = 0;
371 }
372 ifkpTxImg = Fl_Shared_Image::get(n, W, H);
373
374 if (!ifkpTxImg)
375 return 0;
376
377 if (ifkpTxImg->count() > 1) {
378 ifkpTxImg->release();
379 ifkpTxImg = 0;
380 return 0;
381 }
382
383 ifkppicTx->hide();
384 ifkppicTx->clear();
385
386 img_data = (unsigned char *)ifkpTxImg->data()[0];
387
388 D = ifkpTxImg->d();
389
390 if (ifkpxmtimg) delete [] ifkpxmtimg;
391
392 ifkpxmtimg = new unsigned char [W * H * 3];
393 if (D == 3)
394 memcpy(ifkpxmtimg, img_data, W*H*3);
395 else if (D == 4) {
396 int i, j, k;
397 for (i = 0; i < W*H; i++) {
398 j = i*3; k = i*4;
399 ifkpxmtimg[j] = img_data[k];
400 ifkpxmtimg[j+1] = img_data[k+1];
401 ifkpxmtimg[j+2] = img_data[k+2];
402 }
403 } else if (D == 1) {
404 int i, j;
405 for (i = 0; i < W*H; i++) {
406 j = i * 3;
407 ifkpxmtimg[j] = ifkpxmtimg[j+1] = ifkpxmtimg[j+2] = img_data[i];
408 }
409 } else
410 return 0;
411
412 // ifkp_showTxViewer(W, H);
413 char* label = strdup(n);
414 ifkppicTxWin->copy_label(basename(label));
415 free(label);
416 // load the ifkppicture widget with the rgb image
417
418 ifkppicTx->show();
419 ifkppicTxWin->redraw();
420 ifkppicTx->video(ifkpxmtimg, W * H * 3);
421
422 btnifkppicTransmit->activate();
423
424 return 1;
425 }
426
ifkp_updateTxPic(unsigned char data,int pos)427 void ifkp_updateTxPic(unsigned char data, int pos)
428 {
429 if (!ifkppicTxWin->shown()) ifkppicTx->show();
430 ifkppicTx->pixel(data, pos);
431 }
432
cb_ifkppicTxLoad(Fl_Widget *,void *)433 void cb_ifkppicTxLoad(Fl_Widget *, void *)
434 {
435 const char *fn =
436 FSEL::select(_("Load image file"), "Image\t*.{png,,gif,jpg,jpeg}\n", PicsDir.c_str());
437 if (!fn) return;
438 if (!*fn) return;
439 ifkp_load_image(fn);
440 }
441
ifkp_clear_tximage()442 void ifkp_clear_tximage()
443 {
444 ifkppicTx->clear();
445 }
446
cb_ifkppicTxClose(Fl_Widget * w,void *)447 void cb_ifkppicTxClose( Fl_Widget *w, void *)
448 {
449 ifkppicTxWin->hide();
450 }
451
ifkppic_TxGetPixel(int pos,int color)452 int ifkppic_TxGetPixel(int pos, int color)
453 {
454 return ifkpxmtimg[3*pos + color]; // color = {RED, GREEN, BLUE}
455 }
456
cb_ifkppicTransmit(Fl_Widget * w,void *)457 void cb_ifkppicTransmit( Fl_Widget *w, void *)
458 {
459 bool grey = btnifkppicTxGrey->value();
460 char ch = ' ';
461 string picmode = " pic%";
462 switch (selifkppicSize->value()) {
463 case 0 : ifkp_showTxViewer(ch = (grey ? 't' : 'T')); break; // 59 x 74
464 case 1 : ifkp_showTxViewer(ch = (grey ? 'm' : 'M')); break; // 120 x 150
465 case 2 : ifkp_showTxViewer(ch = (grey ? 'p' : 'P')); break; // 240 x 300
466 case 3 : ifkp_showTxViewer(ch = (grey ? 's' : 'S')); break; // 160 x 120
467 case 4 : ifkp_showTxViewer(ch = (grey ? 'l' : 'L')); break; // 320 x 240
468 case 5 : ifkp_showTxViewer(ch = (grey ? 'F' : 'V')); break; // 640 x 480
469 }
470 picmode += ch;
471 active_modem->ifkp_send_image(picmode, grey);
472 }
473
cb_ifkppicTxSendAbort(Fl_Widget * w,void *)474 void cb_ifkppicTxSendAbort( Fl_Widget *w, void *)
475 {
476 }
477
478
cb_selifkppicSize(Fl_Widget * w,void *)479 void cb_selifkppicSize( Fl_Widget *w, void *)
480 {
481 switch (selifkppicSize->value()) {
482 case 0 : ifkp_showTxViewer('T'); break;
483 case 1 : ifkp_showTxViewer('M'); break;
484 case 2 : ifkp_showTxViewer('P'); break;
485 case 3 : ifkp_showTxViewer('S'); break;
486 case 4 : ifkp_showTxViewer('L'); break;
487 case 5 : ifkp_showTxViewer('V'); break;
488 }
489 }
490
ifkp_createTxViewer()491 void ifkp_createTxViewer()
492 {
493
494 ifkppicTxWin = new Fl_Double_Window(324, 270, _("IFKP Send image"));
495 ifkppicTxWin->xclass(PACKAGE_NAME);
496 ifkppicTxWin->begin();
497
498 ifkppicTx = new picture (2, 2, 320, 240);
499 ifkppicTx->noslant();
500 ifkppicTx->hide();
501
502 selifkppicSize = new Fl_Choice(5, 244, 90, 24);
503 selifkppicSize->add("59 x 74");
504 selifkppicSize->add("120x150");
505 selifkppicSize->add("240x300");
506 selifkppicSize->add("160x120");
507 selifkppicSize->add("320x240");
508 selifkppicSize->add("640x480");
509 selifkppicSize->value(1);
510 selifkppicSize->callback(cb_selifkppicSize, 0);
511
512 btnifkppicTxGrey = new Fl_Check_Button(99, 247, 18, 18);
513 btnifkppicTxGrey->tooltip(_("Send grey scale image"));
514 btnifkppicTxGrey->value(0);
515
516 btnifkppicTxLoad = new Fl_Button(120, 244, 60, 24, _("Load"));
517 btnifkppicTxLoad->callback(cb_ifkppicTxLoad, 0);
518
519 btnifkppicTransmit = new Fl_Button(ifkppicTxWin->w() - 130, 244, 60, 24, "Xmt");
520 btnifkppicTransmit->callback(cb_ifkppicTransmit, 0);
521
522 btnifkppicTxSendAbort = new Fl_Button(ifkppicTxWin->w() - 130, 244, 60, 24, "Abort Xmt");
523 btnifkppicTxSendAbort->callback(cb_ifkppicTxSendAbort, 0);
524
525 btnifkppicTxClose = new Fl_Button(ifkppicTxWin->w() - 65, 244, 60, 24, _("Close"));
526 btnifkppicTxClose->callback(cb_ifkppicTxClose, 0);
527
528 btnifkppicTxSendAbort->hide();
529 btnifkppicTransmit->deactivate();
530
531 ifkppicTxWin->end();
532
533 }
534
535
ifkp_load_scaled_image(std::string fname,bool gray)536 void ifkp_load_scaled_image(std::string fname, bool gray)
537 {
538
539 if (!ifkppicTxWin) ifkp_createTxViewer();
540
541 int D = 0;
542 unsigned char *img_data;
543 int W = 160;
544 int H = 120;
545 int winW = 644;
546 int winH = 512;
547 int ifkppicX = 0;
548 int ifkppicY = 0;
549 string picmode = "pic% \n";
550
551 if (ifkpTxImg) {
552 ifkpTxImg->release();
553 ifkpTxImg = 0;
554 }
555
556 ifkpTxImg = Fl_Shared_Image::get(fname.c_str());
557 if (!ifkpTxImg)
558 return;
559
560 int iW = ifkpTxImg->w();
561 int iH = ifkpTxImg->h();
562 int aspect = 0;
563
564 if (iW > iH ) {
565 if (iW >= 640) {
566 W = 640; H = 480;
567 winW = 644; winH = 484;
568 aspect = 5;
569 picmode[4] = 'V';
570 if (gray) picmode[4] = 'F';
571 }
572 else if (iW >= 320) {
573 W = 320; H = 240;
574 winW = 324; winH = 244;
575 aspect = 4;
576 picmode[4] = 'L';
577 if (gray) picmode[4] = 'l';
578 }
579 else {
580 W = 160; H = 120;
581 winW = 164; winH = 124;
582 aspect = 3;
583 picmode[4] = 'S';
584 if (gray) picmode[4] = 's';
585 }
586 } else {
587 if (iH >= 300) {
588 W = 240; H = 300;
589 winW = 244; winH = 304;
590 aspect = 2;
591 picmode[4] = 'P';
592 if (gray) picmode[4] = 'p';
593 }
594 else if (iH >= 150) {
595 W = 120; H = 150;
596 winW = 124; winH = 154;
597 aspect = 1;
598 picmode[4] = 'M';
599 if (gray) picmode[4] = 'm';
600 }
601 else {
602 W = 59; H = 74;
603 winW = 67; winH = 82;
604 aspect = 0;
605 picmode[4] = 'T';
606 if (gray) picmode[4] = 't';
607 }
608 }
609
610 {
611 Fl_Image *temp;
612 selifkppicSize->value(aspect);
613 temp = ifkpTxImg->copy(W, H);
614 ifkpTxImg->release();
615 ifkpTxImg = (Fl_Shared_Image *)temp;
616 }
617
618 if (ifkpTxImg->count() > 1) {
619 ifkpTxImg->release();
620 ifkpTxImg = 0;
621 return;
622 }
623
624 ifkppicTx->hide();
625 ifkppicTx->clear();
626
627 img_data = (unsigned char *)ifkpTxImg->data()[0];
628
629 D = ifkpTxImg->d();
630
631 if (ifkpxmtimg) delete [] ifkpxmtimg;
632
633 ifkpxmtimg = new unsigned char [W * H * 3];
634 if (D == 3)
635 memcpy(ifkpxmtimg, img_data, W*H*3);
636 else if (D == 4) {
637 int i, j, k;
638 for (i = 0; i < W*H; i++) {
639 j = i*3; k = i*4;
640 ifkpxmtimg[j] = img_data[k];
641 ifkpxmtimg[j+1] = img_data[k+1];
642 ifkpxmtimg[j+2] = img_data[k+2];
643 }
644 } else if (D == 1) {
645 int i, j;
646 for (i = 0; i < W*H; i++) {
647 j = i * 3;
648 ifkpxmtimg[j] = ifkpxmtimg[j+1] = ifkpxmtimg[j+2] = img_data[i];
649 }
650 } else
651 return;
652
653 char* label = strdup(fname.c_str());
654 ifkppicTxWin->copy_label(basename(label));
655 free(label);
656
657 // load the ifkppicture widget with the rgb image
658
659 ifkppicTxWin->size(winW, winH);
660 ifkppicX = (winW - W) / 2;
661 ifkppicY = (winH - H) / 2;
662 ifkppicTx->resize(ifkppicX, ifkppicY, W, H);
663
664 selifkppicSize->hide();
665 btnifkppicTransmit->hide();
666 btnifkppicTxLoad->hide();
667 btnifkppicTxClose->hide();
668 btnifkppicTxSendAbort->hide();
669
670 ifkppicTx->video(ifkpxmtimg, W * H * 3);
671 ifkppicTx->show();
672
673 ifkppicTxWin->show();
674
675 active_modem->ifkp_send_image(picmode, gray);
676
677 return;
678 }
679
ifkp_showTxViewer(char c)680 void ifkp_showTxViewer(char c)
681 {
682 if (!ifkppicTxWin) ifkp_createTxViewer();
683
684 int winW = 644, winH = 512, W = 480, H = 320;
685 int ifkppicX, ifkppicY;
686
687 ifkppicTx->clear();
688
689 switch (c) {
690 case 'T' : case 't' :
691 W = 59; H = 74; winW = 324; winH = 184;
692 selifkppicSize->value(0);
693 break;
694 case 'S' : case 's' :
695 W = 160; H = 120; winW = 324; winH = 154;
696 selifkppicSize->value(3);
697 break;
698 case 'L' : case 'l' :
699 W = 320; H = 240; winW = 324; winH = 274;
700 selifkppicSize->value(4);
701 break;
702 case 'F' : case 'V' :
703 W = 640; H = 480; winW = 644; winH = 514;
704 selifkppicSize->value(5);
705 break;
706 case 'P' : case 'p' :
707 W = 240; H = 300; winW = 324; winH = 334;
708 selifkppicSize->value(2);
709 break;
710 case 'M' : case 'm' :
711 W = 120; H = 150; winW = 324; winH = 184;
712 selifkppicSize->value(1);
713 break;
714 }
715
716 ifkppicTxWin->size(winW, winH);
717 ifkppicX = (winW - W) / 2;
718 ifkppicY = (winH - 26 - H) / 2;
719 ifkppicTx->resize(ifkppicX, ifkppicY, W, H);
720
721 selifkppicSize->resize(5, winH - 26, 90, 24);
722
723 btnifkppicTxGrey->resize(selifkppicSize->x() + selifkppicSize->w() + 4, winH - 23, 18, 18);
724
725 btnifkppicTxLoad->resize(btnifkppicTxGrey->x() + btnifkppicTxGrey->w() + 4, winH - 26, 60, 24);
726
727 btnifkppicTransmit->resize(winW - 130, winH - 26, 60, 24);
728 btnifkppicTxSendAbort->resize(winW - 130, winH - 26, 60, 24);
729
730 btnifkppicTxClose->resize(winW -65, winH - 26, 60, 24);
731
732 selifkppicSize->show();
733 btnifkppicTransmit->show();
734 btnifkppicTxLoad->show();
735 btnifkppicTxClose->show();
736 btnifkppicTxSendAbort->hide();
737
738 ifkppicTxWin->show();
739
740 }
741
ifkp_deleteTxViewer()742 void ifkp_deleteTxViewer()
743 {
744 if (ifkppicTxWin) ifkppicTxWin->hide();
745 if (ifkppicTx) {
746 delete ifkppicTx;
747 ifkppicTx = 0;
748 }
749 delete [] ifkpxmtimg;
750 ifkpxmtimg = 0;
751 delete [] ifkpxmtpicbuff;
752 ifkpxmtpicbuff = 0;
753 if (ifkppicTxWin) delete ifkppicTxWin;
754 ifkppicTxWin = 0;
755 }
756
ifkp_deleteRxViewer()757 void ifkp_deleteRxViewer()
758 {
759 if (ifkppicRxWin) ifkppicRxWin->hide();
760 if (ifkppicRx) {
761 delete ifkppicRx;
762 ifkppicRx = 0;
763 }
764 if (ifkppicRxWin) {
765 delete ifkppicRxWin;
766 ifkppicRxWin = 0;
767 }
768 }
769
ifkp_print_time_left(float time_sec,char * str,size_t len,const char * prefix,const char * suffix)770 int ifkp_print_time_left(float time_sec, char *str, size_t len,
771 const char *prefix, const char *suffix)
772 {
773 int time_min = (int)(time_sec / 60);
774 time_sec -= time_min * 60;
775
776 if (time_min)
777 return snprintf(str, len, "%s %02dm %2.1fs%s",
778 prefix, time_min, time_sec, suffix);
779 else
780 return snprintf(str, len, "%s %2.1fs%s", prefix, time_sec, suffix);
781 }
782
783 // -----------------------------------------------------------------------------
784 // avatar send/recv
785 // -----------------------------------------------------------------------------
786
787 static Fl_Shared_Image *shared_avatar_img = (Fl_Shared_Image *)0;
788 static unsigned char *avatar_img = (unsigned char *)0;
789 static Fl_Shared_Image *my_avatar_img = (Fl_Shared_Image *)0;
790 static int avatar_phase_correction = 0;
791 static unsigned char avatar[59 * 74 * 3];
792
ifkp_clear_avatar()793 void ifkp_clear_avatar()
794 {
795 ifkp_avatar->clear();
796 avatar_phase_correction = 0;
797 ifkp_numpixels = 0;
798 ifkp_rawrow = ifkp_rawrgb = ifkp_rawcol = 0;
799 ifkp_avatar->video(tux_img, sizeof(tux_img));
800 }
801
802
803 // W always 59, H always 74
ifkp_load_avatar(std::string image_fname,int W,int H)804 int ifkp_load_avatar(std::string image_fname, int W, int H)
805 {
806 W = 59; H = 74;
807
808 if (image_fname.empty()) {
809 ifkp_clear_avatar();
810 return 1;
811 }
812
813 int D = 0;
814 unsigned char *img_data;
815
816 if (shared_avatar_img) {
817 shared_avatar_img->release();
818 shared_avatar_img = 0;
819 }
820
821 for (size_t n = 0; n < image_fname.length(); n++)
822 image_fname[n] = tolower(image_fname[n]);
823 std::string fname = AvatarDir;
824 fname.append(image_fname).append(".png");
825
826 FILE *temp = fl_fopen(fname.c_str(), "rb");
827 if (temp) {
828 fseek(temp, 0L, SEEK_SET);
829 fclose(temp);
830 } else {
831 ifkp_avatar->video(tux_img, 59 * 74 * 3);
832 return 1;
833 }
834
835 shared_avatar_img = Fl_Shared_Image::get(fname.c_str(), W, H);
836
837 // force image to be retrieved from hard drive vice shared image memory
838 shared_avatar_img->reload();
839
840 if (!shared_avatar_img) {
841 ifkp_avatar->video(tux_img, 59 * 74 * 3);
842 return 1;
843 }
844
845 if (shared_avatar_img->count() > 1) {
846 shared_avatar_img->release();
847 shared_avatar_img = 0;
848 ifkp_avatar->video(tux_img, 59 * 74 * 3);
849 return 0;
850 }
851
852 img_data = (unsigned char *)shared_avatar_img->data()[0];
853
854 D = shared_avatar_img->d();
855
856 if (avatar_img) delete [] avatar_img;
857
858 avatar_img = new unsigned char [W * H * 3];
859 if (D == 3)
860 memcpy(avatar_img, img_data, W*H*3);
861 else if (D == 4) {
862 int i, j, k;
863 for (i = 0; i < W*H; i++) {
864 j = i*3; k = i*4;
865 avatar_img[j] = img_data[k];
866 avatar_img[j+1] = img_data[k+1];
867 avatar_img[j+2] = img_data[k+2];
868 }
869 } else if (D == 1) {
870 int i, j;
871 for (i = 0; i < W*H; i++) {
872 j = i * 3;
873 avatar_img[j] = avatar_img[j+1] = avatar_img[j+2] = img_data[i];
874 }
875 } else {
876 ifkp_avatar->video(tux_img, W * H * 3);
877 return 0;
878 }
879 ifkp_avatar->video(avatar_img, W * H * 3);
880
881 shared_avatar_img->release();
882 shared_avatar_img = 0;
883
884 return 1;
885 }
886
correct_avatar()887 void correct_avatar()
888 {
889 int W = 59;
890 int H = 74;
891 int index, rowptr, colptr;
892 unsigned char vid[W * H * 3];
893
894 if (avatar_phase_correction >= RAWSTART/ifkp::IMAGEspp) {
895 avatar_phase_correction = RAWSTART/ifkp::IMAGEspp - 1;
896 }
897 if (avatar_phase_correction < -RAWSTART/ifkp::IMAGEspp) {
898 avatar_phase_correction = -RAWSTART/ifkp::IMAGEspp;
899 }
900
901 for (int row = 0; row < H; row++) {
902 rowptr = W * 3 * row * ifkp::IMAGEspp;
903 for (int col = 0; col < W; col++) {
904 colptr = ifkp::IMAGEspp*col;
905 for (int rgb = 0; rgb < 3; rgb++) {
906 index = rowptr + colptr + W*rgb*ifkp::IMAGEspp;
907 index += RAWSTART - ifkp::IMAGEspp * avatar_phase_correction;
908 if (index < 2) index = 2;
909 if (index > RAWSIZE - 2) index = RAWSIZE - 2;
910 vid[rgb + 3 * (col + row * W)] = ifkp_rawvideo[index];
911 }
912 }
913 }
914 ifkp_avatar->video(vid, W*H*3);
915 }
916
ifkp_update_avatar(unsigned char data,int pos)917 void ifkp_update_avatar(unsigned char data, int pos)
918 {
919 if (ifkp_rawvideo == 0) {
920 ifkp_rawvideo = new unsigned char [RAWSIZE + 1];
921 memset(ifkp_rawvideo, 0, RAWSIZE);
922 }
923
924 ifkp_avatar->pixel(data, pos);
925 for (int i = 0; i < ifkp::IMAGEspp; i++)
926 ifkp_rawvideo[RAWSTART + ifkp::IMAGEspp*ifkp_numpixels + i] = data;
927
928 ifkp_numpixels++;
929
930 if (ifkp_numpixels >= (RAWSIZE - RAWSTART - ifkp::IMAGEspp))
931 ifkp_numpixels = RAWSIZE - RAWSTART - ifkp::IMAGEspp;
932
933 }
934
ifkp_get_avatar_pixel(int pos,int color)935 int ifkp_get_avatar_pixel(int pos, int color)
936 {
937 // color = {RED, GREEN, BLUE}
938 return (int)avatar[3*pos + color];
939
940 }
941
942 // ADD CALLBACK HANDLING OF PHASE CORRECTIONS
943
cb_ifkp_send_avatar(Fl_Widget * w,void *)944 void cb_ifkp_send_avatar( Fl_Widget *w, void *)
945 {
946 if (Fl::event_button() == FL_RIGHT_MOUSE) {
947 if (Fl::get_key (FL_Shift_L) || Fl::get_key(FL_Shift_R)) {
948 if (ifkp_numpixels == 0) return;
949 avatar_phase_correction += 5;
950 correct_avatar();
951 return;
952 }
953 if (Fl::get_key (FL_Control_L) || Fl::get_key(FL_Control_R)) {
954 if (ifkp_numpixels == 0) return;
955 avatar_phase_correction++;
956 correct_avatar();
957 return;
958 }
959 std::string mycall = progdefaults.myCall;
960 for (size_t n = 0; n < mycall.length(); n++)
961 mycall[n] = tolower(mycall[n]);
962 std::string fname = AvatarDir;
963 fname.append(mycall).append(".png");
964
965 my_avatar_img = Fl_Shared_Image::get(fname.c_str(), 59, 74);
966 if (!my_avatar_img) return;
967 unsigned char *img_data = (unsigned char *)my_avatar_img->data()[0];
968 memset(avatar, 0, sizeof(avatar));
969 int D = my_avatar_img->d();
970
971 if (D == 3)
972 memcpy(avatar, img_data, 59*74*3);
973 else if (D == 4) {
974 int i, j, k;
975 for (i = 0; i < 59*74; i++) {
976 j = i*3; k = i*4;
977 avatar[j] = img_data[k];
978 avatar[j+1] = img_data[k+1];
979 avatar[j+2] = img_data[k+2];
980 }
981 } else if (D == 1) {
982 int i, j;
983 for (i = 0; i < 59*74; i++) {
984 j = i * 3;
985 avatar[j] = avatar[j+1] = avatar[j+2] = img_data[i];
986 }
987 } else
988 return;
989
990 active_modem->ifkp_send_avatar();
991 return;
992 }
993
994 if (Fl::event_button() == FL_LEFT_MOUSE) {
995 if (Fl::get_key (FL_Shift_L) || Fl::get_key(FL_Shift_R)) {
996 if (ifkp_numpixels == 0) return;
997 avatar_phase_correction -= 5;
998 correct_avatar();
999 return;
1000 }
1001 if (Fl::get_key (FL_Control_L) || Fl::get_key(FL_Control_R)) {
1002 if (ifkp_numpixels == 0) return;
1003 avatar_phase_correction--;
1004 correct_avatar();
1005 return;
1006 }
1007 std::string mycall = inpCall->value();
1008 if (mycall.empty()) return;
1009 for (size_t n = 0; n < mycall.length(); n++)
1010 mycall[n] = tolower(mycall[n]);
1011 std::string fname = AvatarDir;
1012 fname.append(mycall).append(".png");
1013 ifkp_avatar->save_png(fname.c_str());
1014 }
1015 }
1016