soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SDIBHelper.cpp
1#include "souistd.h"
2#include "helper/SDIBHelper.h"
3
4#define RGB2GRAY(r, g, b) (((b)*117 + (g)*601 + (r)*306) >> 10)
5
6SNSBEGIN
7struct DIBINFO
8{
9 LPBYTE pBits;
10 UINT nWid;
11 UINT nHei;
12};
13
14// ------------------------------------------------------------
15// 有太多的算法需要用某种方式(map)变换位图的每个像素的颜色,比如
16// 彩色转换为灰度图,gamma校正,颜色空间转换,hsl调整.所以写一个模板做为参数调用的通用算法
17// ------------------------------------------------------------
18template <class Mode, class Param>
19bool ColorTransform(DIBINFO *pDib, Mode mode, const Param &param)
20{
21 if (NULL == pDib || NULL == pDib->pBits)
22 {
23 return false;
24 }
25
26 SMap<DWORD, DWORD> cache;
27 int nPixels = pDib->nWid * pDib->nHei;
28 LPBYTE pBit = pDib->pBits;
29 for (int i = 0; i < nPixels; i++, pBit += 4)
30 {
31 DWORD crFrom = *(DWORD *)pBit;
32 SMap<DWORD, DWORD>::CPair *p = cache.Lookup(crFrom);
33 if (p)
34 {
35 memcpy(pBit, &p->m_value, 4);
36 }
37 else
38 {
39 mode(pBit, param);
40 cache[crFrom] = *(DWORD *)pBit;
41 }
42 }
43
44 return true;
45}
46
47// 灰度 = 0.299 * red + 0.587 * green + 0.114 * blue
48static void GrayMode(BYTE *pColor, const int &)
49{
50 pColor[0] = pColor[1] = pColor[2] = RGB2GRAY(pColor[0], pColor[1], pColor[2]);
51}
52
53struct COLORIZEPARAM
54{
55 BYTE hue;
56 BYTE sat;
57 int a0; //[0-256]
58 int a1; //[0-256]
59};
60
61static void FillColorizeParam(COLORIZEPARAM &param, BYTE hue, BYTE sat, float fBlend)
62{
63 param.hue = hue;
64 param.sat = sat;
65 SASSERT(fBlend >= 0.0f && fBlend <= 1.0f);
66 param.a0 = (int)(fBlend * 256);
67 param.a1 = 256 - param.a0;
68}
69
70////////////////////////////////////////////////////////////////////////////////
71#define HSLMAX 255 /* H,L, and S vary over 0-HSLMAX */
72#define RGBMAX 255 /* R,G, and B vary over 0-RGBMAX */
73/* HSLMAX BEST IF DIVISIBLE BY 6 */
74/* RGBMAX, HSLMAX must each fit in a BYTE. */
75/* Hue is undefined if Saturation is 0 (grey-scale) */
76/* This value determines where the Hue scrollbar is */
77/* initially set for achromatic colors */
78#define HSLUNDEFINED (HSLMAX * 2 / 3)
79////////////////////////////////////////////////////////////////////////////////
80static RGBQUAD RGBtoHSL(RGBQUAD lRGBColor)
81{
82 BYTE R, G, B; /* input RGB values */
83 BYTE H, L, S; /* output HSL values */
84 BYTE cMax, cMin; /* max and min RGB values */
85 WORD Rdelta, Gdelta, Bdelta; /* intermediate value: % of spread from max*/
86
87 R = lRGBColor.rgbRed; /* get R, G, and B out of DWORD */
88 G = lRGBColor.rgbGreen;
89 B = lRGBColor.rgbBlue;
90
91 cMax = smax(smax(R, G), B); /* calculate lightness */
92 cMin = smin(smin(R, G), B);
93 L = (BYTE)((((cMax + cMin) * HSLMAX) + RGBMAX) / (2 * RGBMAX));
94
95 if (cMax == cMin)
96 { /* r=g=b --> achromatic case */
97 S = 0; /* saturation */
98 H = HSLUNDEFINED; /* hue */
99 }
100 else
101 { /* chromatic case */
102 if (L <= (HSLMAX / 2)) /* saturation */
103 S = (BYTE)((((cMax - cMin) * HSLMAX) + ((cMax + cMin) / 2)) / (cMax + cMin));
104 else
105 S = (BYTE)((((cMax - cMin) * HSLMAX) + ((2 * RGBMAX - cMax - cMin) / 2)) / (2 * RGBMAX - cMax - cMin));
106 /* hue */
107 Rdelta = (WORD)((((cMax - R) * (HSLMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin));
108 Gdelta = (WORD)((((cMax - G) * (HSLMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin));
109 Bdelta = (WORD)((((cMax - B) * (HSLMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin));
110
111 if (R == cMax)
112 H = (BYTE)(Bdelta - Gdelta);
113 else if (G == cMax)
114 H = (BYTE)((HSLMAX / 3) + Rdelta - Bdelta);
115 else /* B == cMax */
116 H = (BYTE)(((2 * HSLMAX) / 3) + Gdelta - Rdelta);
117
118 // if (H < 0) H += HSLMAX; //always false
119 if (H > HSLMAX)
120 H -= HSLMAX;
121 }
122 RGBQUAD hsl = { L, S, H, 0 };
123 return hsl;
124}
125
126////////////////////////////////////////////////////////////////////////////////
127static RGBQUAD RGBtoRGBQUAD(COLORREF cr)
128{
129 RGBQUAD c;
130 c.rgbRed = GetRValue(cr); /* get R, G, and B out of DWORD */
131 c.rgbGreen = GetGValue(cr);
132 c.rgbBlue = GetBValue(cr);
133 c.rgbReserved = GetAValue(cr);
134 return c;
135}
136////////////////////////////////////////////////////////////////////////////////
137static COLORREF RGBQUADtoRGB(RGBQUAD c)
138{
139 return RGBA(c.rgbRed, c.rgbGreen, c.rgbBlue, c.rgbReserved);
140}
141
142////////////////////////////////////////////////////////////////////////////////
143static float HueToRGB(float n1, float n2, float hue)
144{
145 //<F. Livraghi> fixed implementation for HSL2RGB routine
146 float rValue;
147
148 if (hue > 360)
149 hue = hue - 360;
150 else if (hue < 0)
151 hue = hue + 360;
152
153 if (hue < 60)
154 rValue = n1 + (n2 - n1) * hue / 60.0f;
155 else if (hue < 180)
156 rValue = n2;
157 else if (hue < 240)
158 rValue = n1 + (n2 - n1) * (240 - hue) / 60;
159 else
160 rValue = n1;
161
162 return rValue;
163}
164////////////////////////////////////////////////////////////////////////////////
165////////////////////////////////////////////////////////////////////////////////
166static RGBQUAD HSLtoRGB(RGBQUAD lHSLColor)
167{
168 //<F. Livraghi> fixed implementation for HSL2RGB routine
169 float h, s, l;
170 float m1, m2;
171 BYTE r, g, b;
172
173 h = (float)lHSLColor.rgbRed * 360.0f / 255.0f;
174 s = (float)lHSLColor.rgbGreen / 255.0f;
175 l = (float)lHSLColor.rgbBlue / 255.0f;
176
177 if (l <= 0.5)
178 m2 = l * (1 + s);
179 else
180 m2 = l + s - l * s;
181
182 m1 = 2 * l - m2;
183
184 if (s == 0)
185 {
186 r = g = b = (BYTE)(l * 255.0f);
187 }
188 else
189 {
190 r = (BYTE)(HueToRGB(m1, m2, h + 120) * 255.0f);
191 g = (BYTE)(HueToRGB(m1, m2, h) * 255.0f);
192 b = (BYTE)(HueToRGB(m1, m2, h - 120) * 255.0f);
193 }
194
195 RGBQUAD rgb = { b, g, r, 0 };
196 return rgb;
197}
198
199static void ColorizeMode(BYTE *pArgb, const COLORIZEPARAM &param)
200{
201 BYTE blue = pArgb[0], green = pArgb[1], red = pArgb[2], alpha = pArgb[3];
202
203 if (alpha == 0)
204 return;
205 if (alpha != 255)
206 {
207 red = (red * 255) / alpha;
208 green = (green * 255) / alpha;
209 blue = (blue * 255) / alpha;
210 }
211 RGBQUAD pixel = { blue, green, red };
212
213 if (param.a0 == 256)
214 {
215 RGBQUAD color = RGBtoHSL(pixel);
216 color.rgbRed = param.hue;
217 color.rgbGreen = param.sat;
218 pixel = HSLtoRGB(color);
219 red = pixel.rgbRed;
220 green = pixel.rgbGreen;
221 blue = pixel.rgbBlue;
222 }
223 else
224 {
225 RGBQUAD color = pixel;
226 RGBQUAD hsl;
227 hsl.rgbRed = param.hue;
228 hsl.rgbGreen = param.sat;
229 hsl.rgbBlue = (BYTE)RGB2GRAY(color.rgbRed, color.rgbGreen, color.rgbBlue);
230 hsl = HSLtoRGB(hsl);
231 red = (BYTE)((hsl.rgbRed * param.a0 + color.rgbRed * param.a1) >> 8);
232 blue = (BYTE)((hsl.rgbBlue * param.a0 + color.rgbBlue * param.a1) >> 8);
233 green = (BYTE)((hsl.rgbGreen * param.a0 + color.rgbGreen * param.a1) >> 8);
234 }
235 if (alpha != 255)
236 {
237 red = (red * alpha) / 255;
238 green = (green * alpha) / 255;
239 blue = (blue * alpha) / 255;
240 }
241 pArgb[0] = blue;
242 pArgb[1] = green;
243 pArgb[2] = red;
244}
245
246bool SDIBHelper::Colorize(IBitmapS *pBmp, COLORREF crRef)
247{
248 RGBQUAD color = RGBtoRGBQUAD(crRef);
249 RGBQUAD hsl = RGBtoHSL(color);
250 COLORIZEPARAM param;
251 float fBlend = 0.8f;
252 BYTE byAlpha = GetAValue(crRef);
253 if (byAlpha != 0)
254 fBlend = byAlpha * 1.0f / 255;
255
256 FillColorizeParam(param, hsl.rgbRed, hsl.rgbGreen, fBlend);
257
258 DIBINFO di = { (LPBYTE)pBmp->LockPixelBits(), pBmp->Width(), pBmp->Height() };
259
260 bool bRet = ColorTransform(&di, ColorizeMode, param);
261
262 pBmp->UnlockPixelBits(di.pBits);
263 return bRet;
264}
265
266bool SDIBHelper::Colorize(COLORREF &crTarget, COLORREF crRef)
267{
268 RGBQUAD color = RGBtoRGBQUAD(crRef);
269 RGBQUAD hsl = RGBtoHSL(color);
270 COLORIZEPARAM param;
271
272 float fBlend = 0.8f;
273 BYTE byAlpha = GetAValue(crRef);
274 if (byAlpha != 0)
275 fBlend = byAlpha * 1.0f / 255;
276
277 FillColorizeParam(param, hsl.rgbRed, hsl.rgbGreen, fBlend);
278
279 RGBQUAD argbTarget = RGBtoRGBQUAD(crTarget);
280 ColorizeMode((BYTE *)&argbTarget, param);
281 crTarget = RGBQUADtoRGB(argbTarget);
282 return true;
283}
284
286{
287 DIBINFO di = { (LPBYTE)pBmp->LockPixelBits(), pBmp->Width(), pBmp->Height() };
288 bool bRet = ColorTransform(&di, GrayMode, 0);
289 pBmp->UnlockPixelBits(di.pBits);
290 return bRet;
291}
292
293static COLORREF CalcAvarageRectColor(const DIBINFO &di, RECT rc)
294{
295 LPBYTE pLine = di.pBits + di.nWid * rc.top * 4;
296 if (rc.right > (int)di.nWid)
297 rc.right = di.nWid;
298 if (rc.bottom > (int)di.nHei)
299 rc.bottom = di.nHei;
300 int nWid = rc.right - rc.left;
301 int nHei = rc.bottom - rc.top;
302
303 int r = 0, g = 0, b = 0;
304 for (int y = 0; y < nHei; y++)
305 {
306 LPBYTE p = pLine + rc.left * 4;
307 for (int x = 0; x < nWid; x++)
308 {
309 b += *p++;
310 g += *p++;
311 r += *p++;
312 p++; // skip alpha
313 }
314 pLine += di.nWid * 4;
315 }
316 int nPixels = (nWid * nHei);
317 r /= nPixels;
318 g /= nPixels;
319 b /= nPixels;
320 return RGB(r, g, b);
321}
322
323static int RgbCmp(const void *p1, const void *p2)
324{
325 const BYTE *cr1 = (const BYTE *)p1;
326 const BYTE *cr2 = (const BYTE *)p2;
327 int deltaR = ((int)cr2[0] - (int)cr1[0]);
328 int deltaG = ((int)cr2[1] - (int)cr1[1]);
329 int deltaB = ((int)cr2[2] - (int)cr1[2]);
330 return deltaR + deltaG + deltaB;
331}
332
333COLORREF SDIBHelper::CalcAvarageColor(IBitmapS *pBmp, int nPercent, int nBlockSize /*=5*/)
334{
335 DIBINFO di = { (LPBYTE)pBmp->LockPixelBits(), pBmp->Width(), pBmp->Height() };
336
337 int xBlocks = (di.nWid + nBlockSize - 1) / nBlockSize;
338 int yBlocks = (di.nHei + nBlockSize - 1) / nBlockSize;
339
340 int nBlocks = xBlocks * yBlocks;
341 COLORREF *pAvgColors = new COLORREF[nBlocks];
342
343 CRect rcBlock(0, 0, nBlockSize, nBlockSize);
344 int iBlock = 0;
345 for (int y = 0; y < yBlocks; y++)
346 {
347 for (int x = 0; x < xBlocks; x++)
348 {
349 pAvgColors[iBlock++] = CalcAvarageRectColor(di, rcBlock);
350 rcBlock.OffsetRect(nBlockSize, 0);
351 }
352 rcBlock.MoveToX(0);
353 rcBlock.OffsetRect(0, nBlockSize);
354 }
355 // RGB排序
356 qsort(pAvgColors, nBlocks, sizeof(COLORREF), RgbCmp);
357
358 int nThrows = nBlocks * (100 - nPercent) / 200; //一端丢弃数量
359 int iBegin = nThrows;
360 int iEnd = nBlocks - nThrows;
361
362 int r = 0, g = 0, b = 0;
363 for (int i = iBegin; i < iEnd; i++)
364 {
365 BYTE *p = (BYTE *)(pAvgColors + i);
366 r += p[0];
367 g += p[1];
368 b += p[2];
369 }
370
371 r /= (iEnd - iBegin);
372 g /= (iEnd - iBegin);
373 b /= (iEnd - iBegin);
374
375 delete[] pAvgColors;
376 pBmp->UnlockPixelBits(di.pBits);
377
378 return RGB(r, g, b);
379}
380
381SNSEND
static bool GrayImage(IBitmapS *pBmp)
将位图转换为灰度图像
static bool Colorize(IBitmapS *pBmp, COLORREF crRef)
对位图进行着色处理
static COLORREF CalcAvarageColor(IBitmapS *pBmp, int nPercent=90, int nBlockSize=5)
计算图片的平均颜色
Bitmap object interface.
Definition SRender-i.h:420
UINT Height() SCONST PURE
Retrieves the height of the bitmap.
UINT Width() SCONST PURE
Retrieves the width of the bitmap.
LPVOID LockPixelBits() PURE
Locks the pixel bits of the bitmap for writing.
void UnlockPixelBits(LPVOID pBuf) PURE
Unlocks the pixel bits of the bitmap.