Dl1quant.cpp
上传用户:qiutianh
上传日期:2022-08-08
资源大小:939k
文件大小:17k
源码类别:

图形图象

开发平台:

Visual C++

  1. //
  2. // This has been modified from Dennis Lee's original version
  3. //
  4. /*
  5.  * DL1 Quantization
  6.  * ================
  7.  *
  8.  * File: dl1quant.c
  9.  * Author: Dennis Lee   E-mail: denlee@ecf.utoronto.ca
  10.  *
  11.  * Copyright (C) 1993-1997 Dennis Lee
  12.  *
  13.  * C implementation of DL1 Quantization.
  14.  * DL1 Quantization is a 2-pass color quantizer optimized for speed.
  15.  * The method was designed around the steps required by a 2-pass
  16.  * quantizer and constructing a model that would require the least
  17.  * amount of extra work.  The resulting method is extremely fast --
  18.  * about half the speed of a memcpy.  That should make DL1 Quant the
  19.  * fastest 2-pass color quantizer.
  20.  *
  21.  * This quantizer's quality is also among the best, slightly
  22.  * better than Wan et al's marginal variance based quantizer.  For
  23.  * more on DL1 Quant's performance and other related information,
  24.  * see DLQUANT.TXT included in this distribution.
  25.  *
  26.  *
  27.  * NOTES
  28.  * =====
  29.  *
  30.  * The dithering code is based on code from the IJG's jpeg library.
  31.  *
  32.  * This source code may be freely copied, modified, and redistributed,
  33.  * provided this copyright notice is attached.
  34.  * Compiled versions of this code, modified or not, are free for
  35.  * personal use.  Compiled versions used in distributed software
  36.  * is also free, but a notification must be sent to the author.
  37.  * An e-mail to denlee@ecf.utoronto.ca will do.
  38.  *
  39.  */
  40. #include "stdafx.h"
  41. #ifdef __cplusplus
  42. extern "C" {
  43. #endif
  44. #include <stdlib.h>
  45. #include "dl1quant.h"
  46. //#define FAST        /* improves speed but uses a lot of memory */
  47. #define QUAL1       /* slightly improves quality */
  48. //#define QUAL2       /* slightly improves quality */
  49. /* define *one* of the following dither options */
  50. //#define DITHER1     /* 1-val error diffusion dither */
  51. #define DITHER2     /* 2-val error diffusion dither */
  52. //#define DITHER4     /* 4-val error diffusion dither (Floyd-Steinberg) */
  53. #define DITHER_MAX  20
  54. LOCAL uchar palette[3][256];
  55. LOCAL CUBE *rgb_table[6];
  56. LOCAL ushort r_offset[256], g_offset[256], b_offset[256];
  57. LOCAL CLOSEST_INFO c_info;
  58. LOCAL int tot_colors, pal_index;
  59. LOCAL ulong *squares;
  60. LOCAL FCUBE *heap = NULL;
  61. LOCAL short *dl_image = NULL;
  62. /* returns 1 on success, 0 on failure */
  63. GLOBAL int dl1quant(uchar *inbuf, 
  64. uchar *outbuf, 
  65. int width, 
  66. int height, 
  67. int quant_to,
  68. int dither, 
  69. uchar userpal[3][256]) {
  70. dlq_init();
  71.     if (dlq_start() == 0) {
  72. dlq_finish();
  73. return 0;
  74. }
  75.     if (build_table(inbuf, (ulong)width * (ulong)height) == 0) {
  76. dlq_finish();
  77. return 0;
  78.     }
  79.     
  80. reduce_table(quant_to);
  81.     set_palette(0, 0);
  82.     
  83. if (quantize_image(inbuf, outbuf, width, height, dither) == 0) {
  84. dlq_finish();
  85. return 0;
  86.     }
  87.     dlq_finish();
  88.     copy_pal(userpal);
  89.     return 1;
  90. }
  91. LOCAL void copy_pal(uchar userpal[3][256]) 
  92. {
  93.     int i;
  94.     for (i = 0; i < 256; i++) {
  95. userpal[0][i] = palette[0][i];
  96. userpal[1][i] = palette[1][i];
  97. userpal[2][i] = palette[2][i];
  98.     }
  99. }
  100. LOCAL void dlq_init(void) 
  101. {
  102.     int i;
  103. for (i=0;i<6;i++) {
  104. rgb_table[i]=NULL;
  105. }
  106. tot_colors=0;
  107. pal_index=0;
  108. heap = NULL;
  109. dl_image = NULL;
  110.     for (i = 0; i < 256; i++) {
  111. r_offset[i] = (i & 128) << 7 | (i & 64) << 5 | (i & 32) << 3 |
  112.   (i & 16)  << 1 | (i & 8)  >> 1;
  113. g_offset[i] = (i & 128) << 6 | (i & 64) << 4 | (i & 32) << 2 |
  114.   (i & 16)  << 0 | (i & 8)  >> 2;
  115. b_offset[i] = (i & 128) << 5 | (i & 64) << 3 | (i & 32) << 1 |
  116.   (i & 16)  >> 1 | (i & 8)  >> 3;
  117.     }
  118. c_info.palette_index=0;
  119. c_info.red=0;
  120. c_info.green=0;
  121. c_info.blue=0;
  122.     c_info.distance=0;
  123.     for (i = (-255); i <= 255; i++)
  124. c_info.squares[i+255] = i*i;
  125. for (i=0;i<256;i++) {
  126. palette[0][i]=0;
  127. palette[1][i]=0;
  128. palette[2][i]=0;
  129. }
  130.     squares = c_info.squares + 255;
  131. }
  132. /* returns 1 on success, 0 on failure */
  133. LOCAL int dlq_start(void) 
  134. {
  135.     int i;
  136.     rgb_table[0] = (CUBE *) calloc(sizeof(CUBE), 1);
  137.     rgb_table[1] = (CUBE *) calloc(sizeof(CUBE), 8);
  138.     rgb_table[2] = (CUBE *) calloc(sizeof(CUBE), 64);
  139.     rgb_table[3] = (CUBE *) calloc(sizeof(CUBE), 512);
  140.     rgb_table[4] = (CUBE *) calloc(sizeof(CUBE), 4096);
  141.     rgb_table[5] = (CUBE *) calloc(sizeof(CUBE), 32768);
  142.     for (i = 0; i <= 5; i++)
  143. if (rgb_table[i] == NULL)
  144.     return 0;
  145.     pal_index = 0;
  146.     return 1;
  147. }
  148. LOCAL void dlq_finish(void) 
  149. {
  150. int i;
  151. for (i=0;i<6;i++) {
  152. if (rgb_table[i] != NULL) {
  153. free(rgb_table[i]);
  154. rgb_table[i]=NULL;
  155. }
  156. }
  157.     if (heap != NULL) {
  158. free(heap);
  159. heap=NULL;
  160. }
  161.     
  162. if (dl_image != NULL) {
  163. free(dl_image);
  164. dl_image=NULL;
  165. }
  166. memset(&c_info, 0, sizeof(CLOSEST_INFO));
  167. tot_colors=pal_index=0;
  168. }
  169. /* returns 1 on success, 0 on failure */
  170. LOCAL int build_table(uchar *image, ulong pixels) 
  171. {
  172.     ulong i=0;
  173. ulong index=0;
  174. ulong cur_count=0;
  175. ulong head=0;
  176. ulong tail=0;
  177.     slong j=0;
  178.     heap = (FCUBE *) malloc(sizeof(FCUBE) * 32769);
  179.     if (heap == NULL)
  180. return 0;
  181. #ifdef FAST
  182.     dl_image = malloc(sizeof(short) * pixels);
  183.     if (dl_image == NULL)
  184. return 0;
  185. #endif
  186.     for (i = 0; i < pixels; i++) {
  187. #ifdef FAST
  188. dl_image[i] = index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
  189. #else
  190. index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
  191. #endif
  192. #ifdef QUAL1
  193. rgb_table[5][index].r += image[0];
  194. rgb_table[5][index].g += image[1];
  195. rgb_table[5][index].b += image[2];
  196. #endif
  197. rgb_table[5][index].pixel_count++;
  198. image += 3;
  199.     }
  200.     tot_colors = 0;
  201. for (i = 0; i < 32768; i++) {
  202. cur_count = rgb_table[5][i].pixel_count;
  203. if (cur_count) {
  204. heap[++tot_colors].level = 5;
  205. heap[tot_colors].index = (ushort)i;
  206. rgb_table[5][i].pixels_in_cube = cur_count;
  207. #ifndef QUAL1
  208. rgb_table[5][i].r = cur_count * (((i & 0x4000) >> 7 |
  209. (i & 0x0800) >> 5 | (i & 0x0100) >> 3 |
  210. (i & 0x0020) >> 1 | (i & 0x0004) << 1) + 4);
  211. rgb_table[5][i].g = cur_count * (((i & 0x2000) >> 6 |
  212. (i & 0x0400) >> 4 | (i & 0x0080) >> 2 |
  213. (i & 0x0010) >> 0 | (i & 0x0002) << 2) + 4);
  214. rgb_table[5][i].b = cur_count * (((i & 0x1000) >> 5 |
  215. (i & 0x0200) >> 3 | (i & 0x0040) >> 1 |
  216. (i & 0x0008) << 1 | (i & 0x0001) << 3) + 4);
  217. #endif
  218. head = i;
  219. for (j = 4; j >= 0; j--) {
  220. tail = head & 0x7;
  221. head >>= 3;
  222. rgb_table[j][head].pixels_in_cube += cur_count;
  223. rgb_table[j][head].children |= 1 << tail;
  224. }
  225. }
  226.     }
  227.     for (i = tot_colors; i > 0; i--)
  228. fixheap(i);
  229.     return 1;
  230. }
  231. LOCAL void fixheap(ulong id) 
  232. {
  233.     uchar thres_level = heap[id].level;
  234.     ulong thres_index = heap[id].index;
  235. ulong index=0;
  236. ulong half_totc = tot_colors >> 1;
  237. ulong thres_val = rgb_table[thres_level][thres_index].pixels_in_cube;
  238.     while (id <= half_totc) {
  239. index = id << 1;
  240. if (index < (ulong)tot_colors)
  241. if (rgb_table[heap[index].level][heap[index].index].pixels_in_cube
  242.   > rgb_table[heap[index+1].level][heap[index+1].index].pixels_in_cube)
  243. index++;
  244. if (thres_val <= rgb_table[heap[index].level][heap[index].index].pixels_in_cube)
  245. break;
  246. else {
  247. heap[id] = heap[index];
  248. id = index;
  249. }
  250.     }
  251.     heap[id].level = thres_level;
  252.     heap[id].index = (ushort)thres_index;
  253. }
  254. LOCAL void reduce_table(int num_colors) 
  255. {
  256. while (tot_colors > num_colors) {
  257. uchar tmp_level = heap[1].level, t_level = max(0,tmp_level - 1);
  258. ulong tmp_index = heap[1].index, t_index = tmp_index >> 3;
  259. if (rgb_table[t_level][t_index].pixel_count)
  260. heap[1] = heap[tot_colors--];
  261. else {
  262. heap[1].level = t_level;
  263. heap[1].index = (ushort)t_index;
  264. }
  265. rgb_table[t_level][t_index].pixel_count += rgb_table[tmp_level][tmp_index].pixel_count;
  266. rgb_table[t_level][t_index].r += rgb_table[tmp_level][tmp_index].r;
  267. rgb_table[t_level][t_index].g += rgb_table[tmp_level][tmp_index].g;
  268. rgb_table[t_level][t_index].b += rgb_table[tmp_level][tmp_index].b;
  269. rgb_table[t_level][t_index].children &= ~(1 << (tmp_index & 0x7));
  270. fixheap(1);
  271.     }
  272. }
  273. LOCAL void set_palette(int index, int level) 
  274. {
  275.     int i;
  276.     if (rgb_table[level][index].children) {
  277. for (i = 7; i >= 0; i--) {
  278. if (rgb_table[level][index].children & (1 << i)) {
  279. set_palette((index << 3) + i, level + 1);
  280. }
  281. }
  282. }
  283.     if (rgb_table[level][index].pixel_count) {
  284. ulong r_sum, g_sum, b_sum, sum;
  285. rgb_table[level][index].palette_index = pal_index;
  286. r_sum = rgb_table[level][index].r;
  287. g_sum = rgb_table[level][index].g;
  288. b_sum = rgb_table[level][index].b;
  289. sum = rgb_table[level][index].pixel_count;
  290. palette[0][pal_index] = (BYTE)((r_sum + (sum >> 1)) / sum);
  291. palette[1][pal_index] = (BYTE)((g_sum + (sum >> 1)) / sum);
  292. palette[2][pal_index] = (BYTE)((b_sum + (sum >> 1)) / sum);
  293. pal_index++;
  294.     }
  295. }
  296. LOCAL void closest_color(int index, int level) 
  297. {
  298.     int i;
  299.     if (rgb_table[level][index].children) {
  300. for (i = 7; i >= 0; i--) {
  301. if (rgb_table[level][index].children & (1 << i)) {
  302. closest_color((index << 3) + i, level + 1);
  303. }
  304. }
  305. }
  306.     if (rgb_table[level][index].pixel_count) {
  307. slong dist, r_dist, g_dist, b_dist;
  308. uchar pal_num = rgb_table[level][index].palette_index;
  309. /* Determine if this color is "closest". */
  310. r_dist = palette[0][pal_num] - c_info.red;
  311. g_dist = palette[1][pal_num] - c_info.green;
  312. b_dist = palette[2][pal_num] - c_info.blue;
  313. dist = squares[r_dist] + squares[g_dist] + squares[b_dist];
  314. if (dist < (slong)c_info.distance) {
  315. c_info.distance = dist;
  316. c_info.palette_index = pal_num;
  317. }
  318.     }
  319. }
  320. /* returns 1 on success, 0 on failure */
  321. LOCAL int quantize_image(uchar *in, uchar *out, int width, int height, int dither) 
  322. {
  323. if (!dither) {
  324. ulong i=0;
  325. ulong pixels = width * height;
  326. ushort level=0;
  327. ushort index=0;
  328. uchar tmp_r=0;
  329. uchar tmp_g=0;
  330. uchar tmp_b=0;
  331. uchar cube=0;
  332. uchar *lookup=NULL;
  333. lookup = (BYTE*)malloc(sizeof(char) * 32768);
  334. if (lookup == NULL)
  335. return 0;
  336. for (i = 0; i < 32768; i++)
  337. if (rgb_table[5][i].pixel_count) {
  338. tmp_r = (BYTE)((i & 0x4000) >> 7 | (i & 0x0800) >> 5 |
  339. (i & 0x0100) >> 3 | (i & 0x0020) >> 1 |
  340. (i & 0x0004) << 1);
  341. tmp_g = (BYTE)((i & 0x2000) >> 6 | (i & 0x0400) >> 4 |
  342. (i & 0x0080) >> 2 | (i & 0x0010) >> 0 |
  343. (i & 0x0002) << 2);
  344. tmp_b = (BYTE)((i & 0x1000) >> 5 | (i & 0x0200) >> 3 |
  345. (i & 0x0040) >> 1 | (i & 0x0008) << 1 |
  346. (i & 0x0001) << 3);
  347. #ifdef QUAL2
  348. lookup[i] = bestcolor(tmp_r, tmp_g, tmp_b);
  349. #else
  350. c_info.red   = tmp_r + 4;
  351. c_info.green = tmp_g + 4;
  352. c_info.blue  = tmp_b + 4;
  353. level = 0;
  354. index = 0;
  355. for (;;) {
  356. cube = (tmp_r&128) >> 5 | (tmp_g&128) >> 6 | (tmp_b&128) >> 7;
  357. if ((rgb_table[level][index].children & (1 << cube)) == 0) {
  358. c_info.distance = (ULONG)~0L;
  359. closest_color(index, level);
  360. lookup[i] = c_info.palette_index;
  361. break;
  362. }
  363. level++;
  364. index = (index << 3) + cube;
  365. tmp_r <<= 1;
  366. tmp_g <<= 1;
  367. tmp_b <<= 1;
  368. }
  369. #endif
  370. }
  371. for (i = 0; i < pixels; i++) {
  372. #ifdef FAST
  373. out[i] = lookup[dl_image[i]];
  374. #else
  375. out[i] = lookup[r_offset[in[0]] + g_offset[in[1]] + b_offset[in[2]]];
  376. in += 3;
  377. #endif
  378. }
  379. free(lookup);
  380. } else { // dither
  381. #if defined(DITHER2) || defined(DITHER4)
  382. slong i=0;
  383. slong j=0;
  384. slong r_pix=0;
  385. slong g_pix=0;
  386. slong b_pix=0;
  387. slong offset=0;
  388. slong dir=0;
  389. slong two_val=0;
  390. slong odd_scanline = 0;
  391. slong err_len = (width + 2) * 3;
  392. uchar *range_tbl = NULL; 
  393. uchar *range = NULL;
  394. sshort *lookup = NULL;
  395. sshort *erowerr = NULL;
  396. sshort *orowerr = NULL;
  397. sshort *thisrowerr = NULL;
  398. sshort *nextrowerr = NULL;
  399. schar *dith_max_tbl = NULL;
  400. schar *dith_max = NULL;
  401. lookup = (sshort *)malloc(sizeof(short) * 32768);
  402. erowerr = (sshort *)malloc(sizeof(short) * err_len);
  403. orowerr = (sshort *)malloc(sizeof(short) * err_len);
  404. range_tbl = (BYTE*)malloc(3 * 256);
  405. range = range_tbl + 256;
  406. dith_max_tbl= (schar *)malloc(512);
  407. dith_max = dith_max_tbl + 256;
  408. if (range_tbl == NULL || lookup == NULL ||
  409. erowerr == NULL || orowerr == NULL || dith_max_tbl == NULL) {
  410. if (range_tbl != NULL) {
  411. free(range_tbl);
  412. range_tbl=NULL;
  413. }
  414. if (lookup != NULL) {
  415. free(lookup);
  416. lookup=NULL;
  417. }
  418. if (erowerr != NULL) {
  419. free(erowerr);
  420. erowerr=NULL;
  421. }
  422. if (orowerr != NULL) {
  423. free(orowerr);
  424. orowerr=NULL;
  425. }
  426. if (dith_max_tbl != NULL) {
  427. free(dith_max_tbl);
  428. dith_max_tbl=NULL;
  429. }
  430. return 0;
  431. }
  432. for (i = 0; i < err_len; i++)
  433. erowerr[i] = 0;
  434. for (i = 0; i < 32768; i++)
  435. lookup[i] = -1;
  436. for (i = 0; i < 256; i++) {
  437. range_tbl[i] = 0;
  438. range_tbl[i + 256] = (uchar) i;
  439. range_tbl[i + 512] = 255;
  440. }
  441. for (i = 0; i < 256; i++) {
  442. dith_max_tbl[i] = -DITHER_MAX;
  443. dith_max_tbl[i + 256] = DITHER_MAX;
  444. }
  445. for (i = -DITHER_MAX; i <= DITHER_MAX; i++)
  446. dith_max_tbl[i + 256] = (schar)i;
  447. for (i = 0 ; i < height; i++) {
  448. if (odd_scanline) {
  449. dir = -1;
  450. in  += (width - 1) * 3;
  451. out += (width - 1);
  452. thisrowerr = orowerr + 3;
  453. nextrowerr = erowerr + width * 3;
  454. } else {
  455. dir = 1;
  456. thisrowerr = erowerr + 3;
  457. nextrowerr = orowerr + width * 3;
  458. }
  459. nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
  460. for (j = 0; j < width; j++) {
  461. #ifdef DITHER2
  462. r_pix = range[(thisrowerr[0] >> 1) + in[0]];
  463. g_pix = range[(thisrowerr[1] >> 1) + in[1]];
  464. b_pix = range[(thisrowerr[2] >> 1) + in[2]];
  465. #else
  466. r_pix = range[((thisrowerr[0] + 8) >> 4) + in[0]];
  467. g_pix = range[((thisrowerr[1] + 8) >> 4) + in[1]];
  468. b_pix = range[((thisrowerr[2] + 8) >> 4) + in[2]];
  469. #endif
  470. offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
  471. if (lookup[offset] < 0)
  472. lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
  473. *out = (BYTE)lookup[offset];
  474. r_pix = dith_max[r_pix - palette[0][lookup[offset]]];
  475. g_pix = dith_max[g_pix - palette[1][lookup[offset]]];
  476. b_pix = dith_max[b_pix - palette[2][lookup[offset]]];
  477. #ifdef DITHER2
  478. nextrowerr[0  ]  = (short)r_pix;
  479. thisrowerr[0+3] += (short)r_pix;
  480. nextrowerr[1  ]  = (short)g_pix;
  481. thisrowerr[1+3] += (short)g_pix;
  482. nextrowerr[2  ]  = (short)b_pix;
  483. thisrowerr[2+3] += (short)b_pix;
  484. #else
  485. two_val = r_pix * 2;
  486. nextrowerr[0-3]  = r_pix;
  487. r_pix += two_val;
  488. nextrowerr[0+3] += r_pix;
  489. r_pix += two_val;
  490. nextrowerr[0  ] += r_pix;
  491. r_pix += two_val;
  492. thisrowerr[0+3] += r_pix;
  493. two_val = g_pix * 2;
  494. nextrowerr[1-3]  = g_pix;
  495. g_pix += two_val;
  496. nextrowerr[1+3] += g_pix;
  497. g_pix += two_val;
  498. nextrowerr[1  ] += g_pix;
  499. g_pix += two_val;
  500. thisrowerr[1+3] += g_pix;
  501. two_val = b_pix * 2;
  502. nextrowerr[2-3]  = b_pix;
  503. b_pix += two_val;
  504. nextrowerr[2+3] += b_pix;
  505. b_pix += two_val;
  506. nextrowerr[2  ] += b_pix;
  507. b_pix += two_val;
  508. thisrowerr[2+3] += b_pix;
  509. #endif
  510. thisrowerr += 3;
  511. nextrowerr -= 3;
  512. in  += dir * 3;
  513. out += dir;
  514. }
  515. if ((i % 2) == 1) {
  516. in  += (width + 1) * 3;
  517. out += (width + 1);
  518. }
  519. odd_scanline = !odd_scanline;
  520. }
  521. free(range_tbl);
  522. free(lookup);
  523. free(erowerr);
  524. free(orowerr);
  525. free(dith_max_tbl);
  526. #else
  527. slong i =0; 
  528. slong j=0; 
  529. slong r_pix=0;
  530. slong g_pix=0;
  531. slong b_pix=0;
  532. slong r_err=0;
  533. slong g_err=0;
  534. slong b_err=0;
  535. slong offset=0;
  536. uchar *range_tbl = (BYTE*)malloc(3 * 256), *range = range_tbl + 256;
  537. sshort *lookup = (sshort *)malloc(sizeof(short) * 32768);
  538. if (range_tbl == NULL || lookup == NULL) {
  539. if (range_tbl != NULL)
  540. free(range_tbl);
  541. if (lookup != NULL)
  542. free(lookup);
  543. return 0;
  544. }
  545. for (i = 0; i < 32768; i++)
  546. lookup[i] = -1;
  547. for (i = 0; i < 256; i++) {
  548. range_tbl[i] = 0;
  549. range_tbl[i + 256] = (uchar) i;
  550. range_tbl[i + 512] = 255;
  551. }
  552. for (i = 0; i < height; i++) {
  553. r_err = g_err = b_err = 0;
  554. for (j = width - 1; j >= 0; j--) {
  555. r_pix = range[(r_err >> 1) + in[0]];
  556. g_pix = range[(g_err >> 1) + in[1]];
  557. b_pix = range[(b_err >> 1) + in[2]];
  558. offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
  559. if (lookup[offset] < 0)
  560. lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
  561. *out++ = (BYTE)lookup[offset];
  562. r_err = r_pix - palette[0][lookup[offset]];
  563. g_err = g_pix - palette[1][lookup[offset]];
  564. b_err = b_pix - palette[2][lookup[offset]];
  565. in += 3;
  566. }
  567. }
  568. free(range_tbl);
  569. free(lookup);
  570. #endif
  571.     }
  572.     return 1;
  573. }
  574. LOCAL int bestcolor(int r, int g, int b) 
  575. {
  576.     ulong i=0;
  577. ulong bestcolor=0;
  578. ulong curdist=0;
  579. ulong mindist=0;
  580.     slong rdist=0;
  581. slong gdist=0;
  582. slong bdist=0;
  583.     r = (r & 248) + 4;
  584.     g = (g & 248) + 4;
  585.     b = (b & 248) + 4;
  586.     mindist = 200000;
  587. for (i = 0; i < (ulong)tot_colors; i++) {
  588. rdist = palette[0][i] - r;
  589. gdist = palette[1][i] - g;
  590. bdist = palette[2][i] - b;
  591. curdist = squares[rdist] + squares[gdist] + squares[bdist];
  592. if (curdist < mindist) {
  593. mindist = curdist;
  594. bestcolor = i;
  595. }
  596. }
  597.     return bestcolor;
  598. }
  599. #ifdef __cplusplus
  600. }
  601. #endif