Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da1843e48c | |||
| e0d473c8c8 | |||
| 92f9920f24 | |||
| f68a9c4d7c | |||
| 027a38cb42 | |||
| 47d5a9fc96 | |||
| 061bb3892e | |||
| b0b1a3a14b | |||
| ea834ebd16 | |||
| ce836a8ff3 | |||
| a1848b27bf | |||
| fabf3f0c1a | |||
| cba8a0bb9c | |||
| 4e6230eef2 | |||
| 2c95364fc4 | |||
| 26be690c70 | |||
| 56d6db8bc3 |
+28
-7
@@ -15,9 +15,10 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
|
|||||||
find_package(Qt5 COMPONENTS Widgets Sql OpenGL REQUIRED)
|
find_package(Qt5 COMPONENTS Widgets Sql OpenGL REQUIRED)
|
||||||
find_package(OpenCV REQUIRED)
|
find_package(OpenCV REQUIRED)
|
||||||
find_library(GSL_LIB gsl REQUIRED)
|
find_library(GSL_LIB gsl REQUIRED)
|
||||||
|
find_library(GSLCBLAS_LIB gslcblas 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 raw REQUIRED)
|
find_library(RAW_LIB NAMES raw_r REQUIRED)
|
||||||
|
|
||||||
set(TENMON_SRC
|
set(TENMON_SRC
|
||||||
database.cpp
|
database.cpp
|
||||||
@@ -30,32 +31,52 @@ set(TENMON_SRC
|
|||||||
loadrunable.cpp
|
loadrunable.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
|
markedfiles.cpp
|
||||||
rawimage.cpp
|
rawimage.cpp
|
||||||
starfit.cpp
|
starfit.cpp
|
||||||
stfslider.cpp
|
stfslider.cpp
|
||||||
stretchpanel.cpp
|
stretchtoolbar.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
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)
|
||||||
add_compile_definitions("__PCL_WINDOWS")
|
add_compile_definitions("__PCL_WINDOWS")
|
||||||
endif(WIN32)
|
else()
|
||||||
if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
|
|
||||||
add_compile_definitions("__PCL_LINUX")
|
add_compile_definitions("__PCL_LINUX")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(tenmon ${TENMON_SRC})
|
add_executable(tenmon WIN32 ${TENMON_SRC})
|
||||||
|
|
||||||
find_path(FITS_INCLUDE fitsio2.h PATH_SUFFIXES cfitsio REQUIRED)
|
find_path(FITS_INCLUDE fitsio2.h PATH_SUFFIXES cfitsio REQUIRED)
|
||||||
target_include_directories(tenmon PRIVATE ${OpenCV_INCLUDE_DIRS} ${FITS_INCLUDE} 3rdparty/include)
|
target_include_directories(tenmon PRIVATE ${OpenCV_INCLUDE_DIRS} ${FITS_INCLUDE} 3rdparty/include)
|
||||||
|
|
||||||
target_link_libraries(tenmon Qt5::Widgets Qt5::Sql Qt5::OpenGL ${OpenCV_LIBS} ${GSL_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB})
|
if(WIN32)
|
||||||
|
target_link_directories(tenmon PRIVATE 3rdparty/lib/Windows)
|
||||||
|
else()
|
||||||
|
target_link_directories(tenmon PRIVATE 3rdparty/lib/Linux)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_directories(tenmon PRIVATE 3rdparty/lib/${CMAKE_HOST_SYSTEM_NAME})
|
target_link_libraries(tenmon Qt5::Widgets Qt5::Sql ${OpenCV_LIBS} ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB})
|
||||||
target_link_libraries(tenmon PCL lcms lz4 RFC6234 zlib)
|
target_link_libraries(tenmon PCL lcms lz4 RFC6234 zlib)
|
||||||
|
|
||||||
|
if(LIBRAW_STATIC)
|
||||||
|
add_compile_definitions("LIBRAW_NODLL")
|
||||||
|
target_link_libraries(tenmon jasper)
|
||||||
|
endif()
|
||||||
|
|
||||||
install(TARGETS tenmon)
|
install(TARGETS tenmon)
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
find_program(XDG-DESKTOP-MENU_EXECUTABLE xdg-desktop-menu)
|
||||||
|
if(XDG-DESKTOP-MENU_EXECUTABLE)
|
||||||
install(SCRIPT install.cmake)
|
install(SCRIPT install.cmake)
|
||||||
|
else()
|
||||||
|
if(DEFINED ENV{FLATPAK_DEST})
|
||||||
|
install(FILES org.nou.tenmon.desktop DESTINATION "$ENV{FLATPAK_DEST}/share/applications")
|
||||||
|
install(FILES org.nou.tenmon.png DESTINATION "$ENV{FLATPAK_DEST}/share/icons/hicolor/32x32/apps")
|
||||||
|
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(UNIX)
|
endif(UNIX)
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
#version 130
|
#version 330
|
||||||
|
|
||||||
uniform sampler2D qt_Texture0;
|
uniform sampler2D qt_Texture0;
|
||||||
in vec2 qt_TexCoord0;
|
|
||||||
uniform vec3 mtf_param;
|
uniform vec3 mtf_param;
|
||||||
uniform bool bw;
|
uniform bool bw;
|
||||||
uniform bool invert;
|
uniform bool invert;
|
||||||
|
in vec2 qt_TexCoord0;
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
vec4 MTF(vec4 x, vec3 m)
|
vec4 MTF(vec4 x, vec3 m)
|
||||||
@@ -16,7 +16,7 @@ vec4 MTF(vec4 x, vec3 m)
|
|||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
color = texture2D(qt_Texture0, qt_TexCoord0);
|
color = texture(qt_Texture0, qt_TexCoord0);
|
||||||
if(bw)color = color.rrra;
|
if(bw)color = color.rrra;
|
||||||
color = MTF(color, mtf_param);
|
color = MTF(color, mtf_param);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
#version 130
|
#version 330
|
||||||
|
|
||||||
uniform sampler2D qt_Texture0;
|
uniform sampler2D qt_Texture0;
|
||||||
in vec2 qt_Vertex;
|
in vec2 qt_Vertex;
|
||||||
|
|||||||
+54
-4
@@ -8,10 +8,11 @@ using namespace std;
|
|||||||
|
|
||||||
const int DEFAULT_WIDTH = 2;
|
const int DEFAULT_WIDTH = 2;
|
||||||
|
|
||||||
Image::Image(const QString name, ImageRingList *ringList) :
|
Image::Image(const QString name, int number, ImageRingList *ringList) :
|
||||||
m_loading(false),
|
m_loading(false),
|
||||||
m_released(true),
|
m_released(true),
|
||||||
m_current(false),
|
m_current(false),
|
||||||
|
m_number(number),
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_ringList(ringList)
|
m_ringList(ringList)
|
||||||
{
|
{
|
||||||
@@ -29,6 +30,14 @@ void Image::load()
|
|||||||
emit pixmapLoaded(this);
|
emit pixmapLoaded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Image::loadThumbnail(QThreadPool *pool)
|
||||||
|
{
|
||||||
|
if(!m_thumbnail)
|
||||||
|
pool->start(new LoadRunable(m_name, this, AnalyzeLevel::None, true));
|
||||||
|
else
|
||||||
|
emit thumbnailLoaded(this);
|
||||||
|
}
|
||||||
|
|
||||||
void Image::release()
|
void Image::release()
|
||||||
{
|
{
|
||||||
m_rawImage.reset();
|
m_rawImage.reset();
|
||||||
@@ -46,6 +55,11 @@ RawImage *Image::rawImage()
|
|||||||
return m_rawImage.get();
|
return m_rawImage.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RawImage *Image::thumbnail() const
|
||||||
|
{
|
||||||
|
return m_thumbnail.get();
|
||||||
|
}
|
||||||
|
|
||||||
ImageInfoData Image::info() const
|
ImageInfoData Image::info() const
|
||||||
{
|
{
|
||||||
return m_info;
|
return m_info;
|
||||||
@@ -56,6 +70,11 @@ bool Image::isCurrent() const
|
|||||||
return !m_released;
|
return !m_released;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Image::number() const
|
||||||
|
{
|
||||||
|
return m_number;
|
||||||
|
}
|
||||||
|
|
||||||
void Image::imageLoaded(void *rawImage, ImageInfoData info)
|
void Image::imageLoaded(void *rawImage, ImageInfoData info)
|
||||||
{
|
{
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
@@ -71,17 +90,28 @@ void Image::imageLoaded(void *rawImage, ImageInfoData info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Image::thumbnailLoadFinish(void *rawImage)
|
||||||
|
{
|
||||||
|
m_thumbnail.reset(static_cast<RawImage*>(rawImage));
|
||||||
|
if(m_thumbnail)
|
||||||
|
emit thumbnailLoaded(this);
|
||||||
|
}
|
||||||
|
|
||||||
ImageRingList::ImageRingList(QObject *parent) : QAbstractItemModel(parent)
|
ImageRingList::ImageRingList(QObject *parent) : QAbstractItemModel(parent)
|
||||||
, m_liveMode(false)
|
, m_liveMode(false)
|
||||||
, m_analyzeLevel(None)
|
, m_analyzeLevel(None)
|
||||||
{
|
{
|
||||||
connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
|
connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
|
||||||
|
m_thumbPool = new QThreadPool(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageRingList::~ImageRingList()
|
ImageRingList::~ImageRingList()
|
||||||
{
|
{
|
||||||
QThreadPool::globalInstance()->clear();
|
QThreadPool::globalInstance()->clear();
|
||||||
|
m_thumbPool->clear();
|
||||||
|
|
||||||
QThreadPool::globalInstance()->waitForDone();
|
QThreadPool::globalInstance()->waitForDone();
|
||||||
|
m_thumbPool->waitForDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageRingList::setDir(const QString path, const QString ¤tFile)
|
bool ImageRingList::setDir(const QString path, const QString ¤tFile)
|
||||||
@@ -93,7 +123,7 @@ bool ImageRingList::setDir(const QString path, const QString ¤tFile)
|
|||||||
QStringList nameFilter;
|
QStringList nameFilter;
|
||||||
nameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.cr2" << "*.fit" << "*.fits" << "*.xisf";
|
nameFilter << "*.jpg" << "*.jpeg" << "*.png" << "*.cr2" << "*.fit" << "*.fits" << "*.xisf";
|
||||||
|
|
||||||
QStringList list = dir.entryList(nameFilter, QDir::Files | QDir::Readable, m_liveMode ? QDir::Time : QDir::Name);
|
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)
|
||||||
{
|
{
|
||||||
@@ -209,6 +239,24 @@ void ImageRingList::loadFile(int row)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageRingList::loadThumbnails()
|
||||||
|
{
|
||||||
|
for(auto &img : m_images)
|
||||||
|
{
|
||||||
|
img->loadThumbnail(m_thumbPool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageRingList::stopLoading()
|
||||||
|
{
|
||||||
|
m_thumbPool->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ImageRingList::imageCount() const
|
||||||
|
{
|
||||||
|
return m_images.size();
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex ImageRingList::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return createIndex(row, column, m_images.at(row).get());
|
return createIndex(row, column, m_images.at(row).get());
|
||||||
@@ -261,10 +309,12 @@ void ImageRingList::setFiles(const QStringList files, const QString ¤tFile
|
|||||||
QThreadPool::globalInstance()->waitForDone();
|
QThreadPool::globalInstance()->waitForDone();
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_images.clear();
|
m_images.clear();
|
||||||
foreach(const QString &file, files)
|
int i = 0;
|
||||||
|
for(const QString &file : files)
|
||||||
{
|
{
|
||||||
ImagePtr ptr = make_shared<Image>(file, this);
|
ImagePtr ptr = make_shared<Image>(file, i++, this);
|
||||||
connect(ptr.get(), SIGNAL(pixmapLoaded(Image*)), this, SLOT(imageLoaded(Image*)));
|
connect(ptr.get(), SIGNAL(pixmapLoaded(Image*)), this, SLOT(imageLoaded(Image*)));
|
||||||
|
connect(ptr.get(), SIGNAL(thumbnailLoaded(Image*)), this, SIGNAL(thumbnailLoaded(Image*)));
|
||||||
m_images.append(ptr);
|
m_images.append(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -10,6 +10,7 @@
|
|||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
|
|
||||||
class ImageRingList;
|
class ImageRingList;
|
||||||
|
class QThreadPool;
|
||||||
|
|
||||||
class Image : public QObject
|
class Image : public QObject
|
||||||
{
|
{
|
||||||
@@ -17,22 +18,29 @@ class Image : public QObject
|
|||||||
bool m_loading;
|
bool m_loading;
|
||||||
bool m_released;
|
bool m_released;
|
||||||
bool m_current;
|
bool m_current;
|
||||||
|
int m_number;
|
||||||
std::unique_ptr<RawImage> m_rawImage;
|
std::unique_ptr<RawImage> m_rawImage;
|
||||||
|
std::unique_ptr<RawImage> m_thumbnail;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
ImageInfoData m_info;
|
ImageInfoData m_info;
|
||||||
ImageRingList *m_ringList;
|
ImageRingList *m_ringList;
|
||||||
public:
|
public:
|
||||||
explicit Image(const QString name, ImageRingList *ringList);
|
explicit Image(const QString name, int number, ImageRingList *ringList);
|
||||||
void load();
|
void load();
|
||||||
|
void loadThumbnail(QThreadPool *pool);
|
||||||
void release();
|
void release();
|
||||||
QString name() const;
|
QString name() const;
|
||||||
RawImage* rawImage();
|
RawImage* rawImage();
|
||||||
|
const RawImage* thumbnail() const;
|
||||||
ImageInfoData info() const;
|
ImageInfoData info() const;
|
||||||
bool isCurrent() const;
|
bool isCurrent() const;
|
||||||
|
int number() const;
|
||||||
signals:
|
signals:
|
||||||
void pixmapLoaded(Image *ptr);
|
void pixmapLoaded(Image *ptr);
|
||||||
|
void thumbnailLoaded(Image *ptr);
|
||||||
protected slots:
|
protected slots:
|
||||||
void imageLoaded(void *rawImage, ImageInfoData info);
|
void imageLoaded(void *rawImage, ImageInfoData info);
|
||||||
|
void thumbnailLoadFinish(void *rawImage);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<Image> ImagePtr;
|
typedef std::shared_ptr<Image> ImagePtr;
|
||||||
@@ -48,6 +56,7 @@ class ImageRingList : public QAbstractItemModel
|
|||||||
QFileSystemWatcher m_fileSystemWatcher;
|
QFileSystemWatcher m_fileSystemWatcher;
|
||||||
bool m_liveMode;
|
bool m_liveMode;
|
||||||
AnalyzeLevel m_analyzeLevel;
|
AnalyzeLevel m_analyzeLevel;
|
||||||
|
QThreadPool *m_thumbPool;
|
||||||
public:
|
public:
|
||||||
explicit ImageRingList(QObject *parent = 0);
|
explicit ImageRingList(QObject *parent = 0);
|
||||||
~ImageRingList();
|
~ImageRingList();
|
||||||
@@ -62,6 +71,9 @@ public:
|
|||||||
void setFindStars(bool findStars);
|
void setFindStars(bool findStars);
|
||||||
AnalyzeLevel analyzeLevel() const;
|
AnalyzeLevel analyzeLevel() const;
|
||||||
void loadFile(int row);
|
void loadFile(int row);
|
||||||
|
void loadThumbnails();
|
||||||
|
void stopLoading();
|
||||||
|
int imageCount() const;
|
||||||
|
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QModelIndex parent(const QModelIndex &child) const override;
|
QModelIndex parent(const QModelIndex &child) const override;
|
||||||
@@ -75,6 +87,7 @@ protected:
|
|||||||
QList<ImagePtr>::iterator decrement(QList<ImagePtr>::iterator iter);
|
QList<ImagePtr>::iterator decrement(QList<ImagePtr>::iterator iter);
|
||||||
signals:
|
signals:
|
||||||
void pixmapLoaded(Image *image);
|
void pixmapLoaded(Image *image);
|
||||||
|
void thumbnailLoaded(Image *image);
|
||||||
void infoLoaded(ImageInfoData info);
|
void infoLoaded(ImageInfoData info);
|
||||||
void currentImageChanged(int index);
|
void currentImageChanged(int index);
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|||||||
+168
-5
@@ -6,6 +6,7 @@
|
|||||||
#include <QOpenGLPixelTransferOptions>
|
#include <QOpenGLPixelTransferOptions>
|
||||||
#include <QOpenGLFramebufferObject>
|
#include <QOpenGLFramebufferObject>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
struct RawImageType
|
struct RawImageType
|
||||||
{
|
{
|
||||||
@@ -54,6 +55,13 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
|
|||||||
m_range = UINT16_MAX;
|
m_range = UINT16_MAX;
|
||||||
m_imgWidth = m_imgHeight = -1;
|
m_imgWidth = m_imgHeight = -1;
|
||||||
m_superpixel = m_invert = false;
|
m_superpixel = m_invert = false;
|
||||||
|
m_showThumbnails = false;
|
||||||
|
m_thumbnailCount = 0;
|
||||||
|
m_updateTimer = new QTimer(this);
|
||||||
|
m_updateTimer->setInterval(500);
|
||||||
|
m_updateTimer->setSingleShot(true);
|
||||||
|
connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(update()));
|
||||||
|
setAcceptDrops(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageWidget::~ImageWidget()
|
ImageWidget::~ImageWidget()
|
||||||
@@ -113,6 +121,22 @@ void ImageWidget::blockRepaint(bool block)
|
|||||||
if(!block)update();
|
if(!block)update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageWidget::allocateThumbnails(int count)
|
||||||
|
{
|
||||||
|
m_thumbnailTexture->destroy();
|
||||||
|
m_thumbnailTexture->create();
|
||||||
|
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
|
||||||
|
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
|
||||||
|
m_thumbnailTexture->setLayers(count);
|
||||||
|
m_thumbnailTexture->allocateStorage();
|
||||||
|
m_bufferSizes->bind();
|
||||||
|
float *tmp = new float[count*3];
|
||||||
|
memset(tmp, 0, count * sizeof(float)*3);
|
||||||
|
m_bufferSizes->allocate(tmp, count * sizeof(float)*3);
|
||||||
|
delete [] tmp;
|
||||||
|
m_thumbnailCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
void ImageWidget::setMTFParams(float low, float mid, float high)
|
void ImageWidget::setMTFParams(float low, float mid, float high)
|
||||||
{
|
{
|
||||||
m_low = low;
|
m_low = low;
|
||||||
@@ -162,6 +186,23 @@ QImage ImageWidget::renderToImage()
|
|||||||
return fbo.toImage(true);
|
return fbo.toImage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageWidget::thumbnailLoaded(const Image *image)
|
||||||
|
{
|
||||||
|
const RawImage *raw = image->thumbnail();
|
||||||
|
m_thumbnailTexture->setData(0, image->number(), QOpenGLTexture::RGB, QOpenGLTexture::UInt16, raw->data(), m_transferOptions.get());
|
||||||
|
float a = raw->thumbAspect();
|
||||||
|
int sizes[3] = { std::max(1, a > 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE * a)), std::max(1, a < 1.0f ? THUMB_SIZE : (int)(THUMB_SIZE / a)), image->number() };
|
||||||
|
m_bufferSizes->bind();
|
||||||
|
m_bufferSizes->write(image->number() * sizeof(sizes), sizes, sizeof(sizes));
|
||||||
|
if(!m_updateTimer->isActive())m_updateTimer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageWidget::showThumbnail(bool enable)
|
||||||
|
{
|
||||||
|
m_showThumbnails = enable;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void ImageWidget::paintGL()
|
void ImageWidget::paintGL()
|
||||||
{
|
{
|
||||||
if(m_blockRepaint)return;
|
if(m_blockRepaint)return;
|
||||||
@@ -173,6 +214,25 @@ void ImageWidget::paintGL()
|
|||||||
if(height() > m_image->height()*m_scale)
|
if(height() > m_image->height()*m_scale)
|
||||||
dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
|
dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
|
||||||
|
|
||||||
|
if(m_showThumbnails)
|
||||||
|
{
|
||||||
|
m_vaoThumb->bind();
|
||||||
|
m_thumbnailTexture->bind(1);
|
||||||
|
m_thumbnailProgram->bind();
|
||||||
|
f->glUniform3i(m_thumbnailProgram->uniformLocation("viewport_row"), width(), height(), width()/THUMB_SIZE_BORDER);
|
||||||
|
m_thumbnailProgram->setUniformValue("mtf_param", m_low, m_mid, m_high);
|
||||||
|
m_thumbnailProgram->setUniformValue("invert", m_invert);
|
||||||
|
m_thumbnailProgram->setUniformValue("offset", 0, m_dy);
|
||||||
|
f3->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1);
|
||||||
|
QMatrix4x4 mvp;
|
||||||
|
mvp.ortho(rect());
|
||||||
|
m_thumbnailProgram->setUniformValue("mvp", mvp);
|
||||||
|
if(f3)f3->glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, m_thumbnailCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_vao->bind();
|
||||||
|
m_image->bind(0);
|
||||||
m_program->bind();
|
m_program->bind();
|
||||||
m_program->setUniformValue("viewport", (float)width(), (float)height());
|
m_program->setUniformValue("viewport", (float)width(), (float)height());
|
||||||
m_program->setUniformValue("offset", dx, dy);
|
m_program->setUniformValue("offset", dx, dy);
|
||||||
@@ -180,9 +240,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);
|
||||||
|
|
||||||
m_image->bind(0);
|
|
||||||
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageWidget::resizeGL(int w, int h)
|
void ImageWidget::resizeGL(int w, int h)
|
||||||
@@ -196,10 +256,12 @@ void ImageWidget::initializeGL()
|
|||||||
{
|
{
|
||||||
f = context()->functions();
|
f = context()->functions();
|
||||||
f->glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
f->glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||||
QOpenGLFunctions_3_2_Core *f3 = context()->versionFunctions<QOpenGLFunctions_3_2_Core>();
|
f3 = context()->versionFunctions<QOpenGLFunctions_3_3_Core>();
|
||||||
|
|
||||||
m_vao = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject);
|
m_vao = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject);
|
||||||
|
m_vaoThumb = std::unique_ptr<QOpenGLVertexArrayObject>(new QOpenGLVertexArrayObject);
|
||||||
m_vao->create();
|
m_vao->create();
|
||||||
|
m_vaoThumb->create();
|
||||||
m_vao->bind();
|
m_vao->bind();
|
||||||
|
|
||||||
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
|
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
|
||||||
@@ -226,7 +288,7 @@ void ImageWidget::initializeGL()
|
|||||||
m_buffer->create();
|
m_buffer->create();
|
||||||
m_buffer->bind();
|
m_buffer->bind();
|
||||||
m_buffer->allocate(vertexs, sizeof(vertexs));
|
m_buffer->allocate(vertexs, sizeof(vertexs));
|
||||||
f->glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float)*4, 0);
|
// f->glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(float)*4, 0);
|
||||||
|
|
||||||
m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
|
m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
|
||||||
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/image.vert");
|
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/image.vert");
|
||||||
@@ -245,6 +307,33 @@ void ImageWidget::initializeGL()
|
|||||||
m_program->setUniformValue("qt_Texture0", (GLuint)0);
|
m_program->setUniformValue("qt_Texture0", (GLuint)0);
|
||||||
m_program->setUniformValue("scale", 1.0f, 0.0f);
|
m_program->setUniformValue("scale", 1.0f, 0.0f);
|
||||||
|
|
||||||
|
m_vaoThumb->bind();
|
||||||
|
|
||||||
|
m_thumbnailProgram = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram);
|
||||||
|
m_thumbnailProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/thumb.vert");
|
||||||
|
m_thumbnailProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/thumb.frag");
|
||||||
|
if(f3)f3->glBindFragDataLocation(m_program->programId(), 0, "color");
|
||||||
|
m_thumbnailProgram->bind();
|
||||||
|
m_thumbnailProgram->enableAttributeArray("qt_Vertex");
|
||||||
|
m_thumbnailProgram->setAttributeBuffer("qt_Vertex", GL_FLOAT, 0, 2, sizeof(float)*4);
|
||||||
|
m_thumbnailProgram->enableAttributeArray("qt_MultiTexCoord0");
|
||||||
|
m_thumbnailProgram->setAttributeBuffer("qt_MultiTexCoord0", GL_FLOAT, sizeof(float)*2, 2, sizeof(float)*4);
|
||||||
|
if(!m_thumbnailProgram->link())
|
||||||
|
{
|
||||||
|
qDebug() << "Link failed" << m_thumbnailProgram->log();
|
||||||
|
}
|
||||||
|
m_thumbnailProgram->setUniformValue("qt_Texture0", (GLuint)1);
|
||||||
|
|
||||||
|
m_bufferSizes = std::unique_ptr<QOpenGLBuffer>(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer));
|
||||||
|
m_bufferSizes->setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||||
|
m_bufferSizes->create();
|
||||||
|
m_bufferSizes->bind();
|
||||||
|
|
||||||
|
m_bufferSizes->allocate(12);
|
||||||
|
m_thumbnailProgram->enableAttributeArray("imageSize_num");
|
||||||
|
m_thumbnailProgram->setAttributeBuffer("imageSize_num", GL_FLOAT, 0, 3);
|
||||||
|
f3->glVertexAttribDivisor(m_thumbnailProgram->attributeLocation("imageSize_num"), 1);
|
||||||
|
|
||||||
m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D));
|
m_image = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2D));
|
||||||
m_image->setFormat(QOpenGLTexture::RGB8U);
|
m_image->setFormat(QOpenGLTexture::RGB8U);
|
||||||
m_image->allocateStorage();
|
m_image->allocateStorage();
|
||||||
@@ -252,10 +341,42 @@ void ImageWidget::initializeGL()
|
|||||||
m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
|
m_image->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
|
||||||
m_image->setMagnificationFilter(QOpenGLTexture::Linear);
|
m_image->setMagnificationFilter(QOpenGLTexture::Linear);
|
||||||
|
|
||||||
|
m_thumbnailTexture = std::unique_ptr<QOpenGLTexture>(new QOpenGLTexture(QOpenGLTexture::Target2DArray));
|
||||||
|
m_thumbnailTexture->setFormat(QOpenGLTexture::RGB16_UNorm);
|
||||||
|
m_thumbnailTexture->setSize(THUMB_SIZE, THUMB_SIZE);
|
||||||
|
m_thumbnailTexture->setLayers(1);
|
||||||
|
m_thumbnailTexture->allocateStorage();
|
||||||
|
m_thumbnailTexture->bind(1);
|
||||||
|
m_thumbnailTexture->setMinificationFilter(QOpenGLTexture::Linear);
|
||||||
|
m_thumbnailTexture->setMinificationFilter(QOpenGLTexture::Linear);
|
||||||
|
|
||||||
m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions);
|
m_transferOptions = std::unique_ptr<QOpenGLPixelTransferOptions>(new QOpenGLPixelTransferOptions);
|
||||||
m_transferOptions->setAlignment(1);
|
m_transferOptions->setAlignment(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageWidget::dragEnterEvent(QDragEnterEvent *event)
|
||||||
|
{
|
||||||
|
if(event->mimeData()->hasUrls() && event->proposedAction() & (Qt::CopyAction | Qt::MoveAction))
|
||||||
|
event->acceptProposedAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageWidget::dropEvent(QDropEvent *event)
|
||||||
|
{
|
||||||
|
if(event->mimeData()->hasUrls() && event->proposedAction() & (Qt::CopyAction | Qt::MoveAction))
|
||||||
|
{
|
||||||
|
for(const QUrl &url : event->mimeData()->urls())
|
||||||
|
{
|
||||||
|
if(url.isLocalFile())
|
||||||
|
{
|
||||||
|
emit fileDropped(url.path());
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QWidget(parent)
|
ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
QGridLayout *layout = new QGridLayout(this);
|
QGridLayout *layout = new QGridLayout(this);
|
||||||
@@ -267,6 +388,7 @@ ImageScrollAreaGL::ImageScrollAreaGL(QWidget *parent) : QWidget(parent)
|
|||||||
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
|
m_horizontalScrollBar = new QScrollBar(Qt::Horizontal, this);
|
||||||
m_scale = 1.0f;
|
m_scale = 1.0f;
|
||||||
m_bestFit = false;
|
m_bestFit = false;
|
||||||
|
m_thumbCount = 0;
|
||||||
|
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
layout->addWidget(m_imageWidget, 0, 0);
|
layout->addWidget(m_imageWidget, 0, 0);
|
||||||
@@ -305,8 +427,33 @@ ImageWidget *ImageScrollAreaGL::imageWidget()
|
|||||||
return m_imageWidget;
|
return m_imageWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageScrollAreaGL::setThumbnails(int count)
|
||||||
|
{
|
||||||
|
m_thumbCount = count;
|
||||||
|
if(m_thumbCount)
|
||||||
|
{
|
||||||
|
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||||
|
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_verticalScrollBar->setPageStep(m_imageWidget->height());
|
||||||
|
m_horizontalScrollBar->setPageStep(m_imageWidget->width());
|
||||||
|
}
|
||||||
|
updateScrollbars();
|
||||||
|
}
|
||||||
|
|
||||||
void ImageScrollAreaGL::updateScrollbars(bool zoom)
|
void ImageScrollAreaGL::updateScrollbars(bool zoom)
|
||||||
{
|
{
|
||||||
|
if(m_thumbCount)
|
||||||
|
{
|
||||||
|
m_horizontalScrollBar->hide();
|
||||||
|
m_verticalScrollBar->show();
|
||||||
|
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||||
|
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if(zoom)
|
if(zoom)
|
||||||
{
|
{
|
||||||
setScrollRange(m_verticalScrollBar, m_imgHeight*m_scale);
|
setScrollRange(m_verticalScrollBar, m_imgHeight*m_scale);
|
||||||
@@ -317,20 +464,29 @@ void ImageScrollAreaGL::updateScrollbars(bool zoom)
|
|||||||
m_verticalScrollBar->setRange(0, m_imgHeight*m_scale - m_verticalScrollBar->pageStep());
|
m_verticalScrollBar->setRange(0, m_imgHeight*m_scale - m_verticalScrollBar->pageStep());
|
||||||
m_horizontalScrollBar->setRange(0, m_imgWidth*m_scale - m_horizontalScrollBar->pageStep());
|
m_horizontalScrollBar->setRange(0, m_imgWidth*m_scale - m_horizontalScrollBar->pageStep());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageScrollAreaGL::resizeEvent(QResizeEvent *event)
|
void ImageScrollAreaGL::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::resizeEvent(event);
|
QWidget::resizeEvent(event);
|
||||||
|
if(m_thumbCount)
|
||||||
|
{
|
||||||
|
m_verticalScrollBar->setRange(0, m_thumbCount / (m_imageWidget->width() / THUMB_SIZE_BORDER) * THUMB_SIZE_BORDER);
|
||||||
|
m_verticalScrollBar->setPageStep(THUMB_SIZE_BORDER);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_verticalScrollBar->setPageStep(m_imageWidget->height());
|
m_verticalScrollBar->setPageStep(m_imageWidget->height());
|
||||||
m_horizontalScrollBar->setPageStep(m_imageWidget->width());
|
m_horizontalScrollBar->setPageStep(m_imageWidget->width());
|
||||||
|
}
|
||||||
updateScrollbars();
|
updateScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageScrollAreaGL::mouseMoveEvent(QMouseEvent *event)
|
void ImageScrollAreaGL::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
QPoint delta = m_lastPos - event->pos();
|
QPoint delta = m_lastPos - event->pos();
|
||||||
m_horizontalScrollBar->setValue(m_horizontalScrollBar->value() + delta.x());
|
if(m_thumbCount == 0)m_horizontalScrollBar->setValue(m_horizontalScrollBar->value() + delta.x());
|
||||||
m_verticalScrollBar->setValue(m_verticalScrollBar->value() + delta.y());
|
m_verticalScrollBar->setValue(m_verticalScrollBar->value() + delta.y());
|
||||||
m_lastPos = event->pos();
|
m_lastPos = event->pos();
|
||||||
}
|
}
|
||||||
@@ -342,9 +498,16 @@ void ImageScrollAreaGL::mousePressEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
void ImageScrollAreaGL::wheelEvent(QWheelEvent *event)
|
void ImageScrollAreaGL::wheelEvent(QWheelEvent *event)
|
||||||
{
|
{
|
||||||
|
if(m_thumbCount)
|
||||||
|
{
|
||||||
|
m_verticalScrollBar->setValue(m_verticalScrollBar->value() - event->angleDelta().y());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_bestFit = false;
|
m_bestFit = false;
|
||||||
if(event->angleDelta().y() != 0)
|
if(event->angleDelta().y() != 0)
|
||||||
zoom(event->angleDelta().y() / 1200.0f);
|
zoom(event->angleDelta().y() / 1200.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageScrollAreaGL::zoom(float delta)
|
void ImageScrollAreaGL::zoom(float delta)
|
||||||
|
|||||||
+20
-1
@@ -4,13 +4,15 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <QOpenGLFunctions_3_2_Core>
|
#include <QOpenGLFunctions_3_3_Core>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
#include <QOpenGLTexture>
|
#include <QOpenGLTexture>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QTimer>
|
||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
|
#include "imageringlist.h"
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -25,11 +27,17 @@ class ImageWidget : public QOpenGLWidget
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QOpenGLFunctions *f;
|
QOpenGLFunctions *f;
|
||||||
|
QOpenGLFunctions_3_3_Core *f3;
|
||||||
|
QTimer *m_updateTimer;
|
||||||
std::unique_ptr<QOpenGLShaderProgram> m_program;
|
std::unique_ptr<QOpenGLShaderProgram> m_program;
|
||||||
|
std::unique_ptr<QOpenGLShaderProgram> m_thumbnailProgram;
|
||||||
std::unique_ptr<QOpenGLBuffer> m_buffer;
|
std::unique_ptr<QOpenGLBuffer> m_buffer;
|
||||||
|
std::unique_ptr<QOpenGLBuffer> m_bufferSizes;
|
||||||
std::unique_ptr<QOpenGLTexture> m_image;
|
std::unique_ptr<QOpenGLTexture> m_image;
|
||||||
std::unique_ptr<QOpenGLVertexArrayObject> m_vao;
|
std::unique_ptr<QOpenGLVertexArrayObject> m_vao;
|
||||||
|
std::unique_ptr<QOpenGLVertexArrayObject> m_vaoThumb;
|
||||||
std::unique_ptr<QOpenGLPixelTransferOptions> m_transferOptions;
|
std::unique_ptr<QOpenGLPixelTransferOptions> m_transferOptions;
|
||||||
|
std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
|
||||||
int m_width, m_height;
|
int m_width, m_height;
|
||||||
int m_imgWidth, m_imgHeight;
|
int m_imgWidth, m_imgHeight;
|
||||||
float m_low;
|
float m_low;
|
||||||
@@ -42,6 +50,8 @@ class ImageWidget : public QOpenGLWidget
|
|||||||
bool m_bwImg;
|
bool m_bwImg;
|
||||||
bool m_invert;
|
bool m_invert;
|
||||||
bool m_superpixel;
|
bool m_superpixel;
|
||||||
|
bool m_showThumbnails;
|
||||||
|
int m_thumbnailCount;
|
||||||
public:
|
public:
|
||||||
explicit ImageWidget(QWidget *parent = nullptr);
|
explicit ImageWidget(QWidget *parent = nullptr);
|
||||||
~ImageWidget();
|
~ImageWidget();
|
||||||
@@ -49,16 +59,23 @@ public:
|
|||||||
void setImage(const QPixmap &pixmap);
|
void setImage(const QPixmap &pixmap);
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
void blockRepaint(bool block);
|
void blockRepaint(bool block);
|
||||||
|
void allocateThumbnails(int count);
|
||||||
public slots:
|
public slots:
|
||||||
void setMTFParams(float low, float mid, float high);
|
void setMTFParams(float low, float mid, float high);
|
||||||
void setOffset(int dx, int dy);
|
void setOffset(int dx, int dy);
|
||||||
void superPixel(bool enable);
|
void superPixel(bool enable);
|
||||||
void invert(bool enable);
|
void invert(bool enable);
|
||||||
QImage renderToImage();
|
QImage renderToImage();
|
||||||
|
void thumbnailLoaded(const Image *image);
|
||||||
|
void showThumbnail(bool enable);
|
||||||
protected:
|
protected:
|
||||||
void paintGL();
|
void paintGL();
|
||||||
void resizeGL(int w, int h);
|
void resizeGL(int w, int h);
|
||||||
void initializeGL();
|
void initializeGL();
|
||||||
|
void dragEnterEvent(QDragEnterEvent *event);
|
||||||
|
void dropEvent(QDropEvent *event);
|
||||||
|
signals:
|
||||||
|
void fileDropped(const QString &path);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImageScrollAreaGL : public QWidget
|
class ImageScrollAreaGL : public QWidget
|
||||||
@@ -71,12 +88,14 @@ class ImageScrollAreaGL : public QWidget
|
|||||||
QPoint m_lastPos;
|
QPoint m_lastPos;
|
||||||
float m_scale;
|
float m_scale;
|
||||||
bool m_bestFit;
|
bool m_bestFit;
|
||||||
|
int m_thumbCount;
|
||||||
public:
|
public:
|
||||||
explicit ImageScrollAreaGL(QWidget *parent = nullptr);
|
explicit ImageScrollAreaGL(QWidget *parent = nullptr);
|
||||||
~ImageScrollAreaGL();
|
~ImageScrollAreaGL();
|
||||||
void setImage(RawImage *image);
|
void setImage(RawImage *image);
|
||||||
void setImage(const QPixmap &pixmap);
|
void setImage(const QPixmap &pixmap);
|
||||||
ImageWidget* imageWidget();
|
ImageWidget* imageWidget();
|
||||||
|
void setThumbnails(int count);
|
||||||
protected:
|
protected:
|
||||||
void updateScrollbars(bool zoom = false);
|
void updateScrollbars(bool zoom = false);
|
||||||
void resizeEvent(QResizeEvent *event);
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
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 org.nou.tenmon.desktop WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
|
||||||
execute_process(COMMAND ${XDG-ICON-RESOURCE_EXECUTABLE} install --novendor --size 32 icon.png org.nou.tenmon 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})
|
||||||
|
|||||||
+165
-4
@@ -13,10 +13,11 @@
|
|||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
#include "starfit.h"
|
#include "starfit.h"
|
||||||
|
|
||||||
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level) :
|
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
|
||||||
m_file(file),
|
m_file(file),
|
||||||
m_receiver(receiver),
|
m_receiver(receiver),
|
||||||
m_analyzeLevel(level)
|
m_analyzeLevel(level),
|
||||||
|
m_thumbnail(thumbnail)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +335,7 @@ bool loadXISF(const QString &path, ImageInfoData &info, RawImage **image)
|
|||||||
|
|
||||||
void LoadRunable::run()
|
void LoadRunable::run()
|
||||||
{
|
{
|
||||||
if(!m_receiver->isCurrent())
|
if(!m_thumbnail && !m_receiver->isCurrent())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -375,7 +376,7 @@ void LoadRunable::run()
|
|||||||
rawImage = new RawImage(img);
|
rawImage = new RawImage(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rawImage && m_analyzeLevel >= Statistics)
|
if(rawImage && m_analyzeLevel >= Statistics && !m_thumbnail)
|
||||||
{
|
{
|
||||||
double mean, median, min, max, mad;
|
double mean, median, min, max, mad;
|
||||||
double stdDev;
|
double stdDev;
|
||||||
@@ -440,6 +441,19 @@ void LoadRunable::run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m_thumbnail)
|
||||||
|
{
|
||||||
|
if(rawImage)
|
||||||
|
{
|
||||||
|
rawImage->convertToThumbnail();
|
||||||
|
QMetaObject::invokeMethod(m_receiver, "thumbnailLoadFinish", Qt::QueuedConnection, Q_ARG(void*, rawImage));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug() << "failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(void*, rawImage), Q_ARG(ImageInfoData, info));
|
QMetaObject::invokeMethod(m_receiver, "imageLoaded", Qt::QueuedConnection, Q_ARG(void*, rawImage), Q_ARG(ImageInfoData, info));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,3 +492,150 @@ bool readXISFHeader(const QString &path, ImageInfoData &info)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConvertRunable::ConvertRunable(const QString &in, const QString &out) :
|
||||||
|
m_infile(in),
|
||||||
|
m_outfile(out)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void writeXISFImage(pcl::XISFWriter &writer, RawImage *rawimg)
|
||||||
|
{
|
||||||
|
const cv::Mat &cvmat = rawimg->mat();
|
||||||
|
T pclimg(rawimg->width(), rawimg->height(), cvmat.channels() == 1 ? pcl::ColorSpace::Gray : pcl::ColorSpace::RGB);
|
||||||
|
if(cvmat.channels() == 1)
|
||||||
|
{
|
||||||
|
memcpy(pclimg.PixelData(0), rawimg->data(), rawimg->size()*sizeof(typename T::sample));
|
||||||
|
}
|
||||||
|
if(cvmat.channels() == 3)
|
||||||
|
{
|
||||||
|
std::vector<cv::Mat> channels;
|
||||||
|
cv::split(cvmat, channels);
|
||||||
|
memcpy(pclimg.PixelData(0), channels[0].data, rawimg->size()*sizeof(typename T::sample));
|
||||||
|
memcpy(pclimg.PixelData(1), channels[1].data, rawimg->size()*sizeof(typename T::sample));
|
||||||
|
memcpy(pclimg.PixelData(2), channels[2].data, rawimg->size()*sizeof(typename T::sample));
|
||||||
|
}
|
||||||
|
writer.WriteImage(pclimg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeFITSImage(fitsfile *fw, RawImage *rawimage, ImageInfoData &imageinfo)
|
||||||
|
{
|
||||||
|
static QStringList skipKeys = {"SIMPLE", "BITPIX", "NAXIS", "NAXIS1", "NAXIS2", "NAXIS3", "BZERO", "BSCALE", "EXTEND"};
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
long firstpix[3] = {1,1,1};
|
||||||
|
|
||||||
|
int channels = rawimage->mat().channels();
|
||||||
|
int naxis = channels == 1 ? 2 : 3;
|
||||||
|
long naxes[3] = {(int)rawimage->width(), (int)rawimage->height(), rawimage->mat().channels()};
|
||||||
|
|
||||||
|
std::vector<cv::Mat> mat;
|
||||||
|
if(channels == 1)
|
||||||
|
mat.push_back(rawimage->mat());
|
||||||
|
else
|
||||||
|
cv::split(rawimage->mat(), mat);
|
||||||
|
|
||||||
|
switch(CV_MAT_DEPTH(rawimage->dataType()))
|
||||||
|
{
|
||||||
|
case CV_8U:
|
||||||
|
fits_create_img(fw, BYTE_IMG, naxis, naxes, &status);
|
||||||
|
for(int i=0; i<channels; i++)
|
||||||
|
{
|
||||||
|
firstpix[2] = i+1;
|
||||||
|
fits_write_pix(fw, TBYTE, firstpix, rawimage->size(), mat[i].data, &status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CV_16U:
|
||||||
|
fits_create_img(fw, USHORT_IMG, naxis, naxes, &status);
|
||||||
|
for(int i=0; i<channels; i++)
|
||||||
|
{
|
||||||
|
firstpix[2] = i+1;
|
||||||
|
fits_write_pix(fw, TUSHORT, firstpix, rawimage->size(), mat[i].data, &status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CV_32F:
|
||||||
|
fits_create_img(fw, FLOAT_IMG, naxis, naxes, &status);
|
||||||
|
for(int i=0; i<channels; i++)
|
||||||
|
{
|
||||||
|
firstpix[2] = i+1;
|
||||||
|
fits_write_pix(fw, TFLOAT, firstpix, rawimage->size(), mat[i].data, &status);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(const FITSRecord &record : imageinfo.fitsHeader)
|
||||||
|
{
|
||||||
|
if(skipKeys.contains(record.key))continue;
|
||||||
|
|
||||||
|
bool isdouble;
|
||||||
|
bool isint;
|
||||||
|
bool isbool = record.value.toString() == "T" || record.value.toString() == "F";
|
||||||
|
double vald = record.value.toDouble(&isdouble);
|
||||||
|
int valb = record.value.toString() == "T";
|
||||||
|
long long vall = record.value.toLongLong(&isint);
|
||||||
|
QByteArray str = record.value.toString().toLatin1();
|
||||||
|
if(isdouble)
|
||||||
|
fits_write_key(fw, TDOUBLE, record.key.data(), &vald, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
else if(isint)
|
||||||
|
fits_write_key(fw, TLONGLONG, record.key.data(), &vall, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
else if(isbool)
|
||||||
|
fits_write_key(fw, TLOGICAL, record.key.data(), &valb, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
else if(record.key == "COMMENT")
|
||||||
|
fits_write_comment(fw, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
else if(record.key == "HISTORY")
|
||||||
|
fits_write_history(fw, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
else
|
||||||
|
fits_write_key(fw, TSTRING, record.key.data(), str.isEmpty() ? nullptr : str.data(), record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertRunable::run()
|
||||||
|
{
|
||||||
|
ImageInfoData imageinfo;
|
||||||
|
RawImage *rawimage = nullptr;
|
||||||
|
if(m_infile.endsWith(".FITS", Qt::CaseInsensitive) || m_infile.endsWith(".FIT", Qt::CaseInsensitive))
|
||||||
|
loadFITS(m_infile, imageinfo, &rawimage);
|
||||||
|
if(m_infile.endsWith(".XISF", Qt::CaseInsensitive))
|
||||||
|
loadXISF(m_infile, imageinfo, &rawimage);
|
||||||
|
|
||||||
|
if(rawimage)
|
||||||
|
{
|
||||||
|
if(m_outfile.endsWith(".XISF", Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
pcl::XISFOptions options;
|
||||||
|
pcl::FITSKeywordArray fitskeywords;
|
||||||
|
for(auto &record : imageinfo.fitsHeader)
|
||||||
|
{
|
||||||
|
pcl::FITSHeaderKeyword key(pcl::IsoString(record.key.data()), pcl::IsoString(record.value.toString().toLatin1().data()), pcl::IsoString(record.comment.data()));
|
||||||
|
fitskeywords.Append(key);
|
||||||
|
}
|
||||||
|
pcl::XISFWriter xisf;
|
||||||
|
xisf.Create(m_outfile.utf16(), 1);
|
||||||
|
xisf.WriteFITSKeywords(fitskeywords);
|
||||||
|
switch(CV_MAT_DEPTH(rawimage->dataType()))
|
||||||
|
{
|
||||||
|
case CV_8U:
|
||||||
|
writeXISFImage<pcl::UInt8Image>(xisf, rawimage);
|
||||||
|
break;
|
||||||
|
case CV_16U:
|
||||||
|
writeXISFImage<pcl::UInt16Image>(xisf, rawimage);
|
||||||
|
break;
|
||||||
|
case CV_32F:
|
||||||
|
writeXISFImage<pcl::Image>(xisf, rawimage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_outfile.endsWith(".FITS", Qt::CaseInsensitive) || m_outfile.endsWith(".FIT", Qt::CaseInsensitive))
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
fitsfile *fw;
|
||||||
|
if(QFileInfo(m_outfile).exists())QFile::remove(m_outfile);
|
||||||
|
fits_create_diskfile(&fw, m_outfile.toLocal8Bit().data(), &status);
|
||||||
|
writeFITSImage(fw, rawimage, imageinfo);
|
||||||
|
fits_close_file(fw, &status);
|
||||||
|
}
|
||||||
|
delete rawimage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+11
-1
@@ -15,8 +15,18 @@ class LoadRunable : public QRunnable
|
|||||||
QString m_file;
|
QString m_file;
|
||||||
Image *m_receiver;
|
Image *m_receiver;
|
||||||
AnalyzeLevel m_analyzeLevel;
|
AnalyzeLevel m_analyzeLevel;
|
||||||
|
bool m_thumbnail;
|
||||||
public:
|
public:
|
||||||
LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level);
|
LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail = false);
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConvertRunable : public QRunnable
|
||||||
|
{
|
||||||
|
QString m_infile;
|
||||||
|
QString m_outfile;
|
||||||
|
public:
|
||||||
|
ConvertRunable(const QString &in, const QString &out);
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
QSurfaceFormat format;
|
QSurfaceFormat format;
|
||||||
format.setMajorVersion(3);
|
format.setMajorVersion(3);
|
||||||
format.setMinorVersion(2);
|
format.setMinorVersion(3);
|
||||||
format.setOption(QSurfaceFormat::DebugContext);
|
format.setOption(QSurfaceFormat::DebugContext);
|
||||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
||||||
QSurfaceFormat::setDefaultFormat(format);
|
QSurfaceFormat::setDefaultFormat(format);
|
||||||
@@ -14,7 +14,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(":/icon.png"));
|
a.setWindowIcon(QIcon(":/org.nou.tenmon.png"));
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
w.show();
|
||||||
|
|||||||
+53
-12
@@ -14,6 +14,9 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QThreadPool>
|
||||||
|
#include "loadrunable.h"
|
||||||
|
#include "markedfiles.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@@ -41,11 +44,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
m_imageGL = new ImageScrollAreaGL(this);
|
m_imageGL = new ImageScrollAreaGL(this);
|
||||||
setCentralWidget(m_imageGL);
|
setCentralWidget(m_imageGL);
|
||||||
|
|
||||||
m_stretchPanel = new StretchPanel(this);
|
m_stretchPanel = new StretchToolbar(this);
|
||||||
connect(m_stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
|
connect(m_stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
|
||||||
connect(m_stretchPanel, &StretchPanel::autoStretch, [&](){ m_stretchPanel->stretchImage(m_ringList->currentImage().get()); });
|
connect(m_stretchPanel, &StretchToolbar::autoStretch, [&](){ m_stretchPanel->stretchImage(m_ringList->currentImage().get()); });
|
||||||
connect(m_stretchPanel, &StretchPanel::invert, m_imageGL->imageWidget(), &ImageWidget::invert);
|
connect(m_stretchPanel, &StretchToolbar::invert, m_imageGL->imageWidget(), &ImageWidget::invert);
|
||||||
connect(m_stretchPanel, &StretchPanel::superPixel, m_imageGL->imageWidget(), &ImageWidget::superPixel);
|
connect(m_stretchPanel, &StretchToolbar::superPixel, m_imageGL->imageWidget(), &ImageWidget::superPixel);
|
||||||
|
|
||||||
m_ringList = new ImageRingList(this);
|
m_ringList = new ImageRingList(this);
|
||||||
m_filesystem = new FilesystemWidget(m_ringList, this);
|
m_filesystem = new FilesystemWidget(m_ringList, this);
|
||||||
@@ -58,10 +61,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
m_databaseView = new DataBaseView(m_database, this);
|
m_databaseView = new DataBaseView(m_database, this);
|
||||||
connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString)));
|
connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString)));
|
||||||
|
|
||||||
QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this);
|
addToolBar(Qt::TopToolBarArea, m_stretchPanel);
|
||||||
stretchDock->setWidget(m_stretchPanel);
|
|
||||||
stretchDock->setObjectName("strechDock");
|
|
||||||
addDockWidget(Qt::TopDockWidgetArea, stretchDock);
|
|
||||||
|
|
||||||
QDockWidget *filesystemDock = new QDockWidget(tr("Filesystem"), this);
|
QDockWidget *filesystemDock = new QDockWidget(tr("Filesystem"), this);
|
||||||
filesystemDock->setWidget(m_filesystem);
|
filesystemDock->setWidget(m_filesystem);
|
||||||
@@ -80,6 +80,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle()));
|
connect(m_ringList, SIGNAL(currentImageChanged(int)), this, SLOT(updateWindowTitle()));
|
||||||
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(const ImageInfoData&)));
|
connect(m_ringList, SIGNAL(infoLoaded(ImageInfoData)), m_info, SLOT(setInfo(const ImageInfoData&)));
|
||||||
connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int)));
|
connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int)));
|
||||||
|
connect(m_ringList, &ImageRingList::thumbnailLoaded, m_imageGL->imageWidget(), &ImageWidget::thumbnailLoaded);
|
||||||
|
connect(m_ringList, &ImageRingList::pixmapLoaded, m_stretchPanel, &StretchToolbar::imageLoaded);
|
||||||
|
connect(m_imageGL->imageWidget(), &ImageWidget::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
|
||||||
|
|
||||||
QMenu *fileMenu = new QMenu(tr("File"), this);
|
QMenu *fileMenu = new QMenu(tr("File"), this);
|
||||||
fileMenu->addAction(tr("Open"), this, SLOT(loadFile()), QKeySequence("Ctrl+O"));
|
fileMenu->addAction(tr("Open"), this, SLOT(loadFile()), QKeySequence("Ctrl+O"));
|
||||||
@@ -96,7 +99,15 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
viewMenu->addAction(tr("Zoom Out"), m_imageGL, SLOT(zoomOut()), QKeySequence::ZoomOut);
|
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("Best Fit"), m_imageGL, SLOT(bestFit()), QKeySequence("Ctrl+1"));
|
||||||
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
|
viewMenu->addAction(tr("100%"), m_imageGL, SLOT(oneToOne()));
|
||||||
viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence::FullScreen);
|
viewMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), Qt::CTRL + Qt::Key_F11);
|
||||||
|
QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), [this](bool checked){
|
||||||
|
m_imageGL->imageWidget()->allocateThumbnails(m_ringList->imageCount());
|
||||||
|
m_imageGL->imageWidget()->showThumbnail(checked);
|
||||||
|
m_imageGL->setThumbnails(checked ? m_ringList->imageCount() : 0);
|
||||||
|
if(checked)m_ringList->loadThumbnails();
|
||||||
|
else m_ringList->stopLoading();
|
||||||
|
}, Qt::Key_F2);
|
||||||
|
thumbnailsAction->setCheckable(true);
|
||||||
menuBar()->addMenu(viewMenu);
|
menuBar()->addMenu(viewMenu);
|
||||||
|
|
||||||
QMenu *selectMenu = new QMenu(tr("Select"), this);
|
QMenu *selectMenu = new QMenu(tr("Select"), this);
|
||||||
@@ -105,6 +116,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
selectMenu->addSeparator();
|
selectMenu->addSeparator();
|
||||||
selectMenu->addAction(tr("Mark and next"), this, SLOT(markAndNext()), Qt::Key_M);
|
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("Unmark and next"), this, SLOT(unmarkAndNext()), Qt::Key_X);
|
||||||
|
selectMenu->addAction(tr("Show marked"), this, &MainWindow::showMarkFilesDialog);
|
||||||
menuBar()->addMenu(selectMenu);
|
menuBar()->addMenu(selectMenu);
|
||||||
|
|
||||||
QMenu *analyzeMenu = new QMenu(tr("Analyze"), this);
|
QMenu *analyzeMenu = new QMenu(tr("Analyze"), this);
|
||||||
@@ -134,7 +146,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
|
|
||||||
QMenu *dockMenu = new QMenu(tr("Docks"), this);
|
QMenu *dockMenu = new QMenu(tr("Docks"), this);
|
||||||
dockMenu->addAction(infoDock->toggleViewAction());
|
dockMenu->addAction(infoDock->toggleViewAction());
|
||||||
dockMenu->addAction(stretchDock->toggleViewAction());
|
dockMenu->addAction(m_stretchPanel->toggleViewAction());
|
||||||
dockMenu->addAction(filesystemDock->toggleViewAction());
|
dockMenu->addAction(filesystemDock->toggleViewAction());
|
||||||
dockMenu->addAction(databaseViewDock->toggleViewAction());
|
dockMenu->addAction(databaseViewDock->toggleViewAction());
|
||||||
menuBar()->addMenu(dockMenu);
|
menuBar()->addMenu(dockMenu);
|
||||||
@@ -256,7 +268,7 @@ void MainWindow::loadFile()
|
|||||||
loadFile(file);
|
loadFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::loadFile(const QString path)
|
void MainWindow::loadFile(const QString &path)
|
||||||
{
|
{
|
||||||
if(!path.isEmpty())
|
if(!path.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -291,13 +303,36 @@ void MainWindow::indexDir()
|
|||||||
|
|
||||||
void MainWindow::saveAs()
|
void MainWindow::saveAs()
|
||||||
{
|
{
|
||||||
QString file = QFileDialog::getSaveFileName(this, tr("Save as"), _lastDir, tr("Images (*.jpg *.png *.JPG *.PNG)"));
|
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);
|
||||||
if(!file.isEmpty())
|
if(!file.isEmpty())
|
||||||
|
{
|
||||||
|
QFileInfo info(file);
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
convert(file);
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::convert(const QString &outfile)
|
||||||
|
{
|
||||||
|
QString file = m_ringList->currentImage()->name();
|
||||||
|
QThreadPool::globalInstance()->start(new ConvertRunable(file, outfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::markImage()
|
void MainWindow::markImage()
|
||||||
@@ -414,6 +449,12 @@ void MainWindow::starFinder(bool findStars)
|
|||||||
m_ringList->setFindStars(findStars);
|
m_ringList->setFindStars(findStars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showMarkFilesDialog()
|
||||||
|
{
|
||||||
|
MarkedFiles markedFiles;
|
||||||
|
markedFiles.exec();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateWindowTitle()
|
void MainWindow::updateWindowTitle()
|
||||||
{
|
{
|
||||||
ImagePtr ptr = m_ringList->currentImage();
|
ImagePtr ptr = m_ringList->currentImage();
|
||||||
|
|||||||
+5
-3
@@ -9,7 +9,7 @@
|
|||||||
#include "imageinfo.h"
|
#include "imageinfo.h"
|
||||||
#include "imagescrollareagl.h"
|
#include "imagescrollareagl.h"
|
||||||
#include "filesystemwidget.h"
|
#include "filesystemwidget.h"
|
||||||
#include "stretchpanel.h"
|
#include "stretchtoolbar.h"
|
||||||
#include "databaseview.h"
|
#include "databaseview.h"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
@@ -18,7 +18,7 @@ class MainWindow : public QMainWindow
|
|||||||
ImageScrollArea *m_image;
|
ImageScrollArea *m_image;
|
||||||
ImageScrollAreaGL *m_imageGL;
|
ImageScrollAreaGL *m_imageGL;
|
||||||
ImageRingList *m_ringList;
|
ImageRingList *m_ringList;
|
||||||
StretchPanel *m_stretchPanel;
|
StretchToolbar *m_stretchPanel;
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
ImageInfo *m_info;
|
ImageInfo *m_info;
|
||||||
FilesystemWidget *m_filesystem;
|
FilesystemWidget *m_filesystem;
|
||||||
@@ -41,10 +41,11 @@ protected slots:
|
|||||||
void updateWindowTitle();
|
void updateWindowTitle();
|
||||||
void pixmapLoaded(Image *image);
|
void pixmapLoaded(Image *image);
|
||||||
void loadFile();
|
void loadFile();
|
||||||
void loadFile(const QString path);
|
void loadFile(const QString &path);
|
||||||
void loadFile(int row);
|
void loadFile(int row);
|
||||||
void indexDir();
|
void indexDir();
|
||||||
void saveAs();
|
void saveAs();
|
||||||
|
void convert(const QString &outfile);
|
||||||
void markImage();
|
void markImage();
|
||||||
void unmarkImage();
|
void unmarkImage();
|
||||||
void markAndNext();
|
void markAndNext();
|
||||||
@@ -55,6 +56,7 @@ protected slots:
|
|||||||
void imageStats(bool imageStats);
|
void imageStats(bool imageStats);
|
||||||
void peakFinder(bool findPeaks);
|
void peakFinder(bool findPeaks);
|
||||||
void starFinder(bool findStars);
|
void starFinder(bool findStars);
|
||||||
|
void showMarkFilesDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#include "markedfiles.h"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QSqlTableModel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
|
||||||
|
MarkedFiles::MarkedFiles(QWidget *parent) : QDialog(parent)
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Marked files"));
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
|
m_tableView = new QTableView(this);
|
||||||
|
m_tableView->verticalHeader()->setDefaultSectionSize(1);
|
||||||
|
|
||||||
|
QSqlDatabase db = QSqlDatabase::database();
|
||||||
|
m_model = new QSqlTableModel(this, db);
|
||||||
|
|
||||||
|
m_model->setTable("files");
|
||||||
|
m_model->removeColumn(0);
|
||||||
|
m_model->setHeaderData(0, Qt::Horizontal, tr("Filename"));
|
||||||
|
m_model->select();
|
||||||
|
|
||||||
|
m_tableView->setModel(m_model);
|
||||||
|
m_tableView->resizeColumnsToContents();
|
||||||
|
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
|
||||||
|
QHBoxLayout *hlayout = new QHBoxLayout;
|
||||||
|
QPushButton *clearSelectedButton = new QPushButton(tr("Clear selected"), this);
|
||||||
|
QPushButton *clearAllButton = new QPushButton(tr("Clear all"), this);
|
||||||
|
|
||||||
|
connect(clearSelectedButton, &QPushButton::pressed, this, &MarkedFiles::clearSelected);
|
||||||
|
connect(clearAllButton, &QPushButton::pressed, this, &MarkedFiles::clearAll);
|
||||||
|
|
||||||
|
layout->addWidget(m_tableView);
|
||||||
|
layout->addLayout(hlayout);
|
||||||
|
hlayout->addWidget(clearSelectedButton);
|
||||||
|
hlayout->addWidget(clearAllButton);
|
||||||
|
|
||||||
|
resize(800, 600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkedFiles::clearSelected()
|
||||||
|
{
|
||||||
|
|
||||||
|
QSqlDatabase db = QSqlDatabase::database();
|
||||||
|
QSqlQuery query("DELETE FROM files where file = ?", db);
|
||||||
|
QModelIndexList rows = m_tableView->selectionModel()->selectedRows();
|
||||||
|
QStringList files;
|
||||||
|
for(const QModelIndex &row : rows)
|
||||||
|
{
|
||||||
|
files.append(row.data().toString());
|
||||||
|
}
|
||||||
|
query.bindValue(0, files);
|
||||||
|
query.execBatch();
|
||||||
|
m_model->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkedFiles::clearAll()
|
||||||
|
{
|
||||||
|
QSqlDatabase db = QSqlDatabase::database();
|
||||||
|
db.exec("DELETE FROM files");
|
||||||
|
m_model->select();
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef MARKEDFILES_H
|
||||||
|
#define MARKEDFILES_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QSqlTableModel>
|
||||||
|
|
||||||
|
class MarkedFiles : public QDialog
|
||||||
|
{
|
||||||
|
QTableView *m_tableView;
|
||||||
|
QSqlTableModel *m_model;
|
||||||
|
public:
|
||||||
|
MarkedFiles(QWidget *parent = nullptr);
|
||||||
|
protected slots:
|
||||||
|
void clearSelected();
|
||||||
|
void clearAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MARKEDFILES_H
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 454 B |
@@ -5,5 +5,5 @@ Icon=org.nou.tenmon
|
|||||||
Comment=FITS Image viewer
|
Comment=FITS Image viewer
|
||||||
Name=Tenmon
|
Name=Tenmon
|
||||||
Categories=Graphics;2DGraphics;RasterGraphics;Viewer;
|
Categories=Graphics;2DGraphics;RasterGraphics;Viewer;
|
||||||
MimeType=image/fits;
|
MimeType=image/fits;image/x-xisf;
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
+40
-1
@@ -1,5 +1,4 @@
|
|||||||
#include "rawimage.h"
|
#include "rawimage.h"
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
RawImage::ImgType CV2Type(int cvtype)
|
RawImage::ImgType CV2Type(int cvtype)
|
||||||
{
|
{
|
||||||
@@ -234,6 +233,11 @@ RawImage::ImgType RawImage::type() const
|
|||||||
return CV2Type(m_img.type());
|
return CV2Type(m_img.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RawImage::dataType() const
|
||||||
|
{
|
||||||
|
return m_img.type();
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t RawImage::norm() const
|
uint32_t RawImage::norm() const
|
||||||
{
|
{
|
||||||
switch(m_img.type())
|
switch(m_img.type())
|
||||||
@@ -259,3 +263,38 @@ const void *RawImage::data() const
|
|||||||
{
|
{
|
||||||
return m_img.ptr();
|
return m_img.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RawImage::convertToThumbnail()
|
||||||
|
{
|
||||||
|
m_thumbAspect = (float)width() / height();
|
||||||
|
switch(CV_MAT_DEPTH(m_img.type()))
|
||||||
|
{
|
||||||
|
case CV_8U:
|
||||||
|
m_img.convertTo(m_img, CV_16U, 255);
|
||||||
|
break;
|
||||||
|
case CV_32F:
|
||||||
|
m_img.convertTo(m_img, CV_16U, 65535);
|
||||||
|
break;
|
||||||
|
case CV_16U:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_img.channels() == 1)
|
||||||
|
cv::cvtColor(m_img, m_img, cv::COLOR_GRAY2RGB);
|
||||||
|
if(m_img.channels() == 4)
|
||||||
|
cv::cvtColor(m_img, m_img, cv::COLOR_BGRA2RGB);
|
||||||
|
cv::Size dsize(THUMB_SIZE, THUMB_SIZE);
|
||||||
|
cv::resize(m_img, m_img, dsize, 0, 0, cv::INTER_NEAREST);
|
||||||
|
}
|
||||||
|
|
||||||
|
float RawImage::thumbAspect() const
|
||||||
|
{
|
||||||
|
return m_thumbAspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cv::Mat& RawImage::mat() const
|
||||||
|
{
|
||||||
|
return m_img;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include <opencv2/imgproc.hpp>
|
#include <opencv2/imgproc.hpp>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
|
const int THUMB_SIZE = 128;
|
||||||
|
const int THUMB_SIZE_BORDER = 138;
|
||||||
|
|
||||||
class Peak
|
class Peak
|
||||||
{
|
{
|
||||||
uint32_t m_v;
|
uint32_t m_v;
|
||||||
@@ -42,6 +45,7 @@ protected:
|
|||||||
double m_min;
|
double m_min;
|
||||||
double m_max;
|
double m_max;
|
||||||
double m_mad;
|
double m_mad;
|
||||||
|
float m_thumbAspect;
|
||||||
public:
|
public:
|
||||||
enum ImgType
|
enum ImgType
|
||||||
{
|
{
|
||||||
@@ -69,9 +73,13 @@ public:
|
|||||||
uint32_t height() const;
|
uint32_t height() const;
|
||||||
uint32_t size() const;
|
uint32_t size() const;
|
||||||
ImgType type() const;
|
ImgType type() const;
|
||||||
|
int dataType() const;
|
||||||
uint32_t norm() const;
|
uint32_t norm() const;
|
||||||
void* data();
|
void* data();
|
||||||
const void* data() const;
|
const void* data() const;
|
||||||
|
void convertToThumbnail();
|
||||||
|
float thumbAspect() const;
|
||||||
|
const cv::Mat& mat() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RAWIMAGE_H
|
#endif // RAWIMAGE_H
|
||||||
|
|||||||
+4
-1
@@ -2,11 +2,14 @@
|
|||||||
<qresource prefix="/shaders">
|
<qresource prefix="/shaders">
|
||||||
<file>image.frag</file>
|
<file>image.frag</file>
|
||||||
<file>image.vert</file>
|
<file>image.vert</file>
|
||||||
|
<file>thumb.frag</file>
|
||||||
|
<file>thumb.vert</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>icon.png</file>
|
|
||||||
<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>nuke_a.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ static float clamp(float x)
|
|||||||
|
|
||||||
STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
|
STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
setMinimumWidth(100);
|
||||||
setMinimumHeight(15);
|
setMinimumHeight(15);
|
||||||
setMaximumHeight(15);
|
setMaximumHeight(15);
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "stretchpanel.h"
|
#include "stretchtoolbar.h"
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
@@ -15,45 +15,34 @@ float MTF(float x, float m)
|
|||||||
return ((m - 1) * x) / ((2 * m - 1) * x - m);
|
return ((m - 1) * x) / ((2 * m - 1) * x - m);
|
||||||
}
|
}
|
||||||
|
|
||||||
StretchPanel::StretchPanel(QWidget *parent) : QWidget(parent)
|
StretchToolbar::StretchToolbar(QWidget *parent) : QToolBar(tr("Stretch toolbar"), parent)
|
||||||
{
|
{
|
||||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
setObjectName("stretchtoolbar");
|
||||||
setLayout(layout);
|
|
||||||
|
|
||||||
m_stfSlider = new STFSlider(this);
|
m_stfSlider = new STFSlider(this);
|
||||||
layout->addWidget(m_stfSlider);
|
addWidget(m_stfSlider);
|
||||||
connect(m_stfSlider, SIGNAL(paramChanged(float, float, float)), this, SIGNAL(paramChanged(float,float,float)));
|
connect(m_stfSlider, SIGNAL(paramChanged(float, float, float)), this, SIGNAL(paramChanged(float,float,float)));
|
||||||
|
|
||||||
QToolButton *autoStretchButton = new QToolButton(this);
|
QAction *autoStretchButton = addAction(QIcon(":/nuke.png"), tr("Auto Stretch F12"));
|
||||||
autoStretchButton->setIcon(QIcon(":/nuke.png"));
|
|
||||||
autoStretchButton->setToolTip(tr("Auto Stretch F12"));
|
|
||||||
autoStretchButton->setShortcut(Qt::Key_F12);
|
autoStretchButton->setShortcut(Qt::Key_F12);
|
||||||
connect(autoStretchButton, SIGNAL(pressed()), this, SIGNAL(autoStretch()));
|
connect(autoStretchButton, SIGNAL(triggered()), this, SIGNAL(autoStretch()));
|
||||||
|
|
||||||
QToolButton *resetButton = new QToolButton(this);
|
QAction *resetButton = addAction(style()->standardIcon(QStyle::SP_DialogResetButton), tr("Reset Screen Transfer Function F11"));
|
||||||
resetButton->setIcon(style()->standardIcon(QStyle::SP_DialogResetButton));
|
|
||||||
resetButton->setToolTip(tr("Reset Screen Transfer Function F11"));
|
|
||||||
resetButton->setShortcut(Qt::Key_F11);
|
resetButton->setShortcut(Qt::Key_F11);
|
||||||
connect(resetButton, &QToolButton::pressed, this, &StretchPanel::resetMTF);
|
connect(resetButton, &QAction::triggered, this, &StretchToolbar::resetMTF);
|
||||||
|
|
||||||
QToolButton *invertButton = new QToolButton(this);
|
QAction *invertButton = addAction(QIcon(":/invert.png"), tr("Invert colors"));
|
||||||
invertButton->setIcon(QIcon(":/invert.png"));
|
|
||||||
invertButton->setCheckable(true);
|
invertButton->setCheckable(true);
|
||||||
connect(invertButton, SIGNAL(toggled(bool)), this, SIGNAL(invert(bool)));
|
connect(invertButton, SIGNAL(toggled(bool)), this, SIGNAL(invert(bool)));
|
||||||
|
|
||||||
QToolButton *superPixelButton = new QToolButton(this);
|
QAction *superPixelButton = addAction(QIcon(":/bayer.png"), tr("Superpixel CFA draw 2x2 pixel as one"));
|
||||||
superPixelButton->setIcon(QIcon(":/bayer.png"));
|
|
||||||
superPixelButton->setCheckable(true);
|
superPixelButton->setCheckable(true);
|
||||||
superPixelButton->setToolTip(tr("Superpixel CFA draw 2x2 pixel as one"));
|
|
||||||
connect(superPixelButton, SIGNAL(toggled(bool)), this, SIGNAL(superPixel(bool)));
|
connect(superPixelButton, SIGNAL(toggled(bool)), this, SIGNAL(superPixel(bool)));
|
||||||
|
|
||||||
layout->addWidget(autoStretchButton);
|
m_autoStretchOnLoad = addAction(QIcon(":/nuke_a.png"), tr("Auto stretch"));
|
||||||
layout->addWidget(resetButton);
|
m_autoStretchOnLoad->setCheckable(true);
|
||||||
layout->addWidget(invertButton);
|
|
||||||
layout->addWidget(superPixelButton);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StretchPanel::stretchImage(Image *img)
|
void StretchToolbar::stretchImage(Image *img)
|
||||||
{
|
{
|
||||||
if(img)
|
if(img)
|
||||||
{
|
{
|
||||||
@@ -71,9 +60,16 @@ void StretchPanel::stretchImage(Image *img)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StretchPanel::resetMTF()
|
void StretchToolbar::resetMTF()
|
||||||
{
|
{
|
||||||
m_stfSlider->setMTFParams(0, 0.5, 1);
|
m_stfSlider->setMTFParams(0, 0.5, 1);
|
||||||
emit paramChanged(0, 0.5, 1);
|
emit paramChanged(0, 0.5, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StretchToolbar::imageLoaded(Image *img)
|
||||||
|
{
|
||||||
|
if(m_autoStretchOnLoad->isChecked())
|
||||||
|
stretchImage(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,20 +1,22 @@
|
|||||||
#ifndef STRETCHPANEL_H
|
#ifndef STRETCHTOOLBAR_H
|
||||||
#define STRETCHPANEL_H
|
#define STRETCHTOOLBAR_H
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QToolBar>
|
||||||
#include "stfslider.h"
|
#include "stfslider.h"
|
||||||
|
|
||||||
class Image;
|
class Image;
|
||||||
|
|
||||||
class StretchPanel : public QWidget
|
class StretchToolbar : public QToolBar
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
STFSlider *m_stfSlider;
|
STFSlider *m_stfSlider;
|
||||||
|
QAction *m_autoStretchOnLoad;
|
||||||
public:
|
public:
|
||||||
explicit StretchPanel(QWidget *parent = nullptr);
|
explicit StretchToolbar(QWidget *parent = nullptr);
|
||||||
public slots:
|
public slots:
|
||||||
void stretchImage(Image *img);
|
void stretchImage(Image *img);
|
||||||
void resetMTF();
|
void resetMTF();
|
||||||
|
void imageLoaded(Image *img);
|
||||||
signals:
|
signals:
|
||||||
void paramChanged(float low, float mid, float high);
|
void paramChanged(float low, float mid, float high);
|
||||||
void autoStretch();
|
void autoStretch();
|
||||||
@@ -22,4 +24,4 @@ signals:
|
|||||||
void superPixel(bool enable);
|
void superPixel(bool enable);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // STRETCHPANEL_H
|
#endif // STRETCHTOOLBAR_H
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
uniform sampler2DArray qt_Texture0;
|
||||||
|
uniform vec3 mtf_param;
|
||||||
|
uniform bool invert;
|
||||||
|
in vec3 qt_TexCoord0;
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
vec4 MTF(vec4 x, vec3 m)
|
||||||
|
{
|
||||||
|
x = (x - m.x) / (m.z - m.x);
|
||||||
|
x = clamp(x, vec4(0.0), vec4(1.0));
|
||||||
|
return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
color = texture(qt_Texture0, qt_TexCoord0);
|
||||||
|
color = MTF(color, mtf_param);
|
||||||
|
if(invert)color = vec4(1.0) - color;
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec2 qt_Vertex;
|
||||||
|
in vec2 qt_MultiTexCoord0;
|
||||||
|
in ivec3 imageSize_num;
|
||||||
|
out vec3 qt_TexCoord0;
|
||||||
|
uniform ivec3 viewport_row;
|
||||||
|
uniform mat4 mvp;
|
||||||
|
uniform vec2 offset;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
vec2 pos = qt_Vertex * 0.5;
|
||||||
|
pos.y *= -1.0;
|
||||||
|
pos = pos * imageSize_num.xy + 69;
|
||||||
|
ivec2 off = ivec2(imageSize_num.z % viewport_row.z, imageSize_num.z / viewport_row.z) * 138;
|
||||||
|
|
||||||
|
gl_Position = mvp * vec4(pos - offset + off, 0.0, 1.0);
|
||||||
|
qt_TexCoord0 = vec3(qt_MultiTexCoord0, imageSize_num.z + 0.1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user