00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <klocale.h>
00022 #include <kmessagebox.h>
00023 #include <kfiledialog.h>
00024 #include <kaction.h>
00025 #include <kaccel.h>
00026 #include <kdebug.h>
00027 #include <ktoolbar.h>
00028 #include <kapplication.h>
00029 #include <kpixmap.h>
00030 #include <ktempfile.h>
00031 #include <kimageeffect.h>
00032 #include <kmenubar.h>
00033 #include <kprogress.h>
00034 #include <kstatusbar.h>
00035 #include <kcommand.h>
00036 #include <klineedit.h>
00037 #include <klistview.h>
00038
00039 #include <qfile.h>
00040 #include <qvbox.h>
00041 #include <qcursor.h>
00042 #include <qstringlist.h>
00043 #include <qlistview.h>
00044 #include <qradiobutton.h>
00045 #include <qclipboard.h>
00046 #include <qimage.h>
00047
00048 #include <math.h>
00049 #include <unistd.h>
00050 #include <stdlib.h>
00051 #include <netinet/in.h>
00052
00053 #include "fitsviewer.h"
00054 #include "fitsimage.h"
00055 #include "fitsprocess.h"
00056 #include "fitshistogram.h"
00057 #include "conbridlg.h"
00058 #include "statform.h"
00059 #include "imagereductiondlg.h"
00060 #include "fitsheaderdialog.h"
00061 #include "ksutils.h"
00062 #include "Options.h"
00063
00064 extern int fits_ieee32_intel;
00065 extern int fits_ieee32_motorola;
00066 extern int fits_ieee64_intel;
00067 extern int fits_ieee64_motorola;
00068
00069 #define FITS_GETBITPIX16(p,val) val = ((p[0] << 8) | (p[1]))
00070 #define FITS_GETBITPIX32(p,val) val = \
00071 ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
00072
00073 #define FITS_GETBITPIXM32(p,val) \
00074 { if (fits_ieee32_intel) {unsigned char uc[4]; \
00075 uc[0] = p[3]; uc[1] = p[2]; uc[2] = p[1]; uc[3] = p[0]; \
00076 val = *(FITS_BITPIXM32 *)uc; } \
00077 else if (fits_ieee32_motorola) { val = *(FITS_BITPIXM32 *)p; } \
00078 else if (fits_ieee64_motorola) {FITS_BITPIXM64 m64; \
00079 unsigned char *uc= (unsigned char *)&m64; \
00080 uc[0]=p[0]; uc[1]=p[1]; uc[2]=p[2]; uc[3]=p[3]; uc[4]=uc[5]=uc[6]=uc[7]=0; \
00081 val = (FITS_BITPIXM32)m64; } \
00082 else if (fits_ieee64_intel) {FITS_BITPIXM64 i64; \
00083 unsigned char *uc= (unsigned char *)&i64; \
00084 uc[0]=uc[1]=uc[2]=uc[3]=0; uc[7]=p[3]; uc[6]=p[2]; uc[5]=p[1]; uc[4]=p[0]; \
00085 val = (FITS_BITPIXM32)i64;}\
00086 }
00087
00088 #define FITS_GETBITPIXM64(p,val) \
00089 { if (fits_ieee64_intel) {unsigned char uc[8]; \
00090 uc[0] = p[7]; uc[1] = p[6]; uc[2] = p[5]; uc[3] = p[4]; \
00091 uc[4] = p[3]; uc[5] = p[2]; uc[6] = p[1]; uc[7] = p[0]; \
00092 val = *(FITS_BITPIXM64 *)uc; } else val = *(FITS_BITPIXM64 *)p; }
00093
00094 FITSViewer::FITSViewer (const KURL *url, QWidget *parent, const char *name)
00095 : KMainWindow (parent, name)
00096 {
00097 image = NULL;
00098 currentURL = *url;
00099 imgBuffer = NULL;
00100 histo = NULL;
00101 Dirty = 0;
00102
00103
00104 history = new KCommandHistory(actionCollection());
00105 history->setUndoLimit(10);
00106 history->setRedoLimit(10);
00107 history->documentSaved();
00108 connect(history, SIGNAL(documentRestored()), this, SLOT(fitsRestore()));
00109
00110
00111 image = new FITSImage(this);
00112 setCentralWidget(image);
00113
00114 statusBar()->insertItem("", 0);
00115 statusBar()->setItemFixed(0, 100);
00116 statusBar()->insertItem("", 1);
00117 statusBar()->setItemFixed(1, 100);
00118 statusBar()->insertItem("", 2);
00119 statusBar()->setItemFixed(2, 100);
00120 statusBar()->insertItem(i18n("Welcome to KStars FITS Viewer"), 3, 1, true);
00121 statusBar()->setItemAlignment(3 , Qt::AlignLeft);
00122
00123
00124 if (!initFITS())
00125 {
00126 close();
00127 return;
00128 }
00129
00130 QFile tempFile;
00131
00132 if (KSUtils::openDataFile( tempFile, "imgreduction.png" ) )
00133 {
00134 new KAction( i18n("Image Reduction"), tempFile.name(), KShortcut( "Ctrl+R" ), this, SLOT( imageReduction()), actionCollection(), "image_reduce");
00135 tempFile.close();
00136 }
00137 else
00138 new KAction( i18n("Image Reduction"), "blend", KShortcut( "Ctrl+R" ), this, SLOT( imageReduction()), actionCollection(), "image_reduce");
00139
00140
00141
00142
00143
00144
00145
00146 new KAction( i18n("Brightness/Contrast"), "contrast+", KShortcut( "Ctrl+T" ), this, SLOT( BrightContrastDlg()), actionCollection(), "image_brightness_contrast");
00147
00148 if (KSUtils::openDataFile( tempFile, "histogram.png" ) )
00149 {
00150 new KAction ( i18n("Histogram"), tempFile.name(), KShortcut("Ctrl+H"), this, SLOT (imageHistogram()), actionCollection(), "image_histogram");
00151 tempFile.close();
00152 }
00153 else
00154 new KAction ( i18n("Histogram"), "wizard", KShortcut("Ctrl+H"), this, SLOT (imageHistogram()), actionCollection(), "image_histogram");
00155
00156 KStdAction::open(this, SLOT(fileOpen()), actionCollection());
00157 KStdAction::save(this, SLOT(fileSave()), actionCollection());
00158 KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
00159 KStdAction::close(this, SLOT(slotClose()), actionCollection());
00160 KStdAction::copy(this, SLOT(fitsCOPY()), actionCollection());
00161 KStdAction::zoomIn(image, SLOT(fitsZoomIn()), actionCollection());
00162 KStdAction::zoomOut(image, SLOT(fitsZoomOut()), actionCollection());
00163 new KAction( i18n( "&Default Zoom" ), "viewmagfit.png", KShortcut( "Ctrl+D" ),
00164 image, SLOT(fitsZoomDefault()), actionCollection(), "zoom_default" );
00165 new KAction( i18n( "Statistics"), "sum", 0, this, SLOT(fitsStatistics()), actionCollection(), "image_stats");
00166 new KAction( i18n( "FITS Header"), "frame_spreadsheet.png", 0, this, SLOT(fitsHeader()), actionCollection(), "fits_editor");
00167
00168
00169 createGUI("fitsviewer.rc");
00170
00171
00172 resize(640, 480);
00173 }
00174
00175 FITSViewer::~FITSViewer()
00176 {
00177 free(imgBuffer);
00178 }
00179
00180 bool FITSViewer::initFITS()
00181 {
00182
00183 free(imgBuffer);
00184 imgBuffer = NULL;
00185 image->clearMem();
00186
00187
00188 if ( (imgBuffer = loadData (currentURL.path().ascii(), imgBuffer)) == NULL) { close(); return false; }
00189
00190 if (image->loadFits(currentURL.path().ascii()) == -1) { close(); return false; }
00191
00192
00193 history->clear();
00194
00195
00196 setCaption(currentURL.fileName());
00197
00198
00199 calculateStats();
00200
00201 image->viewport()->resize(image->viewport()->width() + 5, image->viewport()->height());
00202 image->viewportResizeEvent(NULL);
00203
00204 return true;
00205
00206 }
00207
00208 void FITSViewer::slotClose()
00209 {
00210
00211 if (Dirty)
00212 {
00213
00214 QString caption = i18n( "Save Changes to FITS?" );
00215 QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" );
00216 int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() );
00217 if ( ans == KMessageBox::Yes )
00218 fileSave();
00219 else if ( ans == KMessageBox::No )
00220 fitsRestore();
00221 }
00222
00223 if (Dirty == 0)
00224 close();
00225 }
00226
00227 void FITSViewer::closeEvent(QCloseEvent *ev)
00228 {
00229
00230 if (Dirty)
00231 {
00232
00233 QString caption = i18n( "Save Changes to FITS?" );
00234 QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" );
00235 int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() );
00236 if ( ans == KMessageBox::Yes )
00237 fileSave();
00238 else if ( ans == KMessageBox::No )
00239 fitsRestore();
00240 }
00241
00242 if (Dirty == 0)
00243 ev->accept();
00244 else
00245 ev->ignore();
00246
00247 }
00248
00249 void FITSViewer::show_fits_errors()
00250 {
00251 char *msg;
00252
00253 while ((msg = fits_get_error ()) != NULL)
00254 KMessageBox::error(0, msg);
00255 }
00256
00257 float * FITSViewer::loadData(const char *filename, float *buffer)
00258 {
00259 FILE *fp;
00260 FITS_FILE *ifp;
00261 FITS_HDU_LIST *hdulist;
00262 unsigned char *tempData, *tempDataPtr;
00263 register FITS_BITPIX16 pixval_16 =0;
00264 register FITS_BITPIX32 pixval_32 =0;
00265 register FITS_BITPIXM32 pixval_m32 =0;
00266 register FITS_BITPIXM64 pixval_m64 =0;
00267 int totalCount;
00268 int width, height, bpp, bitpix;
00269
00270 fp = fopen (filename, "rb");
00271 if (!fp)
00272 {
00273 KMessageBox::error(0, i18n("Cannot open file for reading"));
00274 return (NULL);
00275 }
00276 fclose (fp);
00277
00278 ifp = fits_open (filename, "r");
00279 if (ifp == NULL)
00280 {
00281 KMessageBox::error(0, i18n("Error during open of FITS file"));
00282 return (NULL);
00283 }
00284 if (ifp->n_pic <= 0)
00285 {
00286 KMessageBox::error(0, i18n("FITS file keeps no displayable images"));
00287 fits_close (ifp);
00288 return (NULL);
00289 }
00290
00291
00292 hdulist = fits_seek_image (ifp, 1);
00293 if (hdulist == NULL) return (NULL);
00294
00295 width = hdulist->naxisn[0];
00296 height = hdulist->naxisn[1];
00297
00298 totalCount = width * height;
00299
00300 bpp = hdulist->bpp;
00301 bitpix = hdulist->bitpix;
00302
00303 buffer = (float *) malloc (height * width * sizeof(float));
00304 tempData = (unsigned char *) malloc (height * width * bpp * sizeof(unsigned char));
00305 if (buffer == NULL || tempData == NULL)
00306 {
00307 KMessageBox::error(0, i18n("Not enough memory to load FITS."));
00308 return (NULL);
00309 }
00310 tempDataPtr = tempData;
00311
00312 if (fread(tempData, 1, width * height * bpp, ifp->fp) != (unsigned int) (width * height * bpp))
00313 {
00314 KMessageBox::error(0, i18n("Unable to read FITS data from file. %1.\n").arg(strerror(errno)));
00315 return (NULL);
00316 }
00317
00318 switch (bitpix)
00319 {
00320 case 8:
00321 for (int i=0; i < totalCount; i++)
00322 buffer[i] = tempData[i];
00323 break;
00324
00325 case 16:
00326 for (int i=0; i < totalCount ; i++)
00327 {
00328 FITS_GETBITPIX16(tempData, pixval_16);
00329 buffer[i] = pixval_16;
00330 tempData+=2;
00331 }
00332 break;
00333
00334 case 32:
00335 for (int i=0; i < totalCount ; i++)
00336 {
00337 FITS_GETBITPIX32(tempData, pixval_32);
00338
00339 if (isnan(pixval_32)) pixval_32 = 0;
00340 buffer[i] = pixval_32;
00341 tempData+=4;
00342 }
00343 break;
00344
00345 case -32:
00346 for (int i=0; i < totalCount ; i++)
00347 {
00348 if (fits_nan_32 (tempData))
00349 pixval_m32 = 0;
00350 else
00351 FITS_GETBITPIXM32(tempData, pixval_m32);
00352 buffer[i] = pixval_m32;
00353 tempData+=4;
00354 }
00355 break;
00356
00357 case -64:
00358 for (int i=0; i < totalCount ; i++)
00359 {
00360 if (fits_nan_64 (tempData))
00361 pixval_m64 = 0;
00362 else
00363 FITS_GETBITPIXM64(tempData, pixval_m64);
00364 buffer[i] = pixval_m64;
00365 tempData+=8;
00366 }
00367 break;
00368 }
00369
00370 fits_close(ifp);
00371 free(tempDataPtr);
00372 return buffer;
00373
00374 }
00375
00376 void FITSViewer::calculateStats()
00377 {
00378
00379 stats.min = min(stats.minAt);
00380 stats.max = max(stats.maxAt);
00381 stats.average = average();
00382 stats.stddev = stddev();
00383 stats.bitpix = image->bitpix;
00384 stats.width = image->width;
00385 stats.height = image->height;
00386
00387
00388
00389
00390
00391 statusBar()->changeItem( QString("%1 x %2").arg( (int) stats.width).arg( (int) stats.height), 2);
00392
00393 }
00394
00395 double FITSViewer::min(int & minIndex)
00396 {
00397 if (!imgBuffer) return -1;
00398 int width = image->currentRect.width();
00399 int height = image->currentRect.height();
00400 double lmin = imgBuffer[image->currentRect.y() * width + image->currentRect.x()];
00401 int index=0;
00402
00403 for (int i= image->currentRect.y() ; i < height; i++)
00404 for (int j= image->currentRect.x(); j < width; j++)
00405 {
00406 index = (i * width) + j;
00407 if (imgBuffer[index] < lmin)
00408 {
00409 minIndex = index;
00410 lmin = imgBuffer[index];
00411 }
00412
00413 }
00414
00415 return lmin;
00416 }
00417
00418 double FITSViewer::max(int & maxIndex)
00419 {
00420 if (!imgBuffer) return -1;
00421 int width = image->currentRect.width();
00422 int height = image->currentRect.height();
00423 double lmax = imgBuffer[image->currentRect.y() * width + image->currentRect.x()];
00424 int index=0;
00425
00426 for (int i= image->currentRect.y() ; i < height; i++)
00427 for (int j= image->currentRect.x(); j < width; j++)
00428 {
00429 index = (i * width) + j;
00430 if ( imgBuffer[index] > lmax)
00431 {
00432 maxIndex = index;
00433 lmax = imgBuffer[index];
00434 }
00435 }
00436
00437 return lmax;
00438 }
00439
00440 double FITSViewer::average()
00441 {
00442 int index=0;
00443 double sum=0;
00444 int width = image->currentRect.width();
00445 int height = image->currentRect.height();
00446 if (!imgBuffer) return -1;
00447
00448 for (int i= image->currentRect.y() ; i < height; i++)
00449 for (int j= image->currentRect.x(); j < width; j++)
00450 {
00451 index = (i * width) + j;
00452 sum += imgBuffer[index];
00453 }
00454
00455 return (sum / (width * height ));
00456 }
00457
00458 double FITSViewer::stddev()
00459 {
00460 int index=0;
00461 double lsum=0;
00462 int width = image->currentRect.width();
00463 int height = image->currentRect.height();
00464 if (!imgBuffer) return -1;
00465
00466 for (int i= image->currentRect.y() ; i < height; i++)
00467 for (int j= image->currentRect.x(); j < width; j++)
00468 {
00469 index = (i * width) + j;
00470 lsum += (imgBuffer[index] - stats.average) * (imgBuffer[index] - stats.average);
00471 }
00472
00473 return (sqrt(lsum/(width * height - 1)));
00474
00475 }
00476
00477 void FITSViewer::keyPressEvent (QKeyEvent *ev)
00478 {
00479
00480
00481 ev->accept();
00482 switch (ev->key())
00483 {
00484
00485
00486
00487
00488 default : ev->ignore();
00489 }
00490
00491 }
00492
00493 void FITSViewer::fileOpen()
00494 {
00495
00496 if (Dirty)
00497 {
00498
00499 QString caption = i18n( "Save Changes to FITS?" );
00500 QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" );
00501 int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() );
00502 if ( ans == KMessageBox::Yes )
00503 fileSave();
00504 else if ( ans == KMessageBox::No )
00505 fitsRestore();
00506 }
00507
00508 KURL fileURL = KFileDialog::getOpenURL( QDir::homeDirPath(), "*.fits *.fit *.fts|Flexible Image Transport System");
00509
00510 if (fileURL.isEmpty())
00511 return;
00512
00513
00514 currentURL = fileURL;
00515
00516 initFITS();
00517
00518 }
00519
00520 void FITSViewer::fileSave()
00521 {
00522
00523 FITS_FILE *ifp;
00524 QString recordList;
00525 KURL backupCurrent = currentURL;
00526 QString bitpixRec;
00527 FITS_BITPIX16 pixval_16 =0;
00528 FITS_BITPIX32 pixval_32 =0;
00529 FITS_BITPIXM32 pixval_m32 =0;
00530 FITS_BITPIXM64 pixval_m64 =0;
00531 unsigned char *transData;
00532 int index=0, i=0, transCount = 0, totalCount= image->width * image->height;
00533
00534 QString currentDir = Options::fitsSaveDirectory();
00535
00536
00537
00538
00539
00540 if (Dirty == 0 && !currentURL.isEmpty())
00541 return;
00542
00543 if (currentURL.isEmpty())
00544 {
00545 currentURL = KFileDialog::getSaveURL( currentDir, "*.fits |Flexible Image Transport System");
00546
00547 if (currentURL.isEmpty())
00548 {
00549 currentURL = backupCurrent;
00550 return;
00551 }
00552 if (currentURL.path().contains('.') == 0) currentURL.setPath(currentURL.path() + ".fits");
00553
00554 if (QFile::exists(currentURL.path()))
00555 {
00556 int r=KMessageBox::warningContinueCancel(static_cast<QWidget *>(parent()),
00557 i18n( "A file named \"%1\" already exists. "
00558 "Overwrite it?" ).arg(currentURL.fileName()),
00559 i18n( "Overwrite File?" ),
00560 i18n( "&Overwrite" ) );
00561
00562 if(r==KMessageBox::Cancel) return;
00563 }
00564 }
00565
00566 if ( currentURL.isValid() )
00567 {
00568 transData = (unsigned char *) malloc (sizeof(unsigned char) * totalCount * image->bpp);
00569 if (transData == NULL)
00570 {
00571 KMessageBox::error(0, i18n("Error: Low memory. Saving is aborted."));
00572 return;
00573 }
00574
00575 ifp = fits_open (currentURL.path().ascii(), "w");
00576 if (ifp == NULL)
00577 {
00578 KMessageBox::error(0, i18n("Error during open of FITS file."));
00579 return;
00580 }
00581
00582 setbuf(ifp->fp, NULL);
00583
00584 bitpixRec.sprintf("BITPIX = %d /Modified by KStars ", image->bitpix);
00585 bitpixRec.truncate(80);
00586
00587 for (unsigned int j=0; j < record.count(); j++)
00588 {
00589 recordList = record[j];
00590
00591 if ( (index = recordList.find("BITPIX")) != -1)
00592 recordList.replace(index, FITS_CARD_SIZE, bitpixRec);
00593
00594 fwrite(recordList.ascii(), 1, FITS_RECORD_SIZE, ifp->fp);
00595 }
00596
00597 switch (image->bitpix)
00598 {
00599 case 8:
00600 for (i= image->height - 1; i >= 0; i--)
00601 fwrite(image->displayImage->scanLine(i), 1, image->width, ifp->fp);
00602 break;
00603
00604
00605 case 16:
00606 for (i= 0, transCount = 0 ; i < totalCount ; i++, transCount += 2)
00607 {
00608 pixval_16 = (unsigned short) imgBuffer[i];
00609 transData[transCount] = ((unsigned char*) &pixval_16)[1];
00610 transData[transCount+1] = ((unsigned char*) &pixval_16)[0];
00611 }
00612
00613 transCount = 0;
00614 totalCount *= 2;
00615
00616 for (i=0, transCount = 0; i < totalCount; i += transCount)
00617 transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp);
00618
00619 break;
00620
00621 case 32:
00622 for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 4)
00623 {
00624 pixval_32 = (unsigned int) imgBuffer[i];
00625 transData[transCount] = ((unsigned char*) &pixval_32)[3];
00626 transData[transCount+1] = ((unsigned char*) &pixval_32)[2];
00627 transData[transCount+2] = ((unsigned char*) &pixval_32)[1];
00628 transData[transCount+3] = ((unsigned char*) &pixval_32)[0];
00629 }
00630
00631
00632 transCount = 0;
00633 totalCount *= 4;
00634
00635 for (i=0, transCount = 0; i < totalCount; i += transCount)
00636 transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp);
00637 break;
00638
00639 case -32:
00640 for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 4)
00641 {
00642 pixval_m32 = imgBuffer[i];
00643 transData[transCount] = ((unsigned char*) &pixval_m32)[3];
00644 transData[transCount+1] = ((unsigned char*) &pixval_m32)[2];
00645 transData[transCount+2] = ((unsigned char*) &pixval_m32)[1];
00646 transData[transCount+3] = ((unsigned char*) &pixval_m32)[0];
00647
00648 }
00649
00650
00651 transCount = 0;
00652 totalCount *= 4;
00653
00654 for (i=0, transCount = 0; i < totalCount; i += transCount)
00655 transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp);
00656
00657 break;
00658
00659 case -64:
00660 for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 8)
00661 {
00662 pixval_m64 = imgBuffer[i];
00663 transData[transCount] = 0;
00664 transData[transCount+1] = 0;
00665 transData[transCount+2] = 0;
00666 transData[transCount+3] = 0;
00667 transData[transCount+4] = ((unsigned char*) &pixval_m32)[3];
00668 transData[transCount+5] = ((unsigned char*) &pixval_m32)[2];
00669 transData[transCount+6] = ((unsigned char*) &pixval_m32)[1];
00670 transData[transCount+7] = ((unsigned char*) &pixval_m32)[0];
00671
00672 }
00673
00674
00675 transCount = 0;
00676 totalCount *= 8;
00677
00678 for (i=0, transCount = 0; i < totalCount; i += transCount)
00679 transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp);
00680 break;
00681 }
00682
00683 fits_close(ifp);
00684
00685 statusBar()->changeItem(i18n("File saved."), 3);
00686
00687 free(transData);
00688 Dirty = 0;
00689 history->clear();
00690 fitsRestore();
00691
00692 }
00693 else
00694 {
00695 QString message = i18n( "Invalid URL: %1" ).arg( currentURL.url() );
00696 KMessageBox::sorry( 0, message, i18n( "Invalid URL" ) );
00697 }
00698
00699
00700 }
00701
00702 void FITSViewer::fileSaveAs()
00703 {
00704
00705 currentURL = "";
00706 fileSave();
00707 }
00708
00709 void FITSViewer::fitsCOPY()
00710 {
00711 kapp->clipboard()->setImage(*image->displayImage);
00712 }
00713
00714 void FITSViewer::updateImgBuffer()
00715 {
00716 int width = image->width;
00717 int height = image->height;
00718
00719 for (int i=0; i < height; i++)
00720 for (int j=0; j < width; j++)
00721 imgBuffer[i * width + j] = (int) *(image->displayImage->scanLine(height - i - 1) + j);
00722
00723
00724 calculateStats();
00725 }
00726
00727 void FITSViewer::imageReduction()
00728 {
00729 FITSProcessCommand *cbc;
00730 FITSHistogramCommand *hbc;
00731 QStringList darkFiles, flatFiles, darkflatFiles;
00732 int darkCombineMode = 0 , flatCombineMode = 0, darkflatCombineMode =0;
00733 QListViewItem *file;
00734
00735 image->saveTemplateImage();
00736 ImageReductionDlg irDialog(this);
00737
00738 if (irDialog.exec() == QDialog::Accepted)
00739 {
00740 if (irDialog.darkListView->childCount() == 0 &&
00741 irDialog.flatListView->childCount() == 0)
00742 {
00743 image->destroyTemplateImage();
00744 return;
00745 }
00746
00747 darkCombineMode = irDialog.darkAverageB->isChecked() ? 0 : 1;
00748 flatCombineMode = irDialog.flatAverageB->isChecked() ? 0 : 1;
00749 darkflatCombineMode= irDialog.darkflatAverageB->isChecked() ? 0 : 1;
00750
00751 file = irDialog.darkListView->firstChild();
00752 while (file)
00753 {
00754 darkFiles << file->text(0);
00755 file = file->nextSibling();
00756 }
00757
00758 file = irDialog.flatListView->firstChild();
00759 while (file)
00760 {
00761 flatFiles << file->text(0);
00762 file = file->nextSibling();
00763 }
00764
00765 file = irDialog.darkflatListView->firstChild();
00766 while (file)
00767 {
00768 darkflatFiles << file->text(0);
00769 file = file->nextSibling();
00770 }
00771
00772 cbc = new FITSProcessCommand(this);
00773 FITSProcess reduc(this, darkFiles, flatFiles, darkflatFiles, darkCombineMode, flatCombineMode, darkflatCombineMode);
00774 reduc.reduce();
00775 history->addCommand(cbc, false);
00776 calculateStats();
00777 hbc = new FITSHistogramCommand(this, NULL, FITSImage::FITSLinear, (int) stats.min, (int) stats.max);
00778 history->addCommand(hbc);
00779 fitsChange();
00780 }
00781
00782 image->destroyTemplateImage();
00783
00784 }
00785
00786 void FITSViewer::BrightContrastDlg()
00787 {
00788 FITSChangeCommand *cbc;
00789 image->saveTemplateImage();
00790 ContrastBrightnessDlg conbriDlg(this);
00791
00792 if (conbriDlg.exec() == QDialog::Rejected)
00793 {
00794 image->reLoadTemplateImage();
00795 image->zoomToCurrent();
00796 }
00797 else
00798 {
00799 memcpy(imgBuffer , conbriDlg.localImgBuffer, stats.width * stats.height * 4);
00800 free(conbriDlg.localImgBuffer);
00801 fitsChange();
00802 image->update();
00803 cbc = new FITSChangeCommand(this, CONTRAST_BRIGHTNESS, image->displayImage, image->templateImage);
00804 history->addCommand(cbc, false);
00805
00806 }
00807
00808 image->destroyTemplateImage();
00809
00810 }
00811
00812 void FITSViewer::imageHistogram()
00813 {
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826 if (histo == NULL)
00827 {
00828 histo = new FITSHistogram(this);
00829 histo->show();
00830 }
00831 else
00832 {
00833 histo->constructHistogram(imgBuffer);
00834 histo->updateBoxes();
00835 histo->show();
00836 }
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 }
00861
00862 void FITSViewer::fitsRestore()
00863 {
00864
00865 Dirty = 0;
00866 setCaption(currentURL.fileName());
00867 }
00868
00869 void FITSViewer::fitsChange()
00870 {
00871
00872 Dirty = 1;
00873
00874 setCaption(currentURL.fileName() + i18n(" [modified]"));
00875 }
00876
00877 void FITSViewer::fitsStatistics()
00878 {
00879 statForm stat(this);
00880
00881 calculateStats();
00882
00883 stat.widthOUT->setText(QString("%1").arg(stats.width));
00884 stat.heightOUT->setText(QString("%1").arg(stats.height));
00885 stat.bitpixOUT->setText(QString("%1").arg(stats.bitpix));
00886 stat.maxOUT->setText(QString("%1").arg(stats.max));
00887 stat.minOUT->setText(QString("%1").arg(stats.min));
00888 stat.atMaxOUT->setText(QString("%1").arg(stats.maxAt));
00889 stat.atMinOUT->setText(QString("%1").arg(stats.minAt));
00890 stat.meanOUT->setText(QString("%1").arg(stats.average));
00891 stat.stddevOUT->setText(QString("%1").arg(stats.stddev));
00892
00893 stat.exec();
00894
00895 }
00896
00897 void FITSViewer::fitsHeader()
00898 {
00899 QStringList cards;
00900 QString recordList;
00901 QString property;
00902 int equal, slash;
00903
00904 fitsHeaderDialog header(this);
00905 header.headerView->setSorting(-1);
00906 header.headerView->setColumnAlignment(1, Qt::AlignHCenter);
00907
00908 for (unsigned int i=0; i < record.count(); i++)
00909 {
00910 recordList = record[i];
00911
00912
00913 for (int j=0; j < FITS_RECORD_SIZE / FITS_CARD_SIZE; j++)
00914 {
00915 property = recordList.left(FITS_CARD_SIZE);
00916
00917 equal = property.find('=');
00918
00919 if (equal == -1)
00920 {
00921 if (property.contains(" ") != FITS_CARD_SIZE)
00922 cards << property << "" << "";
00923 recordList.remove(0, FITS_CARD_SIZE);
00924 if (property.find("END") != -1)
00925 break;
00926 else
00927 continue;
00928 }
00929
00930
00931 cards << property.left(equal);
00932 slash = property.find("'");
00933 if (slash != -1)
00934 slash = property.find("'", slash + 1) + 1;
00935 else
00936 slash = property.find('/') - 1;
00937
00938 cards << property.mid(equal + 2, slash - (equal + 2)).simplifyWhiteSpace().remove("'");
00939 cards << property.mid(slash + 1, FITS_CARD_SIZE - (slash + 1)).simplifyWhiteSpace();
00940 recordList.remove(0, FITS_CARD_SIZE);
00941
00942 }
00943
00944 }
00945
00946 for (int k= cards.count() - 3; k >=0 ; k-=3)
00947 new QListViewItem( header.headerView, cards[k], cards[k+1], cards[k+2]);
00948
00949
00950 header.exec();
00951
00952 }
00953
00954
00955 FITSChangeCommand::FITSChangeCommand(QWidget * parent, int inType, QImage* newIMG, QImage *oldIMG)
00956 {
00957 viewer = (FITSViewer *) parent;
00958 newImage = new QImage();
00959 oldImage = new QImage();
00960 *newImage = newIMG->copy();
00961 *oldImage = oldIMG->copy();
00962 type = inType;
00963 }
00964
00965 FITSChangeCommand::~FITSChangeCommand() {}
00966
00967 void FITSChangeCommand::execute()
00968 {
00969
00970 viewer->image->displayImage = newImage;
00971 viewer->image->zoomToCurrent();
00972 viewer->fitsChange();
00973
00974 }
00975
00976 void FITSChangeCommand::unexecute()
00977 {
00978
00979 viewer->image->displayImage = oldImage;
00980 viewer->image->zoomToCurrent();
00981
00982 }
00983
00984 QString FITSChangeCommand::name() const
00985 {
00986 switch (type)
00987 {
00988 case FITSViewer::CONTRAST_BRIGHTNESS:
00989 return i18n("Brightness/Contrast");
00990 break;
00991 case FITSViewer::IMAGE_REDUCTION:
00992 return i18n("Image Reduction");
00993 break;
00994 case FITSViewer::IMAGE_FILTER:
00995 return i18n("Image Filter");
00996 break;
00997 default:
00998 return i18n("unknown");
00999 break;
01000 }
01001 }
01002
01003
01004
01005 #include "fitsviewer.moc"