Add FITS to thumbnailer
This commit is contained in:
@@ -12,7 +12,7 @@ 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} XISF)
|
target_link_libraries(tenmonthumbnailer PRIVATE shlwapi ${LCMS2_LIB} ${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
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ STDAPI DllRegisterServer()
|
|||||||
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER L"\\InProcServer32", NULL, szModuleName},
|
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER L"\\InProcServer32", NULL, szModuleName},
|
||||||
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", L"Apartment"},
|
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER L"\\InProcServer32", L"ThreadingModel", L"Apartment"},
|
||||||
{HKEY_CURRENT_USER, L"Software\\Classes\\.xisf\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, SZ_CLSID_TENMONTHUMBHANDLER},
|
{HKEY_CURRENT_USER, L"Software\\Classes\\.xisf\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, SZ_CLSID_TENMONTHUMBHANDLER},
|
||||||
|
{HKEY_CURRENT_USER, L"Software\\Classes\\.fits\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, SZ_CLSID_TENMONTHUMBHANDLER},
|
||||||
|
{HKEY_CURRENT_USER, L"Software\\Classes\\.fit\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, SZ_CLSID_TENMONTHUMBHANDLER},
|
||||||
};
|
};
|
||||||
|
|
||||||
hr = S_OK;
|
hr = S_OK;
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
||||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
||||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
||||||
// PARTICULAR PURPOSE.
|
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
||||||
|
|
||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include <thumbcache.h> // For IThumbnailProvider.
|
#include <thumbcache.h> // For IThumbnailProvider.
|
||||||
#include <new>
|
#include <new>
|
||||||
#include "libxisf.h"
|
#include "libxisf.h"
|
||||||
|
|
||||||
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
||||||
|
bool loadFITS(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
||||||
|
|
||||||
class TenmonThumbProvider : public IInitializeWithStream,
|
class TenmonThumbProvider : public IInitializeWithStream,
|
||||||
public IThumbnailProvider
|
public IThumbnailProvider
|
||||||
@@ -109,8 +103,19 @@ IFACEMETHODIMP TenmonThumbProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_AL
|
|||||||
*pdwAlpha = WTSAT_RGB;
|
*pdwAlpha = WTSAT_RGB;
|
||||||
|
|
||||||
data.resize(readSize);
|
data.resize(readSize);
|
||||||
if(loadXISF(data, phbmp, cx))
|
if(data[0] == 'X' && data[1] == 'I' && data[2] == 'S' && data[3] == 'F')
|
||||||
return S_OK;
|
{
|
||||||
|
if(loadXISF(data, phbmp, cx))
|
||||||
|
return S_OK;
|
||||||
|
else
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return E_FAIL;
|
{
|
||||||
|
if(loadFITS(data, phbmp, cx))
|
||||||
|
return S_OK;
|
||||||
|
else
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|||||||
+177
-65
@@ -1,12 +1,80 @@
|
|||||||
#include "libxisf.h"
|
#include "libxisf.h"
|
||||||
#include <thumbcache.h>
|
#include <thumbcache.h>
|
||||||
#include "../rawimage.h"
|
#include "../rawimage.h"
|
||||||
|
#include <fitsio2.h>
|
||||||
|
|
||||||
bool OpenGLES = false;
|
bool OpenGLES = false;
|
||||||
|
|
||||||
|
void RawImageToHTBITMAP(std::shared_ptr<RawImage> &rawImage, HBITMAP *hbmp, UINT thumbSize)
|
||||||
|
{
|
||||||
|
rawImage->calcStats();
|
||||||
|
if(rawImage->imageStats().m_median[0] < rawImage->norm() * 0.2f)
|
||||||
|
{
|
||||||
|
//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)
|
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
||||||
{
|
{
|
||||||
OutputDebugStringA("TENMON");
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LibXISF::XISFReader xisf;
|
LibXISF::XISFReader xisf;
|
||||||
@@ -25,11 +93,8 @@ bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LibXISF::Image tmpImage = xisfImage;
|
LibXISF::Image tmpImage = xisfImage;
|
||||||
tmpImage.convertPixelStorageTo(LibXISF::Image::Planar);
|
tmpImage.convertPixelStorageTo(LibXISF::Image::Planar);
|
||||||
UINT w = tmpImage.width();
|
|
||||||
UINT h = tmpImage.height();
|
|
||||||
std::shared_ptr<RawImage> rawImage;
|
std::shared_ptr<RawImage> rawImage;
|
||||||
|
|
||||||
if(tmpImage.colorSpace() == LibXISF::Image::ColorSpace::Gray)
|
if(tmpImage.colorSpace() == LibXISF::Image::ColorSpace::Gray)
|
||||||
@@ -42,75 +107,122 @@ bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
|||||||
rawImage = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
|
rawImage = RawImage::fromPlanar(tmpImage.imageData(), tmpImage.width(), tmpImage.height(), tmpImage.channelCount(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
rawImage->calcStats();
|
RawImageToHTBITMAP(rawImage, hbmp, thumbSize);
|
||||||
if(rawImage->imageStats().m_median[0] < rawImage->norm() * 0.2f)
|
|
||||||
{
|
|
||||||
OutputDebugStringA("Stretch image");
|
|
||||||
MTFParam params = rawImage->calcMTFParams();
|
|
||||||
rawImage->applySTF(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(tmpImage.channelCount() == 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;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (LibXISF::Error &err)
|
catch (LibXISF::Error &err)
|
||||||
{
|
{
|
||||||
char text[1024];
|
char text[1024];
|
||||||
sprintf(text, "Failed to open XISF image %s", err.what());
|
sprintf_s(text, 1000, "Failed to open XISF image %s", err.what());
|
||||||
OutputDebugStringA(text);
|
OutputDebugStringA(text);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
bool OpenGLES = false;
|
|
||||||
Reference in New Issue
Block a user