Streamline standalone thumbnailer
This commit is contained in:
@@ -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