dl-fldigi/src/mfsk/mfsk-pic.cxx

514 wiersze
13 KiB
C++

// ----------------------------------------------------------------------------
// mfsk-pic.cxx -- mfsk support functions
//
// Copyright (C) 2006
// Dave Freese, W1HKJ
//
// This file is part of fldigi. Adapted from code contained in gmfsk source code
// distribution.
// gmfsk Copyright (C) 2001, 2002, 2003
// Tomi Manninen (oh2bns@sral.fi)
//
// fldigi is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// fldigi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with fldigi; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ----------------------------------------------------------------------------
#include "gettext.h"
Fl_Double_Window *picRxWin = (Fl_Double_Window *)0;
picture *picRx = (picture *)0;
Fl_Button *btnpicRxSave = (Fl_Button *)0;
Fl_Button *btnpicRxAbort = (Fl_Button *)0;
Fl_Button *btnpicRxClose = (Fl_Button *)0;
Fl_Double_Window *picTxWin = (Fl_Double_Window *)0;
picture *picTx = (picture *)0;
picbox *picTxBox = 0;
Fl_Button *btnpicTxSPP = (Fl_Button *)0;
Fl_Button *btnpicTxSendColor = (Fl_Button *)0;
Fl_Button *btnpicTxSendGrey = (Fl_Button *)0;
Fl_Button *btnpicTxSendAbort = (Fl_Button *)0;
Fl_Button *btnpicTxLoad = (Fl_Button *)0;
Fl_Button *btnpicTxClose = (Fl_Button *)0;
Fl_Shared_Image *TxImg = (Fl_Shared_Image *)0;
unsigned char *xmtimg = (unsigned char *)0;
unsigned char *xmtpicbuff = (unsigned char *)0;
mfsk *serviceme = 0;
int txSPP = 8;
char txclr_tooltip[24];
char txgry_tooltip[24];
void updateRxPic(unsigned char data, int pos)
{
picRx->pixel(data, pos);
}
void cb_picRxClose( Fl_Widget *w, void *)
{
picRxWin->hide();
}
void cb_picRxAbort( Fl_Widget *w, void *)
{
if (serviceme != active_modem) return;
serviceme->rxstate = serviceme->RX_STATE_DATA;
put_status("");
picRx->clear();
}
void cb_picRxSave( Fl_Widget *w, void *)
{
const char ffilter[] = ""
#if USE_LIBPNG
"Portable Network Graphics\t*.png\n"
#endif
#if USE_LIBJPEG
"Independent JPEG Group\t*.{jpg,jpeg}"
#endif
;
const char dfname[] = "image."
#if USE_LIBPNG
"png"
#else
"jpg"
#endif
;
int fsel;
const char *fn = FSEL::saveas(_("Save image as:"), ffilter, dfname, &fsel);
if (!fn) return;
// selected filter determines format
switch (fsel) {
case 0:
#if USE_LIBPNG
picRx->save_png(fn);
break;
#endif
// fall through if no libpng
case 1:
#if USE_LIBJPEG
picRx->save_jpeg(fn);
#endif
break;
}
}
void createRxViewer()
{
FL_LOCK_D();
picRxWin = new Fl_Double_Window(200, 140);
picRxWin->xclass(PACKAGE_NAME);
picRxWin->begin();
picRx = new picture(2, 2, 136, 104);
btnpicRxSave = new Fl_Button(5, 140 - 30, 60, 24,_("Save..."));
btnpicRxSave->callback(cb_picRxSave, 0);
btnpicRxSave->hide();
#if !(USE_LIBPNG || USE_LIBJPEG)
btnpicRxSave->deactivate();
#endif
btnpicRxAbort = new Fl_Button(70, 140 - 30, 60, 24, _("Abort"));
btnpicRxAbort->callback(cb_picRxAbort, 0);
btnpicRxClose = new Fl_Button(135, 140 - 30, 60, 24, _("Hide"));
btnpicRxClose->callback(cb_picRxClose, 0);
picRxWin->end();
FL_UNLOCK_D();
}
void showRxViewer(int W, int H)
{
FL_LOCK_E();
if (!picRxWin) createRxViewer();
int winW, winH;
int picX, picY;
winW = W < 136 ? 140 : W + 4;
winH = H + 34;
picX = (winW - W) / 2;
picY = 2;
picRxWin->size(winW, winH);
picRx->resize(picX, picY, W, H);
btnpicRxSave->resize(winW/2 - 65, H + 6, 60, 24);
btnpicRxSave->hide();
btnpicRxAbort->resize(winW/2 - 65, H + 6, 60, 24);
btnpicRxAbort->show();
btnpicRxClose->resize(winW/2 + 5, H + 6, 60, 24);
picRx->clear();
picRxWin->show();
FL_UNLOCK_E();
}
void load_image(const char *n) {
if (serviceme != active_modem) return;
int W, H, D;
unsigned char *img_data;
if (TxImg) {
TxImg->release();
TxImg = 0;
}
TxImg = Fl_Shared_Image::get(n);
if (!TxImg)
return;
if (TxImg->count() > 1) { // we only handle rgb images
TxImg->release();
TxImg = 0;
return;
}
img_data = (unsigned char *)TxImg->data()[0];
W = TxImg->w();
H = TxImg->h();
D = TxImg->d();
if (xmtimg) delete [] xmtimg;
xmtimg = new unsigned char [W * H * 3];
if (D == 3)
memcpy(xmtimg, img_data, W*H*3);
else if (D == 4) {
int i, j, k;
for (i = 0; i < W*H; i++) {
j = i*3; k = i*4;
xmtimg[j] = img_data[k];
xmtimg[j+1] = img_data[k+1];
xmtimg[j+2] = img_data[k+2];
}
} else if (D == 1) {
int i, j;
for (i = 0; i < W*H; i++) {
j = i * 3;
xmtimg[j] = xmtimg[j+1] = xmtimg[j+2] = img_data[i];
}
} else
return;
TxViewerResize(W, H);
char* label = strdup(n);
picTxWin->copy_label(basename(label));
free(label);
picTxBox->label(0);
// load the picture widget with the rgb image
FL_LOCK_D();
picTx->show();
picTx->clear();
picTxWin->redraw();
picTx->video(xmtimg, W * H * 3);
if (print_time_left( (W * H * 3) * 0.000125 * serviceme->TXspp,
txclr_tooltip, sizeof(txclr_tooltip), _("Time needed: ")) > 0)
btnpicTxSendColor->tooltip(txclr_tooltip);
btnpicTxSendColor->activate();
if (print_time_left( (W * H) * 0.000125 * serviceme->TXspp,
txgry_tooltip, sizeof(txgry_tooltip), _("Time needed: ")) > 0)
btnpicTxSendGrey->tooltip(txgry_tooltip);
btnpicTxSendGrey->activate();
FL_UNLOCK_D();
}
void updateTxPic(unsigned char data)
{
if (serviceme != active_modem) return;
if (serviceme->color) {
serviceme->pixelnbr = serviceme->rgb + serviceme->row + 3*serviceme->col;
picTx->pixel(data, serviceme->pixelnbr);
if (++serviceme->col == TxImg->w()) {
serviceme->col = 0;
if (++serviceme->rgb == 3) {
serviceme->rgb = 0;
serviceme->row += 3 * TxImg->w();
}
}
} else {
picTx->pixel( data, serviceme->pixelnbr++ );
picTx->pixel( data, serviceme->pixelnbr++ );
picTx->pixel( data, serviceme->pixelnbr++ );
}
}
void cb_picTxLoad(Fl_Widget *, void *)
{
const char *fn =
FSEL::select(_("Load image file"), "Portable Network Graphics\t*.png\n"
"Independent JPEG Group\t*.{jpg,jif,jpeg,jpe}\n"
"Graphics Interchange Format\t*.gif");
if (!fn) return;
load_image(fn);
}
void cb_picTxClose( Fl_Widget *w, void *)
{
FL_LOCK_D();
picTxWin->hide();
FL_UNLOCK_D();
}
void cb_picTxSendColor( Fl_Widget *w, void *)
{
int W, H, rowstart;
W = TxImg->w();
H = TxImg->h();
if (xmtpicbuff) delete [] xmtpicbuff;
xmtpicbuff = new unsigned char [W*H*3];
unsigned char *outbuf = xmtpicbuff;
unsigned char *inbuf = xmtimg;
int iy, ix, rgb;
for (iy = 0; iy < H; iy++) {
rowstart = iy * W * 3;
for (rgb = 0; rgb < 3; rgb++)
for (ix = 0; ix < W; ix++)
outbuf[rowstart + rgb*W + ix] = inbuf[rowstart + rgb + ix*3];
}
if (serviceme->TXspp == 8)
snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dC;", W, H);
else
snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dCp%d;", W, H,serviceme->TXspp);
serviceme->xmtbytes = W * H * 3;
serviceme->color = true;
serviceme->rgb = 0;
serviceme->col = 0;
serviceme->row = 0;
serviceme->pixelnbr = 0;
FL_LOCK_D();
btnpicTxSPP->hide();
btnpicTxSendColor->hide();
btnpicTxSendGrey->hide();
btnpicTxLoad->hide();
btnpicTxClose->hide();
btnpicTxSendAbort->show();
picTx->clear();
FL_UNLOCK_D();
// start the transmission
start_tx();
serviceme->startpic = true;
}
void cb_picTxSendGrey( Fl_Widget *w, void *)
{
if (serviceme != active_modem) return;
int W, H;
W = TxImg->w();
H = TxImg->h();
if (xmtpicbuff) delete [] xmtpicbuff;
xmtpicbuff = new unsigned char [W*H];
unsigned char *outbuf = xmtpicbuff;
unsigned char *inbuf = xmtimg;
for (int i = 0; i < W*H; i++)
outbuf[i] = ( 31 * inbuf[i*3] + 61 * inbuf[i*3 + 1] + 8 * inbuf[i*3 + 2])/100;
if (serviceme->TXspp == 8)
snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%d;", W, H);
else
snprintf(serviceme->picheader, PICHEADER, "\nSending Pic:%dx%dp%d;", W, H,serviceme->TXspp);
serviceme->xmtbytes = W * H;
serviceme->color = false;
serviceme->col = 0;
serviceme->row = 0;
serviceme->pixelnbr = 0;
FL_LOCK_D();
btnpicTxSPP->hide();
btnpicTxSendColor->hide();
btnpicTxSendGrey->hide();
btnpicTxLoad->hide();
btnpicTxClose->hide();
btnpicTxSendAbort->show();
picTx->clear();
FL_UNLOCK_D();
// start the transmission
start_tx();
serviceme->startpic = true;
}
void cb_picTxSendAbort( Fl_Widget *w, void *)
{
if (serviceme != active_modem) return;
serviceme->abortxmt = true;
// reload the picture widget with the rgb image
FL_LOCK_D();
picTx->video(xmtimg, TxImg->w() * TxImg->h() * 3);
FL_UNLOCK_D();
}
void cb_picTxSPP( Fl_Widget *w, void *)
{
if (serviceme != active_modem) return;
Fl_Button *b = (Fl_Button *)w;
if (progdefaults.slowcpu == true)
serviceme->TXspp = 8;
else {
if (serviceme->TXspp == 8) serviceme->TXspp = 4;
else if (serviceme->TXspp == 4) serviceme->TXspp = 2;
else serviceme->TXspp = 8;
}
if (serviceme->TXspp == 8) b->label("X1");
else if (serviceme->TXspp == 4) b->label("X2");
else b->label("X4");
b->redraw_label();
txSPP = serviceme->TXspp;
if (TxImg == 0) return;
if (TxImg->w() > 0 && TxImg->h() > 0) {
if (print_time_left( (TxImg->w() * TxImg->h() * 3) * 0.000125 * serviceme->TXspp,
txclr_tooltip, sizeof(txclr_tooltip), _("Time needed: ")) > 0)
btnpicTxSendColor->tooltip(txclr_tooltip);
if (print_time_left( (TxImg->w() * TxImg->h()) * 0.000125 * serviceme->TXspp,
txgry_tooltip, sizeof(txgry_tooltip), _("Time needed: ")) > 0)
btnpicTxSendGrey->tooltip(txgry_tooltip);
}
}
void createTxViewer()
{
FL_LOCK_D();
picTxWin = new Fl_Double_Window(290, 180, _("Send image"));
picTxWin->xclass(PACKAGE_NAME);
picTxWin->begin();
picTx = new picture (2, 2, 286, 150);
picTx->hide();
picTxBox = new picbox(picTxWin->x(), picTxWin->y(), picTxWin->w(), picTxWin->h(),
_("Load or drop an image file\nSupported types: PNG, JPEG, BMP"));
picTxBox->labelfont(FL_HELVETICA_ITALIC);
btnpicTxSPP = new Fl_Button(5, 180 - 30, 40, 24, "X1");
btnpicTxSPP->tooltip(_("Transfer speed, X1-normal"));
btnpicTxSPP->callback( cb_picTxSPP, 0);
btnpicTxSendColor = new Fl_Button(45, 180 - 30, 60, 24, "XmtClr");
btnpicTxSendColor->callback(cb_picTxSendColor, 0);
btnpicTxSendGrey = new Fl_Button(105, 180 - 30, 60, 24, "XmtGry");
btnpicTxSendGrey->callback( cb_picTxSendGrey, 0);
btnpicTxSendAbort = new Fl_Button(84, 180 - 30, 122, 24, "Abort Xmt");
btnpicTxSendAbort->callback(cb_picTxSendAbort, 0);
btnpicTxLoad = new Fl_Button(165, 180 - 30, 60, 24, _("Load"));
btnpicTxLoad->callback(cb_picTxLoad, 0);
btnpicTxClose = new Fl_Button(225, 180 - 30, 60, 24, _("Close"));
btnpicTxClose->callback(cb_picTxClose, 0);
btnpicTxSendAbort->hide();
btnpicTxSendColor->deactivate();
btnpicTxSendGrey->deactivate();
picTxWin->end();
FL_UNLOCK_D();
}
void TxViewerResize(int W, int H)
{
int winW, winH;
int picX, picY;
winW = W < 288 ? 290 : W + 4;
winH = H < 180 ? 180 : H + 30;
picX = (winW - W) / 2;
picY = (winH - 30 - H)/2;
FL_LOCK_D();
picTxWin->size(winW, winH);
picTx->resize(picX, picY, W, H);
picTx->clear();
picTxBox->size(winW, winH);
btnpicTxSPP->resize(winW/2 - 140, winH - 28, 40, 24);
btnpicTxSendColor->resize(winW/2 - 100, winH - 28, 60, 24);
btnpicTxSendGrey->resize(winW/2 - 40, winH - 28, 60, 24);
btnpicTxSendAbort->resize(winW/2 - 61, winH - 28, 122, 24);
btnpicTxLoad->resize(winW/2 + 20, winH - 28, 60, 24);
btnpicTxClose->resize(winW/2 + 80, winH - 28, 60, 24);
FL_UNLOCK_D();
}
void showTxViewer(int W, int H)
{
if (picTxWin) {
picTxWin->show();
return;
}
int winW, winH;
int picX, picY;
winW = W < 288 ? 290 : W + 4;
winH = H < 180 ? 180 : H + 30;
picX = (winW - W) / 2;
picY = 2;
FL_LOCK_D();
picTxWin->size(winW, winH);
picTx->resize(picX, picY, W, H);
btnpicTxSPP->resize(winW/2 - 140, winH - 28, 40, 24);
btnpicTxSendColor->resize(winW/2 - 100, winH - 28, 60, 24);
btnpicTxSendGrey->resize(winW/2 - 40, winH - 28, 60, 24);
btnpicTxSendAbort->resize(winW/2 - 61, winH - 28, 122, 24);
btnpicTxLoad->resize(winW/2 + 20, winH - 28, 60, 24);
btnpicTxClose->resize(winW/2 + 80, winH - 28, 60, 24);
btnpicTxSPP->show();
btnpicTxSendColor->show();
btnpicTxSendGrey->show();
btnpicTxLoad->show();
btnpicTxClose->show();
btnpicTxSendAbort->hide();
picTxWin->show();
FL_UNLOCK_D();
}
void deleteTxViewer()
{
picTxWin->hide();
if (picTx) delete picTx;
delete [] xmtimg;
xmtimg = 0;
delete [] xmtpicbuff;
xmtpicbuff = 0;
delete picTxWin;
picTxWin = 0;
serviceme = 0;
}
void deleteRxViewer()
{
picRxWin->hide();
if (picRx) {
delete picRx;
picRx = 0;
}
delete picRxWin;
picRxWin = 0;
serviceme = 0;
}
int print_time_left(float time_sec, char *str, size_t len,
const char *prefix, const char *suffix)
{
int time_min = (int)(time_sec / 60);
time_sec -= time_min * 60;
if (time_min)
return snprintf(str, len, "%s%02dm%2.1fs%s",
prefix, time_min, time_sec, suffix);
else
return snprintf(str, len, "%s%2.1fs%s", prefix, time_sec, suffix);
}
void setpicture_link(mfsk *me)
{
serviceme = me;
}