Thumbnailer for windows
This commit is contained in:
@@ -3,13 +3,17 @@ option(BUILD_THUMBNAILER "Build generator of thumbnails" OFF)
|
|||||||
if(BUILD_THUMBNAILER)
|
if(BUILD_THUMBNAILER)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
add_library(tenmonthumbnailer SHARED
|
add_library(tenmonthumbnailer SHARED
|
||||||
winmain.cpp
|
Dll.cpp
|
||||||
|
loadxisf.cpp
|
||||||
|
TenmonThumbnailProvider.cpp
|
||||||
|
../rawimage.h
|
||||||
../rawimage.cpp
|
../rawimage.cpp
|
||||||
../rawimage_sse.cpp)
|
../rawimage_sse.cpp)
|
||||||
|
|
||||||
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 ${LCMS2_LIB} XISF)
|
target_link_libraries(tenmonthumbnailer PRIVATE shlwapi ${LCMS2_LIB} XISF)
|
||||||
|
target_link_options(tenmonthumbnailer PRIVATE "-static")
|
||||||
else(WIN32)
|
else(WIN32)
|
||||||
qt_add_executable(tenmonthumbnailer
|
qt_add_executable(tenmonthumbnailer
|
||||||
main.cpp
|
main.cpp
|
||||||
|
|||||||
@@ -0,0 +1,240 @@
|
|||||||
|
#include <objbase.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <thumbcache.h> // For IThumbnailProvider.
|
||||||
|
#include <shlobj.h> // For SHChangeNotify
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
extern HRESULT TenmonThumbnailer_CreateInstance(REFIID riid, void **ppv);
|
||||||
|
|
||||||
|
#define SZ_CLSID_TENMONTHUMBHANDLER L"{0f3881d7-c9f0-45cb-aadb-40192aead2b4}"
|
||||||
|
#define SZ_TENMONTHUMBHANDLER L"Tenmon Thumbnail Handler"
|
||||||
|
|
||||||
|
const CLSID CLSID_TenmonThumbHandler = {0x0f3881d7, 0xc9f0, 0x45cb, {0xaa, 0xdb, 0x40, 0x19, 0x2a, 0xea, 0xd2, 0xb4}};
|
||||||
|
|
||||||
|
typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
|
||||||
|
struct CLASS_OBJECT_INIT
|
||||||
|
{
|
||||||
|
const CLSID *pClsid;
|
||||||
|
PFNCREATEINSTANCE pfnCreate;
|
||||||
|
};
|
||||||
|
|
||||||
|
// add classes supported by this module here
|
||||||
|
const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
|
||||||
|
{
|
||||||
|
{ &CLSID_TenmonThumbHandler, TenmonThumbnailer_CreateInstance }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
long g_cRefModule = 0;
|
||||||
|
|
||||||
|
// Handle the the DLL's module
|
||||||
|
HINSTANCE g_hInst = NULL;
|
||||||
|
|
||||||
|
// Standard DLL functions
|
||||||
|
STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
|
||||||
|
{
|
||||||
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
|
g_hInst = hInstance;
|
||||||
|
DisableThreadLibraryCalls(hInstance);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
STDAPI DllCanUnloadNow()
|
||||||
|
{
|
||||||
|
// Only allow the DLL to be unloaded after all outstanding references have been released
|
||||||
|
return (g_cRefModule == 0) ? S_OK : S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DllAddRef()
|
||||||
|
{
|
||||||
|
InterlockedIncrement(&g_cRefModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DllRelease()
|
||||||
|
{
|
||||||
|
InterlockedDecrement(&g_cRefModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CClassFactory : public IClassFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static HRESULT CreateInstance(REFCLSID clsid, const CLASS_OBJECT_INIT *pClassObjectInits, size_t cClassObjectInits, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
*ppv = NULL;
|
||||||
|
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
|
||||||
|
for (size_t i = 0; i < cClassObjectInits; i++)
|
||||||
|
{
|
||||||
|
if (clsid == *pClassObjectInits[i].pClsid)
|
||||||
|
{
|
||||||
|
IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
|
||||||
|
hr = pClassFactory ? S_OK : E_OUTOFMEMORY;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = pClassFactory->QueryInterface(riid, ppv);
|
||||||
|
pClassFactory->Release();
|
||||||
|
}
|
||||||
|
break; // match found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClassFactory(PFNCREATEINSTANCE pfnCreate) : _cRef(1), _pfnCreate(pfnCreate)
|
||||||
|
{
|
||||||
|
DllAddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
|
||||||
|
{
|
||||||
|
static const QITAB qit[] =
|
||||||
|
{
|
||||||
|
QITABENT(CClassFactory, IClassFactory),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&_cRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
long cRef = InterlockedDecrement(&_cRef);
|
||||||
|
if (cRef == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IClassFactory
|
||||||
|
IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
return punkOuter ? CLASS_E_NOAGGREGATION : _pfnCreate(riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP LockServer(BOOL fLock)
|
||||||
|
{
|
||||||
|
if (fLock)
|
||||||
|
{
|
||||||
|
DllAddRef();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DllRelease();
|
||||||
|
}
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~CClassFactory()
|
||||||
|
{
|
||||||
|
DllRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
long _cRef;
|
||||||
|
PFNCREATEINSTANCE _pfnCreate;
|
||||||
|
};
|
||||||
|
|
||||||
|
STDAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A struct to hold the information required for a registry entry
|
||||||
|
|
||||||
|
struct REGISTRY_ENTRY
|
||||||
|
{
|
||||||
|
HKEY hkeyRoot;
|
||||||
|
PCWSTR pszKeyName;
|
||||||
|
PCWSTR pszValueName;
|
||||||
|
PCWSTR pszData;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates a registry key (if needed) and sets the default value of the key
|
||||||
|
|
||||||
|
HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(pRegistryEntry->hkeyRoot, pRegistryEntry->pszKeyName,
|
||||||
|
0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL));
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(RegSetValueExW(hKey, pRegistryEntry->pszValueName, 0, REG_SZ,
|
||||||
|
(LPBYTE) pRegistryEntry->pszData,
|
||||||
|
((DWORD) wcslen(pRegistryEntry->pszData) + 1) * sizeof(WCHAR)));
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Registers this COM server
|
||||||
|
//
|
||||||
|
STDAPI DllRegisterServer()
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
WCHAR szModuleName[MAX_PATH];
|
||||||
|
|
||||||
|
if (!GetModuleFileNameW(g_hInst, szModuleName, ARRAYSIZE(szModuleName)))
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// List of registry entries we want to create
|
||||||
|
const REGISTRY_ENTRY rgRegistryEntries[] =
|
||||||
|
{
|
||||||
|
// RootKey KeyName ValueName Data
|
||||||
|
{HKEY_CURRENT_USER, L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER, NULL, SZ_TENMONTHUMBHANDLER},
|
||||||
|
{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\\.xisf\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", NULL, SZ_CLSID_TENMONTHUMBHANDLER},
|
||||||
|
};
|
||||||
|
|
||||||
|
hr = S_OK;
|
||||||
|
for (int i = 0; i < ARRAYSIZE(rgRegistryEntries) && SUCCEEDED(hr); i++)
|
||||||
|
{
|
||||||
|
hr = CreateRegKeyAndSetValue(&rgRegistryEntries[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
// This tells the shell to invalidate the thumbnail cache. This is important because any .recipe files
|
||||||
|
// viewed before registering this handler would otherwise show cached blank thumbnails.
|
||||||
|
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Unregisters this COM server
|
||||||
|
//
|
||||||
|
STDAPI DllUnregisterServer()
|
||||||
|
{
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
const PCWSTR rgpszKeys[] =
|
||||||
|
{
|
||||||
|
L"Software\\Classes\\CLSID\\" SZ_CLSID_TENMONTHUMBHANDLER,
|
||||||
|
L"Software\\Classes\\.xisf\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Delete the registry entries
|
||||||
|
for (int i = 0; i < ARRAYSIZE(rgpszKeys) && SUCCEEDED(hr); i++)
|
||||||
|
{
|
||||||
|
hr = HRESULT_FROM_WIN32(RegDeleteTreeW(HKEY_CURRENT_USER, rgpszKeys[i]));
|
||||||
|
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
|
||||||
|
{
|
||||||
|
// If the registry entry has already been deleted, say S_OK.
|
||||||
|
hr = S_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
// 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 <thumbcache.h> // For IThumbnailProvider.
|
||||||
|
#include <new>
|
||||||
|
#include "libxisf.h"
|
||||||
|
|
||||||
|
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize);
|
||||||
|
|
||||||
|
class TenmonThumbProvider : public IInitializeWithStream,
|
||||||
|
public IThumbnailProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TenmonThumbProvider() : _cRef(1), _pStream(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TenmonThumbProvider()
|
||||||
|
{
|
||||||
|
if (_pStream)
|
||||||
|
{
|
||||||
|
_pStream->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IUnknown
|
||||||
|
IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
static const QITAB qit[] =
|
||||||
|
{
|
||||||
|
QITABENT(TenmonThumbProvider, IInitializeWithStream),
|
||||||
|
QITABENT(TenmonThumbProvider, IThumbnailProvider),
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) AddRef()
|
||||||
|
{
|
||||||
|
return InterlockedIncrement(&_cRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
IFACEMETHODIMP_(ULONG) Release()
|
||||||
|
{
|
||||||
|
ULONG cRef = InterlockedDecrement(&_cRef);
|
||||||
|
if (!cRef)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return cRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IInitializeWithStream
|
||||||
|
IFACEMETHODIMP Initialize(IStream *pStream, DWORD grfMode);
|
||||||
|
|
||||||
|
// IThumbnailProvider
|
||||||
|
IFACEMETHODIMP GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
long _cRef;
|
||||||
|
IStream *_pStream; // provided during initialization.
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT TenmonThumbnailer_CreateInstance(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
TenmonThumbProvider *pNew = new (std::nothrow) TenmonThumbProvider();
|
||||||
|
HRESULT hr = pNew ? S_OK : E_OUTOFMEMORY;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = pNew->QueryInterface(riid, ppv);
|
||||||
|
pNew->Release();
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IInitializeWithStream
|
||||||
|
IFACEMETHODIMP TenmonThumbProvider::Initialize(IStream *pStream, DWORD)
|
||||||
|
{
|
||||||
|
HRESULT hr = E_UNEXPECTED; // can only be inited once
|
||||||
|
if (_pStream == NULL)
|
||||||
|
{
|
||||||
|
// take a reference to the stream if we have not been inited yet
|
||||||
|
hr = pStream->QueryInterface(&_pStream);
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IThumbnailProvider
|
||||||
|
IFACEMETHODIMP TenmonThumbProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha)
|
||||||
|
{
|
||||||
|
LibXISF::ByteArray data;
|
||||||
|
ULONG readSize = 0;
|
||||||
|
ULONG read;
|
||||||
|
data.resize(1024*1024);
|
||||||
|
|
||||||
|
while(_pStream->Read(data.data() + readSize, data.size() - readSize, &read) == S_OK)
|
||||||
|
{
|
||||||
|
readSize += read;
|
||||||
|
data.resize(data.size() + 1024*1024);
|
||||||
|
}
|
||||||
|
readSize += read;
|
||||||
|
|
||||||
|
*pdwAlpha = WTSAT_RGB;
|
||||||
|
|
||||||
|
data.resize(readSize);
|
||||||
|
if(loadXISF(data, phbmp, cx))
|
||||||
|
return S_OK;
|
||||||
|
else
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
#include "libxisf.h"
|
||||||
|
#include <thumbcache.h>
|
||||||
|
#include "../rawimage.h"
|
||||||
|
|
||||||
|
bool OpenGLES = false;
|
||||||
|
|
||||||
|
bool loadXISF(const LibXISF::ByteArray &data, HBITMAP *hbmp, UINT thumbSize)
|
||||||
|
{
|
||||||
|
OutputDebugStringA("TENMON");
|
||||||
|
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);
|
||||||
|
UINT w = tmpImage.width();
|
||||||
|
UINT h = tmpImage.height();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
rawImage->calcStats();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
catch (LibXISF::Error &err)
|
||||||
|
{
|
||||||
|
char text[1024];
|
||||||
|
sprintf(text, "Failed to open XISF image %s", err.what());
|
||||||
|
OutputDebugStringA(text);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user