mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
902 lines
18 KiB
C++
902 lines
18 KiB
C++
|
#include "main.h"
|
||
|
#include "./imageCache.h"
|
||
|
#include <wincodec.h>
|
||
|
#include <vector>
|
||
|
#include <algorithm>
|
||
|
|
||
|
|
||
|
struct DeviceColoredImage
|
||
|
{
|
||
|
size_t ref;
|
||
|
DeviceImage *base;
|
||
|
HBITMAP bitmap;
|
||
|
COLORREF color1;
|
||
|
COLORREF color2;
|
||
|
DeviceImageFilter filter;
|
||
|
void *filterParam;
|
||
|
};
|
||
|
|
||
|
typedef std::vector<DeviceColoredImage*> DeviceColoredImageList;
|
||
|
|
||
|
struct DeviceImage
|
||
|
{
|
||
|
size_t ref;
|
||
|
DeviceImageCache *cache;
|
||
|
wchar_t *source;
|
||
|
HBITMAP bitmap;
|
||
|
HBITMAP exactBitmap;
|
||
|
int width;
|
||
|
int height;
|
||
|
DeviceImageLoader loader;
|
||
|
void *loaderParam;
|
||
|
DeviceColoredImageList list;
|
||
|
};
|
||
|
typedef std::vector<DeviceImage*> DeviceImageList;
|
||
|
|
||
|
struct DeviceImageCache
|
||
|
{
|
||
|
DeviceImageList list;
|
||
|
IWICImagingFactory *wicFactory;
|
||
|
};
|
||
|
|
||
|
typedef struct DeviceImageSeachParam
|
||
|
{
|
||
|
const wchar_t *path;
|
||
|
int width;
|
||
|
int height;
|
||
|
} DeviceImageSeachParam;
|
||
|
|
||
|
typedef struct DeviceColoredImageSeachParam
|
||
|
{
|
||
|
COLORREF color1;
|
||
|
COLORREF color2;
|
||
|
} DeviceColoredImageSeachParam;
|
||
|
|
||
|
|
||
|
DeviceImageCache *
|
||
|
DeviceImageCache_Create()
|
||
|
{
|
||
|
DeviceImageCache *self;
|
||
|
|
||
|
self = new DeviceImageCache();
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
self->wicFactory = NULL;
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
DeviceImageCache_Free(DeviceImageCache *self)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
size_t index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
DeviceImage *image = self->list[index];
|
||
|
image->cache = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != self->wicFactory)
|
||
|
self->wicFactory->Release();
|
||
|
|
||
|
delete(self);
|
||
|
}
|
||
|
|
||
|
|
||
|
static DeviceImage *
|
||
|
DeviceImage_Create(DeviceImageCache *cache, const wchar_t *path, int width, int height,
|
||
|
DeviceImageLoader loader, void *loaderParam)
|
||
|
{
|
||
|
DeviceImage *self;
|
||
|
|
||
|
if (NULL == loader)
|
||
|
return NULL;
|
||
|
|
||
|
self = new DeviceImage();
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
self->ref = 1;
|
||
|
self->cache = cache;
|
||
|
self->source = ResourceString_Duplicate(path);
|
||
|
self->loader = loader;
|
||
|
self->loaderParam = loaderParam;
|
||
|
self->bitmap = NULL;
|
||
|
self->exactBitmap = NULL;
|
||
|
self->width = width;
|
||
|
self->height = height;
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
DeviceImage_Free(DeviceImage *self)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
if (NULL != self->source)
|
||
|
ResourceString_Free(self->source);
|
||
|
|
||
|
if (NULL != self->bitmap)
|
||
|
DeleteObject(self->bitmap);
|
||
|
|
||
|
if (NULL != self->exactBitmap &&
|
||
|
self->exactBitmap != self->bitmap)
|
||
|
{
|
||
|
DeleteObject(self->exactBitmap);
|
||
|
}
|
||
|
|
||
|
delete(self);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
DeviceImageCache_SearchCb(const void *key, const void *element)
|
||
|
{
|
||
|
DeviceImageSeachParam *search;
|
||
|
DeviceImage *image;
|
||
|
int result;
|
||
|
|
||
|
search = (DeviceImageSeachParam*)key;
|
||
|
image = (DeviceImage*)element;
|
||
|
|
||
|
result = search->height - image->height;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
result = search->width - image->width;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
if (FALSE != IS_INTRESOURCE(search->path) ||
|
||
|
FALSE != IS_INTRESOURCE(image->source))
|
||
|
{
|
||
|
return (int)(INT_PTR)(search->path - image->source);
|
||
|
}
|
||
|
|
||
|
return CompareString(CSTR_INVARIANT, 0, search->path, -1, image->source, -1) - 2;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
DeviceImageCache_SortCb(const void *element1, const void *element2)
|
||
|
{
|
||
|
DeviceImage *image1;
|
||
|
DeviceImage *image2;
|
||
|
int result;
|
||
|
|
||
|
image1 = (DeviceImage*)element1;
|
||
|
image2 = (DeviceImage*)element2;
|
||
|
|
||
|
result = image1->height - image2->height;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
result = image1->width - image2->width;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
if (FALSE != IS_INTRESOURCE(image1->source) ||
|
||
|
FALSE != IS_INTRESOURCE(image2->source))
|
||
|
{
|
||
|
return (int)(INT_PTR)(image1->source - image2->source);
|
||
|
}
|
||
|
|
||
|
return CompareString(CSTR_INVARIANT, 0, image1->source, -1, image2->source, -1) - 2;
|
||
|
}
|
||
|
static int
|
||
|
DeviceImageCache_SortCb_V2(const void* element1, const void* element2)
|
||
|
{
|
||
|
return DeviceImageCache_SortCb(element1, element2) < 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static HBITMAP
|
||
|
DeviceImage_DefaultImageLoader(const wchar_t *path, int width, int height, void *param)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
unsigned int flags;
|
||
|
|
||
|
flags = ISF_PREMULTIPLY;
|
||
|
if (FALSE == IS_INTRESOURCE(path))
|
||
|
flags |= ISF_LOADFROMFILE;
|
||
|
|
||
|
bitmap = Image_Load(path, SRC_TYPE_PNG, flags, 0, 0);
|
||
|
|
||
|
return bitmap;
|
||
|
}
|
||
|
|
||
|
DeviceImage *
|
||
|
DeviceImageCache_GetImage(DeviceImageCache *self, const wchar_t *path, int width, int height, DeviceImageLoader loader, void *user)
|
||
|
{
|
||
|
DeviceImage *image, *image_ptr = 0;
|
||
|
DeviceImageSeachParam searchParam;
|
||
|
|
||
|
if (width < 1)
|
||
|
width = 0;
|
||
|
|
||
|
if (height < 1)
|
||
|
height = 0;
|
||
|
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL == path ||
|
||
|
(FALSE == IS_INTRESOURCE(path) && L'\0' == *path))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
searchParam.height = height;
|
||
|
searchParam.width = width;
|
||
|
searchParam.path = path;
|
||
|
|
||
|
//image_ptr = (DeviceImage**)bsearch(&searchParam, &self->list[0], self->list.size(),
|
||
|
// sizeof(DeviceImage**),
|
||
|
// DeviceImageCache_SearchCb);
|
||
|
auto it = std::find_if(self->list.begin(), self->list.end(),
|
||
|
[&](DeviceImage* upT) -> bool
|
||
|
{
|
||
|
return DeviceImageCache_SearchCb(&searchParam, upT) == 0;
|
||
|
}
|
||
|
);
|
||
|
if (it != self->list.end())
|
||
|
{
|
||
|
image_ptr = *it;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (NULL != image_ptr)
|
||
|
{
|
||
|
image = image_ptr;
|
||
|
DeviceImage_AddRef(image);
|
||
|
return image;
|
||
|
}
|
||
|
|
||
|
if (NULL == loader)
|
||
|
loader = DeviceImage_DefaultImageLoader;
|
||
|
|
||
|
image = DeviceImage_Create(self, path, width, height, loader, user);
|
||
|
if (NULL != image)
|
||
|
{
|
||
|
self->list.push_back(image);
|
||
|
//qsort(&self->list[0], self->list.size(), sizeof(DeviceImage**), DeviceImageCache_SortCb);
|
||
|
std::sort(self->list.begin(), self->list.end(), DeviceImageCache_SortCb_V2);
|
||
|
}
|
||
|
|
||
|
return image;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
DeviceImageCache_RemoveImage(DeviceImageCache *self, DeviceImage *image)
|
||
|
{
|
||
|
size_t index;
|
||
|
|
||
|
if (NULL == self || NULL == image)
|
||
|
return FALSE;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
if (self->list[index] == image)
|
||
|
{
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
size_t
|
||
|
DeviceImage_AddRef(DeviceImage *self)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return 0;
|
||
|
return InterlockedIncrement((LONG*)&self->ref);
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
DeviceImage_Release(DeviceImage *self)
|
||
|
{
|
||
|
size_t r;
|
||
|
if (NULL == self || 0 == self->ref)
|
||
|
return 0;
|
||
|
|
||
|
r = InterlockedDecrement((LONG*)&self->ref);
|
||
|
if (0 == r)
|
||
|
{
|
||
|
if (NULL != self->cache)
|
||
|
DeviceImageCache_RemoveImage(self->cache, self);
|
||
|
DeviceImage_Free(self);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
DeviceImage_GetSize(DeviceImage *self, int *width, int *height)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL != width)
|
||
|
*width = self->width;
|
||
|
|
||
|
if (NULL != height)
|
||
|
*height = self->height;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static IWICImagingFactory*
|
||
|
DeviceImage_GetWicFactory(DeviceImageCache *cache)
|
||
|
{
|
||
|
IWICImagingFactory *wicFactory;
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL != cache &&
|
||
|
NULL != cache->wicFactory)
|
||
|
{
|
||
|
cache->wicFactory->AddRef();
|
||
|
return cache->wicFactory;
|
||
|
}
|
||
|
|
||
|
hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
|
||
|
IID_PPV_ARGS(&wicFactory));
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL != cache)
|
||
|
{
|
||
|
wicFactory->AddRef();
|
||
|
cache->wicFactory = wicFactory;
|
||
|
}
|
||
|
|
||
|
return wicFactory;
|
||
|
}
|
||
|
|
||
|
|
||
|
static HBITMAP
|
||
|
DeviceImage_HBitmapFromWicSource(IWICBitmapSource *wicSource, unsigned int targetWidth,
|
||
|
unsigned int targetHeight, DeviceImageFlags flags)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
HBITMAP bitmap;
|
||
|
BITMAPINFO bitmapInfo;
|
||
|
unsigned int width, height, bitmapWidth, bitmapHeight;
|
||
|
void *pixelData = NULL;
|
||
|
WICPixelFormatGUID pixelFormat;
|
||
|
HDC windowDC;
|
||
|
unsigned int strideSize, imageSize;
|
||
|
|
||
|
if (NULL == wicSource)
|
||
|
return NULL;
|
||
|
|
||
|
hr = wicSource->GetPixelFormat(&pixelFormat);
|
||
|
if (FAILED(hr) ||
|
||
|
(GUID_WICPixelFormat32bppPBGRA != pixelFormat &&
|
||
|
GUID_WICPixelFormat32bppBGR != pixelFormat &&
|
||
|
GUID_WICPixelFormat32bppBGRA != pixelFormat &&
|
||
|
GUID_WICPixelFormat32bppRGBA != pixelFormat &&
|
||
|
GUID_WICPixelFormat32bppPRGBA != pixelFormat))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
hr = wicSource->GetSize(&width, &height);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
|
||
|
if (0 != (DeviceImage_ExactSize & flags))
|
||
|
{
|
||
|
bitmapWidth = (targetWidth > width) ? targetWidth : width;
|
||
|
bitmapHeight = (targetHeight > height) ? targetHeight : height;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bitmapWidth = width;
|
||
|
bitmapHeight = height;
|
||
|
}
|
||
|
|
||
|
ZeroMemory(&bitmapInfo, sizeof(bitmapInfo));
|
||
|
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bitmapInfo.bmiHeader.biWidth = bitmapWidth;
|
||
|
bitmapInfo.bmiHeader.biHeight = -(LONG)bitmapHeight;
|
||
|
bitmapInfo.bmiHeader.biPlanes = 1;
|
||
|
bitmapInfo.bmiHeader.biBitCount = 32;
|
||
|
bitmapInfo.bmiHeader.biCompression = BI_RGB;
|
||
|
|
||
|
windowDC = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE);
|
||
|
|
||
|
bitmap = CreateDIBSection(windowDC, &bitmapInfo, DIB_RGB_COLORS, &pixelData, NULL, 0);
|
||
|
|
||
|
if (NULL != windowDC)
|
||
|
ReleaseDC(NULL, windowDC);
|
||
|
|
||
|
if (NULL == bitmap)
|
||
|
return NULL;
|
||
|
|
||
|
hr = UIntMult(bitmapWidth, sizeof(DWORD), &strideSize);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (0 != (DeviceImage_ExactSize & flags) &&
|
||
|
(bitmapWidth > width || bitmapHeight > height))
|
||
|
{
|
||
|
if (SUCCEEDED(UIntMult(strideSize, bitmapHeight, &imageSize)))
|
||
|
ZeroMemory(pixelData, imageSize);
|
||
|
}
|
||
|
|
||
|
hr = UIntMult(strideSize, height, &imageSize);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
unsigned int offset, delta;
|
||
|
|
||
|
offset = 0;
|
||
|
|
||
|
if (0 != (DeviceImage_AlignVCenter & flags))
|
||
|
{
|
||
|
delta = bitmapHeight - height;
|
||
|
delta = delta/2 + delta%2;
|
||
|
}
|
||
|
else if (0 != (DeviceImage_AlignBottom & flags))
|
||
|
delta = bitmapHeight - height;
|
||
|
else
|
||
|
delta = 0;
|
||
|
|
||
|
if (0 != delta && SUCCEEDED(UIntMult(delta, strideSize, &delta)))
|
||
|
offset += delta;
|
||
|
|
||
|
if (0 != (DeviceImage_AlignHCenter & flags))
|
||
|
{
|
||
|
delta = bitmapWidth - width;
|
||
|
delta = delta/2;
|
||
|
}
|
||
|
else if (0 != (DeviceImage_AlignRight & flags))
|
||
|
delta = bitmapWidth - width;
|
||
|
else
|
||
|
delta = 0;
|
||
|
|
||
|
if (0 != delta && SUCCEEDED(UIntMult(delta, sizeof(DWORD), &delta)))
|
||
|
offset += delta;
|
||
|
|
||
|
hr = wicSource->CopyPixels(NULL, strideSize, imageSize, ((BYTE*)pixelData) + offset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
DeleteObject(bitmap);
|
||
|
bitmap = NULL;
|
||
|
}
|
||
|
|
||
|
return bitmap;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
DeviceImage_ScaleBitmap(HBITMAP sourceBitmap, int width, int height, DeviceImageCache *cache,
|
||
|
DeviceImageFlags flags, HBITMAP *scalledBitmap)
|
||
|
{
|
||
|
HBITMAP resultBitmap;
|
||
|
BITMAP sourceInfo;
|
||
|
IWICImagingFactory *wicFactory;
|
||
|
unsigned int requestedWidth, requestedHeight;
|
||
|
double scale, scaleH;
|
||
|
int t;
|
||
|
|
||
|
if (NULL == sourceBitmap || NULL == scalledBitmap)
|
||
|
return FALSE;
|
||
|
|
||
|
if (sizeof(sourceInfo) != GetObject(sourceBitmap, sizeof(sourceInfo), &sourceInfo))
|
||
|
return FALSE;
|
||
|
|
||
|
if (sourceInfo.bmHeight < 0)
|
||
|
sourceInfo.bmHeight = -sourceInfo.bmHeight;
|
||
|
|
||
|
scale = (double)width / sourceInfo.bmWidth;
|
||
|
scaleH = (double)height / sourceInfo.bmHeight;
|
||
|
|
||
|
if (scale > scaleH)
|
||
|
scale = scaleH;
|
||
|
|
||
|
if (1.0 == scale)
|
||
|
{
|
||
|
*scalledBitmap = NULL;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
requestedWidth = width;
|
||
|
requestedHeight = height;
|
||
|
|
||
|
t = (int)((sourceInfo.bmWidth * scale) + 0.5);
|
||
|
if (t < width)
|
||
|
width = t;
|
||
|
|
||
|
t = (int)((sourceInfo.bmHeight * scale) + 0.5);
|
||
|
if (t < height)
|
||
|
height = t;
|
||
|
|
||
|
|
||
|
resultBitmap = NULL;
|
||
|
|
||
|
wicFactory = DeviceImage_GetWicFactory(cache);
|
||
|
if (NULL != wicFactory)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
IWICBitmap *wicBitmap;
|
||
|
|
||
|
hr = wicFactory->CreateBitmapFromHBITMAP(sourceBitmap, NULL,
|
||
|
WICBitmapUsePremultipliedAlpha, &wicBitmap);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IWICBitmapScaler *wicScaler;
|
||
|
hr = wicFactory->CreateBitmapScaler(&wicScaler);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = wicScaler->Initialize(wicBitmap, width, height, WICBitmapInterpolationModeFant);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
resultBitmap = DeviceImage_HBitmapFromWicSource(wicScaler,
|
||
|
requestedWidth, requestedHeight, flags);
|
||
|
}
|
||
|
wicScaler->Release();
|
||
|
|
||
|
}
|
||
|
wicBitmap->Release();
|
||
|
}
|
||
|
|
||
|
wicFactory->Release();
|
||
|
}
|
||
|
|
||
|
*scalledBitmap = resultBitmap;
|
||
|
return (NULL != resultBitmap);
|
||
|
}
|
||
|
|
||
|
static HBITMAP
|
||
|
DeviceImage_GetExactBitmap(DeviceImage *self, DeviceImageFlags flags)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL == self->exactBitmap)
|
||
|
{
|
||
|
if (NULL != self->bitmap)
|
||
|
{
|
||
|
BITMAP bi;
|
||
|
if (sizeof(bi) == GetObject(self->bitmap, sizeof(bi), &bi) &&
|
||
|
bi.bmWidth == self->width && bi.bmHeight == self->height)
|
||
|
{
|
||
|
self->exactBitmap = self->bitmap;
|
||
|
return self->exactBitmap;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != self->loader)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
bitmap = self->loader(self->source, self->width, self->height, self->loaderParam);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
if (FALSE != DeviceImage_ScaleBitmap(bitmap, self->width, self->height,
|
||
|
self->cache, flags, &self->exactBitmap))
|
||
|
{
|
||
|
|
||
|
if (NULL == self->exactBitmap)
|
||
|
{
|
||
|
self->exactBitmap = bitmap;
|
||
|
bitmap = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != bitmap)
|
||
|
DeleteObject(bitmap);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return self->exactBitmap;
|
||
|
}
|
||
|
|
||
|
|
||
|
HBITMAP
|
||
|
DeviceImage_GetBitmap(DeviceImage *self, DeviceImageFlags flags)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
if (0 != (DeviceImage_ExactSize & flags))
|
||
|
return DeviceImage_GetExactBitmap(self, flags);
|
||
|
|
||
|
if (NULL == self->bitmap)
|
||
|
{
|
||
|
if (NULL != self->loader)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
bitmap = self->loader(self->source, self->width, self->height, self->loaderParam);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
if (FALSE == DeviceImage_ScaleBitmap(bitmap, self->width, self->height,
|
||
|
self->cache, flags, &self->bitmap))
|
||
|
{
|
||
|
self->bitmap = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != self->bitmap)
|
||
|
DeleteObject(bitmap);
|
||
|
else
|
||
|
self->bitmap = bitmap;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return self->bitmap;
|
||
|
}
|
||
|
|
||
|
|
||
|
static DeviceColoredImage *
|
||
|
DeveiceColoredImage_Create(DeviceImage *base, COLORREF color1, COLORREF color2,
|
||
|
DeviceImageFilter filter, void *user)
|
||
|
{
|
||
|
DeviceColoredImage *coloredImage;
|
||
|
|
||
|
if (NULL == base)
|
||
|
return NULL;
|
||
|
|
||
|
coloredImage = (DeviceColoredImage*)malloc(sizeof(DeviceColoredImage));
|
||
|
if (NULL == coloredImage)
|
||
|
return NULL;
|
||
|
|
||
|
ZeroMemory(coloredImage, sizeof(DeviceColoredImage));
|
||
|
|
||
|
coloredImage->ref = 1;
|
||
|
coloredImage->base = base;
|
||
|
coloredImage->color1 = color1;
|
||
|
coloredImage->color2 = color2;
|
||
|
coloredImage->filter = filter;
|
||
|
coloredImage->filterParam = user;
|
||
|
|
||
|
DeviceImage_AddRef(base);
|
||
|
|
||
|
return coloredImage;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
DeviceColoredImage_Free(DeviceColoredImage *self)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return;
|
||
|
|
||
|
if (NULL != self->bitmap)
|
||
|
DeleteObject(self->bitmap);
|
||
|
|
||
|
free(self);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
DeviceColoredImage_SearchCb(const void *key, const void *element)
|
||
|
{
|
||
|
DeviceColoredImageSeachParam *search;
|
||
|
DeviceColoredImage *image;
|
||
|
int result;
|
||
|
|
||
|
search = (DeviceColoredImageSeachParam*)key;
|
||
|
image = (DeviceColoredImage*)element;
|
||
|
|
||
|
result = search->color1 - image->color1;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
return search->color2- image->color2;
|
||
|
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
DeviceColoredImage_SortCb(const void *element1, const void *element2)
|
||
|
{
|
||
|
DeviceColoredImage *image1;
|
||
|
DeviceColoredImage *image2;
|
||
|
int result;
|
||
|
|
||
|
image1 = (DeviceColoredImage*)element1;
|
||
|
image2 = (DeviceColoredImage*)element2;
|
||
|
|
||
|
result = image1->color1 - image2->color1;
|
||
|
if (0 != result)
|
||
|
return result;
|
||
|
|
||
|
return image1->color2- image2->color2;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
DeviceColoredImage_SortCb_V2(const void* element1, const void* element2)
|
||
|
{
|
||
|
return DeviceColoredImage_SortCb(element1, element2) < 0;
|
||
|
}
|
||
|
|
||
|
DeviceColoredImage *
|
||
|
DeviceImage_GetColoredImage(DeviceImage *self, COLORREF color1, COLORREF color2,
|
||
|
DeviceImageFilter filter, void *user)
|
||
|
{
|
||
|
size_t listSize;
|
||
|
DeviceColoredImage *image;
|
||
|
DeviceColoredImageSeachParam searchParam;
|
||
|
|
||
|
searchParam.color1 = color1;
|
||
|
searchParam.color2 = color2;
|
||
|
|
||
|
listSize = self->list.size();
|
||
|
if (listSize > 0)
|
||
|
{
|
||
|
DeviceColoredImage* image_ptr = NULL;
|
||
|
//DeviceColoredImage **image_ptr = (DeviceColoredImage**)bsearch(&searchParam, &self->list[0], listSize,
|
||
|
// sizeof(DeviceColoredImage**),
|
||
|
// DeviceColoredImage_SearchCb);
|
||
|
|
||
|
auto it = std::find_if(self->list.begin(), self->list.end(),
|
||
|
[&](DeviceColoredImage* upT) -> bool
|
||
|
{
|
||
|
return DeviceColoredImage_SearchCb(&searchParam, upT) == 0;
|
||
|
}
|
||
|
);
|
||
|
if (it != self->list.end())
|
||
|
{
|
||
|
image_ptr = *it;
|
||
|
}
|
||
|
|
||
|
if (NULL != image_ptr)
|
||
|
{
|
||
|
image = image_ptr;
|
||
|
DeviceColoredImage_AddRef(image);
|
||
|
return image;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
image = DeveiceColoredImage_Create(self, color1, color2, filter, user);
|
||
|
if (NULL == image)
|
||
|
return NULL;
|
||
|
|
||
|
self->list.push_back(image);
|
||
|
listSize++;
|
||
|
|
||
|
if (listSize > 1)
|
||
|
{
|
||
|
//qsort(&self->list[0], self->list.size(), sizeof(DeviceColoredImage**),
|
||
|
// DeviceColoredImage_SortCb);
|
||
|
std::sort(self->list.begin(), self->list.end(), DeviceColoredImage_SortCb_V2);
|
||
|
}
|
||
|
|
||
|
return image;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
DeviceImage_RemoveColored(DeviceImage *self, DeviceColoredImage *coloredImage)
|
||
|
{
|
||
|
size_t index;
|
||
|
|
||
|
if (NULL == self || NULL == coloredImage)
|
||
|
return;
|
||
|
|
||
|
index = self->list.size();
|
||
|
while(index--)
|
||
|
{
|
||
|
if (coloredImage == self->list[index])
|
||
|
{
|
||
|
self->list.erase(self->list.begin() + index);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
DeviceColoredImage_AddRef(DeviceColoredImage *self)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return 0;
|
||
|
return InterlockedIncrement((LONG*)&self->ref);
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
DeviceColoredImage_Release(DeviceColoredImage *self)
|
||
|
{
|
||
|
size_t r;
|
||
|
if (NULL == self || 0 == self->ref)
|
||
|
return 0;
|
||
|
|
||
|
r = InterlockedDecrement((LONG*)&self->ref);
|
||
|
if (0 == r)
|
||
|
{
|
||
|
if (NULL != self->base)
|
||
|
{
|
||
|
DeviceImage_RemoveColored(self->base, self);
|
||
|
DeviceImage_Release(self->base);
|
||
|
}
|
||
|
DeviceColoredImage_Free(self);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
DeviceColoredImage_DefaultFilter(HBITMAP bitmap, COLORREF color1, COLORREF color2, void *user)
|
||
|
{
|
||
|
DIBSECTION bitmapDib;
|
||
|
BITMAP *bitmapInfo;
|
||
|
MLIMAGEFILTERAPPLYEX filter;
|
||
|
|
||
|
if (sizeof(bitmapDib) != GetObjectW(bitmap, sizeof(bitmapDib), &bitmapDib))
|
||
|
return FALSE;
|
||
|
|
||
|
bitmapInfo = &bitmapDib.dsBm;
|
||
|
|
||
|
filter.cbSize = sizeof(filter);
|
||
|
filter.pData = (BYTE*)bitmapInfo->bmBits;
|
||
|
filter.cx = bitmapInfo->bmWidth;
|
||
|
filter.cy = bitmapInfo->bmHeight;
|
||
|
filter.bpp = bitmapInfo->bmBitsPixel;
|
||
|
filter.imageTag = NULL;
|
||
|
|
||
|
filter.filterUID = MLIF_GRAYSCALE_UID;
|
||
|
MLImageFilter_ApplyEx(Plugin_GetLibraryWindow(), &filter);
|
||
|
|
||
|
filter.rgbBk = color1;
|
||
|
filter.rgbFg = color2;
|
||
|
|
||
|
if (32 == bitmapInfo->bmBitsPixel)
|
||
|
{
|
||
|
filter.filterUID = MLIF_FILTER1_PRESERVE_ALPHA_UID;
|
||
|
MLImageFilter_ApplyEx(Plugin_GetLibraryWindow(), &filter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
filter.filterUID = MLIF_FILTER1_UID;
|
||
|
MLImageFilter_ApplyEx(Plugin_GetLibraryWindow(), &filter);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
HBITMAP
|
||
|
DeviceColoredImage_GetBitmap(DeviceColoredImage *self, DeviceImageFlags flags)
|
||
|
{
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL == self->bitmap)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
bitmap = DeviceImage_GetBitmap(self->base, flags);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
self->bitmap = Image_DuplicateDib(bitmap);
|
||
|
if (NULL != self->bitmap)
|
||
|
{
|
||
|
DeviceImageFilter filter;
|
||
|
if (NULL == self->filter)
|
||
|
filter = DeviceColoredImage_DefaultFilter;
|
||
|
else
|
||
|
filter = self->filter;
|
||
|
|
||
|
Image_Demultiply(self->bitmap, NULL);
|
||
|
filter(self->bitmap, self->color1, self->color2, self->filterParam);
|
||
|
Image_Premultiply(self->bitmap, NULL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return self->bitmap;
|
||
|
}
|
||
|
|
||
|
DeviceImage*
|
||
|
DeviceColoredImage_GetBaseImage(DeviceColoredImage *self)
|
||
|
{
|
||
|
if (NULL == self || NULL == self->base)
|
||
|
return NULL;
|
||
|
|
||
|
DeviceImage_AddRef(self->base);
|
||
|
return self->base;
|
||
|
}
|