Add loading sub images
This commit is contained in:
@@ -76,6 +76,8 @@ struct ImageInfoData
|
||||
QVector<QPair<QString, QString>> info;
|
||||
std::shared_ptr<WCSDataT> wcs;
|
||||
SkyPointScale getCenterRaDec() const;
|
||||
int index = 0;
|
||||
int num = 1;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
|
||||
+43
-12
@@ -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_WIDTH<m_images.size()/2 ? DEFAULT_WIDTH : m_images.size()/2;
|
||||
if(m_liveMode)
|
||||
@@ -312,9 +343,9 @@ void ImageRingList::loadFile(int row)
|
||||
for(int i=0; i<m_width; 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(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)
|
||||
|
||||
+3
-1
@@ -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());
|
||||
|
||||
+40
-13
@@ -83,11 +83,10 @@ int loadFITSHeader(fitsfile *file, ImageInfoData &info)
|
||||
return status;
|
||||
}
|
||||
|
||||
bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr<RawImage> &image, bool planar)
|
||||
bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr<RawImage> &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<RawImage>
|
||||
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<int> 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<RawImage>
|
||||
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<RawImage>
|
||||
for(size_t i=0; i<size; i++)
|
||||
s[i] -= INT16_MIN;
|
||||
}
|
||||
else if(fitstype == TINT)
|
||||
{
|
||||
uint32_t *s = static_cast<uint32_t*>(img.data());
|
||||
size_t size = img.size() * img.channels();
|
||||
for(size_t i=0; i<size; i++)
|
||||
s[i] -= INT32_MIN;
|
||||
}
|
||||
|
||||
if(img.channels() == 1 || planar)
|
||||
image = std::make_shared<RawImage>(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<RawImage> &image, bool planar)
|
||||
bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &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<RawImage
|
||||
info.fitsHeader.append(prop);
|
||||
}
|
||||
|
||||
info.num = xisf.imagesCount();
|
||||
info.index = index + 1;
|
||||
info.wcs = std::make_shared<WCSDataT>(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<RawImage>
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &rawImage, bool planar)
|
||||
bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &rawImage, int index, bool planar)
|
||||
{
|
||||
bool ret = false;
|
||||
QElapsedTimer timer;
|
||||
@@ -390,12 +417,12 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
|
||||
}
|
||||
else if(path.endsWith(".FIT", Qt::CaseInsensitive) || path.endsWith(".FITS", Qt::CaseInsensitive) || path.endsWith(".FZ", Qt::CaseInsensitive) || path.endsWith(".FTS", Qt::CaseInsensitive))
|
||||
{
|
||||
ret = loadFITS(path, info, rawImage, planar);
|
||||
ret = loadFITS(path, info, rawImage, planar, index);
|
||||
qDebug() << "LoadFITS" << timer.elapsed();
|
||||
}
|
||||
else if(path.endsWith(".XISF", Qt::CaseInsensitive))
|
||||
{
|
||||
ret = loadXISF(path, info, rawImage, planar);
|
||||
ret = loadXISF(path, info, rawImage, planar, index);
|
||||
qDebug() << "LoadXISF" << timer.elapsed();
|
||||
}
|
||||
else
|
||||
|
||||
+1
-1
@@ -9,6 +9,6 @@ class RawImage;
|
||||
QString makeUNCPath(const QString &path);
|
||||
bool readFITSHeader(const QString &path, ImageInfoData &info);
|
||||
bool readXISFHeader(const QString &path, ImageInfoData &info);
|
||||
bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &rawImage, bool planar = false);
|
||||
bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &rawImage, int index, bool planar = false);
|
||||
|
||||
#endif // LOADIMAGE_H
|
||||
|
||||
+5
-4
@@ -10,11 +10,12 @@
|
||||
#include "loadimage.h"
|
||||
#include <lcms2.h>
|
||||
|
||||
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> 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> rawimage;
|
||||
loadImage(m_infile, imageinfo, rawimage);
|
||||
loadImage(m_infile, imageinfo, rawimage, 0);
|
||||
QFileInfo info(m_outfile);
|
||||
info.dir().mkpath(".");
|
||||
|
||||
|
||||
+2
-1
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
+17
-1
@@ -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<void (MainWindow::*)()>(&MainWindow::loadFile));
|
||||
connect(m_filesystem, &FilesystemWidget::fileSelected, this, static_cast<void (MainWindow::*)(int)>(&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<void (ImageRingList::*)()>(&ImageRingList::decrement));
|
||||
connect(nextAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::increment));
|
||||
connect(prevSubAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::prevSubImage));
|
||||
connect(nextSubAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&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);
|
||||
|
||||
+1
-1
@@ -737,7 +737,7 @@ QJSValue File::stats()
|
||||
{
|
||||
ImageInfoData info;
|
||||
std::shared_ptr<RawImage> rawImage;
|
||||
loadImage(_path, info, rawImage);
|
||||
loadImage(_path, info, rawImage, 0);
|
||||
rawImage->calcStats();
|
||||
RawImage::Stats stats = rawImage->imageStats();
|
||||
_stats = _engine->newObject();
|
||||
|
||||
@@ -7,7 +7,7 @@ int generateThumbnail(const QString &input, const QString &output, uint32_t size
|
||||
{
|
||||
ImageInfoData info;
|
||||
std::shared_ptr<RawImage> rawImage;
|
||||
if(!loadImage(input, info, rawImage))
|
||||
if(!loadImage(input, info, rawImage, 0))
|
||||
return 2;
|
||||
|
||||
if(!rawImage)
|
||||
|
||||
Reference in New Issue
Block a user