1 // ----------------------------------------------------------------------------
2 // mfsk-pic.cxx -- mfsk support functions
3 //
4 // Copyright (C) 2006-2008
5 // Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi. Adapted from code contained in gmfsk source code
8 // distribution.
9 // gmfsk Copyright (C) 2001, 2002, 2003
10 // Tomi Manninen (oh2bns@sral.fi)
11 //
12 // Fldigi is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Fldigi is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with fldigi. If not, see <http://www.gnu.org/licenses/>.
24 // ----------------------------------------------------------------------------
25
26 #include "gettext.h"
27
28 Fl_Double_Window *picRxWin = (Fl_Double_Window *)0;
29
30 picture *picRx = (picture *)0;
31
32 Fl_Double_Window *picTxWin = (Fl_Double_Window *)0;
33
34 picture *picTx = (picture *)0;
35 picbox *picTxBox = 0;
36 Fl_Button *btnpicTxSPP = (Fl_Button *)0;
37 Fl_Button *btnpicTxSendColor = (Fl_Button *)0;
38 Fl_Button *btnpicTxSendGrey = (Fl_Button *)0;
39 Fl_Button *btnpicTxSendAbort = (Fl_Button *)0;
40 Fl_Button *btnpicTxLoad = (Fl_Button *)0;
41 Fl_Button *btnpicTxClose = (Fl_Button *)0;
42
43 Fl_Shared_Image *TxImg = (Fl_Shared_Image *)0;
44 unsigned char *xmtimg = (unsigned char *)0;
45 unsigned char *xmtpicbuff = (unsigned char *)0;
46
47 mfsk *serviceme = 0;
48 int txSPP = 8;
49
50 char txclr_tooltip[24];
51 char txgry_tooltip[24];
52
updateRxPic(unsigned char data,int pos)53 void updateRxPic(unsigned char data, int pos)
54 {
55 picRx->pixel(data, pos);
56 }
57
createRxViewer()58 void createRxViewer()
59 {
60 picRxWin = new Fl_Double_Window(200, 140);
61 picRxWin->xclass(PACKAGE_NAME);
62 picRxWin->begin();
63 picRx = new picture(2, 2, 136, 104);
64 picRxWin->end();
65 }
66
showRxViewer(int W,int H)67 void showRxViewer(int W, int H)
68 {
69 if (!picRxWin) createRxViewer();
70 int winW, winH;
71 int picX, picY;
72 winW = W < 136 ? 140 : W + 4;
73 winH = H + 4;
74 picX = (winW - W) / 2;
75 picY = 2;
76 picRxWin->size(winW, winH);
77 picRx->resize(picX, picY, W, H);
78 picRx->clear();
79 picRxWin->show();
80 }
81
load_image(const char * n)82 int load_image(const char *n) {
83
84 if (serviceme != active_modem) {
85 return 0;
86 }
87
88 int W, H, D;
89 unsigned char *img_data;
90
91 if (TxImg) {
92 TxImg->release();
93 TxImg = 0;
94 }
95 TxImg = Fl_Shared_Image::get(n);
96
97 if (!TxImg)
98 return 0;
99
100 if (TxImg->count() > 1) {
101 TxImg->release();
102 TxImg = 0;
103 return 0;
104 }
105
106 img_data = (unsigned char *)TxImg->data()[0];
107 W = TxImg->w();
108 H = TxImg->h();
109 D = TxImg->d();
110 if (xmtimg) delete [] xmtimg;
111 xmtimg = new unsigned char [W * H * 3];
112 if (D == 3)
113 memcpy(xmtimg, img_data, W*H*3);
114 else if (D == 4) {
115 int i, j, k;
116 for (i = 0; i < W*H; i++) {
117 j = i*3; k = i*4;
118 xmtimg[j] = img_data[k];
119 xmtimg[j+1] = img_data[k+1];
120 xmtimg[j+2] = img_data[k+2];
121 }
122 } else if (D == 1) {
123 int i, j;
124 for (i = 0; i < W*H; i++) {
125 j = i * 3;
126 xmtimg[j] = xmtimg[j+1] = xmtimg[j+2] = img_data[i];
127 }
128 } else
129 return 0;
130
131 TxViewerResize(W, H);
132 char* label = strdup(n);
133 picTxWin->copy_label(basename(label));
134 free(label);
135 picTxBox->label(0);
136 // load the picture widget with the rgb image
137 picTx->show();
138 picTx->clear();
139 picTxWin->redraw();
140 picTx->video(xmtimg, W * H * 3);
141 if (print_time_left( (W * H * 3) * 0.000125 * serviceme->TXspp,
142 txclr_tooltip, sizeof(txclr_tooltip), _("Time needed: ")) > 0)
143 btnpicTxSendColor->tooltip(txclr_tooltip);
144 btnpicTxSendColor->activate();
145 if (print_time_left( (W * H) * 0.000125 * serviceme->TXspp,
146 txgry_tooltip, sizeof(txgry_tooltip), _("Time needed: ")) > 0)
147 btnpicTxSendGrey->tooltip(txgry_tooltip);
148 btnpicTxSendGrey->activate();
149 return 1;
150 }
151
updateTxPic(unsigned char data)152 void updateTxPic(unsigned char data)
153 {
154 if (serviceme != active_modem) return;
155 if (serviceme->color) {
156 serviceme->pixelnbr = serviceme->rgb + serviceme->row + 3*serviceme->col;
157 picTx->pixel(data, serviceme->pixelnbr);
158 if (++serviceme->col == TxImg->w()) {
159 serviceme->col = 0;
160 if (++serviceme->rgb == 3) {
161 serviceme->rgb = 0;
162 serviceme->row += 3 * TxImg->w();
163 }
164 }
165 } else {
166 picTx->pixel( data, serviceme->pixelnbr++ );
167 picTx->pixel( data, serviceme->pixelnbr++ );
168 picTx->pixel( data, serviceme->pixelnbr++ );
169 }
170 }
171
cb_picTxLoad(Fl_Widget *,void *)172 void cb_picTxLoad(Fl_Widget *, void *)
173 {
174 const char *fn =
175 FSEL::select(_("Load image file"), "Portable Network Graphics\t*.png\n"
176 "Independent JPEG Group\t*.{jpg,jif,jpeg,jpe}\n"
177 "Graphics Interchange Format\t*.gif", PicsDir.c_str());
178 if (!fn) return;
179 if (!*fn) return;
180 load_image(fn);
181 }
182
cb_picTxClose(Fl_Widget * w,void *)183 void cb_picTxClose( Fl_Widget *w, void *)
184 {
185 picTxWin->hide();
186 }
187
pic_TxSendColor()188 void pic_TxSendColor()
189 {
190 int W, H, rowstart;
191 W = TxImg->w();
192 H = TxImg->h();
193 if (xmtpicbuff) delete [] xmtpicbuff;
194 xmtpicbuff = new unsigned char [W*H*3];
195 unsigned char *outbuf = xmtpicbuff;
196 unsigned char *inbuf = xmtimg;
197 int iy, ix, rgb;
198 for (iy = 0; iy < H; iy++) {
199 rowstart = iy * W * 3;
200 for (rgb = 0; rgb < 3; rgb++)
201 for (ix = 0; ix < W; ix++)
202 outbuf[rowstart + rgb*W + ix] = inbuf[rowstart + rgb + ix*3];
203 }
204 if (serviceme->TXspp == 8)
205 snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dC;", W, H);
206 else
207 snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dCp%d;", W, H,serviceme->TXspp);
208 serviceme->xmtbytes = W * H * 3;
209 serviceme->color = true;
210 serviceme->rgb = 0;
211 serviceme->col = 0;
212 serviceme->row = 0;
213 serviceme->pixelnbr = 0;
214 btnpicTxSPP->hide();
215 btnpicTxSendColor->hide();
216 btnpicTxSendGrey->hide();
217 btnpicTxLoad->hide();
218 btnpicTxClose->hide();
219 btnpicTxSendAbort->show();
220 picTx->clear();
221 if (!picTxWin->visible())
222 picTxWin->show();
223 // start the transmission
224 start_tx();
225 serviceme->startpic = true;
226 }
227
cb_picTxSendColor(Fl_Widget * w,void *)228 void cb_picTxSendColor( Fl_Widget *w, void *)
229 {
230 if (serviceme != active_modem) return;
231 pic_TxSendColor();
232 }
233
pic_TxSendGrey()234 void pic_TxSendGrey()
235 {
236 int W, H;
237 W = TxImg->w();
238 H = TxImg->h();
239 if (xmtpicbuff) delete [] xmtpicbuff;
240 xmtpicbuff = new unsigned char [W*H];
241 unsigned char *outbuf = xmtpicbuff;
242 unsigned char *inbuf = xmtimg;
243 for (int i = 0; i < W*H; i++)
244 outbuf[i] = ( 31 * inbuf[i*3] + 61 * inbuf[i*3 + 1] + 8 * inbuf[i*3 + 2])/100;
245 if (serviceme->TXspp == 8)
246 snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%d;", W, H);
247 else
248 snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dp%d;", W, H,serviceme->TXspp);
249 serviceme->xmtbytes = W * H;
250 serviceme->color = false;
251 serviceme->col = 0;
252 serviceme->row = 0;
253 serviceme->pixelnbr = 0;
254 btnpicTxSPP->hide();
255 btnpicTxSendColor->hide();
256 btnpicTxSendGrey->hide();
257 btnpicTxLoad->hide();
258 btnpicTxClose->hide();
259 btnpicTxSendAbort->show();
260 picTx->clear();
261 // start the transmission
262 if (!picTxWin->visible())
263 picTxWin->show();
264 start_tx();
265 serviceme->startpic = true;
266 }
267
cb_picTxSendGrey(Fl_Widget * w,void *)268 void cb_picTxSendGrey( Fl_Widget *w, void *)
269 {
270 if (serviceme != active_modem) return;
271 pic_TxSendGrey();
272 }
273
cb_picTxSendAbort(Fl_Widget * w,void *)274 void cb_picTxSendAbort( Fl_Widget *w, void *)
275 {
276 if (serviceme != active_modem) return;
277
278 serviceme->abortxmt = true;
279 // reload the picture widget with the rgb image
280 picTx->video(xmtimg, TxImg->w() * TxImg->h() * 3);
281 }
282
cb_picTxSPP(Fl_Widget * w,void *)283 void cb_picTxSPP( Fl_Widget *w, void *)
284 {
285 if (serviceme != active_modem) return;
286
287 Fl_Button *b = (Fl_Button *)w;
288
289 if (serviceme->TXspp == 8) serviceme->TXspp = 4;
290 else if (serviceme->TXspp == 4) serviceme->TXspp = 2;
291 else serviceme->TXspp = 8;
292
293 if (serviceme->TXspp == 8) b->label("X1");
294 else if (serviceme->TXspp == 4) b->label("X2");
295 else b->label("X4");
296 b->redraw_label();
297 txSPP = serviceme->TXspp;
298
299 if (TxImg == 0) return;
300 if (TxImg->w() > 0 && TxImg->h() > 0) {
301 if (print_time_left( (TxImg->w() * TxImg->h() * 3) * 0.000125 * serviceme->TXspp,
302 txclr_tooltip, sizeof(txclr_tooltip), _("Time needed: ")) > 0)
303 btnpicTxSendColor->tooltip(txclr_tooltip);
304 if (print_time_left( (TxImg->w() * TxImg->h()) * 0.000125 * serviceme->TXspp,
305 txgry_tooltip, sizeof(txgry_tooltip), _("Time needed: ")) > 0)
306 btnpicTxSendGrey->tooltip(txgry_tooltip);
307 }
308 }
309
createTxViewer()310 void createTxViewer()
311 {
312 picTxWin = new Fl_Double_Window(290, 180, _("Send image"));
313 picTxWin->xclass(PACKAGE_NAME);
314 picTxWin->begin();
315
316 picTx = new picture (2, 2, 286, 150);
317 picTx->hide();
318 picTxBox = new picbox(picTxWin->x(), picTxWin->y(), picTxWin->w(), picTxWin->h(),
319 _("Load or drop an image file\nSupported types: PNG, JPEG, BMP"));
320 picTxBox->labelfont(FL_HELVETICA_ITALIC);
321
322 btnpicTxSPP = new Fl_Button(5, 180 - 26, 40, 24, "X1");
323 btnpicTxSPP->tooltip(_("Transfer speed, X1-normal"));
324 btnpicTxSPP->callback( cb_picTxSPP, 0);
325
326 btnpicTxSendColor = new Fl_Button(45, 180 - 26, 60, 24, "XmtClr");
327 btnpicTxSendColor->callback(cb_picTxSendColor, 0);
328
329 btnpicTxSendGrey = new Fl_Button(105, 180 - 26, 60, 24, "XmtGry");
330 btnpicTxSendGrey->callback( cb_picTxSendGrey, 0);
331
332 btnpicTxSendAbort = new Fl_Button(84, 180 - 26, 122, 24, "Abort Xmt");
333 btnpicTxSendAbort->callback(cb_picTxSendAbort, 0);
334
335 btnpicTxLoad = new Fl_Button(165, 180 - 26, 60, 24, _("Load"));
336 btnpicTxLoad->callback(cb_picTxLoad, 0);
337
338 btnpicTxClose = new Fl_Button(225, 180 - 26, 60, 24, _("Close"));
339 btnpicTxClose->callback(cb_picTxClose, 0);
340
341 btnpicTxSendAbort->hide();
342 btnpicTxSendColor->deactivate();
343 btnpicTxSendGrey->deactivate();
344
345 picTxWin->end();
346 }
347
TxViewerResize(int W,int H)348 void TxViewerResize(int W, int H)
349 {
350 int winW, winH;
351 int picX, picY;
352 winW = W < 286 ? 290 : W + 4;
353 winH = H < 180 ? 210 : H + 30;
354 picX = (winW - W) / 2;
355 picY = (winH - 26 - H) / 2;
356 picTxWin->size(winW, winH);
357 picTx->resize(picX, picY, W, H);
358 picTx->clear();
359 picTxBox->size(winW, winH);
360 btnpicTxSPP->resize(winW/2 - 140, winH - 26, 40, 24);
361 btnpicTxSendColor->resize(winW/2 - 100, winH - 26, 60, 24);
362 btnpicTxSendGrey->resize(winW/2 - 40, winH - 26, 60, 24);
363 btnpicTxSendAbort->resize(winW/2 - 61, winH - 26, 122, 24);
364 btnpicTxLoad->resize(winW/2 + 20, winH - 26, 60, 24);
365 btnpicTxClose->resize(winW/2 + 80, winH - 26, 60, 24);
366 }
367
showTxViewer(int W,int H)368 void showTxViewer(int W, int H)
369 {
370 if (picTxWin) {
371 picTxWin->show();
372 return;
373 }
374
375 int winW, winH;
376 int picX, picY;
377 winW = W < 288 ? 290 : W + 4;
378 winH = H < 180 ? 180 : H + 30;
379 picX = (winW - W) / 2;
380 picY = (winH - 26 - H) / 2;
381 picTxWin->size(winW, winH);
382 picTx->resize(picX, picY, W, H);
383 btnpicTxSPP->resize(winW/2 - 140, winH - 26, 40, 24);
384 btnpicTxSendColor->resize(winW/2 - 100, winH - 26, 60, 24);
385 btnpicTxSendGrey->resize(winW/2 - 40, winH - 26, 60, 24);
386 btnpicTxSendAbort->resize(winW/2 - 61, winH - 26, 122, 24);
387 btnpicTxLoad->resize(winW/2 + 20, winH - 26, 60, 24);
388 btnpicTxClose->resize(winW/2 + 80, winH - 26, 60, 24);
389 btnpicTxSPP->show();
390 btnpicTxSendColor->show();
391 btnpicTxSendGrey->show();
392 btnpicTxLoad->show();
393 btnpicTxClose->show();
394 btnpicTxSendAbort->hide();
395 picTxWin->show();
396 }
397
deleteTxViewer()398 void deleteTxViewer()
399 {
400 picTxWin->hide();
401 if (picTx) delete picTx;
402 delete [] xmtimg;
403 xmtimg = 0;
404 delete [] xmtpicbuff;
405 xmtpicbuff = 0;
406 delete picTxWin;
407 picTxWin = 0;
408 serviceme = 0;
409 }
410
deleteRxViewer()411 void deleteRxViewer()
412 {
413 picRxWin->hide();
414 if (picRx) {
415 delete picRx;
416 picRx = 0;
417 }
418 delete picRxWin;
419 picRxWin = 0;
420 serviceme = 0;
421 }
422
print_time_left(float time_sec,char * str,size_t len,const char * prefix,const char * suffix)423 int print_time_left(float time_sec, char *str, size_t len,
424 const char *prefix, const char *suffix)
425 {
426 int time_min = (int)(time_sec / 60);
427 time_sec -= time_min * 60;
428
429 if (time_min)
430 return snprintf(str, len, "%s %02dm %2.1fs%s",
431 prefix, time_min, time_sec, suffix);
432 else
433 return snprintf(str, len, "%s %2.1fs%s", prefix, time_sec, suffix);
434 }
435
setpicture_link(mfsk * me)436 void setpicture_link(mfsk *me)
437 {
438 serviceme = me;
439 }
440
441