image.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. #include "main.h"
  2. #include "./image.h"
  3. HBITMAP
  4. Image_Load(const wchar_t *path, unsigned int type,
  5. unsigned int flags, int width, int height)
  6. {
  7. MLIMAGESOURCE source;
  8. HWND libraryWindow = Plugin_GetLibraryWindow();
  9. if (NULL == libraryWindow)
  10. return NULL;
  11. source.cbSize = sizeof(source);
  12. source.lpszName = path;
  13. source.type = type;
  14. source.flags = (flags & ~IMAGE_FILTER_MASK);
  15. source.cxDst = width;
  16. source.cyDst = height;
  17. if (0 == (ISF_LOADFROMFILE & source.flags))
  18. {
  19. source.hInst = WASABI_API_LNG_HINST;
  20. if (NULL != source.hInst)
  21. {
  22. HBITMAP bitmap = MLImageLoader_LoadDib(libraryWindow, &source);
  23. if (NULL != bitmap)
  24. return bitmap;
  25. }
  26. if (WASABI_API_ORIG_HINST == source.hInst)
  27. return NULL;
  28. source.hInst = WASABI_API_ORIG_HINST;
  29. return (NULL != source.hInst) ?
  30. MLImageLoader_LoadDib(libraryWindow, &source) :
  31. NULL;
  32. }
  33. return MLImageLoader_LoadDib(Plugin_GetLibraryWindow(), &source);
  34. }
  35. HBITMAP
  36. Image_LoadEx(HINSTANCE instance, const wchar_t *path, unsigned int type,
  37. unsigned int flags, int width, int height)
  38. {
  39. MLIMAGESOURCE source = {0};
  40. source.cbSize = sizeof(source);
  41. source.hInst = instance;
  42. source.lpszName = path;
  43. source.type = type;
  44. source.flags = (flags & ~IMAGE_FILTER_MASK);
  45. source.cxDst = width;
  46. source.cyDst = height;
  47. return MLImageLoader_LoadDib(Plugin_GetLibraryWindow(), &source);
  48. }
  49. BOOL
  50. Image_FilterEx(void *pixelData, long width, long height, unsigned short bpp,
  51. unsigned int flags, COLORREF backColor, COLORREF frontColor, COLORREF blendColor)
  52. {
  53. MLIMAGEFILTERAPPLYEX filter;
  54. HWND libraryWindow;
  55. BOOL result;
  56. if (NULL == pixelData)
  57. return FALSE;
  58. libraryWindow = Plugin_GetLibraryWindow();
  59. if (NULL == libraryWindow)
  60. return FALSE;
  61. filter.cbSize = sizeof(filter);
  62. filter.pData = (BYTE*)pixelData;
  63. filter.cx = width;
  64. filter.cy = height;
  65. filter.bpp = bpp;
  66. filter.imageTag = NULL;
  67. result = FALSE;
  68. if (0 != (IMAGE_FILTER_GRAYSCALE & flags))
  69. {
  70. filter.filterUID = MLIF_GRAYSCALE_UID;
  71. result = MLImageFilter_ApplyEx(libraryWindow, &filter);
  72. }
  73. filter.rgbBk = backColor;
  74. filter.rgbFg = frontColor;
  75. if (32 == bpp)
  76. {
  77. filter.filterUID = MLIF_FILTER1_PRESERVE_ALPHA_UID;
  78. result = MLImageFilter_ApplyEx(libraryWindow, &filter);
  79. if (0 != (IMAGE_FILTER_BLEND & flags))
  80. {
  81. filter.filterUID = MLIF_BLENDONBK_UID;
  82. filter.rgbBk = blendColor;
  83. result = MLImageFilter_ApplyEx(libraryWindow, &filter);
  84. }
  85. }
  86. else
  87. {
  88. filter.filterUID = MLIF_FILTER1_UID;
  89. result = MLImageFilter_ApplyEx(libraryWindow, &filter);
  90. }
  91. return result;
  92. }
  93. BOOL
  94. Image_Filter(HBITMAP bitmap, unsigned int flags,
  95. COLORREF backColor, COLORREF frontColor, COLORREF blendColor)
  96. {
  97. DIBSECTION bitmapData;
  98. BITMAP *bi;
  99. if (NULL == bitmap)
  100. return NULL;
  101. if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData))
  102. return FALSE;
  103. bi = &bitmapData.dsBm;
  104. return Image_FilterEx(bi->bmBits, bi->bmWidth, bi->bmHeight, bi->bmBitsPixel,
  105. flags, backColor, frontColor, blendColor);
  106. }
  107. BOOL
  108. Image_BlendEx(void *pixelData, long width, long height, unsigned short bpp, COLORREF blendColor)
  109. {
  110. MLIMAGEFILTERAPPLYEX filter;
  111. HWND libraryWindow;
  112. if (NULL == pixelData || 32 != bpp)
  113. return FALSE;
  114. libraryWindow = Plugin_GetLibraryWindow();
  115. if (NULL == libraryWindow)
  116. return FALSE;
  117. filter.cbSize = sizeof(filter);
  118. filter.pData = (BYTE*)pixelData;
  119. filter.cx = width;
  120. filter.cy = height;
  121. filter.bpp = bpp;
  122. filter.imageTag = NULL;
  123. filter.filterUID = MLIF_BLENDONBK_UID;
  124. filter.rgbBk = blendColor;
  125. return MLImageFilter_ApplyEx(libraryWindow, &filter);
  126. }
  127. BOOL
  128. Image_Blend(HBITMAP bitmap, COLORREF blendColor)
  129. {
  130. DIBSECTION bitmapData;
  131. BITMAP *bi;
  132. if (NULL == bitmap)
  133. return NULL;
  134. if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData))
  135. return FALSE;
  136. bi = &bitmapData.dsBm;
  137. return Image_BlendEx(bi->bmBits, bi->bmWidth, bi->bmHeight, bi->bmBitsPixel, blendColor);
  138. }
  139. HBITMAP
  140. Image_LoadSkinnedEx(HINSTANCE instance, const wchar_t *path, unsigned int type,
  141. unsigned int flags, int width, int height,
  142. COLORREF backColor, COLORREF frontColor, COLORREF blendColor)
  143. {
  144. HBITMAP bitmap;
  145. bitmap = Image_LoadEx(instance, path, type, flags, width, height);
  146. if (NULL == bitmap)
  147. return NULL;
  148. Image_Filter(bitmap, flags, backColor, frontColor, blendColor);
  149. return bitmap;
  150. }
  151. HBITMAP
  152. Image_LoadSkinned(const wchar_t *path, unsigned int type,
  153. unsigned int flags, int width, int height,
  154. COLORREF backColor, COLORREF frontColor, COLORREF blendColor)
  155. {
  156. HBITMAP bitmap;
  157. bitmap = Image_Load(path, type, flags, width, height);
  158. if (NULL == bitmap)
  159. return NULL;
  160. Image_Filter(bitmap, flags, backColor, frontColor, blendColor);
  161. return bitmap;
  162. }
  163. HBITMAP
  164. Image_DuplicateDib(HBITMAP source)
  165. {
  166. HBITMAP bitmap;
  167. DIBSECTION sourceDib;
  168. HDC windowDC;
  169. void *pixelData;
  170. if (NULL == source)
  171. return NULL;
  172. if (sizeof(sourceDib) != GetObjectW(source, sizeof(sourceDib), &sourceDib))
  173. return FALSE;
  174. sourceDib.dsBmih.biSize = sizeof(BITMAPINFOHEADER);
  175. if (sourceDib.dsBmih.biHeight > 0)
  176. sourceDib.dsBmih.biHeight = -sourceDib.dsBmih.biHeight;
  177. windowDC = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE);
  178. bitmap = CreateDIBSection(windowDC, (BITMAPINFO*)&sourceDib.dsBmih, DIB_RGB_COLORS, &pixelData, NULL, 0);
  179. if (NULL != windowDC)
  180. ReleaseDC(NULL, windowDC);
  181. if (NULL == bitmap)
  182. return NULL;
  183. CopyMemory(pixelData, sourceDib.dsBm.bmBits, sourceDib.dsBm.bmWidthBytes * sourceDib.dsBm.bmHeight);
  184. return bitmap;
  185. }
  186. BOOL
  187. Image_ColorOver(HBITMAP bitmap, const RECT *prcPart, BOOL premult, COLORREF rgb)
  188. {
  189. DIBSECTION bitmapData;
  190. BITMAP *bi;
  191. if (NULL == bitmap)
  192. return NULL;
  193. if (sizeof(bitmapData) != GetObjectW(bitmap, sizeof(bitmapData), &bitmapData))
  194. return FALSE;
  195. if (BI_RGB != bitmapData.dsBmih.biCompression ||
  196. 1 != bitmapData.dsBmih.biPlanes ||
  197. 32 != bitmapData.dsBm.bmBitsPixel)
  198. {
  199. return FALSE;
  200. }
  201. bi = &bitmapData.dsBm;
  202. return (NULL == prcPart) ?
  203. Image_ColorOverEx((BYTE*)bi->bmBits, bi->bmWidth, bi->bmHeight,
  204. 0, 0, bi->bmWidth, bi->bmHeight,
  205. bi->bmBitsPixel, premult, rgb) :
  206. Image_ColorOverEx((BYTE*)bi->bmBits, bi->bmWidth, bi->bmHeight,
  207. prcPart->left, prcPart->top,
  208. prcPart->right - prcPart->left, prcPart->bottom - prcPart->top,
  209. bi->bmBitsPixel, premult, rgb);
  210. }
  211. BOOL
  212. Image_ColorOverEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  213. long x, long y, long cx, long cy, unsigned short bpp,
  214. BOOL premult, COLORREF rgb)
  215. {
  216. LONG pitch;
  217. UINT a, r, g, b, ma, mr, mg, mb;
  218. INT step = (bpp>>3);
  219. LPBYTE line, cursor;
  220. pitch = bitmapCX * step;
  221. while (pitch%4) pitch++;
  222. if (step < 3)
  223. return TRUE;
  224. if (cy < 0) cy -= cy;
  225. a = (LOBYTE((rgb)>>24)); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb);
  226. ma = 255 - a; mr = r * 255; mg = g * 255; mb = b * 255;
  227. if (0 == a)
  228. return TRUE;
  229. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  230. line = pPixels + pitch * ofs + x*step;
  231. if (0xFF == a)
  232. {
  233. for (; cy-- != 0; line += pitch)
  234. {
  235. for (x = cx, cursor = line; x-- != 0; cursor += step)
  236. {
  237. cursor[0] = (BYTE)b;
  238. cursor[1] = (BYTE)g;
  239. cursor[2] = (BYTE)r;
  240. // cursor[3] = 0xFF;
  241. }
  242. }
  243. return TRUE;
  244. }
  245. if (premult)
  246. {
  247. for (; cy-- != 0; line += pitch)
  248. {
  249. for (x = cx, cursor = line; x-- != 0; cursor += step)
  250. {
  251. int t = (mb + ma * cursor[0] + 127) / 255;
  252. cursor[0] = (t > 0xFF) ? 0xFF : t;
  253. t = (mg + ma * cursor[1] + 127) / 255;
  254. cursor[1] = (t > 0xFF) ? 0xFF : t;
  255. t = (mr+ ma * cursor[2] + 127) / 255;
  256. cursor[2] = (t > 0xFF) ? 0xFF : t;
  257. }
  258. }
  259. }
  260. else
  261. {
  262. WORD k = (((255 - a)*255 + 127)/255);
  263. for (; cy-- != 0; line += pitch)
  264. {
  265. for (x = cx, cursor = line; x-- != 0; cursor += step)
  266. {
  267. cursor[0] = (b*a + k*cursor[0] + 127)/255;
  268. cursor[1] = (g*a + k*cursor[1] + 127)/255;
  269. cursor[2] = (r*a + k*cursor[2] + 127)/255;
  270. // cursor[3] = (a*a + k*cursor[3] + 127)/255;
  271. }
  272. }
  273. }
  274. return TRUE;
  275. }
  276. BOOL
  277. Image_Premultiply(HBITMAP hbmp, const RECT *prcPart)
  278. {
  279. DIBSECTION dibsec;
  280. if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
  281. BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
  282. return FALSE;
  283. return (NULL == prcPart) ?
  284. Image_PremultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  285. 0, 0, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  286. dibsec.dsBm.bmBitsPixel) :
  287. Image_PremultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  288. prcPart->left, prcPart->top, RECTWIDTH(*prcPart), RECTHEIGHT(*prcPart),
  289. dibsec.dsBm.bmBitsPixel);
  290. }
  291. BOOL
  292. Image_PremultiplyEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  293. long x, long y, long cx, long cy, unsigned short bpp)
  294. {
  295. if (32 != bpp)
  296. return FALSE;
  297. LONG pitch;
  298. INT step = (bpp>>3);
  299. LPBYTE line, cursor;
  300. pitch = bitmapCX * step;
  301. while (pitch%4) pitch++;
  302. if (cy < 0)
  303. cy = -cy;
  304. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  305. line = pPixels + pitch * ofs + x*step;
  306. UINT a;
  307. for (; cy-- != 0; line += pitch)
  308. {
  309. for (x = cx, cursor = line; x-- != 0; cursor += step)
  310. {
  311. a = cursor[3];
  312. if (0 == a)
  313. {
  314. cursor[0] = 0;
  315. cursor[1] = 0;
  316. cursor[2] = 0;
  317. }
  318. else if (255 != a)
  319. {
  320. cursor[0] = (BYTE)MulDiv(cursor[0], a, 255);
  321. cursor[1] = (BYTE)MulDiv(cursor[1], a, 255);
  322. cursor[2] = (BYTE)MulDiv(cursor[2], a, 255);
  323. }
  324. }
  325. }
  326. return TRUE;
  327. }
  328. BOOL
  329. Image_Demultiply(HBITMAP hbmp, const RECT *prcPart)
  330. {
  331. DIBSECTION dibsec;
  332. if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
  333. BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
  334. return FALSE;
  335. return (NULL == prcPart) ?
  336. Image_DemultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  337. 0, 0, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  338. dibsec.dsBm.bmBitsPixel) :
  339. Image_DemultiplyEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  340. prcPart->left, prcPart->top, RECTWIDTH(*prcPart), RECTHEIGHT(*prcPart),
  341. dibsec.dsBm.bmBitsPixel);
  342. }
  343. BOOL
  344. Image_DemultiplyEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  345. long x, long y, long cx, long cy, unsigned short bpp)
  346. {
  347. if (32 != bpp)
  348. return FALSE;
  349. LONG pitch;
  350. INT step = (bpp>>3);
  351. LPBYTE line, cursor;
  352. pitch = bitmapCX * step;
  353. while (pitch%4) pitch++;
  354. if (cy < 0)
  355. cy = -cy;
  356. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  357. line = pPixels + pitch * ofs + x*step;
  358. UINT a;
  359. for (; cy-- != 0; line += pitch)
  360. {
  361. for (x = cx, cursor = line; x-- != 0; cursor += step)
  362. {
  363. a = cursor[3];
  364. if (0 == a)
  365. {
  366. cursor[0] = 0;
  367. cursor[1] = 0;
  368. cursor[2] = 0;
  369. }
  370. else if (255 != a)
  371. {
  372. cursor[0] = (BYTE)MulDiv(cursor[0], 255, a);
  373. cursor[1] = (BYTE)MulDiv(cursor[1], 255, a);
  374. cursor[2] = (BYTE)MulDiv(cursor[2], 255, a);
  375. }
  376. }
  377. }
  378. return TRUE;
  379. }
  380. BOOL
  381. Image_Saturate(HBITMAP hbmp, const RECT *prcPart, int n, BOOL fScale)
  382. {
  383. DIBSECTION dibsec;
  384. if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
  385. BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
  386. return FALSE;
  387. return Image_SaturateEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  388. prcPart->left, prcPart->top,
  389. prcPart->right - prcPart->left, prcPart->bottom - prcPart->top,
  390. dibsec.dsBm.bmBitsPixel, n, fScale);
  391. }
  392. BOOL
  393. Image_SaturateEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  394. long x, long y, long cx, long cy, unsigned short bpp,
  395. int n, BOOL fScale)
  396. {
  397. if (32 != bpp)
  398. return FALSE;
  399. LONG pitch;
  400. INT step = (bpp>>3);
  401. LPBYTE line, cursor;
  402. pitch = bitmapCX * step;
  403. while (pitch%4) pitch++;
  404. if (FALSE == fScale)
  405. {
  406. if (n < 0) n = 0;
  407. else if (n > 1000) n = 1000;
  408. }
  409. else
  410. {
  411. if (n < -1000) n = -1000;
  412. else if (n > 1000) n = 1000;
  413. }
  414. if (cy < 0)
  415. cy = -cy;
  416. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  417. line = pPixels + pitch * ofs + x*step;
  418. COLORREF rgb;
  419. INT k;
  420. WORD h, l, s;
  421. for (; cy-- != 0; line += pitch)
  422. {
  423. for (x = cx, cursor = line; x-- != 0; cursor += step)
  424. {
  425. rgb = RGB(cursor[2], cursor[1], cursor[0]);
  426. ColorRGBToHLS(rgb, &h, &l, &s);
  427. if(FALSE == fScale)
  428. s = ((WORD)((240 * n)/1000));
  429. else
  430. {
  431. k = s;
  432. s = (WORD)(k + (k * n) /1000);
  433. }
  434. rgb = ColorHLSToRGB(h, l, s);
  435. cursor[0] = GetBValue(rgb);
  436. cursor[1] = GetGValue(rgb);
  437. cursor[2] = GetRValue(rgb);
  438. }
  439. }
  440. return TRUE;
  441. }
  442. BOOL
  443. Image_AdjustAlpha(HBITMAP hbmp, const RECT *prcPart, int n, BOOL fScale)
  444. {
  445. DIBSECTION dibsec;
  446. if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
  447. BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
  448. return FALSE;
  449. return Image_AdjustAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  450. prcPart->left, prcPart->top,
  451. prcPart->right - prcPart->left, prcPart->bottom - prcPart->top,
  452. dibsec.dsBm.bmBitsPixel, n, fScale);
  453. }
  454. BOOL
  455. Image_AdjustAlphaEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  456. long x, long y, long cx, long cy, unsigned short bpp,
  457. int n, BOOL fScale)
  458. {
  459. if (32 != bpp)
  460. return FALSE;
  461. LONG pitch;
  462. INT step = (bpp>>3);
  463. LPBYTE line, cursor;
  464. pitch = bitmapCX * step;
  465. while (pitch%4) pitch++;
  466. if (FALSE == fScale)
  467. {
  468. if (n < 0) n = 0;
  469. else if (n > 1000) n = 1000;
  470. }
  471. else
  472. {
  473. if (n < -1000) n = -1000;
  474. else if (n > 1000) n = 1000;
  475. }
  476. if (cy < 0)
  477. cy = -cy;
  478. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  479. line = pPixels + pitch * ofs + x*step;
  480. INT k;
  481. for (; cy-- != 0; line += pitch)
  482. {
  483. for (x = cx, cursor = line; x-- != 0; cursor += step)
  484. {
  485. if(FALSE == fScale)
  486. cursor[3] = ((BYTE)((255 * n)/1000));
  487. else
  488. {
  489. k = cursor[3];
  490. k = k + MulDiv(k, n, 1000);
  491. if (k > 255) k = 255;
  492. cursor[3] = (BYTE)k;
  493. }
  494. }
  495. }
  496. return TRUE;
  497. }
  498. BOOL
  499. Image_AdjustSaturationAlpha(HBITMAP hbmp, const RECT *prcPart, int nSaturation, int nAlpha)
  500. {
  501. DIBSECTION dibsec;
  502. if (!hbmp || sizeof(DIBSECTION) != GetObject(hbmp, sizeof(DIBSECTION), &dibsec) ||
  503. BI_RGB != dibsec.dsBmih.biCompression || 1 != dibsec.dsBmih.biPlanes || dibsec.dsBm.bmBitsPixel != 32)
  504. return FALSE;
  505. return Image_AdjustSaturationAlphaEx((BYTE*)dibsec.dsBm.bmBits, dibsec.dsBm.bmWidth, dibsec.dsBm.bmHeight,
  506. prcPart->left, prcPart->top,
  507. prcPart->right - prcPart->left, prcPart->bottom - prcPart->top,
  508. dibsec.dsBm.bmBitsPixel, nSaturation, nAlpha);
  509. }
  510. BOOL
  511. Image_AdjustSaturationAlphaEx(unsigned char *pPixels, int bitmapCX, int bitmapCY,
  512. long x, long y, long cx, long cy,
  513. unsigned short bpp, int nSaturation, int nAlpha)
  514. {
  515. if (32 != bpp)
  516. return FALSE;
  517. LONG pitch;
  518. INT step = (bpp>>3);
  519. LPBYTE line, cursor;
  520. pitch = bitmapCX * step;
  521. while (pitch%4) pitch++;
  522. if (nSaturation < -1000) nSaturation = -1000;
  523. else if (nSaturation > 1000) nSaturation = 1000;
  524. if (nAlpha < -1000) nAlpha = -1000;
  525. else if (nAlpha > 1000) nAlpha = 1000;
  526. if (cy < 0)
  527. cy = -cy;
  528. INT ofs = (bitmapCY > 0) ? (bitmapCY - (y + cy)) : y;
  529. line = pPixels + pitch * ofs + x*step;
  530. INT k;
  531. COLORREF rgb;
  532. WORD h, l, s;
  533. for (; cy-- != 0; line += pitch)
  534. {
  535. for (x = cx, cursor = line; x-- != 0; cursor += step)
  536. {
  537. k = cursor[3];
  538. k = k + MulDiv(k, nAlpha, 1000);
  539. if (k > 255) k = 255;
  540. cursor[3] = (BYTE)k;
  541. rgb = RGB(cursor[2], cursor[1], cursor[0]);
  542. ColorRGBToHLS(rgb, &h, &l, &s);
  543. k = s;
  544. k = k + MulDiv(k, nSaturation, 1000);
  545. if (k > 240) k = 240;
  546. s = (WORD)k;
  547. rgb = ColorHLSToRGB(h, l, s);
  548. cursor[0] = GetBValue(rgb);
  549. cursor[1] = GetGValue(rgb);
  550. cursor[2] = GetRValue(rgb);
  551. }
  552. }
  553. return TRUE;
  554. }
  555. BOOL
  556. Image_FillBorder(HDC targetDC, const RECT *targetRect,
  557. HDC sourceDC, const RECT *sourceRect,
  558. BOOL fillCenter, BYTE alphaConstant)
  559. {
  560. INT prevStretchMode;
  561. long centerWidth, centerHeight;
  562. long sliceWidth, sliceHeight;
  563. const BLENDFUNCTION blendFunction = { AC_SRC_OVER, 0, alphaConstant, AC_SRC_ALPHA };
  564. const long targetWidth = RECTWIDTH(*targetRect);
  565. const long targetHeight = RECTHEIGHT(*targetRect);
  566. const long sourceWidth = RECTWIDTH(*sourceRect);
  567. const long sourceHeight = RECTHEIGHT(*sourceRect);
  568. if (NULL == targetDC || NULL == sourceDC)
  569. return FALSE;
  570. sliceWidth = sourceWidth/2;
  571. sliceHeight = sourceHeight/2;
  572. if (sliceWidth*2 > targetWidth)
  573. sliceWidth = targetWidth/2;
  574. if (sliceHeight*2 > targetHeight)
  575. sliceHeight = targetHeight/2;
  576. if (0 == sliceWidth || 0 == sliceHeight)
  577. return FALSE;
  578. prevStretchMode = SetStretchBltMode(targetDC, COLORONCOLOR);
  579. SetViewportOrgEx(sourceDC, 0, 0, NULL);
  580. GdiAlphaBlend(targetDC, targetRect->left, targetRect->top, sliceWidth, sliceHeight,
  581. sourceDC, sourceRect->left, sourceRect->top, sliceWidth, sliceHeight, blendFunction);
  582. GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->top, sliceWidth, sliceHeight,
  583. sourceDC, sourceRect->right - sliceWidth, sourceRect->top, sliceWidth, sliceHeight, blendFunction);
  584. GdiAlphaBlend(targetDC, targetRect->left, targetRect->bottom - sliceHeight, sliceWidth, sliceHeight,
  585. sourceDC, sourceRect->left, sourceRect->bottom - sliceHeight, sliceWidth, sliceHeight, blendFunction);
  586. GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->bottom - sliceHeight, sliceWidth, sliceHeight,
  587. sourceDC, sourceRect->right - sliceWidth, sourceRect->bottom - sliceHeight, sliceWidth, sliceHeight, blendFunction);
  588. if (targetWidth > 2*sliceWidth)
  589. {
  590. centerWidth = sourceWidth - 2*sliceWidth;
  591. if(centerWidth < 1)
  592. centerWidth = 1;
  593. GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->top, targetWidth - (sliceWidth * 2), sliceHeight,
  594. sourceDC, sourceRect->left + sliceWidth, sourceRect->top, centerWidth, sliceHeight, blendFunction);
  595. GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->bottom - sliceHeight, targetWidth - (sliceWidth * 2), sliceHeight,
  596. sourceDC, sourceRect->left + sliceWidth, sourceRect->bottom - sliceHeight, centerWidth, sliceHeight, blendFunction);
  597. }
  598. else
  599. centerWidth = 0;
  600. if (targetHeight > 2*sliceHeight)
  601. {
  602. centerHeight = sourceHeight - 2*sliceHeight;
  603. if(centerHeight < 1)
  604. centerHeight = 1;
  605. GdiAlphaBlend(targetDC, targetRect->left, targetRect->top + sliceHeight, sliceWidth, targetHeight - (sliceHeight* 2),
  606. sourceDC, sourceRect->left, sourceRect->top + sliceHeight, sliceWidth, centerHeight, blendFunction);
  607. GdiAlphaBlend(targetDC, targetRect->right - sliceWidth, targetRect->top + sliceHeight, sliceWidth, targetHeight - (sliceHeight* 2),
  608. sourceDC, sourceRect->right - sliceWidth, sourceRect->top + sliceHeight, sliceWidth, centerHeight, blendFunction);
  609. }
  610. else
  611. centerHeight = 0;
  612. if (FALSE != fillCenter &&
  613. 0 != centerWidth && 0 != centerHeight)
  614. {
  615. GdiAlphaBlend(targetDC, targetRect->left + sliceWidth, targetRect->top + sliceHeight, targetWidth - (sliceWidth * 2), targetHeight - (sliceHeight* 2),
  616. sourceDC, sourceRect->left + sliceWidth, sourceRect->top + sliceHeight, centerWidth, centerHeight, blendFunction);
  617. }
  618. SetStretchBltMode(targetDC, prevStretchMode);
  619. return TRUE;
  620. }
  621. const ImageInfo *
  622. Image_GetBestFit(const ImageInfo *images, size_t count, unsigned int width, unsigned int height)
  623. {
  624. const ImageInfo *image, *bestFit;
  625. double widthDbl, heightDbl;
  626. double scaleMin, scaleHorz, scaleVert;
  627. if (NULL == images || count < 1)
  628. return NULL;
  629. if (width < 1)
  630. width = 1;
  631. if (height < 1)
  632. height = 1;
  633. widthDbl = width;
  634. heightDbl = height;
  635. image = &images[--count];
  636. scaleHorz = widthDbl/image->width;
  637. scaleVert = heightDbl/image->height;
  638. scaleMin = (scaleHorz < scaleVert) ? scaleHorz : scaleVert;
  639. bestFit = image;
  640. if (1.0 != scaleMin)
  641. {
  642. scaleMin = fabs(1.0 - scaleMin);
  643. while(count--)
  644. {
  645. image = &images[count];
  646. scaleHorz = widthDbl/image->width;
  647. scaleVert = heightDbl/image->height;
  648. if (scaleHorz > scaleVert)
  649. scaleHorz = scaleVert;
  650. if (1.0 == scaleHorz)
  651. {
  652. bestFit = image;
  653. break;
  654. }
  655. scaleHorz = fabs(1.0 - scaleHorz);
  656. if (scaleHorz < scaleMin)
  657. {
  658. scaleMin = scaleHorz;
  659. bestFit = image;
  660. }
  661. }
  662. }
  663. return bestFit;
  664. }
  665. BOOL
  666. Image_AlphaBlend(HDC targetDC, const RECT *targetRect,
  667. HDC sourceDC, const RECT *sourceRect, BYTE sourceAlpha,
  668. HBITMAP sourceBitmap, const RECT *paintRect, AlphaBlendFlags flags,
  669. RECT *rectOut)
  670. {
  671. BOOL result, clipSource;
  672. RECT fillRect;
  673. int sourceX, sourceY, sourceWidth, sourceHeight;
  674. const BLENDFUNCTION blendFunction =
  675. {
  676. AC_SRC_OVER,
  677. 0,
  678. sourceAlpha,
  679. AC_SRC_ALPHA
  680. };
  681. if (NULL != paintRect)
  682. {
  683. if (FALSE == IntersectRect(&fillRect, targetRect, paintRect))
  684. return TRUE;
  685. clipSource = TRUE;
  686. }
  687. else
  688. {
  689. CopyRect(&fillRect, targetRect);
  690. clipSource = FALSE;
  691. }
  692. if (NULL != sourceRect)
  693. {
  694. sourceX = sourceRect->left;
  695. sourceY = sourceRect->top;
  696. sourceWidth = RECTWIDTH(*sourceRect);
  697. sourceHeight = RECTHEIGHT(*sourceRect);
  698. }
  699. else
  700. {
  701. BITMAP bitmapInfo;
  702. if (sizeof(bitmapInfo) != GetObject(sourceBitmap, sizeof(bitmapInfo), &bitmapInfo))
  703. return FALSE;
  704. sourceX = 0;
  705. sourceY = 0;
  706. sourceWidth = bitmapInfo.bmWidth;
  707. sourceHeight = bitmapInfo.bmHeight;
  708. if (sourceHeight < 0)
  709. sourceHeight = -sourceHeight;
  710. }
  711. if (0 != (AlphaBlend_ScaleSource & flags))
  712. {
  713. RECT rect;
  714. double scaleHorz, scaleVert;
  715. scaleHorz = (double)RECTWIDTH(*targetRect) / sourceWidth;
  716. scaleVert = (double)RECTHEIGHT(*targetRect) / sourceHeight;
  717. if (scaleHorz > scaleVert)
  718. scaleHorz = scaleVert;
  719. SetRect(&rect, 0, 0, (int)(sourceWidth * scaleHorz), (int)(sourceHeight * scaleHorz));
  720. if (0 != (AlphaBlend_AlignLeft & flags))
  721. rect.left = targetRect->left;
  722. else if (0 != (AlphaBlend_AlignRight & flags))
  723. rect.left = targetRect->right - rect.right;
  724. else
  725. rect.left = targetRect->left + (RECTWIDTH(*targetRect) - rect.right)/2;
  726. if (0 != (AlphaBlend_AlignTop & flags))
  727. rect.top = targetRect->top;
  728. else if (0 != (AlphaBlend_AlignBottom & flags))
  729. rect.top = targetRect->bottom - rect.bottom;
  730. else
  731. rect.top = targetRect->top + (RECTHEIGHT(*targetRect) - rect.bottom)/2;
  732. rect.right += rect.left;
  733. rect.bottom += rect.top;
  734. if (NULL != rectOut)
  735. CopyRect(rectOut, &rect);
  736. if (NULL != paintRect)
  737. {
  738. if (FALSE == IntersectRect(&fillRect, &rect, paintRect))
  739. return TRUE;
  740. }
  741. else
  742. CopyRect(&fillRect, &rect);
  743. sourceX += (int)((fillRect.left - rect.left)/scaleHorz);
  744. sourceY += (int)((fillRect.top - rect.top)/ scaleHorz);
  745. sourceWidth -= (int)((RECTWIDTH(rect) - RECTWIDTH(fillRect))/scaleHorz);
  746. sourceHeight -= (int)((RECTHEIGHT(rect) - RECTHEIGHT(fillRect))/scaleHorz);
  747. clipSource = FALSE;
  748. }
  749. else
  750. {
  751. if (sourceWidth < RECTWIDTH(*targetRect) ||
  752. sourceHeight < RECTHEIGHT(*targetRect))
  753. {
  754. RECT rect;
  755. if (0 != (AlphaBlend_AlignLeft & flags))
  756. rect.left = targetRect->left;
  757. else if (0 != (AlphaBlend_AlignRight & flags))
  758. rect.left = targetRect->right - sourceWidth;
  759. else
  760. rect.left = targetRect->left + (RECTWIDTH(*targetRect) - sourceWidth)/2;
  761. if (0 != (AlphaBlend_AlignTop & flags))
  762. rect.top = targetRect->top;
  763. else if (0 != (AlphaBlend_AlignBottom & flags))
  764. rect.top = targetRect->bottom - sourceHeight;
  765. else
  766. rect.top = targetRect->top + (RECTHEIGHT(*targetRect) - sourceHeight)/2;
  767. rect.right = rect.left + sourceWidth;
  768. rect.bottom = rect.top + sourceHeight;
  769. if (NULL != paintRect)
  770. {
  771. if (FALSE == IntersectRect(&fillRect, &rect, paintRect))
  772. return TRUE;
  773. sourceX += (fillRect.left - rect.left);
  774. sourceY += (fillRect.top - rect.top);
  775. sourceWidth -= (RECTWIDTH(rect) - RECTWIDTH(fillRect));
  776. sourceHeight -= (RECTHEIGHT(rect) - RECTHEIGHT(fillRect));
  777. }
  778. else
  779. CopyRect(&fillRect, &rect);
  780. if (NULL != rectOut)
  781. CopyRect(rectOut, &rect);
  782. clipSource = FALSE;
  783. }
  784. else if (NULL != rectOut)
  785. CopyRect(rectOut, targetRect);
  786. }
  787. if (FALSE != clipSource)
  788. {
  789. sourceX += (fillRect.left - targetRect->left);
  790. sourceY += (fillRect.top - targetRect->top);
  791. sourceWidth -= (RECTWIDTH(*targetRect) - RECTWIDTH(fillRect));
  792. sourceHeight -= (RECTHEIGHT(*targetRect) - RECTHEIGHT(fillRect));
  793. }
  794. if (NULL != sourceBitmap)
  795. SelectBitmap(sourceDC, sourceBitmap);
  796. result = GdiAlphaBlend(targetDC, fillRect.left, fillRect.top, RECTWIDTH(fillRect), RECTHEIGHT(fillRect),
  797. sourceDC, sourceX, sourceY, sourceWidth, sourceHeight, blendFunction);
  798. return result;
  799. }