Compare commits
7 Commits
6eda2c4e48
...
20260217
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ac5a4e42a | |||
| 83d212aa91 | |||
| bd24fba407 | |||
| 3448f62f31 | |||
| 567e66acb5 | |||
| 9e79133464 | |||
| e08107aa13 |
@@ -2,7 +2,7 @@ FITS/XISF image viewer with multithreaded image loading
|
||||
|
||||
To get all dependencies install these packages
|
||||
|
||||
sudo apt install qt6-base-dev qt6-declarative-dev libqt6opengl6-dev libraw-dev libexif-dev libcfitsio-dev wcslib-dev cmake libzstd-dev libqt6sql6-sqlite
|
||||
sudo apt install qt6-base-dev qt6-declarative-dev qt6-charts-dev libqt6opengl6-dev libraw-dev libexif-dev libcfitsio-dev wcslib-dev cmake libzstd-dev libqt6sql6-sqlite
|
||||
|
||||
on OpenSUSE
|
||||
|
||||
@@ -26,6 +26,10 @@ Then to build run standard cmake sequence
|
||||
cmake --build build
|
||||
./build/tenmon
|
||||
|
||||
To install it to system run this command as root
|
||||
|
||||
cmake --install build
|
||||
|
||||
For working plate solving you must have compiled and installed StellarSolver https://github.com/rlancaste/stellarsolver
|
||||
It is important that you compile StellarSolver with Qt6. By default it use Qt5 but when linked with Qt6 program it will
|
||||
crash.
|
||||
|
||||
+1
-1
Submodule libXISF updated: 2e74d94641...7b70b6a081
@@ -47,6 +47,7 @@
|
||||
</keywords>
|
||||
<url type="homepage">https://nouspiro.space/?page_id=206</url>
|
||||
<url type="bugtracker">https://github.com/flathub/space.nouspiro.tenmon/issues</url>
|
||||
<url type="vcs-browser">https://gitea.nouspiro.space/nou/tenmon</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<caption>Main window with image</caption>
|
||||
@@ -59,6 +60,23 @@
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="20260217" date="2026-02-17">
|
||||
<description>
|
||||
<ul>
|
||||
<li>Fix potentional crash</li>
|
||||
<li>Enable sorting of FITS info</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="20251101" date="2025-11-01">
|
||||
<description>
|
||||
<ul>
|
||||
<li>Better image Save as</li>
|
||||
<li>Fix xisf file corruption when platesolving</li>
|
||||
<li>Add selecting language</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="20250915" date="2025-09-15">
|
||||
<description>
|
||||
<ul>
|
||||
|
||||
@@ -11,6 +11,8 @@ ImageInfo::ImageInfo(QWidget *parent) : QTreeWidget(parent)
|
||||
setIndentation(5);
|
||||
QSettings settings;
|
||||
header()->restoreState(settings.value("imageinfo/headerstate").toByteArray());
|
||||
setSortingEnabled(true);
|
||||
header()->setSortIndicatorClearable(true);
|
||||
}
|
||||
|
||||
ImageInfo::~ImageInfo()
|
||||
|
||||
@@ -111,7 +111,7 @@ void Image::thumbnailLoadFinish(std::shared_ptr<RawImage> rawImage)
|
||||
emit thumbnailLoaded(this);
|
||||
}
|
||||
|
||||
ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractItemModel(parent)
|
||||
ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractListModel(parent)
|
||||
, m_liveMode(false)
|
||||
, m_analyzeLevel(None)
|
||||
, m_database(database)
|
||||
@@ -412,7 +412,7 @@ void ImageRingList::clearThumbnails()
|
||||
img->clearThumbnail();
|
||||
}
|
||||
|
||||
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
|
||||
/*QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return createIndex(row, column, m_images.at(row).get());
|
||||
@@ -422,7 +422,7 @@ QModelIndex ImageRingList::parent(const QModelIndex &child) const
|
||||
{
|
||||
Q_UNUSED(child);
|
||||
return QModelIndex();
|
||||
}
|
||||
}*/
|
||||
|
||||
int ImageRingList::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
@@ -432,14 +432,16 @@ int ImageRingList::rowCount(const QModelIndex &parent) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImageRingList::columnCount(const QModelIndex &parent) const
|
||||
/*int ImageRingList::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
QVariant ImageRingList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(index.isValid() && index.row() >= 0 && index.row() < m_images.size())
|
||||
{
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
@@ -457,6 +459,8 @@ QVariant ImageRingList::data(const QModelIndex &index, int role) const
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ImageRingList::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
|
||||
+4
-4
@@ -51,7 +51,7 @@ typedef std::shared_ptr<Image> ImagePtr;
|
||||
|
||||
class Database;
|
||||
|
||||
class ImageRingList : public QAbstractItemModel
|
||||
class ImageRingList : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
int m_width;
|
||||
@@ -93,10 +93,10 @@ public:
|
||||
void updateMark();
|
||||
void clearThumbnails();
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &child) const override;
|
||||
//QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||
//QModelIndex parent(const QModelIndex &child) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
//int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
public slots:
|
||||
|
||||
+5
-1
@@ -193,7 +193,11 @@ void ConvertRunable::run()
|
||||
QFileInfo info(m_outfile);
|
||||
info.dir().mkpath(".");
|
||||
|
||||
if(m_params.autostretch)
|
||||
if(m_params.stretch)
|
||||
{
|
||||
rawimage->applySTF(m_params.mtf);
|
||||
}
|
||||
else if(m_params.autostretch)
|
||||
{
|
||||
rawimage->calcStats();
|
||||
MTFParam mtfParam = rawimage->calcMTFParams();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QSemaphore>
|
||||
#include <QSize>
|
||||
#include "imageinfodata.h"
|
||||
#include "mtfparam.h"
|
||||
|
||||
class Image;
|
||||
|
||||
@@ -33,6 +34,8 @@ public:
|
||||
QSize resize;
|
||||
Qt::AspectRatioMode aspect = Qt::KeepAspectRatio;
|
||||
bool autostretch = false;
|
||||
bool stretch = false;
|
||||
MTFParam mtf;
|
||||
ConvertParams(){}
|
||||
ConvertParams(const QVariantMap &map);
|
||||
};
|
||||
|
||||
+14
-13
@@ -620,9 +620,13 @@ void MainWindow::reindex()
|
||||
void MainWindow::saveAs()
|
||||
{
|
||||
QString selectedFilter;
|
||||
ImagePtr ptr = m_ringList->currentImage();
|
||||
if(!ptr)return;
|
||||
|
||||
QFileInfo srcFile(ptr->name());
|
||||
QString file = QFileDialog::getSaveFileName(this,
|
||||
tr("Save as"),
|
||||
_lastDir,
|
||||
_lastDir + "/" + srcFile.baseName(),
|
||||
_saveFilter,
|
||||
&selectedFilter);
|
||||
auto filterToFormat = [](const QString &file, const QString &filter) -> const QString
|
||||
@@ -644,25 +648,22 @@ void MainWindow::saveAs()
|
||||
|
||||
if(!file.isEmpty())
|
||||
{
|
||||
auto button = QMessageBox::question(this, tr("Apply stretch?"), tr("Apply current stretch function to image?"));
|
||||
|
||||
QString format = filterToFormat(file, selectedFilter);
|
||||
|
||||
if(format == "fits" || format == "xisf")
|
||||
{
|
||||
convert(file, format);
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage img = m_image->renderToImage();
|
||||
if(!img.isNull())
|
||||
img.save(file, filterToFormat(file, selectedFilter).toLatin1().data());
|
||||
}
|
||||
convert(file, format, button == QMessageBox::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::convert(const QString &outfile, const QString &format)
|
||||
void MainWindow::convert(const QString &outfile, const QString &format, bool stretch)
|
||||
{
|
||||
QString file = m_ringList->currentImage()->name();
|
||||
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile, format));
|
||||
ConvertRunable::ConvertParams param;
|
||||
param.stretch = stretch;
|
||||
param.mtf = m_stretchPanel->params();
|
||||
|
||||
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile, format, param));
|
||||
}
|
||||
|
||||
void MainWindow::markImage()
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ public slots:
|
||||
void indexDir(const QString &dir);
|
||||
void reindex();
|
||||
void saveAs();
|
||||
void convert(const QString &outfile, const QString &format);
|
||||
void convert(const QString &outfile, const QString &format, bool stretch);
|
||||
void markImage();
|
||||
void unmarkImage();
|
||||
void markAndNext();
|
||||
|
||||
@@ -1195,6 +1195,21 @@ void RawImage::applySTF(const MTFParam &mtfParams)
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
float x;
|
||||
if(m_ch == 4)
|
||||
{
|
||||
size_t c = i & 0x3;
|
||||
if(c < 3)
|
||||
{
|
||||
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)x = src[i] * iscale;
|
||||
else x = src[i] * unit.first + unit.second;
|
||||
x = (x - mtfParams.blackPoint[c]) / (mtfParams.whitePoint[c] - mtfParams.blackPoint[c]);
|
||||
x = std::clamp(x, 0.0f, 1.0f);
|
||||
x = ((mtfParams.midPoint[c] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[c] - 1.0f) * x - mtfParams.midPoint[c]);
|
||||
src[i] = x * s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)x = src[i] * iscale;
|
||||
else x = src[i] * unit.first + unit.second;
|
||||
x = (x - mtfParams.blackPoint[0]) / (mtfParams.whitePoint[0] - mtfParams.blackPoint[0]);
|
||||
@@ -1202,6 +1217,7 @@ void RawImage::applySTF(const MTFParam &mtfParams)
|
||||
x = ((mtfParams.midPoint[0] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[0] - 1.0f) * x - mtfParams.midPoint[0]);
|
||||
src[i] = x * s;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch(m_type)
|
||||
|
||||
@@ -104,6 +104,11 @@ StretchToolbar::~StretchToolbar()
|
||||
settings.setValue("stretchtoolbar/autostretch", m_autoStretchOnLoad->isChecked());
|
||||
}
|
||||
|
||||
const MTFParam &StretchToolbar::params() const
|
||||
{
|
||||
return m_mtfParam;
|
||||
}
|
||||
|
||||
void StretchToolbar::stretchImage(Image *img)
|
||||
{
|
||||
if(img && img->rawImage())
|
||||
|
||||
@@ -22,6 +22,7 @@ class StretchToolbar : public QToolBar
|
||||
public:
|
||||
explicit StretchToolbar(QWidget *parent = nullptr);
|
||||
~StretchToolbar();
|
||||
const MTFParam& params() const;
|
||||
public slots:
|
||||
void stretchImage(Image *img);
|
||||
void resetMTF();
|
||||
|
||||
Reference in New Issue
Block a user