diff options
author | Jean-Francois Mauguit <jfmauguit@mac.com> | 2024-09-24 09:03:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 09:03:25 -0400 |
commit | bab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_devices/image.cpp | |
parent | 4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff) | |
parent | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff) | |
download | winamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz |
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/Plugins/Library/ml_devices/image.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_devices/image.cpp | 978 |
1 files changed, 978 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_devices/image.cpp b/Src/Plugins/Library/ml_devices/image.cpp new file mode 100644 index 00000000..5bcb0626 --- /dev/null +++ b/Src/Plugins/Library/ml_devices/image.cpp @@ -0,0 +1,978 @@ +#include "main.h" +#include "./image.h" + + +HBITMAP +Image_Load(const wchar_t *path, unsigned int type, + unsigned int flags, int width, int height) +{ + MLIMAGESOURCE source; + HWND libraryWindow = Plugin_GetLibraryWindow(); + if (NULL == libraryWindow) + return NULL; + + source.cbSize = sizeof(source); + source.lpszName = path; + source.type = type; + source.flags = (flags & ~IMAGE_FILTER_MASK); + source.cxDst = width; + source.cyDst = height; + + if (0 == (ISF_LOADFROMFILE & source.flags)) + { + source.hInst = WASABI_API_LNG_HINST; + if (NULL != source.hInst) + { + HBITMAP bitmap = MLImageLoader_LoadDib(libraryWindow, &source); + if (NULL != bitmap) + return bitmap; + } + + if (WASABI_API_ORIG_HINST == source.hInst) + return NULL; + + source.hInst = WASABI_API_ORIG_HINST; + return (NULL != source.hInst) ? + MLImageLoader_LoadDib(libraryWindow, &source) : + NULL; + } + + return MLImageLoader_LoadDib(Plugin_GetLibraryWindow(), &source); +} + +HBITMAP +Image_LoadEx(HINSTANCE instance, const wchar_t *path, unsigned int type, + unsigned int flags, int width, int height) +{ + MLIMAGESOURCE source = {0}; + + source.cbSize = sizeof(source); + source.hInst = instance; + source.lpszName = path; + source.type = type; + source.flags = (flags & ~IMAGE_FILTER_MASK); + source.cxDst = width; + source.cyDst = height; + + return MLImageLoader_LoadDib(Plugin_GetLibraryWindow(), &source); +} + +BOOL +Image_FilterEx(void *pixelData, long width, long height, unsigned short bpp, + unsigned int flags, COLORREF backColor, COLORREF frontColor, COLORREF blendColor) +{ + MLIMAGEFILTERAPPLYEX filter; + HWND libraryWindow; + BOOL result; + + if (NULL == pixelData) + return FALSE; + + libraryWindow = Plugin_GetLibraryWindow(); + if (NULL == libraryWindow) + return FALSE; + + filter.cbSize = sizeof(filter); + filter.pData = (BYTE*)pixelData; + filter.cx = width; + filter.cy = height; + filter.bpp = bpp; + filter.imageTag = NULL; + + result = FALSE; + + if (0 != (IMAGE_FILTER_GRAYSCALE & flags)) + { + filter.filterUID = MLIF_GRAYSCALE_UID; + result = MLImageFilter_ApplyEx(libraryWindow, &filter); + } + + filter.rgbBk = backColor; + filter.rgbFg = frontColor; + + if (32 == bpp) + { + filter.filterUID = MLIF_FILTER1_PRESERVE_ALPHA_UID; + result = MLImageFilter_ApplyEx(libraryWindow, &filter); + + if (0 != (IMAGE_FILTER_BLEND & flags)) + { + filter.filterUID = MLIF_BLENDONBK_UID; + filter.rgbBk = blendColor; + result = MLImageFilter_ApplyEx(libraryWindow, &filter); + } + } + else + { + filter.filterUID = MLIF_FILTER1_UID; + result = MLImageFilter_ApplyEx(libraryWindow, &filter); + } + + return result; +} + +BOOL +Image_Filter(HBITMAP bitmap, unsigned int flags, + COLORREF backColor, COLORREF frontColor, COLORREF blendColor) +{ + DIBSECTION bitmapData; + BITMAP *bi; + + if (NULL == bitmap) + return NULL; + + if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData)) + return FALSE; + + bi = &bitmapData.dsBm; + + return Image_FilterEx(bi->bmBits, bi->bmWidth, bi->bmHeight, bi->bmBitsPixel, + flags, backColor, frontColor, blendColor); +} + +BOOL +Image_BlendEx(void *pixelData, long width, long height, unsigned short bpp, COLORREF blendColor) +{ + MLIMAGEFILTERAPPLYEX filter; + HWND libraryWindow; + + if (NULL == pixelData || 32 != bpp) + return FALSE; + + libraryWindow = Plugin_GetLibraryWindow(); + if (NULL == libraryWindow) + return FALSE; + + filter.cbSize = sizeof(filter); + filter.pData = (BYTE*)pixelData; + filter.cx = width; + filter.cy = height; + filter.bpp = bpp; + filter.imageTag = NULL; + + + filter.filterUID = MLIF_BLENDONBK_UID; + filter.rgbBk = blendColor; + return MLImageFilter_ApplyEx(libraryWindow, &filter); +} + +BOOL +Image_Blend(HBITMAP bitmap, COLORREF blendColor) +{ + DIBSECTION bitmapData; + BITMAP *bi; + + if (NULL == bitmap) + return NULL; + + if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData)) + return FALSE; + + bi = &bitmapData.dsBm; + + return Image_BlendEx(bi->bmBits, bi->bmWidth, bi->bmHeight, bi->bmBitsPixel, blendColor); +} + +HBITMAP +Image_LoadSkinnedEx(HINSTANCE instance, const wchar_t *path, unsigned int type, + unsigned int flags, int width, int height, + COLORREF backColor, COLORREF frontColor, COLORREF blendColor) +{ + HBITMAP bitmap; + + bitmap = Image_LoadEx(instance, path, type, flags, width, height); + if (NULL == bitmap) + return NULL; + + Image_Filter(bitmap, flags, backColor, frontColor, blendColor); + + return bitmap; +} + +HBITMAP +Image_LoadSkinned(const wchar_t *path, unsigned int type, + unsigned int flags, int width, int height, + COLORREF backColor, COLORREF frontColor, COLORREF blendColor) +{ + HBITMAP bitmap; + + bitmap = Image_Load(path, type, flags, width, height); + if (NULL == bitmap) + return NULL; + + Image_Filter(bitmap, flags, backColor, frontColor, blendColor); + + return bitmap; +} + +HBITMAP +Image_DuplicateDib(HBITMAP source) +{ + HBITMAP bitmap; + DIBSECTION sourceDib; + HDC windowDC; + void *pixelData; + + if (NULL == source) + return NULL; + + if (sizeof(sourceDib) != GetObjectW(source, sizeof(sourceDib), &sourceDib)) + return FALSE; + + + sourceDib.dsBmih.biSize = sizeof(BITMAPINFOHEADER); + if (sourceDib.dsBmih.biHeight > 0) + sourceDib.dsBmih.biHeight = -sourceDib.dsBmih.biHeight; + + windowDC = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE); + + bitmap = CreateDIBSection(windowDC, (BITMAPINFO*)&sourceDib.dsBmih, DIB_RGB_COLORS, &pixelData, NULL, 0); + + if (NULL != windowDC) + ReleaseDC(NULL, windowDC); + + if (NULL == bitmap) + return NULL; + + CopyMemory(pixelData, sourceDib.dsBm.bmBits, sourceDib.dsBm.bmWidthBytes * sourceDib.dsBm.bmHeight); + + return bitmap; + +} +BOOL +Image_ColorOver(HBITMAP bitmap, const RECT *prcPart, BOOL premult, COLORREF rgb) +{ + DIBSECTION bitmapData; + BITMAP *bi; + + if (NULL == bitmap) + return NULL; + + if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData)) + return FALSE; + + if (BI_RGB != bitmapData.dsBmih.biCompression || + 1 != bitmapData.dsBmih.biPlanes || + 32 != bitmapData.dsBm.bmBitsPixel) + { + return FALSE; + } + + bi = &bitmapData.dsBm; + + return (NULL == prcPart) ? + Image_ColorOverEx((BYTE*)bi->bmBits, bi->bmWidth, bi->bmHeight, + 0, 0, bi->bmWidth, bi->bmHeight, + bi->bmBitsPixel, premult, rgb) : + Image_ColorOverEx((BYTE*)bi->bmBits, bi->bmWidth, bi->bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + bi->bmBitsPixel, premult, rgb); + +} + +BOOL +Image_ColorOverEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, unsigned short bpp, + BOOL premult, COLORREF rgb) +{ + LONG pitch; + UINT a, r, g, b, ma, mr, mg, mb; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (step < 3) + return TRUE; + + if (cy < 0) cy -= cy; + + a = (LOBYTE((rgb)>>24)); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); + ma = 255 - a; mr = r * 255; mg = g * 255; mb = b * 255; + + if (0 == a) + return TRUE; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + if (0xFF == a) + { + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + cursor[0] = (BYTE)b; + cursor[1] = (BYTE)g; + cursor[2] = (BYTE)r; + // cursor[3] = 0xFF; + } + } + return TRUE; + } + + + if (premult) + { + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + int t = (mb + ma * cursor[0] + 127) / 255; + cursor[0] = (t > 0xFF) ? 0xFF : t; + t = (mg + ma * cursor[1] + 127) / 255; + cursor[1] = (t > 0xFF) ? 0xFF : t; + t = (mr+ ma * cursor[2] + 127) / 255; + cursor[2] = (t > 0xFF) ? 0xFF : t; + } + } + } + else + { + WORD k = (((255 - a)*255 + 127)/255); + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + cursor[0] = (b*a + k*cursor[0] + 127)/255; + cursor[1] = (g*a + k*cursor[1] + 127)/255; + cursor[2] = (r*a + k*cursor[2] + 127)/255; + // cursor[3] = (a*a + k*cursor[3] + 127)/255; + } + } + + } + return TRUE; +} + +BOOL +Image_Premultiply(HBITMAP hbmp, const RECT *prcPart) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return (NULL == prcPart) ? + Image_PremultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + 0, 0, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + dibsec.dsBm.bmBitsPixel) : + Image_PremultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, RECTWIDTH(*prcPart), RECTHEIGHT(*prcPart), + dibsec.dsBm.bmBitsPixel); +} + +BOOL +Image_PremultiplyEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, unsigned short bpp) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + UINT a; + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + a = cursor[3]; + if (0 == a) + { + cursor[0] = 0; + cursor[1] = 0; + cursor[2] = 0; + } + else if (255 != a) + { + cursor[0] = (BYTE)MulDiv(cursor[0], a, 255); + cursor[1] = (BYTE)MulDiv(cursor[1], a, 255); + cursor[2] = (BYTE)MulDiv(cursor[2], a, 255); + } + } + } + + return TRUE; +} + +BOOL +Image_Demultiply(HBITMAP hbmp, const RECT *prcPart) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return (NULL == prcPart) ? + Image_DemultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + 0, 0, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + dibsec.dsBm.bmBitsPixel) : + Image_DemultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, RECTWIDTH(*prcPart), RECTHEIGHT(*prcPart), + dibsec.dsBm.bmBitsPixel); +} + +BOOL +Image_DemultiplyEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, unsigned short bpp) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + UINT a; + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + a = cursor[3]; + if (0 == a) + { + cursor[0] = 0; + cursor[1] = 0; + cursor[2] = 0; + } + else if (255 != a) + { + cursor[0] = (BYTE)MulDiv(cursor[0], 255, a); + cursor[1] = (BYTE)MulDiv(cursor[1], 255, a); + cursor[2] = (BYTE)MulDiv(cursor[2], 255, a); + } + } + } + + return TRUE; +} +BOOL +Image_Saturate(HBITMAP hbmp, const RECT *prcPart, int n, BOOL fScale) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_SaturateEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, n, fScale); +} + +BOOL +Image_SaturateEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, unsigned short bpp, + int n, BOOL fScale) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (FALSE == fScale) + { + if (n < 0) n = 0; + else if (n > 1000) n = 1000; + } + else + { + if (n < -1000) n = -1000; + else if (n > 1000) n = 1000; + } + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + COLORREF rgb; + INT k; + WORD h, l, s; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + rgb = RGB(cursor[2], cursor[1], cursor[0]); + ColorRGBToHLS(rgb, &h, &l, &s); + if(FALSE == fScale) + s = ((WORD)((240 * n)/1000)); + else + { + k = s; + s = (WORD)(k + (k * n) /1000); + } + + rgb = ColorHLSToRGB(h, l, s); + + cursor[0] = GetBValue(rgb); + cursor[1] = GetGValue(rgb); + cursor[2] = GetRValue(rgb); + } + } + + return TRUE; +} + +BOOL +Image_AdjustAlpha(HBITMAP hbmp, const RECT *prcPart, int n, BOOL fScale) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_AdjustAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, n, fScale); +} + +BOOL +Image_AdjustAlphaEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, unsigned short bpp, + int n, BOOL fScale) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (FALSE == fScale) + { + if (n < 0) n = 0; + else if (n > 1000) n = 1000; + } + else + { + if (n < -1000) n = -1000; + else if (n > 1000) n = 1000; + } + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + INT k; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + if(FALSE == fScale) + cursor[3] = ((BYTE)((255 * n)/1000)); + else + { + k = cursor[3]; + k = k + MulDiv(k, n, 1000); + if (k > 255) k = 255; + cursor[3] = (BYTE)k; + } + } + } + + return TRUE; +} + +BOOL +Image_AdjustSaturationAlpha(HBITMAP hbmp, const RECT *prcPart, int nSaturation, int nAlpha) +{ + DIBSECTION dibsec; + if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) || + BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32) + return FALSE; + + return Image_AdjustSaturationAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight, + prcPart->left, prcPart->top, + prcPart->right - prcPart->left, prcPart->bottom - prcPart->top, + dibsec.dsBm.bmBitsPixel, nSaturation, nAlpha); +} + +BOOL +Image_AdjustSaturationAlphaEx(unsigned char *pPixels, int bitmapCX, int bitmapCY, + long x, long y, long cx, long cy, + unsigned short bpp, int nSaturation, int nAlpha) +{ + if (32 != bpp) + return FALSE; + + LONG pitch; + INT step = (bpp>>3); + LPBYTE line, cursor; + pitch = bitmapCX * step; + while (pitch%4) pitch++; + + if (nSaturation < -1000) nSaturation = -1000; + else if (nSaturation > 1000) nSaturation = 1000; + + if (nAlpha < -1000) nAlpha = -1000; + else if (nAlpha > 1000) nAlpha = 1000; + + if (cy < 0) + cy = -cy; + + INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y; + line = pPixels + pitch * ofs + x*step; + + INT k; + COLORREF rgb; + WORD h, l, s; + + for (; cy-- != 0; line += pitch) + { + for (x = cx, cursor = line; x-- != 0; cursor += step) + { + k = cursor[3]; + k = k + MulDiv(k, nAlpha, 1000); + if (k > 255) k = 255; + cursor[3] = (BYTE)k; + + rgb = RGB(cursor[2], cursor[1], cursor[0]); + ColorRGBToHLS(rgb, &h, &l, &s); + + k = s; + k = k + MulDiv(k, nSaturation, 1000); + if (k > 240) k = 240; + s = (WORD)k; + + rgb = ColorHLSToRGB(h, l, s); + cursor[0] = GetBValue(rgb); + cursor[1] = GetGValue(rgb); + cursor[2] = GetRValue(rgb); + } + } + + return TRUE; +} + +BOOL +Image_FillBorder(HDC targetDC, const RECT *targetRect, + HDC sourceDC, const RECT *sourceRect, + BOOL fillCenter, BYTE alphaConstant) +{ + INT prevStretchMode; + long centerWidth, centerHeight; + long sliceWidth, sliceHeight; + + const BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, alphaConstant, AC_SRC_ALPHA }; + const long targetWidth = RECTWIDTH(*targetRect); + const long targetHeight = RECTHEIGHT(*targetRect); + const long sourceWidth = RECTWIDTH(*sourceRect); + const long sourceHeight = RECTHEIGHT(*sourceRect); + + if (NULL == targetDC || NULL == sourceDC) + return FALSE; + + sliceWidth = sourceWidth/2; + sliceHeight = sourceHeight/2; + + if (sliceWidth*2 > targetWidth) + sliceWidth = targetWidth/2; + + if (sliceHeight*2 > targetHeight) + sliceHeight = targetHeight/2; + + if (0 == sliceWidth || 0 == sliceHeight) + return FALSE; + + prevStretchMode = SetStretchBltMode(targetDC, COLORONCOLOR); + SetViewportOrgEx(sourceDC, 0, 0, NULL); + + GdiAlphaBlend(targetDC, targetRect->left, targetRect->top, sliceWidth, sliceHeight, + sourceDC, sourceRect->left, sourceRect->top, sliceWidth, sliceHeight, blendFunction); + GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->top, sliceWidth, sliceHeight, + sourceDC, sourceRect->right - sliceWidth, sourceRect->top, sliceWidth, sliceHeight, blendFunction); + GdiAlphaBlend(targetDC, targetRect->left, targetRect->bottom - sliceHeight, sliceWidth, sliceHeight, + sourceDC, sourceRect->left, sourceRect->bottom - sliceHeight, sliceWidth, sliceHeight, blendFunction); + GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->bottom - sliceHeight, sliceWidth, sliceHeight, + sourceDC, sourceRect->right - sliceWidth, sourceRect->bottom - sliceHeight, sliceWidth, sliceHeight, blendFunction); + + if (targetWidth > 2*sliceWidth) + { + centerWidth = sourceWidth - 2*sliceWidth; + if(centerWidth < 1) + centerWidth = 1; + + GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->top, targetWidth - (sliceWidth * 2), sliceHeight, + sourceDC, sourceRect->left + sliceWidth, sourceRect->top, centerWidth, sliceHeight, blendFunction); + + GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->bottom - sliceHeight, targetWidth - (sliceWidth * 2), sliceHeight, + sourceDC, sourceRect->left + sliceWidth, sourceRect->bottom - sliceHeight, centerWidth, sliceHeight, blendFunction); + } + else + centerWidth = 0; + + if (targetHeight > 2*sliceHeight) + { + centerHeight = sourceHeight - 2*sliceHeight; + if(centerHeight < 1) + centerHeight = 1; + + GdiAlphaBlend(targetDC, targetRect->left, targetRect->top + sliceHeight, sliceWidth, targetHeight - (sliceHeight* 2), + sourceDC, sourceRect->left, sourceRect->top + sliceHeight, sliceWidth, centerHeight, blendFunction); + + GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->top + sliceHeight, sliceWidth, targetHeight - (sliceHeight* 2), + sourceDC, sourceRect->right - sliceWidth, sourceRect->top + sliceHeight, sliceWidth, centerHeight, blendFunction); + } + else + centerHeight = 0; + + if (FALSE != fillCenter && + 0 != centerWidth && 0 != centerHeight) + { + GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->top + sliceHeight, targetWidth - (sliceWidth * 2), targetHeight - (sliceHeight* 2), + sourceDC, sourceRect->left + sliceWidth, sourceRect->top + sliceHeight, centerWidth, centerHeight, blendFunction); + + } + + SetStretchBltMode(targetDC, prevStretchMode); + return TRUE; +} + +const ImageInfo * +Image_GetBestFit(const ImageInfo *images, size_t count, unsigned int width, unsigned int height) +{ + const ImageInfo *image, *bestFit; + double widthDbl, heightDbl; + double scaleMin, scaleHorz, scaleVert; + + if (NULL == images || count < 1) + return NULL; + + if (width < 1) + width = 1; + + if (height < 1) + height = 1; + + widthDbl = width; + heightDbl = height; + + image = &images[--count]; + scaleHorz = widthDbl/image->width; + scaleVert = heightDbl/image->height; + scaleMin = (scaleHorz < scaleVert) ? scaleHorz : scaleVert; + bestFit = image; + + if (1.0 != scaleMin) + { + scaleMin = fabs(1.0 - scaleMin); + while(count--) + { + image = &images[count]; + scaleHorz = widthDbl/image->width; + scaleVert = heightDbl/image->height; + if (scaleHorz > scaleVert) + scaleHorz = scaleVert; + + if (1.0 == scaleHorz) + { + bestFit = image; + break; + } + + scaleHorz = fabs(1.0 - scaleHorz); + if (scaleHorz < scaleMin) + { + scaleMin = scaleHorz; + bestFit = image; + } + } + } + + return bestFit; +} + +BOOL +Image_AlphaBlend(HDC targetDC, const RECT *targetRect, + HDC sourceDC, const RECT *sourceRect, BYTE sourceAlpha, + HBITMAP sourceBitmap, const RECT *paintRect, AlphaBlendFlags flags, + RECT *rectOut) +{ + BOOL result, clipSource; + RECT fillRect; + int sourceX, sourceY, sourceWidth, sourceHeight; + const BLENDFUNCTION blendFunction = + { + AC_SRC_OVER, + 0, + sourceAlpha, + AC_SRC_ALPHA + }; + + if (NULL != paintRect) + { + if (FALSE == IntersectRect(&fillRect, targetRect, paintRect)) + return TRUE; + + clipSource = TRUE; + } + else + { + CopyRect(&fillRect, targetRect); + clipSource = FALSE; + } + + if (NULL != sourceRect) + { + sourceX = sourceRect->left; + sourceY = sourceRect->top; + sourceWidth = RECTWIDTH(*sourceRect); + sourceHeight = RECTHEIGHT(*sourceRect); + } + else + { + BITMAP bitmapInfo; + if (sizeof(bitmapInfo) != GetObject(sourceBitmap, sizeof(bitmapInfo), &bitmapInfo)) + return FALSE; + + sourceX = 0; + sourceY = 0; + sourceWidth = bitmapInfo.bmWidth; + sourceHeight = bitmapInfo.bmHeight; + if (sourceHeight < 0) + sourceHeight = -sourceHeight; + } + + if (0 != (AlphaBlend_ScaleSource & flags)) + { + RECT rect; + double scaleHorz, scaleVert; + + scaleHorz = (double)RECTWIDTH(*targetRect) / sourceWidth; + scaleVert = (double)RECTHEIGHT(*targetRect) / sourceHeight; + if (scaleHorz > scaleVert) + scaleHorz = scaleVert; + + SetRect(&rect, 0, 0, (int)(sourceWidth * scaleHorz), (int)(sourceHeight * scaleHorz)); + + if (0 != (AlphaBlend_AlignLeft & flags)) + rect.left = targetRect->left; + else if (0 != (AlphaBlend_AlignRight & flags)) + rect.left = targetRect->right - rect.right; + else + rect.left = targetRect->left + (RECTWIDTH(*targetRect) - rect.right)/2; + + if (0 != (AlphaBlend_AlignTop & flags)) + rect.top = targetRect->top; + else if (0 != (AlphaBlend_AlignBottom & flags)) + rect.top = targetRect->bottom - rect.bottom; + else + rect.top = targetRect->top + (RECTHEIGHT(*targetRect) - rect.bottom)/2; + + rect.right += rect.left; + rect.bottom += rect.top; + + if (NULL != rectOut) + CopyRect(rectOut, &rect); + + if (NULL != paintRect) + { + if (FALSE == IntersectRect(&fillRect, &rect, paintRect)) + return TRUE; + } + else + CopyRect(&fillRect, &rect); + + sourceX += (int)((fillRect.left - rect.left)/scaleHorz); + sourceY += (int)((fillRect.top - rect.top)/ scaleHorz); + sourceWidth -= (int)((RECTWIDTH(rect) - RECTWIDTH(fillRect))/scaleHorz); + sourceHeight -= (int)((RECTHEIGHT(rect) - RECTHEIGHT(fillRect))/scaleHorz); + clipSource = FALSE; + } + else + { + if (sourceWidth < RECTWIDTH(*targetRect) || + sourceHeight < RECTHEIGHT(*targetRect)) + { + RECT rect; + + if (0 != (AlphaBlend_AlignLeft & flags)) + rect.left = targetRect->left; + else if (0 != (AlphaBlend_AlignRight & flags)) + rect.left = targetRect->right - sourceWidth; + else + rect.left = targetRect->left + (RECTWIDTH(*targetRect) - sourceWidth)/2; + + if (0 != (AlphaBlend_AlignTop & flags)) + rect.top = targetRect->top; + else if (0 != (AlphaBlend_AlignBottom & flags)) + rect.top = targetRect->bottom - sourceHeight; + else + rect.top = targetRect->top + (RECTHEIGHT(*targetRect) - sourceHeight)/2; + + rect.right = rect.left + sourceWidth; + rect.bottom = rect.top + sourceHeight; + + if (NULL != paintRect) + { + if (FALSE == IntersectRect(&fillRect, &rect, paintRect)) + return TRUE; + + sourceX += (fillRect.left - rect.left); + sourceY += (fillRect.top - rect.top); + sourceWidth -= (RECTWIDTH(rect) - RECTWIDTH(fillRect)); + sourceHeight -= (RECTHEIGHT(rect) - RECTHEIGHT(fillRect)); + } + else + CopyRect(&fillRect, &rect); + + if (NULL != rectOut) + CopyRect(rectOut, &rect); + + clipSource = FALSE; + } + else if (NULL != rectOut) + CopyRect(rectOut, targetRect); + } + + + + if (FALSE != clipSource) + { + sourceX += (fillRect.left - targetRect->left); + sourceY += (fillRect.top - targetRect->top); + sourceWidth -= (RECTWIDTH(*targetRect) - RECTWIDTH(fillRect)); + sourceHeight -= (RECTHEIGHT(*targetRect) - RECTHEIGHT(fillRect)); + } + + if (NULL != sourceBitmap) + SelectBitmap(sourceDC, sourceBitmap); + + result = GdiAlphaBlend(targetDC, fillRect.left, fillRect.top, RECTWIDTH(fillRect), RECTHEIGHT(fillRect), + sourceDC, sourceX, sourceY, sourceWidth, sourceHeight, blendFunction); + + return result; + +}
\ No newline at end of file |