Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1e98d818b | |||
| f3f194bcef | |||
| efd36f96c3 | |||
| 37923b37b3 | |||
| 900453577e | |||
| 34d466c3e0 | |||
| 9e98127084 | |||
| ba6062b925 | |||
| 6411b7cd15 | |||
| 223f7cd0ea | |||
| f8f9ee08b3 | |||
| af5aed7ef8 | |||
| 8f5249b142 | |||
| a7dc942c62 | |||
| 1a1399434b | |||
| be567841bf | |||
| 62d2671112 | |||
| 1f8923512e | |||
| 455c3b2d64 | |||
| 4fe546f0e5 | |||
| 95c6fc5343 | |||
| 2bc54ea0cc | |||
| be6e472081 | |||
| 9746f8f653 | |||
| b51a305c63 | |||
| 39775b5e98 | |||
| 93b56e2966 | |||
| 2e41464ff4 |
+15
-7
@@ -35,12 +35,22 @@ set(TENMON_SRC
|
|||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
markedfiles.cpp
|
markedfiles.cpp
|
||||||
rawimage.cpp
|
rawimage.cpp
|
||||||
|
settingsdialog.cpp
|
||||||
starfit.cpp
|
starfit.cpp
|
||||||
statusbar.cpp
|
statusbar.cpp
|
||||||
stfslider.cpp
|
stfslider.cpp
|
||||||
stretchtoolbar.cpp
|
stretchtoolbar.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option(COLOR_MANAGMENT "Enable sRGB framebuffer support for gamma correct images and color profiles support" ON)
|
||||||
|
if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.14")
|
||||||
|
set(COLOR_MANAGMENT OFF)
|
||||||
|
endif(${Qt5Core_VERSION_STRING} VERSION_LESS "5.14")
|
||||||
|
|
||||||
|
if(COLOR_MANAGMENT)
|
||||||
|
add_compile_definitions("COLOR_MANAGMENT")
|
||||||
|
endif(COLOR_MANAGMENT)
|
||||||
|
|
||||||
qt5_add_resources(TENMON_SRC resources.qrc)
|
qt5_add_resources(TENMON_SRC resources.qrc)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND TENMON_SRC icon.rc)
|
list(APPEND TENMON_SRC icon.rc)
|
||||||
@@ -82,18 +92,16 @@ endif()
|
|||||||
|
|
||||||
install(TARGETS tenmon BUNDLE DESTINATION .)
|
install(TARGETS tenmon BUNDLE DESTINATION .)
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
|
include(GNUInstallDirs)
|
||||||
find_program(XDG-DESKTOP-MENU_EXECUTABLE xdg-desktop-menu)
|
find_program(XDG-DESKTOP-MENU_EXECUTABLE xdg-desktop-menu)
|
||||||
if(XDG-DESKTOP-MENU_EXECUTABLE)
|
if(XDG-DESKTOP-MENU_EXECUTABLE)
|
||||||
install(SCRIPT install.cmake)
|
install(SCRIPT install.cmake)
|
||||||
else()
|
else()
|
||||||
if(DEFINED ENV{FLATPAK_DEST})
|
install(FILES space.nouspiro.tenmon.desktop DESTINATION "${CMAKE_INSTALL_DATADIR}/applications")
|
||||||
install(FILES org.nou.tenmon.desktop DESTINATION "$ENV{FLATPAK_DEST}/share/applications")
|
install(FILES space.nouspiro.tenmon.png DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps")
|
||||||
install(FILES org.nou.tenmon.png DESTINATION "$ENV{FLATPAK_DEST}/share/icons/hicolor/32x32/apps")
|
install(FILES space.nouspiro.tenmon_128.png DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps" RENAME space.nouspiro.tenmon.png)
|
||||||
else()
|
|
||||||
install(FILES org.nou.tenmon.desktop DESTINATION "/usr/share/applications")
|
|
||||||
install(FILES org.nou.tenmon.png DESTINATION "/usr/share/icons/hicolor/32x32/apps")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
install(FILES space.nouspiro.tenmon.metainfo.xml DESTINATION "${CMAKE_INSTALL_DATADIR}/metainfo")
|
||||||
endif(UNIX AND NOT APPLE)
|
endif(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
option(RELEASE_BUILD "Release build" OFF)
|
option(RELEASE_BUILD "Release build" OFF)
|
||||||
|
|||||||
@@ -2,10 +2,23 @@ FITS/XISF image viewer with multithreaded image loading
|
|||||||
|
|
||||||
To get all dependencies install these packages
|
To get all dependencies install these packages
|
||||||
|
|
||||||
sudo apt install qtbase5-dev libraw-dev libexif-dev libcfitsio-dev libgsl-dev cmake
|
sudo apt install qtbase5-dev libraw-dev libexif-dev libcfitsio-dev libgsl-dev wcslib-dev libopencv-dev cmake
|
||||||
|
|
||||||
|
on OpenSUSE
|
||||||
|
|
||||||
|
sudo zypper install opencv-devel gsl-devel exif-devel libraw-devel wcslib-devel libqt5-qtbase-devel
|
||||||
|
|
||||||
|
MacOS X
|
||||||
|
|
||||||
|
To compile on MacOS install XCode first. Then install homebrew in x86_64 mode
|
||||||
|
with "arch -i x86_64". Building on native ARM is not supported.
|
||||||
|
|
||||||
|
homebrew install qt5 libraw cfitsio libexif libgsl wcslib opencv
|
||||||
|
|
||||||
|
You may need to set CMAKE_PREFIX_PATH for Qt5 and OpenCV so CMake can find them.
|
||||||
|
|
||||||
Then to build run standard cmake
|
Then to build run standard cmake
|
||||||
|
|
||||||
cmake -B build -S .
|
cmake -B build -S .
|
||||||
make
|
cmake --build build
|
||||||
./tenmon
|
./build/tenmon
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<table><tr>
|
<table><tr>
|
||||||
<td style="padding-right:10px"><img src=":/org.nou.tenmon.png"></td>
|
<td style="padding-right:10px"><img src=":/space.nouspiro.tenmon.png"></td>
|
||||||
<td><h3>Tenmon</h3>
|
<td><h3>Tenmon</h3>
|
||||||
Tenmon is FITS/XISF image viewer and converter. It also index FITS keywords.<br>
|
Tenmon is FITS/XISF image viewer and converter. It also index FITS keywords.<br>
|
||||||
v@GITVERSION@ Copyright © 2022 Dušan Poizl<br><br>
|
v@GITVERSION@ Copyright © 2022 Dušan Poizl<br><br>
|
||||||
|
|||||||
+13
-6
@@ -20,12 +20,6 @@ FilesystemWidget::FilesystemWidget(QAbstractItemModel *model, QWidget *parent) :
|
|||||||
connect(m_listView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FilesystemWidget::fileClicked);
|
connect(m_listView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FilesystemWidget::fileClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilesystemWidget::setDir(const QString &dir)
|
|
||||||
{
|
|
||||||
//m_model->setRootPath(dir);
|
|
||||||
//m_treeView->setRootIndex(m_model->index(m_model->rootPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FilesystemWidget::selectFile(int row)
|
void FilesystemWidget::selectFile(int row)
|
||||||
{
|
{
|
||||||
QModelIndex index = m_model->index(row, 0);
|
QModelIndex index = m_model->index(row, 0);
|
||||||
@@ -47,6 +41,9 @@ Filetree::Filetree(QWidget *parent) : QTreeView(parent)
|
|||||||
m_fileSystemModel->setRootPath(m_rootDir);
|
m_fileSystemModel->setRootPath(m_rootDir);
|
||||||
m_fileSystemModel->setNameFilters({"*.fits", "*.fit", "*.xisf", "*.jpg", "*.jpeg", "*.png", "*.cr2", "*.nef", "*.dng"});
|
m_fileSystemModel->setNameFilters({"*.fits", "*.fit", "*.xisf", "*.jpg", "*.jpeg", "*.png", "*.cr2", "*.nef", "*.dng"});
|
||||||
m_fileSystemModel->setNameFilterDisables(false);
|
m_fileSystemModel->setNameFilterDisables(false);
|
||||||
|
if(settings.value("filetree/showHidden", false).toBool())
|
||||||
|
m_fileSystemModel->setFilter(m_fileSystemModel->filter() | QDir::Hidden);
|
||||||
|
|
||||||
setModel(m_fileSystemModel);
|
setModel(m_fileSystemModel);
|
||||||
setRootIndex(m_fileSystemModel->index(m_rootDir));
|
setRootIndex(m_fileSystemModel->index(m_rootDir));
|
||||||
header()->restoreState(settings.value("filetree/header").toByteArray());
|
header()->restoreState(settings.value("filetree/header").toByteArray());
|
||||||
@@ -57,6 +54,7 @@ Filetree::~Filetree()
|
|||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("filetree/rootDir", m_rootDir);
|
settings.setValue("filetree/rootDir", m_rootDir);
|
||||||
settings.setValue("filetree/header", header()->saveState());
|
settings.setValue("filetree/header", header()->saveState());
|
||||||
|
settings.setValue("filetree/showHidden", (bool)(m_fileSystemModel->filter() & QDir::Hidden));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Filetree::contextMenuEvent(QContextMenuEvent *event)
|
void Filetree::contextMenuEvent(QContextMenuEvent *event)
|
||||||
@@ -85,6 +83,9 @@ void Filetree::contextMenuEvent(QContextMenuEvent *event)
|
|||||||
|
|
||||||
QAction *resetRoot = menu.addAction(tr("Reset root"));
|
QAction *resetRoot = menu.addAction(tr("Reset root"));
|
||||||
QAction *goUp = menu.addAction(tr("Go up"));
|
QAction *goUp = menu.addAction(tr("Go up"));
|
||||||
|
QAction *showHidden = menu.addAction(tr("Show hidden files"));
|
||||||
|
showHidden->setCheckable(true);
|
||||||
|
showHidden->setChecked(m_fileSystemModel->filter() & QDir::Hidden);
|
||||||
|
|
||||||
QAction *a = menu.exec(event->globalPos());
|
QAction *a = menu.exec(event->globalPos());
|
||||||
if(a == nullptr)
|
if(a == nullptr)
|
||||||
@@ -121,6 +122,12 @@ void Filetree::contextMenuEvent(QContextMenuEvent *event)
|
|||||||
{
|
{
|
||||||
emit indexDirectory(m_fileSystemModel->filePath(index));
|
emit indexDirectory(m_fileSystemModel->filePath(index));
|
||||||
}
|
}
|
||||||
|
else if(a == showHidden)
|
||||||
|
{
|
||||||
|
auto filter = m_fileSystemModel->filter();
|
||||||
|
filter ^= QDir::Hidden;
|
||||||
|
m_fileSystemModel->setFilter(filter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Filetree::mouseDoubleClickEvent(QMouseEvent *event)
|
void Filetree::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ class FilesystemWidget : public QWidget
|
|||||||
QAbstractItemModel *m_model;
|
QAbstractItemModel *m_model;
|
||||||
public:
|
public:
|
||||||
explicit FilesystemWidget(QAbstractItemModel *model, QWidget *parent = nullptr);
|
explicit FilesystemWidget(QAbstractItemModel *model, QWidget *parent = nullptr);
|
||||||
void setDir(const QString &dir);
|
|
||||||
private slots:
|
private slots:
|
||||||
void selectFile(int row);
|
void selectFile(int row);
|
||||||
void fileClicked(const QModelIndex &index, const QModelIndex &);
|
void fileClicked(const QModelIndex &index, const QModelIndex &);
|
||||||
|
|||||||
+6
-6
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const int DEFAULT_WIDTH = 2;
|
int DEFAULT_WIDTH = 2;
|
||||||
|
|
||||||
Image::Image(const QString name, int number, ImageRingList *ringList) :
|
Image::Image(const QString name, int number, ImageRingList *ringList) :
|
||||||
m_loading(false),
|
m_loading(false),
|
||||||
@@ -98,12 +98,14 @@ void Image::thumbnailLoadFinish(void *rawImage)
|
|||||||
emit thumbnailLoaded(this);
|
emit thumbnailLoaded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageRingList::ImageRingList(Database *database, QObject *parent) : QAbstractItemModel(parent)
|
ImageRingList::ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent) : QAbstractItemModel(parent)
|
||||||
, m_liveMode(false)
|
, m_liveMode(false)
|
||||||
, m_analyzeLevel(None)
|
, m_analyzeLevel(None)
|
||||||
, m_database(database)
|
, m_database(database)
|
||||||
|
, m_nameFilter(nameFilter)
|
||||||
{
|
{
|
||||||
connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
|
connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
|
||||||
|
m_nameFilter.replaceInStrings(QRegExp("^"), "*.");
|
||||||
m_thumbPool = new QThreadPool(this);
|
m_thumbPool = new QThreadPool(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +124,7 @@ bool ImageRingList::setDir(const QString path, const QString ¤tFile)
|
|||||||
|
|
||||||
if(dir.exists())
|
if(dir.exists())
|
||||||
{
|
{
|
||||||
QStringList nameFilter;
|
QStringList list = dir.entryList(m_nameFilter, QDir::Files | QDir::Readable, m_liveMode ? QDir::Time : QDir::Name | QDir::IgnoreCase);
|
||||||
nameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.cr2" << "*.nef" << "*.dng" << "*.fit" << "*.fits" << "*.xisf";
|
|
||||||
|
|
||||||
QStringList list = dir.entryList(nameFilter, QDir::Files | QDir::Readable, m_liveMode ? QDir::Time : QDir::Name | QDir::IgnoreCase);
|
|
||||||
QStringList absolutePaths;
|
QStringList absolutePaths;
|
||||||
foreach(const QString &file, list)
|
foreach(const QString &file, list)
|
||||||
{
|
{
|
||||||
@@ -260,6 +259,7 @@ void ImageRingList::loadThumbnails()
|
|||||||
void ImageRingList::stopLoading()
|
void ImageRingList::stopLoading()
|
||||||
{
|
{
|
||||||
m_thumbPool->clear();
|
m_thumbPool->clear();
|
||||||
|
m_thumbPool->waitForDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImageRingList::imageCount() const
|
int ImageRingList::imageCount() const
|
||||||
|
|||||||
+2
-1
@@ -60,8 +60,9 @@ class ImageRingList : public QAbstractItemModel
|
|||||||
AnalyzeLevel m_analyzeLevel;
|
AnalyzeLevel m_analyzeLevel;
|
||||||
QThreadPool *m_thumbPool;
|
QThreadPool *m_thumbPool;
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
|
QStringList m_nameFilter;
|
||||||
public:
|
public:
|
||||||
explicit ImageRingList(Database *database, QObject *parent = 0);
|
explicit ImageRingList(Database *database, const QStringList &nameFilter, QObject *parent = 0);
|
||||||
~ImageRingList() override;
|
~ImageRingList() override;
|
||||||
bool setDir(const QString path, const QString ¤tFile = QString());
|
bool setDir(const QString path, const QString ¤tFile = QString());
|
||||||
void setFile(const QString &file);
|
void setFile(const QString &file);
|
||||||
|
|||||||
+53
-3
@@ -11,6 +11,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
struct RawImageType
|
struct RawImageType
|
||||||
{
|
{
|
||||||
@@ -24,13 +25,20 @@ const RawImageType rawImageTypes[] = {
|
|||||||
{QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, true},
|
{QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, true},
|
||||||
{QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, true},
|
{QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, true},
|
||||||
{QOpenGLTexture::Red, QOpenGLTexture::R32F, QOpenGLTexture::Float32, true},
|
{QOpenGLTexture::Red, QOpenGLTexture::R32F, QOpenGLTexture::Float32, true},
|
||||||
|
#ifdef COLOR_MANAGMENT
|
||||||
|
{QOpenGLTexture::RGB, QOpenGLTexture::SRGB8, QOpenGLTexture::UInt8, false},
|
||||||
|
{QOpenGLTexture::RGBA,QOpenGLTexture::SRGB8_Alpha8, QOpenGLTexture::UInt8, false},
|
||||||
|
#else
|
||||||
{QOpenGLTexture::RGB, QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, false},
|
{QOpenGLTexture::RGB, QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, false},
|
||||||
{QOpenGLTexture::RGBA,QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, false},
|
{QOpenGLTexture::RGBA,QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, false},
|
||||||
|
#endif
|
||||||
{QOpenGLTexture::RGB, QOpenGLTexture::RGB16_UNorm, QOpenGLTexture::UInt16, false},
|
{QOpenGLTexture::RGB, QOpenGLTexture::RGB16_UNorm, QOpenGLTexture::UInt16, false},
|
||||||
{QOpenGLTexture::RGBA, QOpenGLTexture::RGB16_UNorm, QOpenGLTexture::UInt16, false},
|
{QOpenGLTexture::RGBA, QOpenGLTexture::RGB16_UNorm, QOpenGLTexture::UInt16, false},
|
||||||
{QOpenGLTexture::RGB, QOpenGLTexture::RGB32F, QOpenGLTexture::Float32, false}
|
{QOpenGLTexture::RGB, QOpenGLTexture::RGB32F, QOpenGLTexture::Float32, false}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool MANUAL_MIPMAP_GEN = false;
|
||||||
|
|
||||||
void setScrollRange(QScrollBar *scrollBar, int newRange)
|
void setScrollRange(QScrollBar *scrollBar, int newRange)
|
||||||
{
|
{
|
||||||
int page = scrollBar->pageStep();
|
int page = scrollBar->pageStep();
|
||||||
@@ -97,8 +105,11 @@ void ImageWidget::setImage(std::shared_ptr<RawImage> image, int index)
|
|||||||
m_currentImg = index;
|
m_currentImg = index;
|
||||||
|
|
||||||
const RawImageType &rawImageType = rawImageTypes[image->type()];
|
const RawImageType &rawImageType = rawImageTypes[image->type()];
|
||||||
|
m_srgb = rawImageType.textureFormat == QOpenGLTexture::SRGB8 || rawImageType.textureFormat == QOpenGLTexture::SRGB8_Alpha8;
|
||||||
|
m_bwImg = rawImageType.bw;
|
||||||
|
|
||||||
m_image->destroy();
|
m_image->destroy();
|
||||||
|
m_image->setAutoMipMapGenerationEnabled(false);
|
||||||
m_image->setFormat(rawImageType.textureFormat);
|
m_image->setFormat(rawImageType.textureFormat);
|
||||||
m_image->setSize(image->width(), image->height());
|
m_image->setSize(image->width(), image->height());
|
||||||
m_image->setMipLevels([&](){ int c = 0; int s = std::min(m_imgWidth, m_imgHeight); while(s>>=1)c++; return c; }());
|
m_image->setMipLevels([&](){ int c = 0; int s = std::min(m_imgWidth, m_imgHeight); while(s>>=1)c++; return c; }());
|
||||||
@@ -107,9 +118,42 @@ void ImageWidget::setImage(std::shared_ptr<RawImage> image, int index)
|
|||||||
m_image->setWrapMode(QOpenGLTexture::ClampToEdge);
|
m_image->setWrapMode(QOpenGLTexture::ClampToEdge);
|
||||||
m_image->setBorderColor(0, 0, 0, 0);
|
m_image->setBorderColor(0, 0, 0, 0);
|
||||||
m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data(), m_transferOptions.get());
|
m_image->setData(0, rawImageType.pixelFormat, rawImageType.dataType, (const void*)image->data(), m_transferOptions.get());
|
||||||
|
|
||||||
|
auto sRGB_linear = [](cv::Point3f &pixel, const int *pos)
|
||||||
|
{
|
||||||
|
pixel.x = pixel.x <= 0.04045f ? pixel.x / 12.92f : std::pow((pixel.x + 0.055) / 1.055f, 2.4f);
|
||||||
|
pixel.y = pixel.y <= 0.04045f ? pixel.y / 12.92f : std::pow((pixel.y + 0.055) / 1.055f, 2.4f);
|
||||||
|
pixel.z = pixel.z <= 0.04045f ? pixel.z / 12.92f : std::pow((pixel.z + 0.055) / 1.055f, 2.4f);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto linear_sRGB = [](cv::Point3f &pixel, const int *pos)
|
||||||
|
{
|
||||||
|
pixel.x = pixel.x <= 0.0031308f ? pixel.x * 12.92f : 1.055f * std::pow(pixel.x , 1/2.4f) - 0.055f;
|
||||||
|
pixel.y = pixel.y <= 0.0031308f ? pixel.y * 12.92f : 1.055f * std::pow(pixel.y , 1/2.4f) - 0.055f;
|
||||||
|
pixel.z = pixel.z <= 0.0031308f ? pixel.z * 12.92f : 1.055f * std::pow(pixel.z , 1/2.4f) - 0.055f;
|
||||||
|
};
|
||||||
|
|
||||||
|
//AMD OpenGL driver on Windows doesn't generate mipmaps for sRGB textures correctly
|
||||||
|
if(m_srgb && MANUAL_MIPMAP_GEN)
|
||||||
|
{
|
||||||
|
cv::Mat img = image->mat();
|
||||||
|
img.convertTo(img, CV_32FC3, 1/255.0);
|
||||||
|
img.forEach<cv::Point3f>(sRGB_linear);
|
||||||
|
cv::Size size(img.cols, img.rows);
|
||||||
|
for(int i=1; i<m_image->mipLevels(); i++)
|
||||||
|
{
|
||||||
|
cv::Mat mip;
|
||||||
|
size /= 2;
|
||||||
|
cv::resize(img, mip, size);
|
||||||
|
mip.copyTo(img);
|
||||||
|
mip.forEach<cv::Point3f>(linear_sRGB);
|
||||||
|
mip.convertTo(mip, CV_8UC3, 255);
|
||||||
|
m_image->setData(i, rawImageType.pixelFormat, rawImageType.dataType, (const void*)mip.ptr(), m_transferOptions.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else m_image->generateMipMaps();
|
||||||
|
|
||||||
m_image->setLevelOfDetailRange(m_superpixel ? 1 : 0, m_image->mipMaxLevel());
|
m_image->setLevelOfDetailRange(m_superpixel ? 1 : 0, m_image->mipMaxLevel());
|
||||||
m_image->generateMipMaps();
|
|
||||||
m_bwImg = rawImageType.bw;
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +293,7 @@ void ImageWidget::paintGL()
|
|||||||
}
|
}
|
||||||
m_thumbnailProgram->bind();
|
m_thumbnailProgram->bind();
|
||||||
f->glUniform3i(m_thumbnailProgram->uniformLocation("viewport_row"), width(), height(), width()/THUMB_SIZE_BORDER);
|
f->glUniform3i(m_thumbnailProgram->uniformLocation("viewport_row"), width(), height(), width()/THUMB_SIZE_BORDER);
|
||||||
|
f->glUniform3i(m_thumbnailProgram->uniformLocation("thumb_size"), THUMB_SIZE_BORDER/2, THUMB_SIZE_BORDER, THUMB_SIZE_BORDER_Y);
|
||||||
m_thumbnailProgram->setUniformValue("mtf_param", m_low, m_mid, m_high);
|
m_thumbnailProgram->setUniformValue("mtf_param", m_low, m_mid, m_high);
|
||||||
m_thumbnailProgram->setUniformValue("invert", m_invert);
|
m_thumbnailProgram->setUniformValue("invert", m_invert);
|
||||||
m_thumbnailProgram->setUniformValue("offset", 0, m_dy);
|
m_thumbnailProgram->setUniformValue("offset", 0, m_dy);
|
||||||
@@ -296,6 +341,9 @@ void ImageWidget::paintGL()
|
|||||||
m_program->setUniformValue("zoom", 1.0f/m_scale);
|
m_program->setUniformValue("zoom", 1.0f/m_scale);
|
||||||
m_program->setUniformValue("bw", m_bwImg);
|
m_program->setUniformValue("bw", m_bwImg);
|
||||||
m_program->setUniformValue("invert", m_invert);
|
m_program->setUniformValue("invert", m_invert);
|
||||||
|
#ifdef COLOR_MANAGMENT
|
||||||
|
m_program->setUniformValue("srgb", m_srgb);
|
||||||
|
#endif
|
||||||
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +383,8 @@ void ImageWidget::initializeGL()
|
|||||||
qDebug() << (char*)f->glGetString(GL_RENDERER);
|
qDebug() << (char*)f->glGetString(GL_RENDERER);
|
||||||
qDebug() << (char*)f->glGetString(GL_VERSION);
|
qDebug() << (char*)f->glGetString(GL_VERSION);
|
||||||
|
|
||||||
|
MANUAL_MIPMAP_GEN = QString((const char*)f->glGetString(GL_VENDOR)).startsWith("ATI Technologies Inc", Qt::CaseInsensitive);
|
||||||
|
|
||||||
qDebug() << context()->format();
|
qDebug() << context()->format();
|
||||||
|
|
||||||
// each vertex is x,y 2D position and s,t texture coordinates
|
// each vertex is x,y 2D position and s,t texture coordinates
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class ImageWidget : public QOpenGLWidget
|
|||||||
bool m_showThumbnails;
|
bool m_showThumbnails;
|
||||||
bool m_selecting;
|
bool m_selecting;
|
||||||
bool m_sizesDirty;
|
bool m_sizesDirty;
|
||||||
|
bool m_srgb;
|
||||||
int m_thumbnailCount;
|
int m_thumbnailCount;
|
||||||
QVector<ImageThumb> m_thumnails;
|
QVector<ImageThumb> m_thumnails;
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,5 @@
|
|||||||
find_program(XDG-DESKTOP-MENU_EXECUTABLE xdg-desktop-menu)
|
find_program(XDG-DESKTOP-MENU_EXECUTABLE xdg-desktop-menu)
|
||||||
find_program(XDG-ICON-RESOURCE_EXECUTABLE xdg-icon-resource)
|
find_program(XDG-ICON-RESOURCE_EXECUTABLE xdg-icon-resource)
|
||||||
execute_process(COMMAND ${XDG-DESKTOP-MENU_EXECUTABLE} install --novendor org.nou.tenmon.desktop WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
execute_process(COMMAND ${XDG-DESKTOP-MENU_EXECUTABLE} install --novendor space.nouspiro.tenmon.desktop WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||||
execute_process(COMMAND ${XDG-ICON-RESOURCE_EXECUTABLE} install --novendor --size 32 org.nou.tenmon.png org.nou.tenmon WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
execute_process(COMMAND ${XDG-ICON-RESOURCE_EXECUTABLE} install --novendor --size 64 space.nouspiro.tenmon.png space.nouspiro.tenmon WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
execute_process(COMMAND ${XDG-ICON-RESOURCE_EXECUTABLE} install --novendor --size 128 space.nouspiro.tenmon_128.png space.nouspiro.tenmon WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|||||||
+42
-15
@@ -14,6 +14,11 @@
|
|||||||
#include "starfit.h"
|
#include "starfit.h"
|
||||||
#include "wcslib/wcshdr.h"
|
#include "wcslib/wcshdr.h"
|
||||||
|
|
||||||
|
#ifdef COLOR_MANAGMENT
|
||||||
|
#include <QColorSpace>
|
||||||
|
static pcl::ICCProfile sRgbIccProfile((void*)QColorSpace(QColorSpace::SRgb).iccProfile().data());
|
||||||
|
#endif
|
||||||
|
|
||||||
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
|
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
|
||||||
m_file(file),
|
m_file(file),
|
||||||
m_receiver(receiver),
|
m_receiver(receiver),
|
||||||
@@ -83,17 +88,17 @@ bool loadRAW(const QString path, ImageInfoData &info, RawImage **image)
|
|||||||
if(!image)
|
if(!image)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LibRaw raw;
|
std::unique_ptr<LibRaw> raw = std::make_unique<LibRaw>();
|
||||||
raw.open_file(path.toLocal8Bit().data());
|
raw->open_file(path.toLocal8Bit().data());
|
||||||
raw.imgdata.params.half_size = true;
|
raw->imgdata.params.half_size = true;
|
||||||
raw.imgdata.params.use_camera_wb = true;
|
raw->imgdata.params.use_camera_wb = true;
|
||||||
raw.imgdata.params.user_flip = 0;
|
raw->imgdata.params.user_flip = 0;
|
||||||
if(raw.unpack())
|
if(raw->unpack())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(image)
|
if(image)
|
||||||
{
|
{
|
||||||
libraw_rawdata_t rawdata = raw.imgdata.rawdata;
|
libraw_rawdata_t rawdata = raw->imgdata.rawdata;
|
||||||
size_t size = rawdata.sizes.width*rawdata.sizes.height;
|
size_t size = rawdata.sizes.width*rawdata.sizes.height;
|
||||||
|
|
||||||
std::vector<uint16_t> out;
|
std::vector<uint16_t> out;
|
||||||
@@ -115,14 +120,14 @@ bool loadRAW(const QString path, ImageInfoData &info, RawImage **image)
|
|||||||
memcpy((*image)->data(), &out[0], sizeof(uint16_t)*d);
|
memcpy((*image)->data(), &out[0], sizeof(uint16_t)*d);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString shutterSpeed = QString::number(raw.imgdata.other.shutter);
|
QString shutterSpeed = QString::number(raw->imgdata.other.shutter);
|
||||||
if(raw.imgdata.other.shutter < 1)
|
if(raw->imgdata.other.shutter < 1)
|
||||||
{
|
{
|
||||||
shutterSpeed = QString("1/%1s").arg(1.0f/raw.imgdata.other.shutter);
|
shutterSpeed = QString("1/%1s").arg(1.0f/raw->imgdata.other.shutter);
|
||||||
}
|
}
|
||||||
//info.append(StringPair(QObject::tr("Width"), QString::number(rawImg->width)));
|
//info.append(StringPair(QObject::tr("Width"), QString::number(rawImg->width)));
|
||||||
//info.append(StringPair(QObject::tr("Height"), QString::number(rawImg->height)));
|
//info.append(StringPair(QObject::tr("Height"), QString::number(rawImg->height)));
|
||||||
info.info.append({QObject::tr("ISO"), QString::number(raw.imgdata.other.iso_speed)});
|
info.info.append({QObject::tr("ISO"), QString::number(raw->imgdata.other.iso_speed)});
|
||||||
info.info.append({QObject::tr("Shutter speed"), shutterSpeed});
|
info.info.append({QObject::tr("Shutter speed"), shutterSpeed});
|
||||||
#if LIBRAW_MINOR_VERSION>=19
|
#if LIBRAW_MINOR_VERSION>=19
|
||||||
// info.append(StringPair(QObject::tr("Camera temperature"), QString::number(raw.imgdata.other.CameraTemperature)));
|
// info.append(StringPair(QObject::tr("Camera temperature"), QString::number(raw.imgdata.other.CameraTemperature)));
|
||||||
@@ -281,11 +286,26 @@ bool loadFITS(const QString path, ImageInfoData &info, RawImage **image)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "pcl/ICCProfileTransformation.h"
|
||||||
|
|
||||||
template<typename T, typename PCLtype, int CVtype>
|
template<typename T, typename PCLtype, int CVtype>
|
||||||
bool loadPCLImage(pcl::XISFReader &xisf, RawImage **image)
|
bool loadPCLImage(pcl::XISFReader &xisf, RawImage **image)
|
||||||
{
|
{
|
||||||
PCLtype pclImage;
|
PCLtype pclImage;
|
||||||
xisf.ReadImage(pclImage);
|
xisf.ReadImage(pclImage);
|
||||||
|
pclImage.Status().DisableInitialization();
|
||||||
|
|
||||||
|
#ifdef COLOR_MANAGMENT
|
||||||
|
pcl::ICCProfile iccProfile = xisf.ReadICCProfile();
|
||||||
|
if(iccProfile.IsProfile())
|
||||||
|
{
|
||||||
|
pcl::ICCProfileTransformation iccTran;
|
||||||
|
iccTran.DisableParallelProcessing();
|
||||||
|
iccTran.Add(iccProfile);
|
||||||
|
iccTran.Add(sRgbIccProfile);
|
||||||
|
iccTran >> pclImage;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int numChannels = pclImage.NumberOfChannels();
|
int numChannels = pclImage.NumberOfChannels();
|
||||||
cv::Mat cvImg[numChannels];
|
cv::Mat cvImg[numChannels];
|
||||||
@@ -315,6 +335,7 @@ bool loadXISF(const QString &path, ImageInfoData &info, RawImage **image)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
pcl::XISF::EnsurePTLUTInitialized();
|
||||||
pcl::String pclPath = path.utf16();
|
pcl::String pclPath = path.utf16();
|
||||||
pcl::XISFReader xisf;
|
pcl::XISFReader xisf;
|
||||||
xisf.Open(pclPath);
|
xisf.Open(pclPath);
|
||||||
@@ -384,6 +405,11 @@ void LoadRunable::run()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
QImage img(m_file);
|
QImage img(m_file);
|
||||||
|
#ifdef COLOR_MANAGMENT
|
||||||
|
if(img.colorSpace().isValid() && img.colorSpace() != QColorSpace::SRgb)
|
||||||
|
img.convertToColorSpace(QColorSpace::SRgb);
|
||||||
|
#endif
|
||||||
|
|
||||||
ExifData *exif = exif_data_new_from_file(m_file.toLocal8Bit().constData());
|
ExifData *exif = exif_data_new_from_file(m_file.toLocal8Bit().constData());
|
||||||
info.info.append({QObject::tr("Width"), QString::number(img.width())});
|
info.info.append({QObject::tr("Width"), QString::number(img.width())});
|
||||||
info.info.append({QObject::tr("Height"), QString::number(img.height())});
|
info.info.append({QObject::tr("Height"), QString::number(img.height())});
|
||||||
@@ -515,9 +541,10 @@ bool readXISFHeader(const QString &path, ImageInfoData &info)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertRunable::ConvertRunable(const QString &in, const QString &out) :
|
ConvertRunable::ConvertRunable(const QString &in, const QString &out, const QString &format) :
|
||||||
m_infile(in),
|
m_infile(in),
|
||||||
m_outfile(out)
|
m_outfile(out),
|
||||||
|
m_format(format)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +649,7 @@ void ConvertRunable::run()
|
|||||||
|
|
||||||
if(rawimage)
|
if(rawimage)
|
||||||
{
|
{
|
||||||
if(m_outfile.endsWith(".XISF", Qt::CaseInsensitive))
|
if(m_format == "XISF")
|
||||||
{
|
{
|
||||||
pcl::XISFOptions options;
|
pcl::XISFOptions options;
|
||||||
pcl::FITSKeywordArray fitskeywords;
|
pcl::FITSKeywordArray fitskeywords;
|
||||||
@@ -649,7 +676,7 @@ void ConvertRunable::run()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_outfile.endsWith(".FITS", Qt::CaseInsensitive) || m_outfile.endsWith(".FIT", Qt::CaseInsensitive))
|
if(m_format == "FITS")
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
fitsfile *fw;
|
fitsfile *fw;
|
||||||
|
|||||||
+2
-1
@@ -25,8 +25,9 @@ class ConvertRunable : public QRunnable
|
|||||||
{
|
{
|
||||||
QString m_infile;
|
QString m_infile;
|
||||||
QString m_outfile;
|
QString m_outfile;
|
||||||
|
QString m_format;
|
||||||
public:
|
public:
|
||||||
ConvertRunable(const QString &in, const QString &out);
|
ConvertRunable(const QString &in, const QString &out, const QString &format);
|
||||||
void run() override;
|
void run() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ int main(int argc, char *argv[])
|
|||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
a.setOrganizationName("nou");
|
a.setOrganizationName("nou");
|
||||||
a.setApplicationName("Tenmon");
|
a.setApplicationName("Tenmon");
|
||||||
a.setWindowIcon(QIcon(":/org.nou.tenmon.png"));
|
a.setWindowIcon(QIcon(":/space.nouspiro.tenmon.png"));
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
QTranslator translator2;
|
QTranslator translator2;
|
||||||
|
|||||||
+96
-28
@@ -13,13 +13,16 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QCoreApplication>
|
#include <QGuiApplication>
|
||||||
#include <QThreadPool>
|
#include <QThreadPool>
|
||||||
#include <QStatusBar>
|
#include <QStatusBar>
|
||||||
|
#include <QImageReader>
|
||||||
|
#include <QMimeDatabase>
|
||||||
#include "loadrunable.h"
|
#include "loadrunable.h"
|
||||||
#include "markedfiles.h"
|
#include "markedfiles.h"
|
||||||
#include "about.h"
|
#include "about.h"
|
||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
|
#include "settingsdialog.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@@ -34,6 +37,26 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
qRegisterMetaType<ImageInfoData>("ImageInfoData");
|
qRegisterMetaType<ImageInfoData>("ImageInfoData");
|
||||||
qRegisterMetaType<RawImage*>("RawImage");
|
qRegisterMetaType<RawImage*>("RawImage");
|
||||||
|
|
||||||
|
SettingsDialog::loadSettings();
|
||||||
|
|
||||||
|
QStringList nameFilter;
|
||||||
|
_saveFilter = tr("FITS (*.fits *.fit);;XISF (*.xisf);;");
|
||||||
|
_openFilter = tr("Images (");
|
||||||
|
QMimeDatabase db;
|
||||||
|
auto supportedFormats = QImageReader::supportedMimeTypes();
|
||||||
|
QStringList filters;
|
||||||
|
for(auto format : supportedFormats)
|
||||||
|
{
|
||||||
|
QMimeType mimeType = db.mimeTypeForName(format);
|
||||||
|
_saveFilter.append(mimeType.filterString() + ";;");
|
||||||
|
_openFilter.append("*.");
|
||||||
|
_openFilter.append(mimeType.suffixes().join(" *."));
|
||||||
|
_openFilter.append(" ");
|
||||||
|
nameFilter.append(mimeType.suffixes());
|
||||||
|
}
|
||||||
|
_openFilter.append("*.fit *.fits *.xisf *.cr2 *.nef *.dng)");
|
||||||
|
nameFilter.append({"fit", "fits", "xisf", "cr2", "nef", "dng"});
|
||||||
|
|
||||||
m_info = new ImageInfo(this);
|
m_info = new ImageInfo(this);
|
||||||
QDockWidget *infoDock = new QDockWidget(tr("Image info"), this);
|
QDockWidget *infoDock = new QDockWidget(tr("Image info"), this);
|
||||||
infoDock->setWidget(m_info);
|
infoDock->setWidget(m_info);
|
||||||
@@ -59,7 +82,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
connect(m_stretchPanel, &StretchToolbar::invert, m_imageGL->imageWidget(), &ImageWidget::invert);
|
connect(m_stretchPanel, &StretchToolbar::invert, m_imageGL->imageWidget(), &ImageWidget::invert);
|
||||||
connect(m_stretchPanel, &StretchToolbar::superPixel, m_imageGL->imageWidget(), &ImageWidget::superPixel);
|
connect(m_stretchPanel, &StretchToolbar::superPixel, m_imageGL->imageWidget(), &ImageWidget::superPixel);
|
||||||
|
|
||||||
m_ringList = new ImageRingList(m_database, this);
|
m_ringList = new ImageRingList(m_database, nameFilter, this);
|
||||||
m_filesystem = new FilesystemWidget(m_ringList, this);
|
m_filesystem = new FilesystemWidget(m_ringList, this);
|
||||||
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
|
connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int)));
|
||||||
|
|
||||||
@@ -117,6 +140,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
exitAction->setShortcut(QKeySequence::Quit);
|
exitAction->setShortcut(QKeySequence::Quit);
|
||||||
menuBar()->addMenu(fileMenu);
|
menuBar()->addMenu(fileMenu);
|
||||||
|
|
||||||
|
QMenu *editMenu = new QMenu(tr("Edit"), this);
|
||||||
|
editMenu->addAction(tr("Settings"), this, &MainWindow::showSettingsDialog);
|
||||||
|
menuBar()->addMenu(editMenu);
|
||||||
|
|
||||||
QMenu *viewMenu = new QMenu(tr("View"), this);
|
QMenu *viewMenu = new QMenu(tr("View"), this);
|
||||||
viewMenu->addAction(tr("Zoom In"), m_imageGL, SLOT(zoomIn()), QKeySequence::ZoomIn);
|
viewMenu->addAction(tr("Zoom In"), m_imageGL, SLOT(zoomIn()), QKeySequence::ZoomIn);
|
||||||
viewMenu->addAction(tr("Zoom Out"), m_imageGL, SLOT(zoomOut()), QKeySequence::ZoomOut);
|
viewMenu->addAction(tr("Zoom Out"), m_imageGL, SLOT(zoomOut()), QKeySequence::ZoomOut);
|
||||||
@@ -190,7 +217,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
_lastDir = standardLocations.first();
|
_lastDir = standardLocations.first();
|
||||||
|
|
||||||
_lastDir = settings.value("mainwindow/lastdir", _lastDir).toString();
|
_lastDir = settings.value("mainwindow/lastdir", _lastDir).toString();
|
||||||
m_filesystem->setDir(_lastDir);
|
|
||||||
|
|
||||||
QStringList args = QCoreApplication::arguments();
|
QStringList args = QCoreApplication::arguments();
|
||||||
args.removeFirst();
|
args.removeFirst();
|
||||||
@@ -208,6 +234,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_imageGL->setFocus();
|
m_imageGL->setFocus();
|
||||||
|
|
||||||
|
// workaround for nasty wayland backend bug https://bugreports.qt.io/browse/QTBUG-87332
|
||||||
|
if(static_cast<QGuiApplication*>(QCoreApplication::instance())->platformName() == "wayland")
|
||||||
|
{
|
||||||
|
infoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
|
filesystemDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
|
databaseViewDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
|
filetreeDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
|
||||||
|
m_stretchPanel->setFloatable(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
@@ -277,7 +313,10 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||||||
|
|
||||||
void MainWindow::copyOrMove(bool copy)
|
void MainWindow::copyOrMove(bool copy)
|
||||||
{
|
{
|
||||||
QString dest = QFileDialog::getExistingDirectory(this, tr("Select destination"), _lastDir);
|
QString dest = QFileDialog::getExistingDirectory(this,
|
||||||
|
tr("Select destination"),
|
||||||
|
_lastDir,
|
||||||
|
QFileDialog::ShowDirsOnly);
|
||||||
copyOrMove(copy, dest);
|
copyOrMove(copy, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,6 +332,7 @@ void MainWindow::copyOrMove(bool copy, const QString &dest)
|
|||||||
progress.show();
|
progress.show();
|
||||||
foreach(const QString &file, files)
|
foreach(const QString &file, files)
|
||||||
{
|
{
|
||||||
|
bool result = false;
|
||||||
QFileInfo info(file);
|
QFileInfo info(file);
|
||||||
QFile srcFile(file);
|
QFile srcFile(file);
|
||||||
QFile dstFile(dir.absoluteFilePath(info.fileName()));
|
QFile dstFile(dir.absoluteFilePath(info.fileName()));
|
||||||
@@ -301,7 +341,7 @@ void MainWindow::copyOrMove(bool copy, const QString &dest)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(progress.wasCanceled())
|
if(progress.wasCanceled())
|
||||||
break;
|
return;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
if(copy)
|
if(copy)
|
||||||
{
|
{
|
||||||
@@ -311,20 +351,30 @@ void MainWindow::copyOrMove(bool copy, const QString &dest)
|
|||||||
{
|
{
|
||||||
dstFile.remove();
|
dstFile.remove();
|
||||||
dstFile.close();
|
dstFile.close();
|
||||||
qDebug() << dstFile.fileName();
|
result = srcFile.copy(dstFile.fileName());
|
||||||
srcFile.copy(dstFile.fileName());
|
|
||||||
}
|
}
|
||||||
|
else result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
srcFile.rename(dstFile.fileName());
|
result = srcFile.rename(dstFile.fileName());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if(copy)
|
if(copy)
|
||||||
srcFile.copy(dstFile.fileName());
|
result = srcFile.copy(dstFile.fileName());
|
||||||
else
|
else
|
||||||
srcFile.rename(dstFile.fileName());
|
result = srcFile.rename(dstFile.fileName());
|
||||||
#endif
|
#endif
|
||||||
|
if(!result)
|
||||||
|
{
|
||||||
|
QString t = copy ? tr("Failed to copy") : tr("Failed to move");
|
||||||
|
QString m = copy ? tr("Failed to copy from %1 to %2") : tr("Failed to move from %1 to %2");
|
||||||
|
QMessageBox::StandardButton button = QMessageBox::warning(this, t,
|
||||||
|
m.arg(srcFile.fileName()).arg(dir.absolutePath()),
|
||||||
|
QMessageBox::Ignore | QMessageBox::Abort);
|
||||||
|
qDebug() << button;
|
||||||
|
if(button == QMessageBox::Abort)return;
|
||||||
|
}
|
||||||
progress.setValue(i++);
|
progress.setValue(i++);
|
||||||
}
|
}
|
||||||
m_database->clearMarkedFiles();
|
m_database->clearMarkedFiles();
|
||||||
@@ -350,7 +400,10 @@ void MainWindow::pixmapLoaded(Image *image)
|
|||||||
|
|
||||||
void MainWindow::loadFile()
|
void MainWindow::loadFile()
|
||||||
{
|
{
|
||||||
QString file = QFileDialog::getOpenFileName(this, tr("Open file"), _lastDir, tr("Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)"));
|
QString file = QFileDialog::getOpenFileName(this,
|
||||||
|
tr("Open file"),
|
||||||
|
_lastDir,
|
||||||
|
_openFilter);
|
||||||
loadFile(file);
|
loadFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +420,6 @@ void MainWindow::loadFile(const QString &path)
|
|||||||
_lastDir = info.canonicalPath();
|
_lastDir = info.canonicalPath();
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("mainwindow/lastdir", _lastDir);
|
settings.setValue("mainwindow/lastdir", _lastDir);
|
||||||
m_filesystem->setDir(_lastDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +430,7 @@ void MainWindow::loadFile(int row)
|
|||||||
|
|
||||||
void MainWindow::indexDir()
|
void MainWindow::indexDir()
|
||||||
{
|
{
|
||||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir);
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir, QFileDialog::ShowDirsOnly);
|
||||||
indexDir(dir);
|
indexDir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,35 +454,45 @@ void MainWindow::reindex()
|
|||||||
void MainWindow::saveAs()
|
void MainWindow::saveAs()
|
||||||
{
|
{
|
||||||
QString selectedFilter;
|
QString selectedFilter;
|
||||||
QString file = QFileDialog::getSaveFileName(this, tr("Save as"), _lastDir, tr("JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)"), &selectedFilter);
|
QString file = QFileDialog::getSaveFileName(this,
|
||||||
|
tr("Save as"),
|
||||||
|
_lastDir,
|
||||||
|
_saveFilter,
|
||||||
|
&selectedFilter);
|
||||||
|
auto filterToFormat = [](const QString &file, const QString &filter) -> const char*
|
||||||
|
{
|
||||||
|
QString suffix = QFileInfo(file).suffix();
|
||||||
|
if(!suffix.compare("jpg", Qt::CaseInsensitive) || !suffix.compare("jpeg", Qt::CaseInsensitive))return "JPEG";
|
||||||
|
if(!suffix.compare("png", Qt::CaseInsensitive))return "PNG";
|
||||||
|
if(!suffix.compare("fits", Qt::CaseInsensitive) || !suffix.compare("fit", Qt::CaseInsensitive))return "FITS";
|
||||||
|
if(!suffix.compare("xisf", Qt::CaseInsensitive))return "XISF";
|
||||||
|
if(filter.contains("png"))return "PNG";
|
||||||
|
if(filter.contains("fits"))return "FITS";
|
||||||
|
if(filter.contains("xisf"))return "XISF";
|
||||||
|
return "JPEG";
|
||||||
|
};
|
||||||
|
|
||||||
if(!file.isEmpty())
|
if(!file.isEmpty())
|
||||||
{
|
{
|
||||||
QFileInfo info(file);
|
QString format = filterToFormat(file, selectedFilter);
|
||||||
if(info.suffix().isEmpty())
|
|
||||||
{
|
|
||||||
if(selectedFilter.contains("jpg"))file += ".jpg";
|
|
||||||
if(selectedFilter.contains("png"))file += ".png";
|
|
||||||
if(selectedFilter.contains("fits"))file += ".fits";
|
|
||||||
if(selectedFilter.contains("xisf"))file += ".xisf";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(file.endsWith(".fits") || file.endsWith(".xisf"))
|
if(format == "FITS" || format == "XISF")
|
||||||
{
|
{
|
||||||
convert(file);
|
convert(file, format);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QImage img = m_imageGL->imageWidget()->renderToImage();
|
QImage img = m_imageGL->imageWidget()->renderToImage();
|
||||||
if(!img.isNull())
|
if(!img.isNull())
|
||||||
img.save(file);
|
img.save(file, filterToFormat(file, selectedFilter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::convert(const QString &outfile)
|
void MainWindow::convert(const QString &outfile, const QString &format)
|
||||||
{
|
{
|
||||||
QString file = m_ringList->currentImage()->name();
|
QString file = m_ringList->currentImage()->name();
|
||||||
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile));
|
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile, format));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::markImage()
|
void MainWindow::markImage()
|
||||||
@@ -525,10 +587,16 @@ void MainWindow::starFinder(bool findStars)
|
|||||||
|
|
||||||
void MainWindow::showMarkFilesDialog()
|
void MainWindow::showMarkFilesDialog()
|
||||||
{
|
{
|
||||||
MarkedFiles markedFiles;
|
MarkedFiles markedFiles(this);
|
||||||
markedFiles.exec();
|
markedFiles.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showSettingsDialog()
|
||||||
|
{
|
||||||
|
SettingsDialog settingsDialog(this);
|
||||||
|
settingsDialog.exec();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateWindowTitle()
|
void MainWindow::updateWindowTitle()
|
||||||
{
|
{
|
||||||
ImagePtr ptr = m_ringList->currentImage();
|
ImagePtr ptr = m_ringList->currentImage();
|
||||||
|
|||||||
+4
-1
@@ -28,6 +28,8 @@ class MainWindow : public QMainWindow
|
|||||||
QSocketNotifier *socketNotifier;
|
QSocketNotifier *socketNotifier;
|
||||||
QString _lastDir;
|
QString _lastDir;
|
||||||
bool _maximized;
|
bool _maximized;
|
||||||
|
QString _openFilter;
|
||||||
|
QString _saveFilter;
|
||||||
public:
|
public:
|
||||||
MainWindow(QWidget *parent = 0);
|
MainWindow(QWidget *parent = 0);
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
@@ -50,7 +52,7 @@ protected slots:
|
|||||||
void indexDir(const QString &dir);
|
void indexDir(const QString &dir);
|
||||||
void reindex();
|
void reindex();
|
||||||
void saveAs();
|
void saveAs();
|
||||||
void convert(const QString &outfile);
|
void convert(const QString &outfile, const QString &format);
|
||||||
void markImage();
|
void markImage();
|
||||||
void unmarkImage();
|
void unmarkImage();
|
||||||
void markAndNext();
|
void markAndNext();
|
||||||
@@ -63,6 +65,7 @@ protected slots:
|
|||||||
void peakFinder(bool findPeaks);
|
void peakFinder(bool findPeaks);
|
||||||
void starFinder(bool findStars);
|
void starFinder(bool findStars);
|
||||||
void showMarkFilesDialog();
|
void showMarkFilesDialog();
|
||||||
|
void showSettingsDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
|
|
||||||
|
int THUMB_SIZE = 128;
|
||||||
|
int THUMB_SIZE_BORDER = 138;
|
||||||
|
int THUMB_SIZE_BORDER_Y = 158;
|
||||||
|
|
||||||
RawImage::ImgType CV2Type(int cvtype)
|
RawImage::ImgType CV2Type(int cvtype)
|
||||||
{
|
{
|
||||||
switch (cvtype)
|
switch (cvtype)
|
||||||
@@ -67,6 +71,7 @@ RawImage::RawImage(cv::Mat &img)
|
|||||||
{
|
{
|
||||||
m_img = img;
|
m_img = img;
|
||||||
m_stats = false;
|
m_stats = false;
|
||||||
|
scaleToUnit();
|
||||||
}
|
}
|
||||||
|
|
||||||
RawImage::RawImage(const RawImage &d)
|
RawImage::RawImage(const RawImage &d)
|
||||||
@@ -378,3 +383,18 @@ bool RawImage::pixel(int x, int y, QVector3D &rgb) const
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RawImage::scaleToUnit()
|
||||||
|
{
|
||||||
|
if(CV_MAT_DEPTH(m_img.type()) == CV_32F)
|
||||||
|
{
|
||||||
|
double min, max;
|
||||||
|
cv::minMaxIdx(m_img, &min, &max);
|
||||||
|
if(min < 0 || max > 1)
|
||||||
|
{
|
||||||
|
float scale = 1.0 / (max - min);
|
||||||
|
float zero = min * scale;
|
||||||
|
m_img = m_img * scale - zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+4
-3
@@ -10,9 +10,9 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
|
||||||
const int THUMB_SIZE = 128;
|
extern int THUMB_SIZE;
|
||||||
const int THUMB_SIZE_BORDER = 138;
|
extern int THUMB_SIZE_BORDER;
|
||||||
const int THUMB_SIZE_BORDER_Y = 158;
|
extern int THUMB_SIZE_BORDER_Y;
|
||||||
|
|
||||||
class Peak
|
class Peak
|
||||||
{
|
{
|
||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
float thumbAspect() const;
|
float thumbAspect() const;
|
||||||
const cv::Mat& mat() const;
|
const cv::Mat& mat() const;
|
||||||
bool pixel(int x, int y, QVector3D &rgb) const;
|
bool pixel(int x, int y, QVector3D &rgb) const;
|
||||||
|
void scaleToUnit();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RAWIMAGE_H
|
#endif // RAWIMAGE_H
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<file>invert.png</file>
|
<file>invert.png</file>
|
||||||
<file>nuke.png</file>
|
<file>nuke.png</file>
|
||||||
<file>bayer.png</file>
|
<file>bayer.png</file>
|
||||||
<file>org.nou.tenmon.png</file>
|
<file>space.nouspiro.tenmon.png</file>
|
||||||
<file>nuke_a.png</file>
|
<file>nuke_a.png</file>
|
||||||
<file>about/tenmon</file>
|
<file>about/tenmon</file>
|
||||||
<file>about/pcl</file>
|
<file>about/pcl</file>
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include "settingsdialog.h"
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QSettings>
|
||||||
|
#include "rawimage.h"
|
||||||
|
|
||||||
|
extern int DEFAULT_WIDTH;
|
||||||
|
|
||||||
|
class EvenNumber : public QSpinBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit EvenNumber(QWidget *parent) : QSpinBox(parent){}
|
||||||
|
protected:
|
||||||
|
QValidator::State validate(QString &text, int &) const
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
int val = text.toInt(&ok);
|
||||||
|
if(ok && (val & 1) == 0)return QValidator::Acceptable;
|
||||||
|
if(ok)return QValidator::Intermediate;
|
||||||
|
return QValidator::Invalid;
|
||||||
|
}
|
||||||
|
void fixup(QString &input) const
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
int val = input.toInt(&ok);
|
||||||
|
val -= val & 1;
|
||||||
|
input = QString::number(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
|
||||||
|
{
|
||||||
|
QFormLayout *layout = new QFormLayout(this);
|
||||||
|
setWindowTitle(tr("Settings"));
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
m_preloadImages = new QSpinBox(this);
|
||||||
|
m_preloadImages->setRange(0, 8);
|
||||||
|
m_preloadImages->setValue(settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt());
|
||||||
|
m_preloadImages->setToolTip(tr("How many images are preloaded before and after current image."));
|
||||||
|
|
||||||
|
m_thumSize = new EvenNumber(this);
|
||||||
|
m_thumSize->setRange(64, 512);
|
||||||
|
m_thumSize->setSingleStep(2);
|
||||||
|
m_thumSize->setValue(settings.value("settings/thumnailsize", THUMB_SIZE).toInt());
|
||||||
|
m_thumSize->setToolTip(tr("Thumbnail size in pixels"));
|
||||||
|
|
||||||
|
layout->addRow(tr("Image preload count"), m_preloadImages);
|
||||||
|
layout->addRow(tr("Thumbnails size"), m_thumSize);
|
||||||
|
layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart.")));
|
||||||
|
|
||||||
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
|
||||||
|
buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
connect(this, &QDialog::accepted, this, &SettingsDialog::saveSettings);
|
||||||
|
|
||||||
|
layout->addRow(buttonBox);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::loadSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
THUMB_SIZE = settings.value("settings/thumbnailsize", THUMB_SIZE).toInt();
|
||||||
|
THUMB_SIZE_BORDER = THUMB_SIZE + 10;
|
||||||
|
THUMB_SIZE_BORDER_Y = THUMB_SIZE + 30;
|
||||||
|
DEFAULT_WIDTH = settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::saveSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue("settings/thumbnailsize", m_thumSize->value());
|
||||||
|
settings.setValue("settings/preloadimagecount", m_preloadImages->value());
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef SETTINGSDIALOG_H
|
||||||
|
#define SETTINGSDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
|
class SettingsDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SettingsDialog(QWidget *parent = nullptr);
|
||||||
|
static void loadSettings();
|
||||||
|
private:
|
||||||
|
void saveSettings();
|
||||||
|
|
||||||
|
QSpinBox *m_preloadImages;
|
||||||
|
QSpinBox *m_thumSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGSDIALOG_H
|
||||||
@@ -4,9 +4,17 @@ uniform sampler2D qt_Texture0;
|
|||||||
uniform vec3 mtf_param;
|
uniform vec3 mtf_param;
|
||||||
uniform bool bw;
|
uniform bool bw;
|
||||||
uniform bool invert;
|
uniform bool invert;
|
||||||
|
uniform bool srgb;
|
||||||
in vec2 qt_TexCoord0;
|
in vec2 qt_TexCoord0;
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
vec3 Linear2sRGB(vec3 color)
|
||||||
|
{
|
||||||
|
return mix(12.92 * color.rgb,
|
||||||
|
1.055 * pow(color, vec3(1.0 / 2.4)) - 0.055,
|
||||||
|
greaterThan(color, vec3(0.0031308)));
|
||||||
|
}
|
||||||
|
|
||||||
vec4 MTF(vec4 x, vec3 m)
|
vec4 MTF(vec4 x, vec3 m)
|
||||||
{
|
{
|
||||||
x = (x - m.x) / (m.z - m.x);
|
x = (x - m.x) / (m.z - m.x);
|
||||||
@@ -14,6 +22,12 @@ vec4 MTF(vec4 x, vec3 m)
|
|||||||
return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y);
|
return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 checker()
|
||||||
|
{
|
||||||
|
vec2 pattern = fract(gl_FragCoord.xy * 0.0625) - 0.5;
|
||||||
|
return vec3(step(pattern.x * pattern.y, 0.0) * 0.25 + 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
color = texture(qt_Texture0, qt_TexCoord0);
|
color = texture(qt_Texture0, qt_TexCoord0);
|
||||||
@@ -22,6 +36,10 @@ void main(void)
|
|||||||
|
|
||||||
if(invert)color = vec4(1.0) - color;
|
if(invert)color = vec4(1.0) - color;
|
||||||
|
|
||||||
|
color.rgb = mix(checker(), color.rgb, color.a);
|
||||||
|
|
||||||
|
if(srgb)color.rgb = Linear2sRGB(color.rgb);
|
||||||
|
|
||||||
if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0))))
|
if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0))))
|
||||||
color = vec4(0.0, 0.0, 0.0, 1.0);
|
color = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -7,13 +7,14 @@ out vec3 qt_TexCoord0;
|
|||||||
uniform ivec3 viewport_row;
|
uniform ivec3 viewport_row;
|
||||||
uniform mat4 mvp;
|
uniform mat4 mvp;
|
||||||
uniform vec2 offset;
|
uniform vec2 offset;
|
||||||
|
uniform ivec3 thumb_size;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
vec2 pos = qt_Vertex * 0.5;
|
vec2 pos = qt_Vertex * 0.5;
|
||||||
pos.y *= -1.0;
|
pos.y *= -1.0;
|
||||||
pos = pos * imageSize_num.xy + 69;
|
pos = pos * imageSize_num.xy + thumb_size.x;
|
||||||
ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * ivec2(138, 158);
|
ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * thumb_size.yz;
|
||||||
|
|
||||||
gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0);
|
gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0);
|
||||||
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
|
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Exec=tenmon %U
|
Exec=tenmon %U
|
||||||
Icon=org.nou.tenmon
|
Icon=space.nouspiro.tenmon
|
||||||
Comment=FITS Image viewer
|
Comment=FITS Image viewer
|
||||||
Name=Tenmon
|
Name=Tenmon
|
||||||
Categories=Graphics;2DGraphics;RasterGraphics;Viewer;
|
Categories=Graphics;2DGraphics;RasterGraphics;Viewer;Science;Astronomy
|
||||||
MimeType=image/fits;image/x-xisf;
|
MimeType=image/fits;image/x-xisf;
|
||||||
Terminal=false
|
Terminal=false
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop">
|
||||||
|
<id>space.nouspiro.tenmon</id>
|
||||||
|
<launchable type="desktop-id">space.nouspiro.tenmon.desktop</launchable>
|
||||||
|
<name>Tenmon</name>
|
||||||
|
<summary>FITS/XISF image viewer, converter, index and search</summary>
|
||||||
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
|
<project_license>GPL-3.0</project_license>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
It is intended primarily for viewing astro photos and images. It supports the following formats:
|
||||||
|
<ul>
|
||||||
|
<li>FITS 8, 16 bit integer and 32 bit float</li>
|
||||||
|
<li>XISF 8, 16 bit integer and 32 bit float</li>
|
||||||
|
<li>JPEG, PNG, BMP, GIF, PBM, PGM, PPM and SVG images</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Features:
|
||||||
|
<ul>
|
||||||
|
<li>Using same stretch function as PixInsight</li>
|
||||||
|
<li>OpenGL accelerated drawing</li>
|
||||||
|
<li>Index and search FITS XISF header data</li>
|
||||||
|
<li>Quick mark images and then copy/move marked files</li>
|
||||||
|
<li>Convert FITS <-> XISF</li>
|
||||||
|
<li>Convert FITS/XISF -> JPEG/PNG</li>
|
||||||
|
<li>Image statistics mean, media, min, max</li>
|
||||||
|
<li>Support for WCS</li>
|
||||||
|
<li>Thumbnails</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
<url type="homepage">https://nouspiro.space/?page_id=206</url>
|
||||||
|
<screenshots>
|
||||||
|
<screenshot type="default">
|
||||||
|
<image>https://nouspiro.space/wp-content/uploads/2022/04/tenmon-1024x579.png</image>
|
||||||
|
</screenshot>
|
||||||
|
</screenshots>
|
||||||
|
<content_rating type="oars-1.1"/>
|
||||||
|
<releases>
|
||||||
|
<release version="20221209" date="2022-12-09"/>
|
||||||
|
<release version="20221126" date="2022-11-26"/>
|
||||||
|
<release version="20221121" date="2022-11-11"/>
|
||||||
|
<release version="20221023" date="2022-10-23"/>
|
||||||
|
</releases>
|
||||||
|
</component>
|
||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="128"
|
||||||
|
height="128"
|
||||||
|
viewBox="0 0 33.866666 33.866668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg5"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
sodipodi:docname="space.nouspiro.tenmon.svg"
|
||||||
|
inkscape:export-filename="/home/nou/c++/tenmon/space.nouspiro.tenmon_128.png"
|
||||||
|
inkscape:export-xdpi="96.000008"
|
||||||
|
inkscape:export-ydpi="96.000008"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
width="128px"
|
||||||
|
inkscape:zoom="2.6547419"
|
||||||
|
inkscape:cx="54.430903"
|
||||||
|
inkscape:cy="78.162024"
|
||||||
|
inkscape:window-width="1862"
|
||||||
|
inkscape:window-height="1136"
|
||||||
|
inkscape:window-x="58"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Vrstva 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke:#ffffff;stroke-width:0;stroke-linejoin:round"
|
||||||
|
id="rect1196"
|
||||||
|
width="33.866665"
|
||||||
|
height="33.866665"
|
||||||
|
x="5e-07"
|
||||||
|
y="5e-07" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:17.276px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.359917"
|
||||||
|
x="-0.41414261"
|
||||||
|
y="23.331123"
|
||||||
|
id="text8592"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan8590"
|
||||||
|
style="fill:#ffffff;stroke-width:0.359917"
|
||||||
|
x="-0.41414261"
|
||||||
|
y="23.331123">天文</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -1,9 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
Exec=Tenmon %U
|
|
||||||
Icon=org.nou.tenmon
|
|
||||||
Comment=FITS Image viewer
|
|
||||||
Name=Tenmon
|
|
||||||
Categories=Graphics;2DGraphics;RasterGraphics;Viewer;
|
|
||||||
MimeType=image/fits;image/x-xisf;
|
|
||||||
Terminal=false
|
|
||||||
Binary file not shown.
@@ -71,6 +71,10 @@
|
|||||||
<source>Go up</source>
|
<source>Go up</source>
|
||||||
<translation>Go up</translation>
|
<translation>Go up</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show hidden files</source>
|
||||||
|
<translation>Show hidden files</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>HelpDialog</name>
|
<name>HelpDialog</name>
|
||||||
@@ -300,7 +304,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
||||||
<translation>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
<translation type="vanished">JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reindex files</source>
|
<source>Reindex files</source>
|
||||||
@@ -320,7 +324,51 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
||||||
<translation>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
<translation type="vanished">Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit</source>
|
||||||
|
<translation>Edit</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS header editor</source>
|
||||||
|
<translation type="vanished">FITS header editor</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Settings</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Images (</source>
|
||||||
|
<translation>Images (</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS (*.fits *.fit);;XISF (*.xisf);;</source>
|
||||||
|
<translation>FITS image (*.fits *.fit);;XISF image (*.xisf);;</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy</source>
|
||||||
|
<translation>Failed to copy</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move</source>
|
||||||
|
<translation>Failed to move</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy %1 from to %2</source>
|
||||||
|
<translation type="vanished">Failed to copy from %1 to %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2</source>
|
||||||
|
<translation>Failed to move from %1 to %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy from %1 to %2</source>
|
||||||
|
<translation>Failed to copy from %1 to %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2ˇ</source>
|
||||||
|
<translation type="obsolete">Failed to move from %1 to %2ˇ {1 ?}</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -420,6 +468,33 @@
|
|||||||
<translation>Select columns</translation>
|
<translation>Select columns</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SettingsDialog</name>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Settings</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>How many images are preloaded before and after current image.</source>
|
||||||
|
<translation>How many images are preloaded before and after current image.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnail size in pixels</source>
|
||||||
|
<translation>Thumbnail size in pixels</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Image preload count</source>
|
||||||
|
<translation>Image preload count</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnails size</source>
|
||||||
|
<translation>Thumbnails size</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Changes in settings will take effect after program restart.</source>
|
||||||
|
<translation>Changes in settings will take effect after program restart.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>StretchToolbar</name>
|
<name>StretchToolbar</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
Binary file not shown.
@@ -71,6 +71,10 @@
|
|||||||
<source>Go up</source>
|
<source>Go up</source>
|
||||||
<translation>Monter</translation>
|
<translation>Monter</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show hidden files</source>
|
||||||
|
<translation>Afficher les fichiers cachés</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>HelpDialog</name>
|
<name>HelpDialog</name>
|
||||||
@@ -300,7 +304,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
||||||
<translation>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
<translation type="vanished">JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reindex files</source>
|
<source>Reindex files</source>
|
||||||
@@ -320,7 +324,51 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
||||||
<translation>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
<translation type="vanished">Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit</source>
|
||||||
|
<translation>Éditer</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS header editor</source>
|
||||||
|
<translation type="vanished">Éditeur d'en-tête FITS</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Réglages</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Images (</source>
|
||||||
|
<translation>Images (</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS (*.fits *.fit);;XISF (*.xisf);;</source>
|
||||||
|
<translation>FITS image (*.fits *.fit);;XISF image (*.xisf);;</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy</source>
|
||||||
|
<translation type="unfinished">Échec de la copie</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move</source>
|
||||||
|
<translation type="unfinished">Échec du déplacement</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy %1 from to %2</source>
|
||||||
|
<translation type="obsolete">Échec de la copie de %1 vers %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2</source>
|
||||||
|
<translation type="unfinished">Échec du déplacement de %1 vers %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy from %1 to %2</source>
|
||||||
|
<translation type="unfinished">Échec de la copie de %1 vers %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2ˇ</source>
|
||||||
|
<translation type="obsolete">Échec du déplacement de %1 vers %2ˇ {1 ?}</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -420,6 +468,33 @@
|
|||||||
<translation>Choix des colonnes</translation>
|
<translation>Choix des colonnes</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SettingsDialog</name>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Réglages</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>How many images are preloaded before and after current image.</source>
|
||||||
|
<translation>Combien d'images sont préchargées avant et après l'image courante.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnail size in pixels</source>
|
||||||
|
<translation>Taille des vignettes en pixels</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Image preload count</source>
|
||||||
|
<translation>Nombre d'images préchargées</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnails size</source>
|
||||||
|
<translation>Taille des vignette</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Changes in settings will take effect after program restart.</source>
|
||||||
|
<translation>Les changements de paramètres prendront effet après le redémarrage du programme.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>StretchToolbar</name>
|
<name>StretchToolbar</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
Binary file not shown.
@@ -72,6 +72,10 @@
|
|||||||
<source>Go up</source>
|
<source>Go up</source>
|
||||||
<translation>O úroveň vyššie</translation>
|
<translation>O úroveň vyššie</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show hidden files</source>
|
||||||
|
<translation>Zobraz skryté súbory</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>HelpDialog</name>
|
<name>HelpDialog</name>
|
||||||
@@ -313,7 +317,7 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
<source>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</source>
|
||||||
<translation>JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
<translation type="vanished">JPEG (*.jpg *.JPG);; PNG (*.png *.PNG);;FITS (*.fits *.FITS);;XISF (*.xisf *.XISF)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reindex files</source>
|
<source>Reindex files</source>
|
||||||
@@ -333,7 +337,51 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
<source>Images (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</source>
|
||||||
<translation>Obrázky (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
<translation type="vanished">Obrázky (*.jpg *.jpeg *.png *.cr2 *.nef *.dng *.fit *.fits *.xisf *.JPG *.JPEG *.PNG *.CR2 *.NEF *.DNG *.FIT *.FITS *.XISF)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit</source>
|
||||||
|
<translation>Upraviť</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS header editor</source>
|
||||||
|
<translation type="vanished">Editor FITS hlavičky</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Nastavenia</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Images (</source>
|
||||||
|
<translation>Obrázky (</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>FITS (*.fits *.fit);;XISF (*.xisf);;</source>
|
||||||
|
<translation>Obrázok FITS (*.fits *.fit);;Obrázok XISF (*.xisf);;</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy</source>
|
||||||
|
<translation>Zlyhalo kopírovanie</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move</source>
|
||||||
|
<translation>Zlyhalo presúvanie</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy %1 from to %2</source>
|
||||||
|
<translation type="vanished">Zlyhalo kopírovanie z %1 do %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2</source>
|
||||||
|
<translation>Zlyhalo presúvanie z %1 do %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to copy from %1 to %2</source>
|
||||||
|
<translation>Zlyhalo kopírovanie z %1 do %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Failed to move from %1 to %2ˇ</source>
|
||||||
|
<translation type="obsolete">Zlyhalo presúvanie z %1 do %2ˇ {1 ?}</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@@ -433,6 +481,33 @@
|
|||||||
<translation>Výber stĺpcov</translation>
|
<translation>Výber stĺpcov</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SettingsDialog</name>
|
||||||
|
<message>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation>Nastavenia</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>How many images are preloaded before and after current image.</source>
|
||||||
|
<translation>Koľko obrázkov sa prednačíta pred a za aktuálnym obrázkom.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnail size in pixels</source>
|
||||||
|
<translation>Veľkosť náhľadu v pixeloch</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Image preload count</source>
|
||||||
|
<translation>Počet prednačítaných obrázkov</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Thumbnails size</source>
|
||||||
|
<translation>Veľkosť náhľadu</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Changes in settings will take effect after program restart.</source>
|
||||||
|
<translation>Zmeny v nastaveniach sa prejavia po reštarte programu.</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>StretchToolbar</name>
|
<name>StretchToolbar</name>
|
||||||
<message>
|
<message>
|
||||||
|
|||||||
Reference in New Issue
Block a user