Compare commits
4 Commits
85f9822b96
...
90026f931f
| Author | SHA1 | Date | |
|---|---|---|---|
| 90026f931f | |||
| eee4613b25 | |||
| 24a9e96bbf | |||
| 5af5f4f068 |
+2
-2
@@ -17,7 +17,7 @@ if(SANITIZE_ADDRESS_LEAK)
|
|||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak")
|
||||||
endif(SANITIZE_ADDRESS_LEAK)
|
endif(SANITIZE_ADDRESS_LEAK)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Widgets Sql OpenGLWidgets Qml REQUIRED)
|
find_package(Qt6 COMPONENTS Widgets Sql OpenGLWidgets Qml Charts REQUIRED)
|
||||||
find_library(EXIF_LIB exif REQUIRED)
|
find_library(EXIF_LIB exif REQUIRED)
|
||||||
find_library(FITS_LIB cfitsio REQUIRED)
|
find_library(FITS_LIB cfitsio REQUIRED)
|
||||||
find_library(RAW_LIB NAMES raw_r REQUIRED)
|
find_library(RAW_LIB NAMES raw_r REQUIRED)
|
||||||
@@ -102,7 +102,7 @@ if(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
|||||||
message(STATUS "Found stellarsolver ${STELLARSOLVER_INCLUDE} ${STELLARSOLVER_LIB}")
|
message(STATUS "Found stellarsolver ${STELLARSOLVER_INCLUDE} ${STELLARSOLVER_LIB}")
|
||||||
endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
||||||
|
|
||||||
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} ${LCMS2_LIB} XISF)
|
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml Qt6::Charts ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} ${LCMS2_LIB} XISF)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
|
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
|
|||||||
+48
-13
@@ -10,6 +10,9 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
#include <QChart>
|
||||||
|
#include <QChartView>
|
||||||
|
#include <QLineSeries>
|
||||||
#include "scriptengine.h"
|
#include "scriptengine.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
@@ -180,19 +183,7 @@ void BatchProcessing::browse()
|
|||||||
|
|
||||||
void BatchProcessing::openScriptDir()
|
void BatchProcessing::openScriptDir()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
openDir(_scriptBasePath);
|
||||||
QDBusConnection con = QDBusConnection::sessionBus();
|
|
||||||
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1", "ShowFolders");
|
|
||||||
QList<QVariant> args = {QStringList(QUrl::fromLocalFile(_scriptBasePath).toString()), QString()};
|
|
||||||
message.setArguments(args);
|
|
||||||
con.call(message);
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_WINDOWS
|
|
||||||
QProcess::startDetached("explorer.exe", {QDir::toNativeSeparators(_scriptBasePath)});
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(_scriptBasePath));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchProcessing::runScript()
|
void BatchProcessing::runScript()
|
||||||
@@ -279,3 +270,47 @@ QJSValue BatchProcessing::getItem(const QStringList &items, const QString &label
|
|||||||
QString ret = QInputDialog::getItem(this, tr("Select item"), label, items, current, false, &ok);
|
QString ret = QInputDialog::getItem(this, tr("Select item"), label, items, current, false, &ok);
|
||||||
return ok ? ret : QJSValue();
|
return ok ? ret : QJSValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::plot(const QVector<QPointF> &points)
|
||||||
|
{
|
||||||
|
QDialog *diag = new QDialog(this);
|
||||||
|
diag->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
diag->setModal(false);
|
||||||
|
diag->setWindowTitle(tr("Chart"));
|
||||||
|
|
||||||
|
QChartView *chartView = new QChartView(diag);
|
||||||
|
diag->setLayout(new QVBoxLayout);
|
||||||
|
diag->layout()->addWidget(chartView);
|
||||||
|
|
||||||
|
QChart *chart = new QChart;
|
||||||
|
chart->setParent(chartView);
|
||||||
|
|
||||||
|
auto series = new QLineSeries(chartView);
|
||||||
|
series->append(points);
|
||||||
|
chart->addSeries(series);
|
||||||
|
chart->createDefaultAxes();
|
||||||
|
chart->setTitle("Simple line graph");
|
||||||
|
chart->legend()->hide();
|
||||||
|
|
||||||
|
chartView->setChart(chart);
|
||||||
|
chartView->setRenderHint(QPainter::Antialiasing);
|
||||||
|
diag->resize(640, 480);
|
||||||
|
diag->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void openDir(const QString &path)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QDBusConnection con = QDBusConnection::sessionBus();
|
||||||
|
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1", "ShowFolders");
|
||||||
|
QList<QVariant> args = {QStringList(QUrl::fromLocalFile(path).toString()), QString()};
|
||||||
|
message.setArguments(args);
|
||||||
|
con.call(message);
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
QProcess::startDetached("explorer.exe", {QDir::toNativeSeparators(path)});
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ public slots:
|
|||||||
QJSValue getInt(const QString &label, int value);
|
QJSValue getInt(const QString &label, int value);
|
||||||
QJSValue getFloat(const QString &label, double value, int decimals);
|
QJSValue getFloat(const QString &label, double value, int decimals);
|
||||||
QJSValue getItem(const QStringList &items, const QString &label, int current);
|
QJSValue getItem(const QStringList &items, const QString &label, int current);
|
||||||
|
|
||||||
|
void plot(const QVector<QPointF> &points);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void openDir(const QString &path);
|
||||||
|
|
||||||
#endif // BATCHPROCESSING_H
|
#endif // BATCHPROCESSING_H
|
||||||
|
|||||||
+18
-1
@@ -10,6 +10,7 @@
|
|||||||
#include <QContextMenuEvent>
|
#include <QContextMenuEvent>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "batchprocessing.h"
|
||||||
|
|
||||||
const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};
|
const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};
|
||||||
|
|
||||||
@@ -214,6 +215,8 @@ void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
|
|||||||
QMenu menu;
|
QMenu menu;
|
||||||
QAction *mark = menu.addAction(tr("Mark"));
|
QAction *mark = menu.addAction(tr("Mark"));
|
||||||
QAction *unmark = menu.addAction(tr("Unmark"));
|
QAction *unmark = menu.addAction(tr("Unmark"));
|
||||||
|
QAction *open = menu.addAction(tr("Open"));
|
||||||
|
QAction *openDirAction = menu.addAction(tr("Open file location"));
|
||||||
|
|
||||||
QAction *a = menu.exec(event->globalPos());
|
QAction *a = menu.exec(event->globalPos());
|
||||||
if(a == nullptr)
|
if(a == nullptr)
|
||||||
@@ -225,7 +228,10 @@ void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
|
|||||||
emit filesMarked(indexes);
|
emit filesMarked(indexes);
|
||||||
else if(a == unmark)
|
else if(a == unmark)
|
||||||
emit filesUnmarked(indexes);
|
emit filesUnmarked(indexes);
|
||||||
|
else if(a == open)
|
||||||
|
emit openFile(indexes);
|
||||||
|
else if(a == openDirAction)
|
||||||
|
emit openDir(indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
|
DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
|
||||||
@@ -270,6 +276,17 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
|
|||||||
m_database->unmark(files);
|
m_database->unmark(files);
|
||||||
m_model->filesUnmarked(indexes);
|
m_model->filesUnmarked(indexes);
|
||||||
});
|
});
|
||||||
|
connect(m_tableView, &DatabaseTableView::openFile, [this](QModelIndexList indexes){
|
||||||
|
if(indexes.size())
|
||||||
|
emit loadFile(m_model->data(indexes.front().siblingAtColumn(0)).toString());
|
||||||
|
});
|
||||||
|
connect(m_tableView, &DatabaseTableView::openDir, [this](QModelIndexList indexes){
|
||||||
|
if(indexes.size())
|
||||||
|
{
|
||||||
|
QFileInfo info(m_model->data(indexes.front().siblingAtColumn(0)).toString());
|
||||||
|
openDir(info.absolutePath());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
auto addFilterItems = [](QComboBox *combobox, const QStringList &fitsKeywords)
|
auto addFilterItems = [](QComboBox *combobox, const QStringList &fitsKeywords)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ protected:
|
|||||||
signals:
|
signals:
|
||||||
void filesMarked(QModelIndexList indexes);
|
void filesMarked(QModelIndexList indexes);
|
||||||
void filesUnmarked(QModelIndexList indexes);
|
void filesUnmarked(QModelIndexList indexes);
|
||||||
|
void openFile(QModelIndexList indexes);
|
||||||
|
void openDir(QModelIndexList indexes);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataBaseView : public QWidget
|
class DataBaseView : public QWidget
|
||||||
|
|||||||
+11
-28
@@ -118,9 +118,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
navigationToolbar->setObjectName("navigationtoolbar");
|
navigationToolbar->setObjectName("navigationtoolbar");
|
||||||
navigationToolbar->hide();
|
navigationToolbar->hide();
|
||||||
QAction *prevAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowLeft), tr("Previous image"));
|
QAction *prevAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowLeft), tr("Previous image"));
|
||||||
|
prevAction->setShortcuts({Qt::Key_Left, Qt::Key_Up});
|
||||||
QAction *nextAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowRight), tr("Next image"));
|
QAction *nextAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowRight), tr("Next image"));
|
||||||
QAction *prevSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowUp), tr("Prev sub image"));
|
nextAction->setShortcuts({Qt::Key_Right, Qt::Key_Down});
|
||||||
QAction *nextSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowDown), tr("Next sub image"));
|
QAction *prevSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowUp), tr("Prev sub image"), Qt::Key_PageUp);
|
||||||
|
QAction *nextSubAction = navigationToolbar->addAction(style()->standardIcon(QStyle::SP_ArrowDown), tr("Next sub image"), Qt::Key_PageDown);
|
||||||
connect(prevAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::decrement));
|
connect(prevAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::decrement));
|
||||||
connect(nextAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::increment));
|
connect(nextAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::increment));
|
||||||
connect(prevSubAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::prevSubImage));
|
connect(prevSubAction, &QAction::triggered, m_ringList, static_cast<void (ImageRingList::*)()>(&ImageRingList::prevSubImage));
|
||||||
@@ -195,6 +197,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
editMenu->addAction(tr("Settings"), this, &MainWindow::showSettingsDialog);
|
editMenu->addAction(tr("Settings"), this, &MainWindow::showSettingsDialog);
|
||||||
menuBar()->addMenu(editMenu);
|
menuBar()->addMenu(editMenu);
|
||||||
|
|
||||||
|
QMenu *navigationMenu = new QMenu(tr("Navigation"), this);
|
||||||
|
navigationMenu->addAction(prevAction);
|
||||||
|
navigationMenu->addAction(nextAction);
|
||||||
|
navigationMenu->addAction(prevSubAction);
|
||||||
|
navigationMenu->addAction(nextSubAction);
|
||||||
|
menuBar()->addMenu(navigationMenu);
|
||||||
|
|
||||||
QMenu *viewMenu = new QMenu(tr("View"), this);
|
QMenu *viewMenu = new QMenu(tr("View"), this);
|
||||||
viewMenu->addAction(tr("Zoom In"), QKeySequence::ZoomIn, m_image, &ImageScrollArea::zoomIn);
|
viewMenu->addAction(tr("Zoom In"), QKeySequence::ZoomIn, m_image, &ImageScrollArea::zoomIn);
|
||||||
viewMenu->addAction(tr("Zoom Out"), QKeySequence::ZoomOut, m_image, &ImageScrollArea::zoomOut);
|
viewMenu->addAction(tr("Zoom Out"), QKeySequence::ZoomOut, m_image, &ImageScrollArea::zoomOut);
|
||||||
@@ -359,32 +368,6 @@ MainWindow::~MainWindow()
|
|||||||
delete m_database;
|
delete m_database;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::keyPressEvent(QKeyEvent *event)
|
|
||||||
{
|
|
||||||
switch (event->key())
|
|
||||||
{
|
|
||||||
case Qt::Key_Left:
|
|
||||||
case Qt::Key_Up:
|
|
||||||
m_ringList->decrement();
|
|
||||||
break;
|
|
||||||
case Qt::Key_Right:
|
|
||||||
case Qt::Key_Down:
|
|
||||||
m_ringList->increment();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
event->ignore();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event->isAccepted())
|
|
||||||
updateWindowTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::keyReleaseEvent(QKeyEvent *event)
|
|
||||||
{
|
|
||||||
event->ignore();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::setupSigterm()
|
void MainWindow::setupSigterm()
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ public:
|
|||||||
MainWindow(QWidget *parent = 0);
|
MainWindow(QWidget *parent = 0);
|
||||||
~MainWindow() override;
|
~MainWindow() override;
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
|
||||||
void keyReleaseEvent(QKeyEvent *event) override;
|
|
||||||
void setupSigterm();
|
void setupSigterm();
|
||||||
static void signalHandler(int);
|
static void signalHandler(int);
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|||||||
@@ -134,6 +134,21 @@ QJSValue ScriptEngine::getItem(const QStringList &items, const QString &label, i
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::plot(const QJSValue &pointsArray)
|
||||||
|
{
|
||||||
|
if(pointsArray.isArray())
|
||||||
|
{
|
||||||
|
int len = pointsArray.property("length").toInt();
|
||||||
|
QVector<QPointF> points;
|
||||||
|
for(int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
QJSValue point = pointsArray.property(i);
|
||||||
|
points.append(QPointF(point.property("x").toNumber(), point.property("y").toNumber()));
|
||||||
|
}
|
||||||
|
QMetaObject::invokeMethod(_parent, "plot", Qt::QueuedConnection, Q_ARG(QVector<QPointF>, points));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ScriptEngine::convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async)
|
bool ScriptEngine::convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async)
|
||||||
{
|
{
|
||||||
QString path;
|
QString path;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public:
|
|||||||
Q_INVOKABLE QJSValue getInt(const QString &label = QString(), int value = 0);
|
Q_INVOKABLE QJSValue getInt(const QString &label = QString(), int value = 0);
|
||||||
Q_INVOKABLE QJSValue getFloat(const QString &label = QString(), double value = 0, int decimals = 3) const;
|
Q_INVOKABLE QJSValue getFloat(const QString &label = QString(), double value = 0, int decimals = 3) const;
|
||||||
Q_INVOKABLE QJSValue getItem(const QStringList &items, const QString &label = "", int current = 0) const;
|
Q_INVOKABLE QJSValue getItem(const QStringList &items, const QString &label = "", int current = 0) const;
|
||||||
|
Q_INVOKABLE void plot(const QJSValue &pointsArray);
|
||||||
bool convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async);
|
bool convert(File *file, QString &outpath, const QString &format, const QVariantMap ¶ms, bool async);
|
||||||
#ifdef PLATESOLVER
|
#ifdef PLATESOLVER
|
||||||
Q_INVOKABLE void setSolverProfile(int index);
|
Q_INVOKABLE void setSolverProfile(int index);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ if(BUILD_THUMBNAILER)
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_library(tenmonthumbnailer SHARED
|
add_library(tenmonthumbnailer SHARED
|
||||||
Dll.cpp
|
Dll.cpp
|
||||||
loadxisf.cpp
|
loadimage.cpp
|
||||||
TenmonThumbnailProvider.cpp
|
TenmonThumbnailProvider.cpp
|
||||||
../rawimage.h
|
../rawimage.h
|
||||||
../rawimage.cpp
|
../rawimage.cpp
|
||||||
@@ -13,19 +13,19 @@ if(BUILD_THUMBNAILER)
|
|||||||
|
|
||||||
target_compile_definitions(tenmonthumbnailer PRIVATE NO_QT)
|
target_compile_definitions(tenmonthumbnailer PRIVATE NO_QT)
|
||||||
target_include_directories(tenmonthumbnailer PRIVATE ../libXISF)
|
target_include_directories(tenmonthumbnailer PRIVATE ../libXISF)
|
||||||
target_link_libraries(tenmonthumbnailer PRIVATE shlwapi ${LCMS2_LIB} ${FITS_LIB} XISF)
|
target_link_libraries(tenmonthumbnailer PRIVATE shlwapi ${FITS_LIB} XISF)
|
||||||
target_link_options(tenmonthumbnailer PRIVATE "-static")
|
target_link_options(tenmonthumbnailer PRIVATE "-static")
|
||||||
else(WIN32)
|
else(WIN32)
|
||||||
qt_add_executable(tenmonthumbnailer
|
qt_add_executable(tenmonthumbnailer
|
||||||
main.cpp
|
main.cpp
|
||||||
../loadimage.cpp
|
loadimage.cpp
|
||||||
../rawimage.cpp
|
../rawimage.cpp
|
||||||
../rawimage_sse.cpp
|
../rawimage_sse.cpp)
|
||||||
../imageinfodata.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(tenmonthumbnailer PRIVATE Qt6::Core Qt6::Gui ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} ${LCMS2_LIB} XISF)
|
target_link_libraries(tenmonthumbnailer PRIVATE ${FITS_LIB} XISF)
|
||||||
|
|
||||||
target_include_directories(tenmonthumbnailer PRIVATE ../libXISF)
|
target_include_directories(tenmonthumbnailer PRIVATE ../libXISF)
|
||||||
|
target_compile_definitions(tenmonthumbnailer PRIVATE NO_QT)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
endif(BUILD_THUMBNAILER)
|
endif(BUILD_THUMBNAILER)
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,87 @@
|
|||||||
#include <thumbcache.h> // For IThumbnailProvider.
|
#include <thumbcache.h> // For IThumbnailProvider.
|
||||||
#include <new>
|
#include <new>
|
||||||
#include "libxisf.h"
|
#include "libxisf.h"
|
||||||
|
#include "../rawimage.h"
|
||||||
|
|
||||||
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
bool loadXISF(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage);
|
||||||
bool loadFITS(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
bool loadFITS(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage);
|
||||||
|
|
||||||
|
void RawImageToHTBITMAP(std::shared_ptr<RawImage> &rawImage, HBITMAP *hbmp, UINT thumbSize)
|
||||||
|
{
|
||||||
|
rawImage->calcStats();
|
||||||
|
|
||||||
|
DWORD thre = 20;
|
||||||
|
DWORD dataSize = 4;
|
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\nou\\Tenmon\\settings", L"thumbnailstretchthreshold", RRF_RT_DWORD, NULL, &thre, &dataSize));
|
||||||
|
|
||||||
|
float thref = 0.1f;
|
||||||
|
if(hr == S_OK)
|
||||||
|
thref = thre / 100.0f;
|
||||||
|
|
||||||
|
if(rawImage->imageStats().m_median[0] < rawImage->norm() * thref)
|
||||||
|
{
|
||||||
|
//OutputDebugStringA("Stretch image");
|
||||||
|
MTFParam params = rawImage->calcMTFParams();
|
||||||
|
rawImage->applySTF(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT w = rawImage->width();
|
||||||
|
UINT h = rawImage->height();
|
||||||
|
|
||||||
|
UINT cw = thumbSize;
|
||||||
|
UINT ch = thumbSize;
|
||||||
|
if (w > h)
|
||||||
|
ch = h * thumbSize / w;
|
||||||
|
else
|
||||||
|
cw = w * thumbSize / h;
|
||||||
|
|
||||||
|
|
||||||
|
rawImage->resize(cw, ch);
|
||||||
|
rawImage->convertToType(RawImage::UINT8);
|
||||||
|
|
||||||
|
BITMAPINFO bmi = {};
|
||||||
|
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||||||
|
bmi.bmiHeader.biWidth = cw;
|
||||||
|
bmi.bmiHeader.biHeight = -static_cast<LONG>(ch);
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 32;
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
UINT lw = cw * 4;
|
||||||
|
|
||||||
|
BYTE *pBits;
|
||||||
|
HBITMAP bmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&pBits), NULL, 0);
|
||||||
|
|
||||||
|
const unsigned char *p = (const unsigned char*)rawImage->data();
|
||||||
|
const unsigned short *ps = (const unsigned short*)rawImage->data();
|
||||||
|
if(rawImage->channels() == 1)
|
||||||
|
{
|
||||||
|
for(UINT y = 0; y < ch; y++)
|
||||||
|
{
|
||||||
|
for(UINT x = 0; x < cw; x++)
|
||||||
|
{
|
||||||
|
pBits[(y * lw) + x * 4 + 0] = p[y * cw + x];
|
||||||
|
pBits[(y * lw) + x * 4 + 1] = p[y * cw + x];
|
||||||
|
pBits[(y * lw) + x * 4 + 2] = p[y * cw + x];
|
||||||
|
pBits[(y * lw) + x * 4 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(UINT y = 0; y < ch; y++)
|
||||||
|
{
|
||||||
|
for(UINT x = 0; x < cw; x++)
|
||||||
|
{
|
||||||
|
pBits[(y * lw) + x * 4 + 0] = p[y * cw * 4 + x * 4 + 2];
|
||||||
|
pBits[(y * lw) + x * 4 + 1] = p[y * cw * 4 + x * 4 + 1];
|
||||||
|
pBits[(y * lw) + x * 4 + 2] = p[y * cw * 4 + x * 4 + 0];
|
||||||
|
pBits[(y * lw) + x * 4 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*hbmp = bmp;
|
||||||
|
}
|
||||||
|
|
||||||
class TenmonThumbProvider : public IInitializeWithStream,
|
class TenmonThumbProvider : public IInitializeWithStream,
|
||||||
public IThumbnailProvider
|
public IThumbnailProvider
|
||||||
@@ -103,19 +181,19 @@ IFACEMETHODIMP TenmonThumbProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_AL
|
|||||||
*pdwAlpha = WTSAT_RGB;
|
*pdwAlpha = WTSAT_RGB;
|
||||||
|
|
||||||
data.resize(readSize);
|
data.resize(readSize);
|
||||||
|
|
||||||
|
std::shared_ptr<RawImage> rawImage;
|
||||||
if(data[0] == 'X' && data[1] == 'I' && data[2] == 'S' && data[3] == 'F')
|
if(data[0] == 'X' && data[1] == 'I' && data[2] == 'S' && data[3] == 'F')
|
||||||
{
|
{
|
||||||
if(loadXISF(data, phbmp, cx))
|
if(!loadXISF(data, rawImage))
|
||||||
return S_OK;
|
|
||||||
else
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(loadFITS(data, phbmp, cx))
|
if(!loadFITS(data, rawImage))
|
||||||
return S_OK;
|
|
||||||
else
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
return E_FAIL;
|
|
||||||
|
RawImageToHTBITMAP(rawImage, phbmp, cx);
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
#include "libxisf.h"
|
||||||
|
#include "../rawimage.h"
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
#include <fitsio2.h>
|
||||||
|
|
||||||
|
bool OpenGLES = false;
|
||||||
|
|
||||||
|
bool loadXISF(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LibXISF::XISFReader xisf;
|
||||||
|
xisf.open(data);
|
||||||
|
|
||||||
|
const LibXISF::Image &xisfImage = xisf.getImage(0);
|
||||||
|
|
||||||
|
RawImage::DataType type;
|
||||||
|
switch(xisfImage.sampleFormat())
|
||||||
|
{
|
||||||
|
case LibXISF::Image::UInt8: type = RawImage::UINT8; break;
|
||||||
|
case LibXISF::Image::UInt16: type = RawImage::UINT16; break;
|
||||||
|
case LibXISF::Image::UInt32: type = RawImage::UINT32; break;
|
||||||
|
case LibXISF::Image::Float32: type = RawImage::FLOAT32; break;
|
||||||
|
case LibXISF::Image::Float64: type = RawImage::FLOAT64; break;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibXISF::Image tmpImage = xisfImage;
|
||||||
|
tmpImage.convertPixelStorageTo(LibXISF::Image::Planar);
|
||||||
|
|
||||||
|
if(tmpImage.colorSpace() == LibXISF::Image::ColorSpace::Gray)
|
||||||
|
{
|
||||||
|
rawImage = std::make_shared<RawImage>(tmpImage.width(), tmpImage.height(), 1, type);
|
||||||
|
std::memcpy(rawImage->data(), tmpImage.imageData(), tmpImage.imageDataSize() / tmpImage.channelCount());
|
||||||
|
}
|
||||||
|
else if(tmpImage.channelCount() == 3 || tmpImage.channelCount() == 4)
|
||||||
|
{
|
||||||
|
rawImage = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (LibXISF::Error &err)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
char text[1024];
|
||||||
|
sprintf_s(text, 1000, "Failed to open XISF image %s", err.what());
|
||||||
|
OutputDebugStringA(text);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadFITS(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage)
|
||||||
|
{
|
||||||
|
fitsfile *file;
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
int hdutype = -1;
|
||||||
|
int num = 0;
|
||||||
|
long naxes[3] = {0};
|
||||||
|
|
||||||
|
auto checkError = [&status]()
|
||||||
|
{
|
||||||
|
char err[100];
|
||||||
|
fits_get_errstatus(status, err);
|
||||||
|
#ifdef WIN32
|
||||||
|
char text[1000];
|
||||||
|
sprintf_s(text, 1000, "Failed to load FITS file %s", err);
|
||||||
|
OutputDebugStringA(text);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const void *dataPtr = data.data();
|
||||||
|
size_t size = data.size();
|
||||||
|
fits_open_memfile(&file, "file.fits", READONLY, (void**)&dataPtr, &size, 0, nullptr, &status);
|
||||||
|
if(status)return checkError();
|
||||||
|
fits_get_num_hdus(file, &num, &status);
|
||||||
|
if(status)return checkError();
|
||||||
|
|
||||||
|
int imgtype;
|
||||||
|
int naxis;
|
||||||
|
for(int i=1; i <= num; i++)
|
||||||
|
{
|
||||||
|
fits_movabs_hdu(file, i, &hdutype, &status);if(status)return checkError();
|
||||||
|
if(hdutype == IMAGE_HDU)
|
||||||
|
{
|
||||||
|
naxes[0] = naxes[1] = naxes[2] = 0;
|
||||||
|
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);if(status)return checkError();
|
||||||
|
fits_get_img_equivtype(file, &imgtype, &status);if(status)return checkError();
|
||||||
|
|
||||||
|
if(hdutype == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0)
|
||||||
|
{
|
||||||
|
RawImage::DataType type;
|
||||||
|
int fitstype;
|
||||||
|
long fpixel[3] = {1,1,1};
|
||||||
|
switch(imgtype)
|
||||||
|
{
|
||||||
|
case BYTE_IMG:
|
||||||
|
type = RawImage::UINT8;
|
||||||
|
fitstype = TBYTE;
|
||||||
|
break;
|
||||||
|
case SHORT_IMG:
|
||||||
|
type = RawImage::UINT16;
|
||||||
|
fitstype = TSHORT;
|
||||||
|
break;
|
||||||
|
case USHORT_IMG:
|
||||||
|
type = RawImage::UINT16;
|
||||||
|
fitstype = TUSHORT;
|
||||||
|
break;
|
||||||
|
case ULONG_IMG:
|
||||||
|
type = RawImage::UINT32;
|
||||||
|
fitstype = TUINT;
|
||||||
|
break;
|
||||||
|
case FLOAT_IMG:
|
||||||
|
type = RawImage::FLOAT32;
|
||||||
|
fitstype = TFLOAT;
|
||||||
|
break;
|
||||||
|
case DOUBLE_IMG:
|
||||||
|
type = RawImage::FLOAT64;
|
||||||
|
fitstype = TDOUBLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = naxes[0]*naxes[1];
|
||||||
|
size_t w = naxes[0];
|
||||||
|
size_t h = naxes[1];
|
||||||
|
|
||||||
|
RawImage img(w, h, naxis == 2 ? 1 : naxes[2], type);
|
||||||
|
uint8_t *data = static_cast<uint8_t*>(img.data());
|
||||||
|
for (int i=1; i==1 || i<=naxes[2]; i++)
|
||||||
|
{
|
||||||
|
fpixel[2] = i;
|
||||||
|
fits_read_pix(file, fitstype, fpixel, size, NULL, data + img.size() * RawImage::typeSize(type) * (i-1), NULL, &status);
|
||||||
|
if(status)return checkError();
|
||||||
|
}
|
||||||
|
if(fitstype == TSHORT)
|
||||||
|
{
|
||||||
|
uint16_t *s = static_cast<uint16_t*>(img.data());
|
||||||
|
size_t size = img.size() * img.channels();
|
||||||
|
for(size_t i=0; i<size; i++)
|
||||||
|
s[i] -= INT16_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(img.channels() == 1)
|
||||||
|
rawImage = std::make_shared<RawImage>(std::move(img));
|
||||||
|
else
|
||||||
|
rawImage = RawImage::fromPlanar(img);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
#include "libxisf.h"
|
|
||||||
#include <thumbcache.h>
|
|
||||||
#include "../rawimage.h"
|
|
||||||
#include <fitsio2.h>
|
|
||||||
|
|
||||||
bool OpenGLES = false;
|
|
||||||
|
|
||||||
void RawImageToHTBITMAP(std::shared_ptr<RawImage> &rawImage, HBITMAP *hbmp, UINT thumbSize)
|
|
||||||
{
|
|
||||||
rawImage->calcStats();
|
|
||||||
|
|
||||||
DWORD thre = 10;
|
|
||||||
DWORD dataSize = 4;
|
|
||||||
//HRESULT hr = HRESULT_FROM_WIN32(RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\nou\\Tenmon\\settings", L"thumbnailstretchthreshold", RRF_RT_DWORD, NULL, &thre, &dataSize));
|
|
||||||
|
|
||||||
float thref = 0.1f;
|
|
||||||
/*if(hr == S_OK)
|
|
||||||
thref = thre / 100.0f;*/
|
|
||||||
|
|
||||||
if(rawImage->imageStats().m_mean[0] < rawImage->norm() * thref)
|
|
||||||
{
|
|
||||||
//OutputDebugStringA("Stretch image");
|
|
||||||
MTFParam params = rawImage->calcMTFParams();
|
|
||||||
rawImage->applySTF(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
UINT w = rawImage->width();
|
|
||||||
UINT h = rawImage->height();
|
|
||||||
|
|
||||||
UINT cw = thumbSize;
|
|
||||||
UINT ch = thumbSize;
|
|
||||||
if (w > h)
|
|
||||||
ch = h * thumbSize / w;
|
|
||||||
else
|
|
||||||
cw = w * thumbSize / h;
|
|
||||||
|
|
||||||
|
|
||||||
rawImage->resize(cw, ch);
|
|
||||||
rawImage->convertToType(RawImage::UINT8);
|
|
||||||
|
|
||||||
BITMAPINFO bmi = {};
|
|
||||||
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
|
||||||
bmi.bmiHeader.biWidth = cw;
|
|
||||||
bmi.bmiHeader.biHeight = -static_cast<LONG>(ch);
|
|
||||||
bmi.bmiHeader.biPlanes = 1;
|
|
||||||
bmi.bmiHeader.biBitCount = 32;
|
|
||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
|
||||||
UINT lw = cw * 4;
|
|
||||||
|
|
||||||
BYTE *pBits;
|
|
||||||
HBITMAP bmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&pBits), NULL, 0);
|
|
||||||
|
|
||||||
const unsigned char *p = (const unsigned char*)rawImage->data();
|
|
||||||
const unsigned short *ps = (const unsigned short*)rawImage->data();
|
|
||||||
if(rawImage->channels() == 1)
|
|
||||||
{
|
|
||||||
for(UINT y = 0; y < ch; y++)
|
|
||||||
{
|
|
||||||
for(UINT x = 0; x < cw; x++)
|
|
||||||
{
|
|
||||||
pBits[(y * lw) + x * 4 + 0] = p[y * cw + x];
|
|
||||||
pBits[(y * lw) + x * 4 + 1] = p[y * cw + x];
|
|
||||||
pBits[(y * lw) + x * 4 + 2] = p[y * cw + x];
|
|
||||||
pBits[(y * lw) + x * 4 + 3] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(UINT y = 0; y < ch; y++)
|
|
||||||
{
|
|
||||||
for(UINT x = 0; x < cw; x++)
|
|
||||||
{
|
|
||||||
pBits[(y * lw) + x * 4 + 0] = p[y * cw * 4 + x * 4 + 2];
|
|
||||||
pBits[(y * lw) + x * 4 + 1] = p[y * cw * 4 + x * 4 + 1];
|
|
||||||
pBits[(y * lw) + x * 4 + 2] = p[y * cw * 4 + x * 4 + 0];
|
|
||||||
pBits[(y * lw) + x * 4 + 3] = 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*hbmp = bmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LibXISF::XISFReader xisf;
|
|
||||||
xisf.open(data);
|
|
||||||
|
|
||||||
const LibXISF::Image &xisfImage = xisf.getImage(0);
|
|
||||||
|
|
||||||
RawImage::DataType type;
|
|
||||||
switch(xisfImage.sampleFormat())
|
|
||||||
{
|
|
||||||
case LibXISF::Image::UInt8: type = RawImage::UINT8; break;
|
|
||||||
case LibXISF::Image::UInt16: type = RawImage::UINT16; break;
|
|
||||||
case LibXISF::Image::UInt32: type = RawImage::UINT32; break;
|
|
||||||
case LibXISF::Image::Float32: type = RawImage::FLOAT32; break;
|
|
||||||
case LibXISF::Image::Float64: type = RawImage::FLOAT64; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LibXISF::Image tmpImage = xisfImage;
|
|
||||||
tmpImage.convertPixelStorageTo(LibXISF::Image::Planar);
|
|
||||||
std::shared_ptr<RawImage> rawImage;
|
|
||||||
|
|
||||||
if(tmpImage.colorSpace() == LibXISF::Image::ColorSpace::Gray)
|
|
||||||
{
|
|
||||||
rawImage = std::make_shared<RawImage>(tmpImage.width(), tmpImage.height(), 1, type);
|
|
||||||
std::memcpy(rawImage->data(), tmpImage.imageData(), tmpImage.imageDataSize() / tmpImage.channelCount());
|
|
||||||
}
|
|
||||||
else if(tmpImage.channelCount() == 3 || tmpImage.channelCount() == 4)
|
|
||||||
{
|
|
||||||
rawImage = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
RawImageToHTBITMAP(rawImage, hbmp, thumbSize);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (LibXISF::Error &err)
|
|
||||||
{
|
|
||||||
char text[1024];
|
|
||||||
sprintf_s(text, 1000, "Failed to open XISF image %s", err.what());
|
|
||||||
OutputDebugStringA(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadFITS(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
|
||||||
{
|
|
||||||
fitsfile *file;
|
|
||||||
|
|
||||||
int status = 0;
|
|
||||||
int type = -1;
|
|
||||||
int num = 0;
|
|
||||||
long naxes[3] = {0};
|
|
||||||
|
|
||||||
auto checkError = [&status]()
|
|
||||||
{
|
|
||||||
char err[100];
|
|
||||||
char text[1000];
|
|
||||||
fits_get_errstatus(status, err);
|
|
||||||
sprintf_s(text, 1000, "Failed to load FITS file %s", err);
|
|
||||||
OutputDebugStringA(text);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const void *dataPtr = data.data();
|
|
||||||
size_t size = data.size();
|
|
||||||
fits_open_memfile(&file, "file.fits", READONLY, (void**)&dataPtr, &size, 0, nullptr, &status);
|
|
||||||
if(status)return checkError();
|
|
||||||
fits_get_num_hdus(file, &num, &status);
|
|
||||||
if(status)return checkError();
|
|
||||||
|
|
||||||
int imgtype;
|
|
||||||
int naxis;
|
|
||||||
for(int i=1; i <= num; i++)
|
|
||||||
{
|
|
||||||
fits_movabs_hdu(file, i, IMAGE_HDU, &status);if(status)return checkError();
|
|
||||||
fits_get_hdu_type(file, &type, &status);if(status)return checkError();
|
|
||||||
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);if(status)return checkError();
|
|
||||||
fits_get_img_equivtype(file, &imgtype, &status);if(status)return checkError();
|
|
||||||
|
|
||||||
if(type == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0)
|
|
||||||
{
|
|
||||||
RawImage::DataType type;
|
|
||||||
int fitstype;
|
|
||||||
long fpixel[3] = {1,1,1};
|
|
||||||
switch(imgtype)
|
|
||||||
{
|
|
||||||
case BYTE_IMG:
|
|
||||||
type = RawImage::UINT8;
|
|
||||||
fitstype = TBYTE;
|
|
||||||
break;
|
|
||||||
case SHORT_IMG:
|
|
||||||
type = RawImage::UINT16;
|
|
||||||
fitstype = TSHORT;
|
|
||||||
break;
|
|
||||||
case USHORT_IMG:
|
|
||||||
type = RawImage::UINT16;
|
|
||||||
fitstype = TUSHORT;
|
|
||||||
break;
|
|
||||||
case ULONG_IMG:
|
|
||||||
type = RawImage::UINT32;
|
|
||||||
fitstype = TUINT;
|
|
||||||
break;
|
|
||||||
case FLOAT_IMG:
|
|
||||||
type = RawImage::FLOAT32;
|
|
||||||
fitstype = TFLOAT;
|
|
||||||
break;
|
|
||||||
case DOUBLE_IMG:
|
|
||||||
type = RawImage::FLOAT64;
|
|
||||||
fitstype = TDOUBLE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size = naxes[0]*naxes[1];
|
|
||||||
size_t w = naxes[0];
|
|
||||||
size_t h = naxes[1];
|
|
||||||
|
|
||||||
RawImage img(w, h, naxis == 2 ? 1 : naxes[2], type);
|
|
||||||
uint8_t *data = static_cast<uint8_t*>(img.data());
|
|
||||||
for (int i=1; i==1 || i<=naxes[2]; i++)
|
|
||||||
{
|
|
||||||
fpixel[2] = i;
|
|
||||||
fits_read_pix(file, fitstype, fpixel, size, NULL, data + img.size() * RawImage::typeSize(type) * (i-1), NULL, &status);
|
|
||||||
if(status)return checkError();
|
|
||||||
}
|
|
||||||
if(fitstype == TSHORT)
|
|
||||||
{
|
|
||||||
uint16_t *s = static_cast<uint16_t*>(img.data());
|
|
||||||
size_t size = img.size() * img.channels();
|
|
||||||
for(size_t i=0; i<size; i++)
|
|
||||||
s[i] -= INT16_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<RawImage> image;
|
|
||||||
if(img.channels() == 1)
|
|
||||||
image = std::make_shared<RawImage>(std::move(img));
|
|
||||||
else
|
|
||||||
image = RawImage::fromPlanar(img);
|
|
||||||
|
|
||||||
RawImageToHTBITMAP(image, hbmp, thumbSize);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
+53
-35
@@ -1,62 +1,80 @@
|
|||||||
#include <QCoreApplication>
|
#include <vector>
|
||||||
#include <QCommandLineParser>
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
#include "../rawimage.h"
|
#include "../rawimage.h"
|
||||||
#include "../loadimage.h"
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "stb_image_write.h"
|
||||||
|
|
||||||
bool OpenGLES = false;
|
bool loadXISF(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage);
|
||||||
|
bool loadFITS(const LibXISF::ByteArray &data, std::shared_ptr<RawImage> &rawImage);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication a(argc, argv);
|
std::vector<std::string> args;
|
||||||
|
for(int i=0; i<argc; i++)
|
||||||
|
args.push_back(argv[i]);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
if(args.size() < 3)
|
||||||
parser.addOption({{"s", "size"}, "Size of the thumbnail in pixels (default: 128)", "size", "128"});
|
|
||||||
parser.addPositionalArgument("input", "Input image file");
|
|
||||||
parser.addPositionalArgument("output", "Output image file");
|
|
||||||
parser.addHelpOption();
|
|
||||||
|
|
||||||
parser.process(a);
|
|
||||||
|
|
||||||
QStringList args = parser.positionalArguments();
|
|
||||||
|
|
||||||
if(args.size() < 2)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
QString input = args[0];
|
std::string input = args[1];
|
||||||
QString output = args[1];
|
std::string output = args[2];
|
||||||
|
|
||||||
ImageInfoData info;
|
|
||||||
std::shared_ptr<RawImage> rawImage;
|
std::shared_ptr<RawImage> rawImage;
|
||||||
if(!loadImage(input, info, rawImage))
|
|
||||||
|
LibXISF::ByteArray data;
|
||||||
|
std::ifstream fr;
|
||||||
|
fr.open(input, std::ios_base::in | std::ios_base::binary);
|
||||||
|
if(!fr.is_open())
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
if(!rawImage)
|
fr.seekg(0, std::ios_base::end);
|
||||||
|
size_t len = fr.tellg();
|
||||||
|
fr.seekg(0, std::ios_base::beg);
|
||||||
|
data.resize(len);
|
||||||
|
fr.read(data.data(), len);
|
||||||
|
if(fr.bad())
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
bool ok;
|
if(input.find(".xisf") != std::string::npos)
|
||||||
int size = parser.value("s").toInt(&ok);
|
{
|
||||||
if(!ok)
|
if(!loadXISF(data, rawImage))
|
||||||
size = 128;
|
return 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!loadFITS(data, rawImage))
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!rawImage)
|
||||||
|
return 5;
|
||||||
|
|
||||||
|
uint32_t thumbSize = 256;
|
||||||
|
|
||||||
|
uint32_t w = rawImage->width();
|
||||||
|
uint32_t h = rawImage->height();
|
||||||
|
|
||||||
|
uint32_t cw = thumbSize;
|
||||||
|
uint32_t ch = thumbSize;
|
||||||
|
if (w > h)
|
||||||
|
ch = h * thumbSize / w;
|
||||||
|
else
|
||||||
|
cw = w * thumbSize / h;
|
||||||
|
|
||||||
QSize rect(rawImage->width(), rawImage->height());
|
|
||||||
rect.scale(size, size, Qt::KeepAspectRatio);
|
|
||||||
rawImage->calcStats();
|
rawImage->calcStats();
|
||||||
rawImage->resize(rect.width(), rect.height());
|
rawImage->resize(cw, ch);
|
||||||
if(rawImage->imageStats().m_median[0] < rawImage->norm() * 0.2f)
|
if(rawImage->imageStats().m_median[0] < rawImage->norm() * 0.1f)
|
||||||
{
|
{
|
||||||
MTFParam mtfParams = rawImage->calcMTFParams(true);
|
MTFParam mtfParams = rawImage->calcMTFParams(true);
|
||||||
rawImage->applySTF(mtfParams);
|
rawImage->applySTF(mtfParams);
|
||||||
}
|
}
|
||||||
rawImage->convertToType(RawImage::UINT8);
|
rawImage->convertToType(RawImage::UINT8);
|
||||||
|
|
||||||
QImage img;
|
|
||||||
if(rawImage->channels() == 1)
|
if(rawImage->channels() == 1)
|
||||||
img = QImage((const uchar*)rawImage->data(), rawImage->width(), rawImage->height(), rawImage->widthBytes(), QImage::Format_Grayscale8);
|
stbi_write_png(output.c_str(), cw, ch, 1, rawImage->data(), rawImage->widthBytes());
|
||||||
else
|
else
|
||||||
img = QImage((const uchar*)rawImage->data(), rawImage->width(), rawImage->height(), rawImage->widthBytes(), QImage::Format_RGBA8888);
|
stbi_write_png(output.c_str(), cw, ch, 4, rawImage->data(), rawImage->widthBytes());
|
||||||
|
|
||||||
if(!img.save(output, "png"))
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user