Compare commits

..

8 Commits

Author SHA1 Message Date
nou d288810d5d Fix saving image 2024-08-16 15:16:37 +02:00
nou fb66e82428 Workaround for huge PCL keywords 2024-08-16 15:04:25 +02:00
nou 71486efeef Remove unused method 2024-06-17 09:47:56 +02:00
nou 8213f6213f Fix convert scripts 2024-06-17 09:44:48 +02:00
nou f8c9fec77e Add scripts 2024-06-16 16:31:53 +02:00
nou af4be850cb Embeded scripts 2024-06-16 00:14:51 +02:00
nou ca1a13ed9d Solve deprectation warnings 2024-06-15 17:45:30 +02:00
nou 1873da6c49 Fix issue in thumbnails 2024-06-11 17:09:35 +02:00
13 changed files with 169 additions and 42 deletions
+1
View File
@@ -61,6 +61,7 @@ endif(COLOR_MANAGMENT)
qt_add_resources(TENMON_SRC resources/resources.qrc)
qt_add_resources(TENMON_SRC shaders/shaders.qrc)
qt_add_resources(TENMON_SRC scripts/scripts.qrc)
if(WIN32)
list(APPEND TENMON_SRC resources/icon.rc)
set(tenmon_ICON "")
+10 -1
View File
@@ -57,7 +57,10 @@ void BatchProcessing::scanScriptDir()
_ui->scriptsList->clear();
QDir dir(_scriptBasePath);
QDir embededDir(":/scripts");
QStringList scripts = dir.entryList(QDir::Files | QDir::Readable);
scripts.append(embededDir.entryList(QDir::Files));
scripts.removeDuplicates();
_ui->scriptsList->addItems(scripts);
int idx = scripts.indexOf(current);
@@ -207,7 +210,13 @@ void BatchProcessing::runScript()
QFileInfo outDir(_ui->outputPath->text());
if(outDir.exists() && outDir.isWritable())
{
_engineThread->setParams(_scriptBasePath + selectedItems.first()->text(), scanDirectories(paths), _ui->outputPath->text());
QString script = selectedItems.first()->text();
if(QDir(_scriptBasePath).exists(script))
script = _scriptBasePath + script;
else
script = ":/scripts/" + script;
_engineThread->setParams(script, scanDirectories(paths), _ui->outputPath->text());
_engineThread->start();
_ui->startButton->setEnabled(false);
_ui->stopButton->setEnabled(true);
+1
View File
@@ -286,6 +286,7 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
for(int i=0; i<3; i++)
{
m_filterKeyword[i] = new QComboBox(this);
m_filterKeyword[i]->setMaximumWidth(300);
addFilterItems(m_filterKeyword[i], fitsKeywords);
+1 -8
View File
@@ -188,12 +188,6 @@ void ImageWidget::bestFit()
setOffset(0, 0);
}
void ImageWidget::blockRepaint(bool block)
{
m_blockRepaint = block;
if(!block)update();
}
void ImageWidget::allocateThumbnails(const QStringList &paths)
{
makeCurrent();
@@ -323,8 +317,6 @@ void ImageWidget::showThumbnail(bool enable)
void ImageWidget::paintGL()
{
if(m_blockRepaint)return;
float dx = m_dx;
float dy = m_dy;
if(m_width > m_image->width() * m_scale)
@@ -333,6 +325,7 @@ void ImageWidget::paintGL()
dy = -height() * 0.5f + m_image->height() * m_scale * 0.5f;
QBrush highlight = style()->standardPalette().highlight();
f->glClear(GL_COLOR_BUFFER_BIT);
if(m_showThumbnails)
{
m_vaoThumb->bind();
-2
View File
@@ -53,7 +53,6 @@ class ImageWidget : public QOpenGLWidget
float m_scale = 1.0f;
int m_scaleStop = 0;
bool m_bestFit = false;
bool m_blockRepaint = false;
bool m_bwImg = false;
bool m_falseColor = false;
bool m_invert = false;
@@ -78,7 +77,6 @@ public:
void setWCS(std::shared_ptr<WCSData> wcs);
void zoom(int zoom, const QPointF &mousePos = QPointF());
void bestFit();
void blockRepaint(bool block);
void allocateThumbnails(const QStringList &paths);
QVector2D getImagePixelCoord(const QVector2D &pos);
void setBayerMask(int mask);
+1 -1
Submodule libXISF updated: 922d4b73c9...d00de2041d
+29 -29
View File
@@ -143,22 +143,22 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(m_imageGL->imageWidget(), &ImageWidget::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
QMenu *fileMenu = new QMenu(tr("File"), this);
fileMenu->addAction(tr("Open"), this, SLOT(loadFile()), QKeySequence::Open);
fileMenu->addAction(tr("Open"), QKeySequence::Open, this, SLOT(loadFile()));
fileMenu->addAction(tr("Open directory recursively"), this, &MainWindow::loadDir);
fileMenu->addAction(tr("Save as"), this, SLOT(saveAs()), QKeySequence::Save);
fileMenu->addAction(tr("Save as"), QKeySequence::Save, this, SLOT(saveAs()));
fileMenu->addSeparator();
fileMenu->addAction(tr("Copy marked files"), this, SLOT(copyMarked()), Qt::Key_F5);
fileMenu->addAction(tr("Move marked files"), this, SLOT(moveMarked()), Qt::Key_F6);
fileMenu->addAction(tr("Move marked files to trash"), this, &MainWindow::deleteMarked, QKeySequence::Delete);
fileMenu->addAction(tr("Copy marked files"), Qt::Key_F5, this, SLOT(copyMarked()));
fileMenu->addAction(tr("Move marked files"), Qt::Key_F6, this, SLOT(moveMarked()));
fileMenu->addAction(tr("Move marked files to trash"), QKeySequence::Delete, this, &MainWindow::deleteMarked);
fileMenu->addSeparator();
fileMenu->addAction(tr("Index directory"), this, SLOT(indexDir()));
fileMenu->addAction(tr("Reindex files"), this, SLOT(reindex()));
fileMenu->addAction(tr("Export database to CSV"), this, &MainWindow::exportCSV);
fileMenu->addAction(tr("Batch processing"), [this](){
fileMenu->addAction(tr("Batch processing"), Qt::Key_B | Qt::CTRL, [this](){
BatchProcessing *batchProcessing = new BatchProcessing(this);
batchProcessing->exec();
delete batchProcessing;
}, Qt::Key_B | Qt::CTRL);
});
fileMenu->addSeparator();
QAction *liveModeAction = fileMenu->addAction(tr("Live mode"), this, SLOT(liveMode(bool)));
liveModeAction->setCheckable(true);
@@ -171,9 +171,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
menuBar()->addMenu(editMenu);
QMenu *viewMenu = new QMenu(tr("View"), this);
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("Best Fit"), m_imageGL, SLOT(bestFit()), QKeySequence("Ctrl+1"));
viewMenu->addAction(tr("Zoom In"), QKeySequence::ZoomIn, m_imageGL, SLOT(zoomIn()));
viewMenu->addAction(tr("Zoom Out"), QKeySequence::ZoomOut, m_imageGL, SLOT(zoomOut()));
viewMenu->addAction(tr("Best Fit"), QKeySequence("Ctrl+1"), m_imageGL, SLOT(bestFit()));
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
viewMenu->addSeparator();
QMenu *bayerMenu = viewMenu->addMenu(tr("Bayer mask"));
@@ -195,28 +195,28 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
settings.setValue("mainwindow/bayermask", data);
});
QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), [this](bool checked){
QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), Qt::Key_F2, [this](bool checked){
if(SettingsDialog::loadThumbsizes())m_ringList->clearThumbnails();
m_imageGL->imageWidget()->allocateThumbnails(m_ringList->imageNames());
m_imageGL->imageWidget()->showThumbnail(checked);
if(checked)m_ringList->loadThumbnails();
else m_ringList->stopLoading();
}, Qt::Key_F2);
});
thumbnailsAction->setCheckable(true);
QAction *slideshowAction = viewMenu->addAction(tr("Slideshow"), m_ringList, &ImageRingList::toggleSlideshow, Qt::Key_F3);
QAction *slideshowAction = viewMenu->addAction(tr("Slideshow"), Qt::Key_F3, m_ringList, &ImageRingList::toggleSlideshow);
slideshowAction->setCheckable(true);
menuBar()->addMenu(viewMenu);
QMenu *selectMenu = new QMenu(tr("Select"), this);
selectMenu->addAction(tr("Mark"), this, SLOT(markImage()), Qt::Key_F7);
selectMenu->addAction(tr("Unmark"), this, SLOT(unmarkImage()), Qt::Key_F8);
selectMenu->addAction(tr("Mark"), Qt::Key_F7, this, SLOT(markImage()));
selectMenu->addAction(tr("Unmark"), Qt::Key_F8, this, SLOT(unmarkImage()));
selectMenu->addSeparator();
selectMenu->addAction(tr("Mark and next"), this, SLOT(markAndNext()), Qt::Key_M);
selectMenu->addAction(tr("Unmark and next"), this, SLOT(unmarkAndNext()), Qt::Key_X);
selectMenu->addAction(tr("Mark and next"), Qt::Key_M, this, SLOT(markAndNext()));
selectMenu->addAction(tr("Unmark and next"), Qt::Key_X, this, SLOT(unmarkAndNext()));
selectMenu->addAction(tr("Show marked"), this, &MainWindow::showMarkFilesDialog);
menuBar()->addMenu(selectMenu);
QMenu *analyzeMenu = new QMenu(tr("Analyze"), this);
/*QMenu *analyzeMenu = new QMenu(tr("Analyze"), this);
QActionGroup *analyzeGroup = new QActionGroup(this);
connect(analyzeGroup, &QActionGroup::triggered, [](QAction* action) {
static QAction* lastAction = nullptr;
@@ -239,7 +239,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(peakAction, SIGNAL(toggled(bool)), this, SLOT(peakFinder(bool)));
connect(starAction, SIGNAL(toggled(bool)), this, SLOT(starFinder(bool)));
analyzeMenu->addActions({statsAction, peakAction, starAction});
//menuBar()->addMenu(analyzeMenu);
menuBar()->addMenu(analyzeMenu);*/
QMenu *dockMenu = new QMenu(tr("Docks"), this);
dockMenu->addAction(infoDock->toggleViewAction());
@@ -251,7 +251,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
menuBar()->addMenu(dockMenu);
QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
helpMenu->addAction(tr("Help"), [this]{ HelpDialog help(this); help.exec(); }, QKeySequence::HelpContents);
helpMenu->addAction(tr("Help"), QKeySequence::HelpContents, [this]{ HelpDialog help(this); help.exec(); });
helpMenu->addAction(tr("About Tenmon"), [this]{ About about(this); about.exec(); });
helpMenu->addAction(tr("About Qt"), [this](){ QMessageBox::aboutQt(this); });
@@ -536,21 +536,21 @@ void MainWindow::saveAs()
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(!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())
{
QString format = filterToFormat(file, selectedFilter);
if(format == "FITS" || format == "XISF")
if(format == "fits" || format == "xisf")
{
convert(file, format);
}
+18
View File
@@ -0,0 +1,18 @@
core.log("This script convert any FITS file into XISF with ZSTD compression");
if(files.length == 0)
{
core.log("No input files");
throw "";
}
let compression = {"compressionType": "zstd+sh"};
for(file of files)
{
if(file.suffix() == "fits" || file.suffix() == "fit")
{
core.log("Converting " + file.fileName());
file.convertAsync(file.relativeFilePath(), "XISF", compression);
}
}
+36
View File
@@ -0,0 +1,36 @@
// how to get input from user
let d = core.getFloat("Getting float value");
let i = core.getInt("Getting integer value");
let s = core.getString("Getting string value");
// print user input
core.log("Your input " + d + " " + i + " " + s);
for(file of files)
{
if(file.suffix() == "fits" || file.suffix() == "fit" || file.suffix() == "xisf")
{
let keywords = file.fitsKeywords();
let item = core.getItem(keywords, "Select keyword");
core.log("You selected keyword " + item); core.log(file.fitsKeywords());
core.log("fileName() " + file.fileName());
core.log("absoluteFilePath() " + file.absoluteFilePath());
core.log("absolutePath() " + file.absolutePath());
core.log("relativeFilePath() " + file.relativeFilePath());
core.log("relativePath() " + file.relativePath());
core.log("baseName() " + file.baseName());
core.log("completeBase() " + file.completeBaseName());
core.log("suffix() " + file.suffix());
core.log("size() " + file.size());
let stats = file.stats();
core.log("Image statistics");
core.log("\tMinimum: " + stats.min);
core.log("\tMaximum: " + stats.max);
core.log("\tMedian:" + stats.median);
core.log("\tStandard deviation:" + stats.stddev);
core.log("\tMedian Absolute Deviation:" + stats.mad);
break;
}
}
+8
View File
@@ -0,0 +1,8 @@
for(file of files)
{
if(file.suffix() == "fits" || file.suffix() == "fit" || file.suffix() == "xisf")
{
let stats = file.stats();
core.log("File: \"" + file.fileName() + "\" - median: " + stats.median);
}
}
+50
View File
@@ -0,0 +1,50 @@
function checkFITS(key)
{
const noEditableKey = ["SIMPLE", "BITPIX", "NAXIS", "NAXIS1", "NAXIS2", "NAXIS3", "EXTEND", "BZERO", "BSCALE"];
return noEditableKey.indexOf(key) < 0;
}
if(files.length == 0)
{
core.log("No input files");
throw "";
}
let action = core.getItem(["UPDATE", "ADD", "REMOVE"], "Do you want update, add or remove record?");
let modify = new FITSRecordModify();
if(action == "UPDATE")
{
let keywords = files[0].fitsKeywords().filter(checkFITS);
let keyword = core.getItem(keywords, "Select keyword to update");
let value = files[0].fitsValue(keyword);
if(isNaN(value))
value = core.getString("Enter new value", value);
else
value = core.getFloat("Enter new value", value);
modify.updateKeyword(keyword, value);
}
else if(action == "ADD")
{
let keyword = core.getString("Enter keyword to add");
let value = core.getString("Enter new value");
keyword = keyword.toUpperCase();
modify.addKeyword(keyword, value);
}
else if(action == "REMOVE")
{
let keywords = files[0].fitsKeywords().filter(checkFITS);
let keyword = core.getItem(keywords, "Select keyword to remove");
modify.removeKeyword(keyword);
}
for(file of files)
{
if(file.suffix() == "fits" || file.suffix() == "fit" || file.suffix() == "xisf")
{
core.log("Modifing " + file.fileName());
file.modifyFITSRecords(modify);
}
}
+8
View File
@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/scripts">
<file>example script</file>
<file>convert to XISF</file>
<file>median</file>
<file>modify FITS header</file>
</qresource>
</RCC>
+6 -1
View File
@@ -57,7 +57,12 @@
</screenshots>
<content_rating type="oars-1.1"/>
<releases>
<release version="20240610" date="2024-06-10">
<release version="20240816" date="2024-08-16">
<description>
Fix saving image
</description>
</release>
<release version="20240616" date="2024-06-16">
<description>
<ul>
<li>Batch processing with JavaScript</li>