diff --git a/imageinfodata.h b/imageinfodata.h index 99d2469..77a1759 100644 --- a/imageinfodata.h +++ b/imageinfodata.h @@ -76,6 +76,8 @@ struct ImageInfoData QVector> info; std::shared_ptr wcs; SkyPointScale getCenterRaDec() const; + int index = 0; + int num = 1; }; typedef enum diff --git a/imageringlist.cpp b/imageringlist.cpp index 0617e91..3b4c094 100644 --- a/imageringlist.cpp +++ b/imageringlist.cpp @@ -23,13 +23,16 @@ Image::Image(const QString name, int number, ImageRingList *ringList) : { } -void Image::load(QThreadPool *pool) +void Image::load(int index, QThreadPool *pool) { + if(index != m_info.index && !m_loading) + m_rawImage.reset(); + if(!m_rawImage && !m_loading) { m_loading = true; m_released = false; - pool->start(new LoadRunable(m_name, this, m_ringList->analyzeLevel())); + pool->start(new LoadRunable(m_name, this, m_ringList->analyzeLevel(), index)); } if(!m_loading && m_rawImage) emit pixmapLoaded(this); @@ -38,7 +41,7 @@ void Image::load(QThreadPool *pool) void Image::loadThumbnail(QThreadPool *pool) { if(!m_thumbnail) - pool->start(new LoadRunable(m_name, this, AnalyzeLevel::None, true)); + pool->start(new LoadRunable(m_name, this, AnalyzeLevel::None, 0, true)); else emit thumbnailLoaded(this); } @@ -230,9 +233,9 @@ void ImageRingList::increment() (*m_firstImage)->release(); m_firstImage = increment(m_firstImage); m_currImage = increment(m_currImage); - (*m_currImage)->load(m_loadPool); + (*m_currImage)->load(0, m_loadPool); m_lastImage = increment(m_lastImage); - (*m_lastImage)->load(m_loadPool); + (*m_lastImage)->load(0, m_loadPool); } } @@ -247,9 +250,37 @@ void ImageRingList::decrement() (*m_lastImage)->release(); m_firstImage = decrement(m_firstImage); m_currImage = decrement(m_currImage); - (*m_currImage)->load(m_loadPool); + (*m_currImage)->load(0, m_loadPool); m_lastImage = decrement(m_lastImage); - (*m_firstImage)->load(m_loadPool); + (*m_firstImage)->load(0, m_loadPool); + } +} + +void ImageRingList::prevSubImage() +{ + if(m_images.size()) + { + if((*m_currImage)->isLoading()) + return; + + int index = (*m_currImage)->info().index; + int num = (*m_currImage)->info().num; + if(num > 1) + (*m_currImage)->load(index == 1 ? num - 1 : index - 1, m_loadPool); + } +} + +void ImageRingList::nextSubImage() +{ + if(m_images.size()) + { + if((*m_currImage)->isLoading()) + return; + + int index = (*m_currImage)->info().index; + int num = (*m_currImage)->info().num; + if(num > 1) + (*m_currImage)->load((index + 1) % num, m_loadPool); } } @@ -303,7 +334,7 @@ void ImageRingList::loadFile(int row) if(m_images.empty()) return; - (*m_currImage)->load(m_loadPool); + (*m_currImage)->load(0, m_loadPool); m_width = DEFAULT_WIDTHload(m_loadPool); + (*m_firstImage)->load(0, m_loadPool); m_lastImage = increment(m_lastImage); - (*m_lastImage)->load(m_loadPool); + (*m_lastImage)->load(0, m_loadPool); } if(m_lastImage != m_firstImage) { @@ -438,9 +469,9 @@ void ImageRingList::setPreload(int width) for(int i = newWidth - m_width; i>0; i--) { m_firstImage = decrement(m_firstImage); - (*m_firstImage)->load(m_loadPool); + (*m_firstImage)->load(0, m_loadPool); m_lastImage = increment(m_lastImage); - (*m_lastImage)->load(m_loadPool); + (*m_lastImage)->load(0, m_loadPool); } } if(newWidth < m_width) diff --git a/imageringlist.h b/imageringlist.h index 932a215..d90d8df 100644 --- a/imageringlist.h +++ b/imageringlist.h @@ -28,7 +28,7 @@ class Image : public QObject ImageRingList *m_ringList; public: explicit Image(const QString name, int number, ImageRingList *ringList); - void load(QThreadPool *pool); + void load(int index, QThreadPool *pool); void loadThumbnail(QThreadPool *pool); void release(); QString name() const; @@ -106,6 +106,8 @@ public slots: void toggleSlideshow(bool start); void increment(); void decrement(); + void prevSubImage(); + void nextSubImage(); void setMarked(); protected: void setFilesPrivate(const QStringList files, const QString ¤tFile = QString()); diff --git a/loadimage.cpp b/loadimage.cpp index 03e265b..8beabc2 100644 --- a/loadimage.cpp +++ b/loadimage.cpp @@ -83,11 +83,10 @@ int loadFITSHeader(fitsfile *file, ImageInfoData &info) return status; } -bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr &image, bool planar) +bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr &image, bool planar, uint32_t index) { fitsfile *file; int status = 0; - int type = -1; int num = 0; long naxes[3] = {0}; @@ -105,16 +104,32 @@ bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr fits_get_num_hdus(file, &num, &status); if(status)return checkError(); + int hdutype; int imgtype; int naxis; - for(int i=1; i <= num; i++) + std::vector imageIdxs; + for(int i = 1; i <= num; i++) { - fits_movabs_hdu(file, i, IMAGE_HDU, &status);if(status)return checkError(); - fits_get_hdu_type(file, &type, &status);if(status)return checkError(); + fits_movabs_hdu(file, i, &hdutype, &status);if(status)return checkError(); + if(hdutype == IMAGE_HDU) + { + fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);if(status)return checkError(); + if(naxis >= 2 && naxis <= 3)imageIdxs.push_back(i); + } + } + info.num = imageIdxs.size(); + info.index = index; + + if(index >= imageIdxs.size())return false; + + fits_movabs_hdu(file, imageIdxs[index], &hdutype, &status);if(status)return checkError(); + if(hdutype == IMAGE_HDU) + { + naxes[0] = naxes[1] = naxes[2] = 0; fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);if(status)return checkError(); fits_get_img_equivtype(file, &imgtype, &status);if(status)return checkError(); - if(type == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0) + if(hdutype == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0) { RawImage::DataType type; int fitstype; @@ -133,6 +148,10 @@ bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr type = RawImage::UINT16; fitstype = TUSHORT; break; + case LONG_IMG: + type = RawImage::UINT32; + fitstype = TINT; + break; case ULONG_IMG: type = RawImage::UINT32; fitstype = TUINT; @@ -173,13 +192,18 @@ bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr for(size_t i=0; i(img.data()); + size_t size = img.size() * img.channels(); + for(size_t i=0; i(std::move(img)); else image = RawImage::fromPlanar(img); - - break; } } noload: @@ -202,14 +226,15 @@ noload: return true; } -bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr &image, bool planar) +bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr &image, bool planar, uint32_t index) { try { LibXISF::XISFReader xisf; xisf.open(path.toLocal8Bit().data()); - const LibXISF::Image &xisfImage = xisf.getImage(0); + if(index >= (uint32_t)xisf.imagesCount())return false; + const LibXISF::Image &xisfImage = xisf.getImage(index); auto fitskeywords = xisfImage.fitsKeywords(); for(auto fits : fitskeywords) @@ -222,6 +247,8 @@ bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr(xisfImage.width(), xisfImage.height(), info.fitsHeader); info.info.append({QObject::tr("Width"), QString::number(xisfImage.width())}); info.info.append({QObject::tr("Height"), QString::number(xisfImage.height())}); @@ -378,7 +405,7 @@ bool loadRAW(const QString path, ImageInfoData &info, std::shared_ptr return true; } -bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr &rawImage, bool planar) +bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr &rawImage, int index, bool planar) { bool ret = false; QElapsedTimer timer; @@ -390,12 +417,12 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr &rawImage, bool planar = false); +bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr &rawImage, int index, bool planar = false); #endif // LOADIMAGE_H diff --git a/loadrunable.cpp b/loadrunable.cpp index 79d41f8..728db2c 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -10,11 +10,12 @@ #include "loadimage.h" #include -LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) : +LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, int index, bool thumbnail) : m_file(makeUNCPath(file)), m_receiver(receiver), m_analyzeLevel(level), - m_thumbnail(thumbnail) + m_thumbnail(thumbnail), + m_index(index) { } @@ -32,7 +33,7 @@ void LoadRunable::run() info.info.append({QObject::tr("Filename"), finfo.fileName()}); std::shared_ptr rawImage; - if(!loadImage(m_file, info, rawImage)) + if(!loadImage(m_file, info, rawImage, m_index)) info.info.append({QObject::tr("Error"), QObject::tr("Failed to load image")}); @@ -187,7 +188,7 @@ void ConvertRunable::run() ImageInfoData imageinfo; std::shared_ptr rawimage; - loadImage(m_infile, imageinfo, rawimage); + loadImage(m_infile, imageinfo, rawimage, 0); QFileInfo info(m_outfile); info.dir().mkpath("."); diff --git a/loadrunable.h b/loadrunable.h index cf83902..ab96439 100644 --- a/loadrunable.h +++ b/loadrunable.h @@ -15,8 +15,9 @@ class LoadRunable : public QRunnable Image *m_receiver; AnalyzeLevel m_analyzeLevel; bool m_thumbnail; + int m_index = 0; public: - LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false); + LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, int index, bool thumbnail = false); void run() override; }; diff --git a/mainwindow.cpp b/mainwindow.cpp index d5a1832..ac4df1a 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -95,7 +95,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) m_ringList = new ImageRingList(m_database, nameFilter, this); m_filesystem = new FilesystemWidget(m_ringList, this); - connect(m_filesystem, &FilesystemWidget::fileSelected, this, static_cast(&MainWindow::loadFile)); + connect(m_filesystem, &FilesystemWidget::fileSelected, this, static_cast(&MainWindow::loadFile)); connect(m_filesystem, &FilesystemWidget::sortChanged, m_ringList, &ImageRingList::setSort); connect(m_filesystem, &FilesystemWidget::reverseSort, m_ringList, &ImageRingList::reverseSort); @@ -114,6 +114,19 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) _plateSolving->hide(); #endif + QToolBar *navigationToolbar = new QToolBar(tr("Navigation toolbar"), this); + navigationToolbar->setObjectName("navigationtoolbar"); + navigationToolbar->hide(); + QAction *prevAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowLeft), tr("Previous image")); + QAction *nextAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowRight), tr("Next image")); + QAction *prevSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowUp), tr("Prev sub image")); + QAction *nextSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowDown), tr("Next sub image")); + connect(prevAction, &QAction::triggered, m_ringList, static_cast(&ImageRingList::decrement)); + connect(nextAction, &QAction::triggered, m_ringList, static_cast(&ImageRingList::increment)); + connect(prevSubAction, &QAction::triggered, m_ringList, static_cast(&ImageRingList::prevSubImage)); + connect(nextSubAction, &QAction::triggered, m_ringList, static_cast(&ImageRingList::nextSubImage)); + + addToolBar(Qt::TopToolBarArea, navigationToolbar); addToolBar(Qt::TopToolBarArea, m_stretchPanel); QDockWidget *filesystemDock = new QDockWidget(tr("Filesystem"), this); @@ -282,6 +295,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) QMenu *dockMenu = new QMenu(tr("Docks"), this); dockMenu->addAction(infoDock->toggleViewAction()); dockMenu->addAction(m_stretchPanel->toggleViewAction()); + dockMenu->addAction(navigationToolbar->toggleViewAction()); dockMenu->addAction(filesystemDock->toggleViewAction()); dockMenu->addAction(databaseViewDock->toggleViewAction()); dockMenu->addAction(filetreeDock->toggleViewAction()); @@ -813,6 +827,8 @@ void MainWindow::updateWindowTitle() { QDir dir(m_ringList->currentDir()); QString title = dir.relativeFilePath(ptr->name()); + if(ptr->info().num > 1) + title += QString(" [%1/%2]").arg(ptr->info().index + 1).arg(ptr->info().num); if(m_database->isMarked(ptr->name())) title += " *"; setWindowTitle(title); diff --git a/scriptengine.cpp b/scriptengine.cpp index 4f77b0f..67d6da4 100644 --- a/scriptengine.cpp +++ b/scriptengine.cpp @@ -737,7 +737,7 @@ QJSValue File::stats() { ImageInfoData info; std::shared_ptr rawImage; - loadImage(_path, info, rawImage); + loadImage(_path, info, rawImage, 0); rawImage->calcStats(); RawImage::Stats stats = rawImage->imageStats(); _stats = _engine->newObject(); diff --git a/thumbnailer/genthumbnail.cpp b/thumbnailer/genthumbnail.cpp index 9eeeb39..ef51c7a 100644 --- a/thumbnailer/genthumbnail.cpp +++ b/thumbnailer/genthumbnail.cpp @@ -7,7 +7,7 @@ int generateThumbnail(const QString &input, const QString &output, uint32_t size { ImageInfoData info; std::shared_ptr rawImage; - if(!loadImage(input, info, rawImage)) + if(!loadImage(input, info, rawImage, 0)) return 2; if(!rawImage)