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