Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1090 lines
28 KiB

  1. /****************************************************************************
  2. *
  3. * dibmap.c
  4. *
  5. * Histrogram and optimal palette processing module.
  6. *
  7. * Microsoft Video for Windows Sample Capture Class
  8. *
  9. * Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. #include <windows.h>
  19. #include <win32.h>
  20. #include "dibmap.h"
  21. #ifndef _WIN32
  22. extern NEAR PASCAL MemCopy(LPVOID,LPVOID,DWORD);
  23. #endif
  24. extern NEAR PASCAL MemFill(LPVOID,DWORD,BYTE);
  25. void Histogram24(BYTE huge *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram);
  26. void Histogram16(BYTE huge *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram);
  27. void Histogram8(BYTE huge *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors);
  28. void Histogram4(BYTE huge *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors);
  29. void Histogram1(BYTE huge *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors);
  30. void Reduce24(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp16to8);
  31. void Reduce16(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp16to8);
  32. void Reduce8(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp8to8);
  33. void Reduce4(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp8to8);
  34. void Reduce1(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp8to8);
  35. //
  36. // InitHistogram
  37. //
  38. // create a zero'ed histogram table, or initialize a existing table
  39. // to all zeros.
  40. //
  41. LPHISTOGRAM InitHistogram(LPHISTOGRAM lpHistogram)
  42. {
  43. if (lpHistogram == NULL)
  44. lpHistogram = (LPVOID)GlobalAllocPtr(GHND,32768l*sizeof(DWORD));
  45. #if 0
  46. if (lpHistogram)
  47. MemFill(lpHistogram, 32768l * sizeof(DWORD), 0);
  48. #endif
  49. return lpHistogram;
  50. }
  51. //
  52. // FreeHistogram
  53. //
  54. // free a histogram table
  55. //
  56. void FreeHistogram(LPHISTOGRAM lpHistogram)
  57. {
  58. GlobalFreePtr(lpHistogram);
  59. }
  60. //
  61. // DibHistogram
  62. //
  63. // take all colors in a dib and increment its entry in the Histogram table
  64. //
  65. // supports the following DIB formats: 1,4,8,16,24
  66. //
  67. BOOL DibHistogram(LPBITMAPINFOHEADER lpbi, LPBYTE lpBits, int x, int y, int dx, int dy, LPHISTOGRAM lpHistogram)
  68. {
  69. int i;
  70. UINT WidthBytes;
  71. RGBQUAD FAR * prgbq;
  72. WORD argb16[256];
  73. if (lpbi == NULL || lpHistogram == NULL)
  74. return FALSE;
  75. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  76. lpbi->biClrUsed = (1 << (int)lpbi->biBitCount);
  77. if (lpBits == NULL)
  78. lpBits = (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed*sizeof(RGBQUAD);
  79. WidthBytes = (UINT)((lpbi->biBitCount * lpbi->biWidth + 7) / 8 + 3) & ~3;
  80. ((BYTE huge *)lpBits) += (DWORD)y*WidthBytes + ((x*(int)lpbi->biBitCount)/8);
  81. if (dx < 0 || dx > (int)lpbi->biWidth)
  82. dx = (int)lpbi->biWidth;
  83. if (dy < 0 || dy > (int)lpbi->biHeight)
  84. dy = (int)lpbi->biHeight;
  85. if ((int)lpbi->biBitCount <= 8)
  86. {
  87. prgbq = (LPVOID)((LPBYTE)lpbi + lpbi->biSize);
  88. for (i=0; i<(int)lpbi->biClrUsed; i++)
  89. {
  90. argb16[i] = RGB16(prgbq[i].rgbRed,prgbq[i].rgbGreen,prgbq[i].rgbBlue);
  91. }
  92. for (i=(int)lpbi->biClrUsed; i<256; i++)
  93. {
  94. argb16[i] = 0x0000; // just in case!
  95. }
  96. }
  97. switch ((int)lpbi->biBitCount)
  98. {
  99. case 24:
  100. Histogram24(lpBits, dx, dy, WidthBytes, lpHistogram);
  101. break;
  102. case 16:
  103. Histogram16(lpBits, dx, dy, WidthBytes, lpHistogram);
  104. break;
  105. case 8:
  106. Histogram8(lpBits, dx, dy, WidthBytes, lpHistogram, argb16);
  107. break;
  108. case 4:
  109. Histogram4(lpBits, dx, dy, WidthBytes, lpHistogram, argb16);
  110. break;
  111. case 1:
  112. Histogram1(lpBits, dx, dy, WidthBytes, lpHistogram, argb16);
  113. break;
  114. }
  115. return TRUE;
  116. }
  117. //
  118. // will convert the given DIB to a 8bit DIB with the specifed palette
  119. //
  120. HANDLE DibReduce(LPBITMAPINFOHEADER lpbiIn, LPBYTE pbIn, HPALETTE hpal, LPBYTE lp16to8)
  121. {
  122. HANDLE hdib;
  123. int nPalColors;
  124. int nDibColors;
  125. UINT cbOut;
  126. UINT cbIn;
  127. BYTE xlat[256];
  128. BYTE HUGE * pbOut;
  129. RGBQUAD FAR * prgb;
  130. DWORD dwSize;
  131. int i;
  132. int dx;
  133. int dy;
  134. PALETTEENTRY pe;
  135. LPBITMAPINFOHEADER lpbiOut;
  136. dx = (int)lpbiIn->biWidth;
  137. dy = (int)lpbiIn->biHeight;
  138. cbIn = ((lpbiIn->biBitCount*dx+7)/8+3)&~3;
  139. cbOut = (dx+3)&~3;
  140. #ifdef _WIN32
  141. // careful with GetObject in Win32: this (counter-intuitively) writes
  142. // a short not an INT for the number of colours
  143. // (despite being passed a 32 bit variable)
  144. // BUT the code uses INTs more efficiently
  145. // So we must initialize the variable to 0 to clear the high 16bits
  146. nPalColors = 0;
  147. #endif
  148. GetObject(hpal, sizeof(nPalColors), (LPVOID)&nPalColors);
  149. nDibColors = (int)lpbiIn->biClrUsed;
  150. if (nDibColors == 0 && lpbiIn->biBitCount <= 8)
  151. nDibColors = (1 << (int)lpbiIn->biBitCount);
  152. if (pbIn == NULL)
  153. pbIn = (LPBYTE)lpbiIn + (int)lpbiIn->biSize + nDibColors*sizeof(RGBQUAD);
  154. dwSize = (DWORD)cbOut * dy;
  155. hdib = GlobalAlloc(GMEM_MOVEABLE,sizeof(BITMAPINFOHEADER)
  156. + nPalColors*sizeof(RGBQUAD) + dwSize);
  157. if (!hdib)
  158. return NULL;
  159. lpbiOut = (LPVOID)GlobalLock(hdib);
  160. lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
  161. lpbiOut->biWidth = lpbiIn->biWidth;
  162. lpbiOut->biHeight = lpbiIn->biHeight;
  163. lpbiOut->biPlanes = 1;
  164. lpbiOut->biBitCount = 8;
  165. lpbiOut->biCompression = BI_RGB;
  166. lpbiOut->biSizeImage = dwSize;
  167. lpbiOut->biXPelsPerMeter= 0;
  168. lpbiOut->biYPelsPerMeter= 0;
  169. lpbiOut->biClrUsed = nPalColors;
  170. lpbiOut->biClrImportant = 0;
  171. pbOut = (LPBYTE)lpbiOut + (int)lpbiOut->biSize + nPalColors*sizeof(RGBQUAD);
  172. prgb = (LPVOID)((LPBYTE)lpbiOut + (int)lpbiOut->biSize);
  173. for (i=0; i<nPalColors; i++)
  174. {
  175. GetPaletteEntries(hpal, i, 1, &pe);
  176. prgb[i].rgbRed = pe.peRed;
  177. prgb[i].rgbGreen = pe.peGreen;
  178. prgb[i].rgbBlue = pe.peBlue;
  179. prgb[i].rgbReserved = 0;
  180. }
  181. if ((int)lpbiIn->biBitCount <= 8)
  182. {
  183. prgb = (LPVOID)((LPBYTE)lpbiIn + lpbiIn->biSize);
  184. for (i=0; i<nDibColors; i++)
  185. xlat[i] = lp16to8[RGB16(prgb[i].rgbRed,prgb[i].rgbGreen,prgb[i].rgbBlue)];
  186. for (; i<256; i++)
  187. xlat[i] = 0;
  188. }
  189. switch ((int)lpbiIn->biBitCount)
  190. {
  191. case 24:
  192. Reduce24(pbIn, dx, dy, cbIn, pbOut, cbOut, lp16to8);
  193. break;
  194. case 16:
  195. Reduce16(pbIn, dx, dy, cbIn, pbOut, cbOut, lp16to8);
  196. break;
  197. case 8:
  198. Reduce8(pbIn, dx, dy, cbIn, pbOut, cbOut, xlat);
  199. break;
  200. case 4:
  201. Reduce4(pbIn, dx, dy, cbIn, pbOut, cbOut, xlat);
  202. break;
  203. case 1:
  204. Reduce1(pbIn, dx, dy, cbIn, pbOut, cbOut, xlat);
  205. break;
  206. }
  207. return hdib;
  208. }
  209. ///////////////////////////////////////////////////////////////////////////////
  210. // cluster.c
  211. ///////////////////////////////////////////////////////////////////////////////
  212. #define IN_DEPTH 5 // # bits/component kept from input
  213. #define IN_SIZE (1 << IN_DEPTH) // max value of a color component
  214. typedef enum { red, green, blue } color;
  215. typedef struct tagCut {
  216. int cutpoint;
  217. color cutaxis;
  218. } Cut;
  219. typedef struct tagColorBox { // from cluster.c
  220. struct tagColorBox *next; /* pointer to next box */
  221. int rmin, rmax, gmin, gmax, bmin, bmax; /* bounding box */
  222. long variance, wt; /* weighted variance */
  223. long sum[3]; /* sum of values */
  224. } ColorBox;
  225. static int InitBoxes(int nBoxes);
  226. static void DeleteBoxes(void);
  227. static int SplitBoxAxis(ColorBox *box, Cut cutaxis);
  228. static void ShrinkBox(ColorBox *box);
  229. static int ComputePalette(LPHISTOGRAM lpHistogram, LPBYTE lp16to8, LPPALETTEENTRY palette);
  230. static COLORREF DetermineRepresentative(ColorBox *box, int palIndex);
  231. static Cut FindSplitAxis(ColorBox *box);
  232. static void SplitBox(ColorBox *box);
  233. static void SortBoxes(void);
  234. HANDLE hBoxes;
  235. ColorBox *UsedBoxes;
  236. ColorBox *FreeBoxes;
  237. LPBYTE glp16to8;
  238. #ifdef _WIN32
  239. /*
  240. * to avoid all this 16 bit assembler with minimal changes to the
  241. * rest of the code the Win32 version will use a global pointer set by
  242. * UseHistogram and accessed by the hist() and IncHistogram macros.
  243. */
  244. DWORD HUGE* glpHistogram;
  245. #define UseHistogram(p) (glpHistogram = (p))
  246. #define hist(r,g,b) ((DWORD HUGE *)glpHistogram)[(WORD)(b) | ((WORD)(g)<<IN_DEPTH) | ((WORD)(r)<<(IN_DEPTH*2))]
  247. #define IncHistogram(w) if (lpHistogram[(UINT)(w)] < 0xFFFFFFFF) { \
  248. lpHistogram[(UINT)(w)]++;\
  249. }
  250. #else
  251. #define hist(r,g,b) GetHistogram((BYTE)(r),(BYTE)(g),(BYTE)(b))
  252. #pragma optimize ("", off)
  253. //
  254. // set FS == lpHistogram.sel, so we can get at it quickly!
  255. //
  256. void NEAR PASCAL UseHistogram(LPHISTOGRAM lpHistogram)
  257. {
  258. _asm {
  259. mov ax,word ptr lpHistogram[2]
  260. _emit 08Eh ; mov fs,ax
  261. _emit 0E0h
  262. }
  263. }
  264. //
  265. // get the DWORD histogram count of a RGB
  266. //
  267. DWORD NEAR _FASTCALL GetHistogram(BYTE r, BYTE g, BYTE b)
  268. {
  269. if (0) // avoid compiler warning NO RETURN VALUE
  270. return 0;
  271. _asm {
  272. ;
  273. ; on entry al=r, dl=g, bl=b [0-31]
  274. ;
  275. ; map to a RGB16
  276. ;
  277. xor ah,ah
  278. shl ax,5
  279. or al,dl
  280. shl ax,5
  281. or al,bl
  282. ; now ax = RGB16
  283. _emit 66h _asm xor bx,bx ; xor ebx,ebx
  284. _asm mov bx,ax ; mov bx,ax
  285. _emit 66h _asm shl bx,2 ; shl ebx,2
  286. _emit 64h _asm _emit 67h ; mov dx,fs:[ebx][2]
  287. _emit 8Bh _asm _emit 53h
  288. _emit 02h
  289. _emit 64h _asm _emit 67h ; mov ax,fs:[ebx][0]
  290. _emit 8Bh _asm _emit 03h
  291. }
  292. }
  293. //
  294. // increment the histogram count of a RGB16
  295. //
  296. //
  297. // #define IncHistogram(w) if (lpHistogram[(WORD)(w)] < 0xFFFFFFFF)
  298. // lpHistogram[(WORD)(w)]++;
  299. //
  300. void NEAR _FASTCALL IncHistogram(WORD rgb16)
  301. {
  302. _asm {
  303. ;
  304. ; on entry ax = rgb16
  305. ;
  306. _emit 66h _asm xor bx,bx ; xor ebx,ebx
  307. _asm mov bx,ax ; mov bx,ax
  308. _emit 66h _asm shl bx,2 ; shl ebx,2
  309. _emit 64h _asm _emit 67h ; cmp dword ptr fs:[ebx], -1
  310. _emit 66h _asm _emit 83h
  311. _emit 3Bh _asm _emit 0FFh
  312. _emit 74h _asm _emit 05h ; je short @f
  313. _emit 64h _asm _emit 67h ; inc dword ptr fs:[ebx]
  314. _emit 66h _asm _emit 0FFh
  315. _emit 03h
  316. }
  317. }
  318. #pragma optimize ("", on)
  319. // !!! C8 generates a Jump into the middle of a 2 byte instruction
  320. //
  321. #pragma optimize ("", off)
  322. #endif //_WIN32
  323. //
  324. // HistogramPalette
  325. //
  326. // given a histogram, will reduce it to 'nColors' number of colors.
  327. // returns a optimal palette. if specifed lp16to8 will contain the
  328. // translate table from RGB16 to the palette index.
  329. //
  330. // you can specify lpHistogram as lp16to8
  331. //
  332. HPALETTE HistogramPalette(LPHISTOGRAM lpHistogram, LPBYTE lp16to8, int nColors)
  333. {
  334. UINT w;
  335. DWORD dwMax;
  336. COLORREF rgb;
  337. ColorBox *box;
  338. int i;
  339. // Had to make this global to prevent VB 2.0 stack explosion
  340. static struct {
  341. WORD palVersion;
  342. WORD palNumEntries;
  343. PALETTEENTRY palPalEntry[256];
  344. } pal;
  345. //
  346. // the 'C' code cant handle >64k histogram counts.
  347. // !!!fix this
  348. //
  349. for (dwMax=0,w=0; w<0x8000; w++)
  350. dwMax = max(dwMax,lpHistogram[w]);
  351. while (dwMax > 0xFFFFl)
  352. {
  353. for (w=0; w<0x8000; w++)
  354. lpHistogram[w] /= 2;
  355. dwMax /= 2;
  356. }
  357. if (!InitBoxes(min(nColors, 236)))
  358. return NULL;
  359. UseHistogram(lpHistogram);
  360. glp16to8 = lp16to8;
  361. /* while there are free boxes left, split the largest */
  362. i = 0;
  363. do {
  364. i++;
  365. SplitBox(UsedBoxes);
  366. }
  367. while (FreeBoxes && UsedBoxes->variance);
  368. SortBoxes();
  369. i=0;
  370. //
  371. // add some standard colors to the histogram
  372. //
  373. if (nColors > 236)
  374. {
  375. HDC hdc;
  376. HPALETTE hpal;
  377. hdc = GetDC(NULL);
  378. if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  379. {
  380. GetSystemPaletteEntries(hdc, 0, 10, &pal.palPalEntry[0]);
  381. GetSystemPaletteEntries(hdc, 246, 10, &pal.palPalEntry[246]);
  382. i = 10;
  383. } else { // we're a true colour device, so get the system
  384. // colours from the default palette.
  385. hpal = GetStockObject(DEFAULT_PALETTE);
  386. GetPaletteEntries(hpal, 0, 10, &pal.palPalEntry[0]);
  387. GetPaletteEntries(hpal, 10, 10, &pal.palPalEntry[246]);
  388. i = 10;
  389. }
  390. ReleaseDC(NULL, hdc);
  391. }
  392. // probably not needed on C-only versions (NT).
  393. UseHistogram(lpHistogram); // Register FS trashed by above!
  394. /* Generate the representitives and the associated Palette mapping */
  395. /* NOTE: Might loop less than nColors times. */
  396. for (box = UsedBoxes; box; box = box->next, i++)
  397. {
  398. rgb = DetermineRepresentative(box, i);
  399. pal.palPalEntry[i].peRed = GetRValue(rgb);
  400. pal.palPalEntry[i].peGreen = GetGValue(rgb);
  401. pal.palPalEntry[i].peBlue = GetBValue(rgb);
  402. pal.palPalEntry[i].peFlags = 0;
  403. }
  404. DeleteBoxes();
  405. if (nColors > 236)
  406. {
  407. for (; i<246; i++)
  408. {
  409. pal.palPalEntry[i].peRed = 0;
  410. pal.palPalEntry[i].peGreen = 0;
  411. pal.palPalEntry[i].peBlue = 0;
  412. pal.palPalEntry[i].peFlags = 0;
  413. }
  414. i = 256;
  415. }
  416. glp16to8 = NULL;
  417. pal.palVersion = 0x300;
  418. pal.palNumEntries = (WORD) i;
  419. return CreatePalette((LPLOGPALETTE)&pal);
  420. }
  421. #pragma optimize ("", on)
  422. static void SortBoxes()
  423. {
  424. ColorBox *box;
  425. ColorBox *newList;
  426. ColorBox *insBox;
  427. ColorBox *nextBox;
  428. newList = UsedBoxes;
  429. nextBox = newList->next;
  430. newList->next = NULL;
  431. for (box = nextBox; box; box = nextBox) { // just an insertion sort...
  432. nextBox = box->next;
  433. if (box->wt > newList->wt) {
  434. box->next = newList;
  435. newList = box;
  436. } else {
  437. for (insBox = newList;
  438. insBox->next && (box->wt < insBox->next->wt);
  439. insBox = insBox->next) ;
  440. box->next = insBox->next;
  441. insBox->next = box;
  442. }
  443. }
  444. UsedBoxes = newList;
  445. }
  446. /*
  447. allocate space for nBoxes boxes, set up links. On exit UsedBoxes
  448. points to one box, FreeBoxes points to remaining (nBoxes-1) boxes.
  449. return 0 if successful.
  450. */
  451. static BOOL InitBoxes(int nBoxes)
  452. {
  453. int i;
  454. hBoxes = LocalAlloc(LHND, nBoxes*sizeof(ColorBox));
  455. if (!hBoxes)
  456. return FALSE;
  457. UsedBoxes = (ColorBox*)LocalLock(hBoxes);
  458. FreeBoxes = UsedBoxes + 1;
  459. UsedBoxes->next = NULL;
  460. for (i = 0; i < nBoxes - 1; ++i)
  461. {
  462. FreeBoxes[i].next = FreeBoxes + i + 1;
  463. }
  464. FreeBoxes[nBoxes-2].next = NULL;
  465. /* save the bounding box */
  466. UsedBoxes->rmin = UsedBoxes->gmin = UsedBoxes->bmin = 0;
  467. UsedBoxes->rmax = UsedBoxes->gmax = UsedBoxes->bmax = IN_SIZE - 1;
  468. UsedBoxes->variance = 9999999; /* arbitrary large # */
  469. return TRUE;
  470. }
  471. static void DeleteBoxes()
  472. {
  473. LocalUnlock(hBoxes);
  474. LocalFree(hBoxes);
  475. hBoxes = NULL;
  476. }
  477. static void SplitBox(ColorBox *box)
  478. {
  479. /*
  480. split box into two roughly equal halves and update the data structures
  481. appropriately.
  482. */
  483. Cut cutaxis;
  484. ColorBox *temp, *temp2, *prev;
  485. cutaxis = FindSplitAxis(box);
  486. /* split the box along that axis. If rc != 0 then the box contains
  487. one color, and should not be split */
  488. if (SplitBoxAxis(box, cutaxis))
  489. return;
  490. /* shrink each of the boxes to fit the points they enclose */
  491. ShrinkBox(box);
  492. ShrinkBox(FreeBoxes);
  493. /* move old box down in list, if necessary */
  494. if (box->next && box->variance < box->next->variance)
  495. {
  496. UsedBoxes = box->next;
  497. temp = box;
  498. do {
  499. prev = temp;
  500. temp = temp->next;
  501. } while (temp && temp->variance > box->variance);
  502. box->next = temp;
  503. prev->next = box;
  504. }
  505. /* insert the new box in sorted order (descending), removing it
  506. from the free list. */
  507. if (FreeBoxes->variance >= UsedBoxes->variance)
  508. {
  509. temp = FreeBoxes;
  510. FreeBoxes = FreeBoxes->next;
  511. temp->next = UsedBoxes;
  512. UsedBoxes = temp;
  513. }
  514. else
  515. {
  516. temp = UsedBoxes;
  517. do {
  518. prev = temp;
  519. temp = temp->next;
  520. } while (temp && temp->variance > FreeBoxes->variance);
  521. temp2 = FreeBoxes->next;
  522. FreeBoxes->next = temp;
  523. prev->next = FreeBoxes;
  524. FreeBoxes = temp2;
  525. }
  526. }
  527. static Cut FindSplitAxis(ColorBox *box)
  528. {
  529. unsigned long proj_r[IN_SIZE],proj_g[IN_SIZE],proj_b[IN_SIZE];
  530. unsigned long f;
  531. double currentMax,mean;
  532. unsigned long w,w1,m,m1;
  533. short r,g,b;
  534. short bestCut;
  535. color bestAxis;
  536. Cut cutRet;
  537. double temp1,temp2;
  538. for (r = 0; r < IN_SIZE; r++) {
  539. proj_r[r] = proj_g[r] = proj_b[r] = 0;
  540. }
  541. w = 0;
  542. // Project contents of box down onto axes
  543. for (r = (WORD) box->rmin; r <= (WORD) box->rmax; r++) {
  544. for (g = (WORD) box->gmin; g <= (WORD) box->gmax; ++g) {
  545. for (b = (WORD) box->bmin; b <= (WORD) box->bmax; ++b) {
  546. f = hist(r,g,b);
  547. proj_r[r] += f;
  548. proj_g[g] += f;
  549. proj_b[b] += f;
  550. }
  551. }
  552. w += proj_r[r];
  553. }
  554. currentMax = 0.0f;
  555. #define Check_Axis(l,color) \
  556. m = 0; \
  557. for (l = (WORD) box->l##min; l <= (WORD) box->l##max; (l)++) { \
  558. m += l * proj_##l[l]; \
  559. } \
  560. mean = ((double) m) / ((double) w); \
  561. \
  562. w1 = 0; \
  563. m1 = 0; \
  564. for (l = (WORD) box->l##min; l <= box->l##max; l++) { \
  565. w1 += proj_##l[l]; \
  566. if (w1 == 0) \
  567. continue; \
  568. if (w1 == w) \
  569. break; \
  570. m1 += l * proj_##l[l]; \
  571. temp1 = mean - (((double) m1) / ((double) w1)); \
  572. temp2 = (((double) w1) / ((double) (w-w1))) * temp1 * temp1; \
  573. if (temp2 > currentMax) { \
  574. bestCut = l; \
  575. bestAxis = color; \
  576. currentMax = temp2; \
  577. } \
  578. }
  579. Check_Axis(r,red);
  580. Check_Axis(g,green);
  581. Check_Axis(b,blue);
  582. cutRet.cutaxis = bestAxis;
  583. cutRet.cutpoint = bestCut;
  584. return cutRet;
  585. }
  586. static int SplitBoxAxis(ColorBox *box, Cut cutaxis)
  587. {
  588. /*
  589. Split box along splitaxis into two boxes, one of which is placed
  590. back in box, the other going in the first free box (FreeBoxes)
  591. If the box only contains one color, return non-zero, else return 0.
  592. */
  593. ColorBox *next;
  594. if ( box->variance == 0)
  595. return 1;
  596. /* copy all non-link information to new box */
  597. next = FreeBoxes->next;
  598. *FreeBoxes = *box;
  599. FreeBoxes->next = next;
  600. switch (cutaxis.cutaxis)
  601. {
  602. case red:
  603. box->rmax = cutaxis.cutpoint;
  604. FreeBoxes->rmin = cutaxis.cutpoint+1;
  605. break;
  606. case green:
  607. box->gmax = cutaxis.cutpoint;
  608. FreeBoxes->gmin = cutaxis.cutpoint+1;
  609. break;
  610. case blue:
  611. box->bmax = cutaxis.cutpoint;
  612. FreeBoxes->bmin = cutaxis.cutpoint+1;
  613. break;
  614. }
  615. return 0;
  616. }
  617. static void ShrinkBox(ColorBox *box)
  618. {
  619. unsigned long n, sxx, sx2, var, quotient, remainder;
  620. int r,g,b;
  621. unsigned long f;
  622. unsigned long proj_r[IN_SIZE],proj_g[IN_SIZE],proj_b[IN_SIZE];
  623. n = 0;
  624. for (r = 0; r < IN_SIZE; r++) {
  625. proj_r[r] = proj_g[r] = proj_b[r] = 0;
  626. }
  627. // Project contents of box down onto axes
  628. for (r = box->rmin; r <= box->rmax; r++) {
  629. for (g = box->gmin; g <= box->gmax; ++g) {
  630. for (b = box->bmin; b <= box->bmax; ++b) {
  631. f = hist(r,g,b);
  632. proj_r[r] += f;
  633. proj_g[g] += f;
  634. proj_b[b] += f;
  635. }
  636. }
  637. n += proj_r[r];
  638. }
  639. box->wt = n;
  640. var = 0;
  641. #define AddAxisVariance(c) \
  642. sxx = 0; sx2 = 0; \
  643. for (c = box->c##min; c <= box->c##max; c++) { \
  644. sxx += proj_##c[c] * c * c; \
  645. sx2 += proj_##c[c] * c; \
  646. } \
  647. quotient = sx2 / n; /* This stuff avoids overflow */ \
  648. remainder = sx2 % n; \
  649. var += sxx - quotient * sx2 - ((remainder * sx2)/n);
  650. AddAxisVariance(r);
  651. AddAxisVariance(g);
  652. AddAxisVariance(b);
  653. box->variance = var;
  654. }
  655. static COLORREF DetermineRepresentative(ColorBox *box, int palIndex)
  656. {
  657. /*
  658. determines the rgb value to represent the pixels contained in
  659. box. nbits is the # bits/component we're allowed to return.
  660. */
  661. long f;
  662. long Rval, Gval, Bval;
  663. unsigned long total;
  664. int r, g, b;
  665. UINT w;
  666. /* compute the weighted sum of the elements in the box */
  667. Rval = Gval = Bval = total = 0;
  668. for (r = box->rmin; r <= box->rmax; ++r)
  669. {
  670. for (g = box->gmin; g <= box->gmax; ++g)
  671. {
  672. for (b = box->bmin; b <= box->bmax; ++b)
  673. {
  674. if (glp16to8)
  675. {
  676. w = (UINT)(b) | ((WORD)(g)<<IN_DEPTH) | ((WORD)(r)<<(IN_DEPTH*2));
  677. glp16to8[w] = (BYTE)palIndex;
  678. }
  679. f = hist(r,g,b);
  680. if (f == 0L)
  681. continue;
  682. Rval += f * (long) r;
  683. Gval += f * (long) g;
  684. Bval += f * (long) b;
  685. total += f;
  686. }
  687. }
  688. }
  689. /* Bias the sum so that we round up at .5 */
  690. Rval += total / 2;
  691. Gval += total / 2;
  692. Bval += total / 2;
  693. return RGB(Rval*255/total/IN_SIZE, Gval*255/total/IN_SIZE, Bval*255/total/IN_SIZE);
  694. }
  695. ///////////////////////////////////////////////////////////////////////////////
  696. //
  697. ///////////////////////////////////////////////////////////////////////////////
  698. ///////////////////////////////////////////////////////////////////////////////
  699. //
  700. // write this stuff in ASM!
  701. //
  702. ///////////////////////////////////////////////////////////////////////////////
  703. void Histogram24(BYTE HUGE *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram)
  704. {
  705. int x,y;
  706. BYTE r,g,b;
  707. UINT w;
  708. UseHistogram(lpHistogram);
  709. WidthBytes -= dx*3;
  710. for (y=0; y<dy; y++)
  711. {
  712. for (x=0; x<dx; x++)
  713. {
  714. b = *pb++;
  715. g = *pb++;
  716. r = *pb++;
  717. w = RGB16(r,g,b);
  718. IncHistogram(w);
  719. }
  720. pb += WidthBytes;
  721. }
  722. }
  723. void Histogram16(BYTE HUGE *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram)
  724. {
  725. int x,y;
  726. UINT w;
  727. UseHistogram(lpHistogram);
  728. WidthBytes -= dx*2;
  729. for (y=0; y<dy; y++)
  730. {
  731. for (x=0; x<dx; x++)
  732. {
  733. w = *((WORD HUGE *)pb)++;
  734. w &= 0x7FFF;
  735. IncHistogram(w);
  736. }
  737. pb += WidthBytes;
  738. }
  739. }
  740. void Histogram8(BYTE HUGE *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors)
  741. {
  742. int x,y;
  743. UINT w;
  744. UseHistogram(lpHistogram);
  745. WidthBytes -= dx;
  746. for (y=0; y<dy; y++)
  747. {
  748. for (x=0; x<dx; x++)
  749. {
  750. w = lpColors[*pb++];
  751. IncHistogram(w);
  752. }
  753. pb += WidthBytes;
  754. }
  755. }
  756. void Histogram4(BYTE HUGE *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors)
  757. {
  758. int x,y;
  759. BYTE b;
  760. UINT w;
  761. UseHistogram(lpHistogram);
  762. WidthBytes -= (dx+1)/2;
  763. for (y=0; y<dy; y++)
  764. {
  765. for (x=0; x<(dx+1)/2; x++)
  766. {
  767. b = *pb++;
  768. w = lpColors[b>>4];
  769. IncHistogram(w);
  770. w = lpColors[b&0x0F];
  771. IncHistogram(w);
  772. }
  773. pb += WidthBytes;
  774. }
  775. }
  776. void Histogram1(BYTE HUGE *pb, int dx, int dy, UINT WidthBytes, LPHISTOGRAM lpHistogram, LPWORD lpColors)
  777. {
  778. int x,y,i;
  779. BYTE b;
  780. UINT w;
  781. UseHistogram(lpHistogram);
  782. WidthBytes -= (dx+7)/8;
  783. for (y=0; y<dy; y++)
  784. {
  785. for (x=0; x<(dx+7)/8; x++)
  786. {
  787. b = *pb++;
  788. for (i=0; i<8; i++)
  789. {
  790. w = lpColors[b>>7];
  791. IncHistogram(w);
  792. b<<=1;
  793. }
  794. }
  795. pb += WidthBytes;
  796. }
  797. }
  798. ///////////////////////////////////////////////////////////////////////////////
  799. //
  800. // write this stuff in ASM! too
  801. // -- if you do - please leave the C version #ifdef _WIN32
  802. //
  803. ///////////////////////////////////////////////////////////////////////////////
  804. void Reduce24(BYTE HUGE *pbIn, int dx, int dy, UINT cbIn, BYTE HUGE *pbOut, UINT cbOut, LPBYTE lp16to8)
  805. {
  806. int x,y;
  807. BYTE r,g,b;
  808. cbOut -= dx;
  809. cbIn -= dx*3;
  810. for (y=0; y<dy; y++)
  811. {
  812. for (x=0; x<dx; x++)
  813. {
  814. b = *pbIn++;
  815. g = *pbIn++;
  816. r = *pbIn++;
  817. *pbOut++ = lp16to8[RGB16(r,g,b)];
  818. }
  819. pbIn += cbIn;
  820. pbOut+= cbOut;
  821. }
  822. }
  823. void Reduce16(BYTE huge *pbIn, int dx, int dy, UINT cbIn, BYTE huge *pbOut, UINT cbOut, LPBYTE lp16to8)
  824. {
  825. int x,y;
  826. WORD w;
  827. cbOut -= dx;
  828. cbIn -= dx*2;
  829. for (y=0; y<dy; y++)
  830. {
  831. for (x=0; x<dx; x++)
  832. {
  833. w = *((WORD HUGE *)pbIn)++;
  834. *pbOut++ = lp16to8[w&0x7FFF];
  835. }
  836. pbIn += cbIn;
  837. pbOut+= cbOut;
  838. }
  839. }
  840. void Reduce8(BYTE HUGE *pbIn, int dx, int dy, UINT cbIn, BYTE HUGE *pbOut, UINT cbOut, LPBYTE lp8to8)
  841. {
  842. int x,y;
  843. cbIn -= dx;
  844. cbOut -= dx;
  845. for (y=0; y<dy; y++)
  846. {
  847. for (x=0; x<dx; x++)
  848. {
  849. *pbOut++ = lp8to8[*pbIn++];
  850. }
  851. pbIn += cbIn;
  852. pbOut += cbOut;
  853. }
  854. }
  855. void Reduce4(BYTE HUGE *pbIn, int dx, int dy, UINT cbIn, BYTE HUGE *pbOut, UINT cbOut, LPBYTE lp8to8)
  856. {
  857. int x,y;
  858. BYTE b;
  859. cbIn -= (dx+1)/2;
  860. cbOut -= (dx+1)&~1;
  861. for (y=0; y<dy; y++)
  862. {
  863. for (x=0; x<(dx+1)/2; x++)
  864. {
  865. b = *pbIn++;
  866. *pbOut++ = lp8to8[b>>4];
  867. *pbOut++ = lp8to8[b&0x0F];
  868. }
  869. pbIn += cbIn;
  870. pbOut += cbOut;
  871. }
  872. }
  873. void Reduce1(BYTE HUGE *pbIn, int dx, int dy, UINT cbIn, BYTE HUGE *pbOut, UINT cbOut, LPBYTE lp8to8)
  874. {
  875. int x,y;
  876. BYTE b;
  877. cbIn -= (dx+7)/8;
  878. cbOut -= dx;
  879. for (y=0; y<dy; y++)
  880. {
  881. for (x=0; x<dx; x++)
  882. {
  883. if (x%8 == 0)
  884. b = *pbIn++;
  885. *pbOut++ = lp8to8[b>>7];
  886. b<<=1;
  887. }
  888. pbIn += cbIn;
  889. pbOut += cbOut;
  890. }
  891. }
  892.