diff options
Diffstat (limited to 'kstars/kstars/fitsviewer.cpp')
-rw-r--r-- | kstars/kstars/fitsviewer.cpp | 1005 |
1 files changed, 1005 insertions, 0 deletions
diff --git a/kstars/kstars/fitsviewer.cpp b/kstars/kstars/fitsviewer.cpp new file mode 100644 index 00000000..e7bd0cb9 --- /dev/null +++ b/kstars/kstars/fitsviewer.cpp @@ -0,0 +1,1005 @@ +/*************************************************************************** + FITSViewer.cpp - A FITSViewer for KStars + ------------------- + begin : Thu Jan 22 2004 + copyright : (C) 2004 by Jasem Mutlaq + email : mutlaqja@ikarustech.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program 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. * + * * + * Some code fragments were adapted from Peter Kirchgessner's FITS plugin* + * See http://members.aol.com/pkirchg for more details. * + ***************************************************************************/ + + +#include <klocale.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kaction.h> +#include <kaccel.h> +#include <kdebug.h> +#include <ktoolbar.h> +#include <kapplication.h> +#include <kpixmap.h> +#include <ktempfile.h> +#include <kimageeffect.h> +#include <kmenubar.h> +#include <kprogress.h> +#include <kstatusbar.h> +#include <kcommand.h> +#include <klineedit.h> +#include <klistview.h> + +#include <qfile.h> +#include <qvbox.h> +#include <qcursor.h> +#include <qstringlist.h> +#include <qlistview.h> +#include <qradiobutton.h> +#include <qclipboard.h> +#include <qimage.h> + +#include <math.h> +#include <unistd.h> +#include <stdlib.h> +#include <netinet/in.h> + +#include "fitsviewer.h" +#include "fitsimage.h" +#include "fitsprocess.h" +#include "fitshistogram.h" +#include "conbridlg.h" +#include "statform.h" +#include "imagereductiondlg.h" +#include "fitsheaderdialog.h" +#include "ksutils.h" +#include "Options.h" + +extern int fits_ieee32_intel; +extern int fits_ieee32_motorola; +extern int fits_ieee64_intel; +extern int fits_ieee64_motorola; + +#define FITS_GETBITPIX16(p,val) val = ((p[0] << 8) | (p[1])) +#define FITS_GETBITPIX32(p,val) val = \ + ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + +#define FITS_GETBITPIXM32(p,val) \ + { if (fits_ieee32_intel) {unsigned char uc[4]; \ + uc[0] = p[3]; uc[1] = p[2]; uc[2] = p[1]; uc[3] = p[0]; \ + val = *(FITS_BITPIXM32 *)uc; } \ + else if (fits_ieee32_motorola) { val = *(FITS_BITPIXM32 *)p; } \ + else if (fits_ieee64_motorola) {FITS_BITPIXM64 m64; \ + unsigned char *uc= (unsigned char *)&m64; \ + 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; \ + val = (FITS_BITPIXM32)m64; } \ + else if (fits_ieee64_intel) {FITS_BITPIXM64 i64; \ + unsigned char *uc= (unsigned char *)&i64; \ + 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]; \ + val = (FITS_BITPIXM32)i64;}\ +} + +#define FITS_GETBITPIXM64(p,val) \ + { if (fits_ieee64_intel) {unsigned char uc[8]; \ + uc[0] = p[7]; uc[1] = p[6]; uc[2] = p[5]; uc[3] = p[4]; \ + uc[4] = p[3]; uc[5] = p[2]; uc[6] = p[1]; uc[7] = p[0]; \ + val = *(FITS_BITPIXM64 *)uc; } else val = *(FITS_BITPIXM64 *)p; } + +FITSViewer::FITSViewer (const KURL *url, QWidget *parent, const char *name) + : KMainWindow (parent, name) +{ + image = NULL; + currentURL = *url; + imgBuffer = NULL; + histo = NULL; + Dirty = 0; + + /* Initiliaze menu actions */ + history = new KCommandHistory(actionCollection()); + history->setUndoLimit(10); + history->setRedoLimit(10); + history->documentSaved(); + connect(history, SIGNAL(documentRestored()), this, SLOT(fitsRestore())); + + /* Setup image widget */ + image = new FITSImage(this); + setCentralWidget(image); + + statusBar()->insertItem("", 0); + statusBar()->setItemFixed(0, 100); + statusBar()->insertItem("", 1); + statusBar()->setItemFixed(1, 100); + statusBar()->insertItem("", 2); + statusBar()->setItemFixed(2, 100); + statusBar()->insertItem(i18n("Welcome to KStars FITS Viewer"), 3, 1, true); + statusBar()->setItemAlignment(3 , Qt::AlignLeft); + + /* FITS initializations */ + if (!initFITS()) + { + close(); + return; + } + + QFile tempFile; + + if (KSUtils::openDataFile( tempFile, "imgreduction.png" ) ) + { + new KAction( i18n("Image Reduction"), tempFile.name(), KShortcut( "Ctrl+R" ), this, SLOT( imageReduction()), actionCollection(), "image_reduce"); + tempFile.close(); + } + else + new KAction( i18n("Image Reduction"), "blend", KShortcut( "Ctrl+R" ), this, SLOT( imageReduction()), actionCollection(), "image_reduce"); + + /*if (KSUtils::openDataFile( tempFile, "bricon.png" ) ) + { + new KAction( i18n("Brightness/Contrast"), tempFile.name(), KShortcut( "Ctrl+T" ), this, SLOT( BrightContrastDlg()), actionCollection(), "image_brightness_contrast"); + tempFile.close(); + } + else*/ + new KAction( i18n("Brightness/Contrast"), "contrast+", KShortcut( "Ctrl+T" ), this, SLOT( BrightContrastDlg()), actionCollection(), "image_brightness_contrast"); + + if (KSUtils::openDataFile( tempFile, "histogram.png" ) ) + { + new KAction ( i18n("Histogram"), tempFile.name(), KShortcut("Ctrl+H"), this, SLOT (imageHistogram()), actionCollection(), "image_histogram"); + tempFile.close(); + } + else + new KAction ( i18n("Histogram"), "wizard", KShortcut("Ctrl+H"), this, SLOT (imageHistogram()), actionCollection(), "image_histogram"); + + KStdAction::open(this, SLOT(fileOpen()), actionCollection()); + KStdAction::save(this, SLOT(fileSave()), actionCollection()); + KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection()); + KStdAction::close(this, SLOT(slotClose()), actionCollection()); + KStdAction::copy(this, SLOT(fitsCOPY()), actionCollection()); + KStdAction::zoomIn(image, SLOT(fitsZoomIn()), actionCollection()); + KStdAction::zoomOut(image, SLOT(fitsZoomOut()), actionCollection()); + new KAction( i18n( "&Default Zoom" ), "viewmagfit.png", KShortcut( "Ctrl+D" ), + image, SLOT(fitsZoomDefault()), actionCollection(), "zoom_default" ); + new KAction( i18n( "Statistics"), "sum", 0, this, SLOT(fitsStatistics()), actionCollection(), "image_stats"); + new KAction( i18n( "FITS Header"), "frame_spreadsheet.png", 0, this, SLOT(fitsHeader()), actionCollection(), "fits_editor"); + + /* Create GUI */ + createGUI("fitsviewer.rc"); + + /* initially resize in accord with KDE rules */ + resize(640, 480); +} + +FITSViewer::~FITSViewer() +{ + free(imgBuffer); +} + +bool FITSViewer::initFITS() +{ + + free(imgBuffer); + imgBuffer = NULL; + image->clearMem(); + + /* Load image into buffer */ + if ( (imgBuffer = loadData (currentURL.path().ascii(), imgBuffer)) == NULL) { close(); return false; } + /* Display image in the central widget */ + if (image->loadFits(currentURL.path().ascii()) == -1) { close(); return false; } + + /* Clear history */ + history->clear(); + + /* Set new file caption */ + setCaption(currentURL.fileName()); + + /* Get initial statistics */ + calculateStats(); + + image->viewport()->resize(image->viewport()->width() + 5, image->viewport()->height()); + image->viewportResizeEvent(NULL); + + return true; + +} + +void FITSViewer::slotClose() +{ + + if (Dirty) + { + + QString caption = i18n( "Save Changes to FITS?" ); + QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" ); + int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( ans == KMessageBox::Yes ) + fileSave(); + else if ( ans == KMessageBox::No ) + fitsRestore(); + } + + if (Dirty == 0) + close(); +} + +void FITSViewer::closeEvent(QCloseEvent *ev) +{ + + if (Dirty) + { + + QString caption = i18n( "Save Changes to FITS?" ); + QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" ); + int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( ans == KMessageBox::Yes ) + fileSave(); + else if ( ans == KMessageBox::No ) + fitsRestore(); + } + + if (Dirty == 0) + ev->accept(); + else + ev->ignore(); + +} + +void FITSViewer::show_fits_errors() +{ + char *msg; + /* Write out error messages of FITS-Library */ + while ((msg = fits_get_error ()) != NULL) + KMessageBox::error(0, msg); +} + +float * FITSViewer::loadData(const char *filename, float *buffer) +{ + FILE *fp; + FITS_FILE *ifp; + FITS_HDU_LIST *hdulist; + unsigned char *tempData, *tempDataPtr; + register FITS_BITPIX16 pixval_16 =0; + register FITS_BITPIX32 pixval_32 =0; + register FITS_BITPIXM32 pixval_m32 =0; + register FITS_BITPIXM64 pixval_m64 =0; + int totalCount; + int width, height, bpp, bitpix; + + fp = fopen (filename, "rb"); + if (!fp) + { + KMessageBox::error(0, i18n("Cannot open file for reading")); + return (NULL); + } + fclose (fp); + + ifp = fits_open (filename, "r"); + if (ifp == NULL) + { + KMessageBox::error(0, i18n("Error during open of FITS file")); + return (NULL); + } + if (ifp->n_pic <= 0) + { + KMessageBox::error(0, i18n("FITS file keeps no displayable images")); + fits_close (ifp); + return (NULL); + } + + // We only deal with 1 image in a FITS for now. + hdulist = fits_seek_image (ifp, 1); + if (hdulist == NULL) return (NULL); + + width = hdulist->naxisn[0]; + height = hdulist->naxisn[1]; + + totalCount = width * height; + + bpp = hdulist->bpp; + bitpix = hdulist->bitpix; + + buffer = (float *) malloc (height * width * sizeof(float)); + tempData = (unsigned char *) malloc (height * width * bpp * sizeof(unsigned char)); + if (buffer == NULL || tempData == NULL) + { + KMessageBox::error(0, i18n("Not enough memory to load FITS.")); + return (NULL); + } + tempDataPtr = tempData; + + if (fread(tempData, 1, width * height * bpp, ifp->fp) != (unsigned int) (width * height * bpp)) + { + KMessageBox::error(0, i18n("Unable to read FITS data from file. %1.\n").arg(strerror(errno))); + return (NULL); + } + + switch (bitpix) + { + case 8: + for (int i=0; i < totalCount; i++) + buffer[i] = tempData[i]; + break; + + case 16: + for (int i=0; i < totalCount ; i++) + { + FITS_GETBITPIX16(tempData, pixval_16); + buffer[i] = pixval_16;//ntohs(pixval_16); + tempData+=2; + } + break; + + case 32: + for (int i=0; i < totalCount ; i++) + { + FITS_GETBITPIX32(tempData, pixval_32); + //pixval_32 = ntohl(pixval_32); + if (isnan(pixval_32)) pixval_32 = 0; + buffer[i] = pixval_32; + tempData+=4; + } + break; + + case -32: + for (int i=0; i < totalCount ; i++) + { + if (fits_nan_32 (tempData)) + pixval_m32 = 0; + else + FITS_GETBITPIXM32(tempData, pixval_m32); + buffer[i] = pixval_m32; + tempData+=4; + } + break; + + case -64: + for (int i=0; i < totalCount ; i++) + { + if (fits_nan_64 (tempData)) + pixval_m64 = 0; + else + FITS_GETBITPIXM64(tempData, pixval_m64); + buffer[i] = pixval_m64; + tempData+=8; + } + break; + } + + fits_close(ifp); + free(tempDataPtr); + return buffer; + +} + +void FITSViewer::calculateStats() +{ + /*kdDebug() << "Calculating statistics..." << endl;*/ + stats.min = min(stats.minAt); + stats.max = max(stats.maxAt); + stats.average = average(); + stats.stddev = stddev(); + stats.bitpix = image->bitpix; + stats.width = image->width; + stats.height = image->height; + + /*kdDebug() << "Min: " << stats.min << " - Max: " << stats.max << endl; + kdDebug() << "Average: " << stats.average << " - stddev: " << stats.stddev << endl; + kdDebug() << "Width: " << stats.width << " - Height " << stats.height << " - bitpix " << stats.bitpix << endl;*/ + + statusBar()->changeItem( QString("%1 x %2").arg( (int) stats.width).arg( (int) stats.height), 2); + +} + +double FITSViewer::min(int & minIndex) +{ + if (!imgBuffer) return -1; + int width = image->currentRect.width(); + int height = image->currentRect.height(); + double lmin = imgBuffer[image->currentRect.y() * width + image->currentRect.x()]; + int index=0; + + for (int i= image->currentRect.y() ; i < height; i++) + for (int j= image->currentRect.x(); j < width; j++) + { + index = (i * width) + j; + if (imgBuffer[index] < lmin) + { + minIndex = index; + lmin = imgBuffer[index]; + } + + } + + return lmin; +} + +double FITSViewer::max(int & maxIndex) +{ + if (!imgBuffer) return -1; + int width = image->currentRect.width(); + int height = image->currentRect.height(); + double lmax = imgBuffer[image->currentRect.y() * width + image->currentRect.x()]; + int index=0; + + for (int i= image->currentRect.y() ; i < height; i++) + for (int j= image->currentRect.x(); j < width; j++) + { + index = (i * width) + j; + if ( imgBuffer[index] > lmax) + { + maxIndex = index; + lmax = imgBuffer[index]; + } + } + + return lmax; +} + +double FITSViewer::average() +{ + int index=0; + double sum=0; + int width = image->currentRect.width(); + int height = image->currentRect.height(); + if (!imgBuffer) return -1; + + for (int i= image->currentRect.y() ; i < height; i++) + for (int j= image->currentRect.x(); j < width; j++) + { + index = (i * width) + j; + sum += imgBuffer[index]; + } + + return (sum / (width * height )); +} + +double FITSViewer::stddev() +{ + int index=0; + double lsum=0; + int width = image->currentRect.width(); + int height = image->currentRect.height(); + if (!imgBuffer) return -1; + + for (int i= image->currentRect.y() ; i < height; i++) + for (int j= image->currentRect.x(); j < width; j++) + { + index = (i * width) + j; + lsum += (imgBuffer[index] - stats.average) * (imgBuffer[index] - stats.average); + } + + return (sqrt(lsum/(width * height - 1))); + +} + +void FITSViewer::keyPressEvent (QKeyEvent *ev) +{ + //QImage Tempimage = imageList.at(undo+1)->copy(); + + ev->accept(); //make sure key press events are captured. + switch (ev->key()) + { + //case Key_H : KImageEffect::contrastHSV(image); break; + //case Key_S : KImageEffect::sharpen(image); break; + //case Key_B : KImageEffect::blur(image); break; + + default : ev->ignore(); + } + +} + +void FITSViewer::fileOpen() +{ + + if (Dirty) + { + + QString caption = i18n( "Save Changes to FITS?" ); + QString message = i18n( "The current FITS file has unsaved changes. Would you like to save before closing it?" ); + int ans = KMessageBox::warningYesNoCancel( 0, message, caption, KStdGuiItem::save(), KStdGuiItem::discard() ); + if ( ans == KMessageBox::Yes ) + fileSave(); + else if ( ans == KMessageBox::No ) + fitsRestore(); + } + + KURL fileURL = KFileDialog::getOpenURL( QDir::homeDirPath(), "*.fits *.fit *.fts|Flexible Image Transport System"); + + if (fileURL.isEmpty()) + return; + + + currentURL = fileURL; + + initFITS(); + +} + +void FITSViewer::fileSave() +{ + + FITS_FILE *ifp; + QString recordList; + KURL backupCurrent = currentURL; + QString bitpixRec; + FITS_BITPIX16 pixval_16 =0; + FITS_BITPIX32 pixval_32 =0; + FITS_BITPIXM32 pixval_m32 =0; + FITS_BITPIXM64 pixval_m64 =0; + unsigned char *transData; + int index=0, i=0, transCount = 0, totalCount= image->width * image->height; + + QString currentDir = Options::fitsSaveDirectory(); + + //kdDebug() << "We doing stats BEFORE we save!! " << endl; + //calculateStats(); + + // If no changes made, return. + if (Dirty == 0 && !currentURL.isEmpty()) + return; + + if (currentURL.isEmpty()) + { + currentURL = KFileDialog::getSaveURL( currentDir, "*.fits |Flexible Image Transport System"); + // if user presses cancel + if (currentURL.isEmpty()) + { + currentURL = backupCurrent; + return; + } + if (currentURL.path().contains('.') == 0) currentURL.setPath(currentURL.path() + ".fits"); + + if (QFile::exists(currentURL.path())) + { + int r=KMessageBox::warningContinueCancel(static_cast<QWidget *>(parent()), + i18n( "A file named \"%1\" already exists. " + "Overwrite it?" ).arg(currentURL.fileName()), + i18n( "Overwrite File?" ), + i18n( "&Overwrite" ) ); + + if(r==KMessageBox::Cancel) return; + } + } + + if ( currentURL.isValid() ) + { + transData = (unsigned char *) malloc (sizeof(unsigned char) * totalCount * image->bpp); + if (transData == NULL) + { + KMessageBox::error(0, i18n("Error: Low memory. Saving is aborted.")); + return; + } + + ifp = fits_open (currentURL.path().ascii(), "w"); + if (ifp == NULL) + { + KMessageBox::error(0, i18n("Error during open of FITS file.")); + return; + } + + setbuf(ifp->fp, NULL); + + bitpixRec.sprintf("BITPIX = %d /Modified by KStars ", image->bitpix); + bitpixRec.truncate(80); + + for (unsigned int j=0; j < record.count(); j++) + { + recordList = record[j]; + + if ( (index = recordList.find("BITPIX")) != -1) + recordList.replace(index, FITS_CARD_SIZE, bitpixRec); + + fwrite(recordList.ascii(), 1, FITS_RECORD_SIZE, ifp->fp); + } + + switch (image->bitpix) + { + case 8: + for (i= image->height - 1; i >= 0; i--) + fwrite(image->displayImage->scanLine(i), 1, image->width, ifp->fp); + break; + + + case 16: + for (i= 0, transCount = 0 ; i < totalCount ; i++, transCount += 2) + { + pixval_16 = (unsigned short) imgBuffer[i]; + transData[transCount] = ((unsigned char*) &pixval_16)[1]; + transData[transCount+1] = ((unsigned char*) &pixval_16)[0]; + } + // Now we need to write all uchars to file. We have 2 bytes per pixel + transCount = 0; + totalCount *= 2; + + for (i=0, transCount = 0; i < totalCount; i += transCount) + transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp); + + break; + + case 32: + for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 4) + { + pixval_32 = (unsigned int) imgBuffer[i]; + transData[transCount] = ((unsigned char*) &pixval_32)[3]; + transData[transCount+1] = ((unsigned char*) &pixval_32)[2]; + transData[transCount+2] = ((unsigned char*) &pixval_32)[1]; + transData[transCount+3] = ((unsigned char*) &pixval_32)[0]; + } + + // Now we need to write all uchars to file. We have 4 bytes per pixel + transCount = 0; + totalCount *= 4; + + for (i=0, transCount = 0; i < totalCount; i += transCount) + transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp); + break; + + case -32: + for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 4) + { + pixval_m32 = imgBuffer[i]; + transData[transCount] = ((unsigned char*) &pixval_m32)[3]; + transData[transCount+1] = ((unsigned char*) &pixval_m32)[2]; + transData[transCount+2] = ((unsigned char*) &pixval_m32)[1]; + transData[transCount+3] = ((unsigned char*) &pixval_m32)[0]; + + } + + // Now we need to write all uchars to file. We have 4 bytes per pixel + transCount = 0; + totalCount *= 4; + + for (i=0, transCount = 0; i < totalCount; i += transCount) + transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp); + + break; + + case -64: + for (i=0, transCount = 0 ; i < totalCount ; i++, transCount += 8) + { + pixval_m64 = imgBuffer[i]; + transData[transCount] = 0; + transData[transCount+1] = 0; + transData[transCount+2] = 0; + transData[transCount+3] = 0; + transData[transCount+4] = ((unsigned char*) &pixval_m32)[3]; + transData[transCount+5] = ((unsigned char*) &pixval_m32)[2]; + transData[transCount+6] = ((unsigned char*) &pixval_m32)[1]; + transData[transCount+7] = ((unsigned char*) &pixval_m32)[0]; + + } + + // Now we need to write all uchars to file. We have 4 bytes per pixel + transCount = 0; + totalCount *= 8; + + for (i=0, transCount = 0; i < totalCount; i += transCount) + transCount = fwrite( transData + i , 1, totalCount - i, ifp->fp); + break; + } + + fits_close(ifp); + + statusBar()->changeItem(i18n("File saved."), 3); + + free(transData); + Dirty = 0; + history->clear(); + fitsRestore(); + //updateImgBuffer(); + } + else + { + QString message = i18n( "Invalid URL: %1" ).arg( currentURL.url() ); + KMessageBox::sorry( 0, message, i18n( "Invalid URL" ) ); + } + + +} + +void FITSViewer::fileSaveAs() +{ + + currentURL = ""; + fileSave(); +} + +void FITSViewer::fitsCOPY() +{ + kapp->clipboard()->setImage(*image->displayImage); +} + +void FITSViewer::updateImgBuffer() +{ + int width = image->width; + int height = image->height; + + for (int i=0; i < height; i++) + for (int j=0; j < width; j++) + imgBuffer[i * width + j] = (int) *(image->displayImage->scanLine(height - i - 1) + j); + //image->reducedImgBuffer[i * width + j]; + + calculateStats(); +} + +void FITSViewer::imageReduction() +{ + FITSProcessCommand *cbc; + FITSHistogramCommand *hbc; + QStringList darkFiles, flatFiles, darkflatFiles; + int darkCombineMode = 0 , flatCombineMode = 0, darkflatCombineMode =0; + QListViewItem *file; + + image->saveTemplateImage(); + ImageReductionDlg irDialog(this); + + if (irDialog.exec() == QDialog::Accepted) + { + if (irDialog.darkListView->childCount() == 0 && + irDialog.flatListView->childCount() == 0) + { + image->destroyTemplateImage(); + return; + } + + darkCombineMode = irDialog.darkAverageB->isChecked() ? 0 : 1; + flatCombineMode = irDialog.flatAverageB->isChecked() ? 0 : 1; + darkflatCombineMode= irDialog.darkflatAverageB->isChecked() ? 0 : 1; + + file = irDialog.darkListView->firstChild(); + while (file) + { + darkFiles << file->text(0); + file = file->nextSibling(); + } + + file = irDialog.flatListView->firstChild(); + while (file) + { + flatFiles << file->text(0); + file = file->nextSibling(); + } + + file = irDialog.darkflatListView->firstChild(); + while (file) + { + darkflatFiles << file->text(0); + file = file->nextSibling(); + } + + cbc = new FITSProcessCommand(this); + FITSProcess reduc(this, darkFiles, flatFiles, darkflatFiles, darkCombineMode, flatCombineMode, darkflatCombineMode); + reduc.reduce(); + history->addCommand(cbc, false); + calculateStats(); + hbc = new FITSHistogramCommand(this, NULL, FITSImage::FITSLinear, (int) stats.min, (int) stats.max); + history->addCommand(hbc); + fitsChange(); + } + + image->destroyTemplateImage(); + +} + +void FITSViewer::BrightContrastDlg() +{ + FITSChangeCommand *cbc; + image->saveTemplateImage(); + ContrastBrightnessDlg conbriDlg(this); + + if (conbriDlg.exec() == QDialog::Rejected) + { + image->reLoadTemplateImage(); + image->zoomToCurrent(); + } + else + { + memcpy(imgBuffer , conbriDlg.localImgBuffer, stats.width * stats.height * 4); + free(conbriDlg.localImgBuffer); + fitsChange(); + image->update(); + cbc = new FITSChangeCommand(this, CONTRAST_BRIGHTNESS, image->displayImage, image->templateImage); + history->addCommand(cbc, false); + + } + + image->destroyTemplateImage(); + +} + +void FITSViewer::imageHistogram() +{ + + /*FITSHistogramCommand *histC; + unsigned int * backupBuf = (unsigned int *) malloc (image->width * image->height * sizeof(unsigned int)); + if (backBuf == NULL) + { + KMessageBox::error(0, i18n("Not enough memory to complete the operation.")); + return; + } + memcpy(backupBuf, imgBuffer, width * height);*/ + + //image->saveTemplateImage(); + + if (histo == NULL) + { + histo = new FITSHistogram(this); + histo->show(); + } + else + { + histo->constructHistogram(imgBuffer); + histo->updateBoxes(); + histo->show(); + } + + /*if (hist.exec() == QDialog::Rejected) + { + if (hist.napply > 0) + for (int i=0; i < hist.napply; i++) + history->undo(); + else + { + image->reLoadTemplateImage(); + image->zoomToCurrent(); + } + //free (backupBuf); + } + else + { + if (hist.napply > 0) fitsChange(); + //histC = new FITSHistogramCommand(this, hist.type, backupBuf, image->displayImage, image->templateImage); + //history->addCommand(histC, false); + + } + + image->destroyTemplateImage();*/ + +} + +void FITSViewer::fitsRestore() +{ + + Dirty = 0; + setCaption(currentURL.fileName()); + } + +void FITSViewer::fitsChange() +{ + + Dirty = 1; + + setCaption(currentURL.fileName() + i18n(" [modified]")); +} + +void FITSViewer::fitsStatistics() +{ + statForm stat(this); + + calculateStats(); + + stat.widthOUT->setText(QString("%1").arg(stats.width)); + stat.heightOUT->setText(QString("%1").arg(stats.height)); + stat.bitpixOUT->setText(QString("%1").arg(stats.bitpix)); + stat.maxOUT->setText(QString("%1").arg(stats.max)); + stat.minOUT->setText(QString("%1").arg(stats.min)); + stat.atMaxOUT->setText(QString("%1").arg(stats.maxAt)); + stat.atMinOUT->setText(QString("%1").arg(stats.minAt)); + stat.meanOUT->setText(QString("%1").arg(stats.average)); + stat.stddevOUT->setText(QString("%1").arg(stats.stddev)); + + stat.exec(); + +} + +void FITSViewer::fitsHeader() +{ + QStringList cards; + QString recordList; + QString property; + int equal, slash; + + fitsHeaderDialog header(this); + header.headerView->setSorting(-1); + header.headerView->setColumnAlignment(1, Qt::AlignHCenter); + + for (unsigned int i=0; i < record.count(); i++) + { + recordList = record[i]; + //recordList = QString((char *) record); + + for (int j=0; j < FITS_RECORD_SIZE / FITS_CARD_SIZE; j++) + { + property = recordList.left(FITS_CARD_SIZE); + + equal = property.find('='); + + if (equal == -1) + { + if (property.contains(" ") != FITS_CARD_SIZE) + cards << property << "" << ""; + recordList.remove(0, FITS_CARD_SIZE); + if (property.find("END") != -1) + break; + else + continue; + } + + + cards << property.left(equal); + slash = property.find("'"); + if (slash != -1) + slash = property.find("'", slash + 1) + 1; + else + slash = property.find('/') - 1; + + cards << property.mid(equal + 2, slash - (equal + 2)).simplifyWhiteSpace().remove("'"); + cards << property.mid(slash + 1, FITS_CARD_SIZE - (slash + 1)).simplifyWhiteSpace(); + recordList.remove(0, FITS_CARD_SIZE); + + } + + } + + for (int k= cards.count() - 3; k >=0 ; k-=3) + new QListViewItem( header.headerView, cards[k], cards[k+1], cards[k+2]); + + + header.exec(); + +} + + +FITSChangeCommand::FITSChangeCommand(QWidget * parent, int inType, QImage* newIMG, QImage *oldIMG) +{ + viewer = (FITSViewer *) parent; + newImage = new QImage(); + oldImage = new QImage(); + *newImage = newIMG->copy(); + *oldImage = oldIMG->copy(); + type = inType; +} + +FITSChangeCommand::~FITSChangeCommand() {} + +void FITSChangeCommand::execute() +{ + + viewer->image->displayImage = newImage; + viewer->image->zoomToCurrent(); + viewer->fitsChange(); + +} + +void FITSChangeCommand::unexecute() +{ + + viewer->image->displayImage = oldImage; + viewer->image->zoomToCurrent(); + +} + +QString FITSChangeCommand::name() const +{ + switch (type) + { + case FITSViewer::CONTRAST_BRIGHTNESS: + return i18n("Brightness/Contrast"); + break; + case FITSViewer::IMAGE_REDUCTION: + return i18n("Image Reduction"); + break; + case FITSViewer::IMAGE_FILTER: + return i18n("Image Filter"); + break; + default: + return i18n("unknown"); + break; + } +} + + + +#include "fitsviewer.moc" |