Dl1quant_bak.cpp
上传用户:cjw5120
上传日期:2022-05-11
资源大小:5032k
文件大小: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.    
  146.     pal_index = 0;
  147.     return 1;
  148. }
  149. LOCAL void dlq_finish(void) 
  150. {
  151. int i;
  152. for (i=0;i<6;i++) {
  153. if (rgb_table[i] != NULL) {
  154. free(rgb_table[i]);
  155. rgb_table[i]=NULL;
  156. }
  157. }
  158.     if (heap != NULL) {
  159. free(heap);
  160. heap=NULL;
  161. }
  162.     
  163. if (dl_image != NULL) {
  164. free(dl_image);
  165. dl_image=NULL;
  166. }
  167. memset(&c_info, 0, sizeof(CLOSEST_INFO));
  168. tot_colors=pal_index=0;
  169. }
  170. /* returns 1 on success, 0 on failure */
  171. LOCAL int build_table(uchar *image, ulong pixels) 
  172. {
  173.     ulong i=0;
  174. ulong index=0;
  175. ulong cur_count=0;
  176. ulong head=0;
  177. ulong tail=0;
  178.     slong j=0;
  179.     heap = (FCUBE *) malloc(sizeof(FCUBE) * 32769);
  180.     if (heap == NULL)
  181. return 0;
  182. #ifdef FAST
  183.     dl_image = malloc(sizeof(short) * pixels);
  184.     if (dl_image == NULL)
  185. return 0;
  186. #endif
  187.     for (i = 0; i < pixels; i++) {
  188. #ifdef FAST
  189. dl_image[i] = index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
  190. #else
  191. index = r_offset[image[0]] + g_offset[image[1]] + b_offset[image[2]];
  192. #endif
  193. #ifdef QUAL1
  194. rgb_table[5][index].r += image[0];
  195. rgb_table[5][index].g += image[1];
  196. rgb_table[5][index].b += image[2];
  197. #endif
  198. rgb_table[5][index].pixel_count++;
  199. image += 3;
  200.     }
  201.     tot_colors = 0;
  202. for (i = 0; i < 32768; i++) {
  203. cur_count = rgb_table[5][i].pixel_count;
  204. if (cur_count) {
  205. heap[++tot_colors].level = 5;
  206. heap[tot_colors].index = (ushort)i;
  207. rgb_table[5][i].pixels_in_cube = cur_count;
  208. #ifndef QUAL1
  209. rgb_table[5][i].r = cur_count * (((i & 0x4000) >> 7 |
  210. (i & 0x0800) >> 5 | (i & 0x0100) >> 3 |
  211. (i & 0x0020) >> 1 | (i & 0x0004) << 1) + 4);
  212. rgb_table[5][i].g = cur_count * (((i & 0x2000) >> 6 |
  213. (i & 0x0400) >> 4 | (i & 0x0080) >> 2 |
  214. (i & 0x0010) >> 0 | (i & 0x0002) << 2) + 4);
  215. rgb_table[5][i].b = cur_count * (((i & 0x1000) >> 5 |
  216. (i & 0x0200) >> 3 | (i & 0x0040) >> 1 |
  217. (i & 0x0008) << 1 | (i & 0x0001) << 3) + 4);
  218. #endif
  219. head = i;
  220. for (j = 4; j >= 0; j--) {
  221. tail = head & 0x7;
  222. head >>= 3;
  223. rgb_table[j][head].pixels_in_cube += cur_count;
  224. rgb_table[j][head].children |= 1 << tail;
  225. }
  226. }
  227.     }
  228.     for (i = tot_colors; i > 0; i--)
  229. fixheap(i);
  230.     return 1;
  231. }
  232. LOCAL void fixheap(ulong id) 
  233. {
  234.     uchar thres_level = heap[id].level;
  235.     ulong thres_index = heap[id].index;
  236. ulong index=0;
  237. ulong half_totc = tot_colors >> 1;
  238. ulong thres_val = rgb_table[thres_level][thres_index].pixels_in_cube;
  239.     while (id <= half_totc) {
  240. index = id << 1;
  241. if (index < (ulong)tot_colors)
  242. if (rgb_table[heap[index].level][heap[index].index].pixels_in_cube
  243.   > rgb_table[heap[index+1].level][heap[index+1].index].pixels_in_cube)
  244. index++;
  245. if (thres_val <= rgb_table[heap[index].level][heap[index].index].pixels_in_cube)
  246. break;
  247. else {
  248. heap[id] = heap[index];
  249. id = index;
  250. }
  251.     }
  252.     heap[id].level = thres_level;
  253.     heap[id].index = (ushort)thres_index;
  254. }
  255. LOCAL void reduce_table(int num_colors) 
  256. {
  257. while (tot_colors > num_colors) {
  258. uchar tmp_level = heap[1].level, t_level = max(0,tmp_level - 1);
  259. ulong tmp_index = heap[1].index, t_index = tmp_index >> 3;
  260. if (rgb_table[t_level][t_index].pixel_count)
  261. heap[1] = heap[tot_colors--];
  262. else {
  263. heap[1].level = t_level;
  264. heap[1].index = (ushort)t_index;
  265. }
  266. rgb_table[t_level][t_index].pixel_count += rgb_table[tmp_level][tmp_index].pixel_count;
  267. rgb_table[t_level][t_index].r += rgb_table[tmp_level][tmp_index].r;
  268. rgb_table[t_level][t_index].g += rgb_table[tmp_level][tmp_index].g;
  269. rgb_table[t_level][t_index].b += rgb_table[tmp_level][tmp_index].b;
  270. rgb_table[t_level][t_index].children &= ~(1 << (tmp_index & 0x7));
  271. fixheap(1);
  272.     }
  273. }
  274. LOCAL void set_palette(int index, int level) 
  275. {
  276.     int i;
  277.     if (rgb_table[level][index].children) {
  278. for (i = 7; i >= 0; i--) {
  279. if (rgb_table[level][index].children & (1 << i)) {
  280. set_palette((index << 3) + i, level + 1);
  281. }
  282. }
  283. }
  284.     if (rgb_table[level][index].pixel_count) {
  285. ulong r_sum, g_sum, b_sum, sum;
  286. rgb_table[level][index].palette_index = pal_index;
  287. r_sum = rgb_table[level][index].r;
  288. g_sum = rgb_table[level][index].g;
  289. b_sum = rgb_table[level][index].b;
  290. sum = rgb_table[level][index].pixel_count;
  291. palette[0][pal_index] = (BYTE)((r_sum + (sum >> 1)) / sum);
  292. palette[1][pal_index] = (BYTE)((g_sum + (sum >> 1)) / sum);
  293. palette[2][pal_index] = (BYTE)((b_sum + (sum >> 1)) / sum);
  294. pal_index++;
  295.     }
  296. }
  297. LOCAL void closest_color(int index, int level) 
  298. {
  299.     int i;
  300.     if (rgb_table[level][index].children) {
  301. for (i = 7; i >= 0; i--) {
  302. if (rgb_table[level][index].children & (1 << i)) {
  303. closest_color((index << 3) + i, level + 1);
  304. }
  305. }
  306. }
  307.     if (rgb_table[level][index].pixel_count) {
  308. slong dist, r_dist, g_dist, b_dist;
  309. uchar pal_num = rgb_table[level][index].palette_index;
  310. /* Determine if this color is "closest". */
  311. r_dist = palette[0][pal_num] - c_info.red;
  312. g_dist = palette[1][pal_num] - c_info.green;
  313. b_dist = palette[2][pal_num] - c_info.blue;
  314. dist = squares[r_dist] + squares[g_dist] + squares[b_dist];
  315. if (dist < (slong)c_info.distance) {
  316. c_info.distance = dist;
  317. c_info.palette_index = pal_num;
  318. }
  319.     }
  320. }
  321. /* returns 1 on success, 0 on failure */
  322. LOCAL int quantize_image(uchar *in, uchar *out, int width, int height, int dither) 
  323. {
  324. if (!dither) {
  325. ulong i=0;
  326. ulong pixels = width * height;
  327. ushort level=0;
  328. ushort index=0;
  329. uchar tmp_r=0;
  330. uchar tmp_g=0;
  331. uchar tmp_b=0;
  332. uchar cube=0;
  333. uchar *lookup=NULL;
  334. lookup = (BYTE*)malloc(sizeof(char) * 32768);
  335. if (lookup == NULL)
  336. return 0;
  337. for (i = 0; i < 32768; i++)
  338. if (rgb_table[5][i].pixel_count) {
  339. tmp_r = (BYTE)((i & 0x4000) >> 7 | (i & 0x0800) >> 5 |
  340. (i & 0x0100) >> 3 | (i & 0x0020) >> 1 |
  341. (i & 0x0004) << 1);
  342. tmp_g = (BYTE)((i & 0x2000) >> 6 | (i & 0x0400) >> 4 |
  343. (i & 0x0080) >> 2 | (i & 0x0010) >> 0 |
  344. (i & 0x0002) << 2);
  345. tmp_b = (BYTE)((i & 0x1000) >> 5 | (i & 0x0200) >> 3 |
  346. (i & 0x0040) >> 1 | (i & 0x0008) << 1 |
  347. (i & 0x0001) << 3);
  348. #ifdef QUAL2
  349. lookup[i] = bestcolor(tmp_r, tmp_g, tmp_b);
  350. #else
  351. c_info.red   = tmp_r + 4;
  352. c_info.green = tmp_g + 4;
  353. c_info.blue  = tmp_b + 4;
  354. level = 0;
  355. index = 0;
  356. for (;;) {
  357. cube = (tmp_r&128) >> 5 | (tmp_g&128) >> 6 | (tmp_b&128) >> 7;
  358. if ((rgb_table[level][index].children & (1 << cube)) == 0) {
  359. c_info.distance = (ULONG)~0L;
  360. closest_color(index, level);
  361. lookup[i] = c_info.palette_index;
  362. break;
  363. }
  364. level++;
  365. index = (index << 3) + cube;
  366. tmp_r <<= 1;
  367. tmp_g <<= 1;
  368. tmp_b <<= 1;
  369. }
  370. #endif
  371. }
  372. for (i = 0; i < pixels; i++) {
  373. #ifdef FAST
  374. out[i] = lookup[dl_image[i]];
  375. #else
  376. out[i] = lookup[r_offset[in[0]] + g_offset[in[1]] + b_offset[in[2]]];
  377. in += 3;
  378. #endif
  379. }
  380. free(lookup);
  381. } else { // dither
  382. #if defined(DITHER2) || defined(DITHER4)
  383. slong i=0;
  384. slong j=0;
  385. slong r_pix=0;
  386. slong g_pix=0;
  387. slong b_pix=0;
  388. slong offset=0;
  389. slong dir=0;
  390. slong two_val=0;
  391. slong odd_scanline = 0;
  392. slong err_len = (width + 2) * 3;
  393. uchar *range_tbl = NULL; 
  394. uchar *range = NULL;
  395. sshort *lookup = NULL;
  396. sshort *erowerr = NULL;
  397. sshort *orowerr = NULL;
  398. sshort *thisrowerr = NULL;
  399. sshort *nextrowerr = NULL;
  400. schar *dith_max_tbl = NULL;
  401. schar *dith_max = NULL;
  402. lookup = (sshort *)malloc(sizeof(short) * 32768);
  403. erowerr = (sshort *)malloc(sizeof(short) * err_len);
  404. orowerr = (sshort *)malloc(sizeof(short) * err_len);
  405. range_tbl = (BYTE*)malloc(3 * 256);
  406. range = range_tbl + 256;
  407. dith_max_tbl= (schar *)malloc(512);
  408. dith_max = dith_max_tbl + 256;
  409. if (range_tbl == NULL || lookup == NULL ||
  410. erowerr == NULL || orowerr == NULL || dith_max_tbl == NULL) {
  411. if (range_tbl != NULL) {
  412. free(range_tbl);
  413. range_tbl=NULL;
  414. }
  415. if (lookup != NULL) {
  416. free(lookup);
  417. lookup=NULL;
  418. }
  419. if (erowerr != NULL) {
  420. free(erowerr);
  421. erowerr=NULL;
  422. }
  423. if (orowerr != NULL) {
  424. free(orowerr);
  425. orowerr=NULL;
  426. }
  427. if (dith_max_tbl != NULL) {
  428. free(dith_max_tbl);
  429. dith_max_tbl=NULL;
  430. }
  431. return 0;
  432. }
  433. for (i = 0; i < err_len; i++)
  434. erowerr[i] = 0;
  435. for (i = 0; i < 32768; i++)
  436. lookup[i] = -1;
  437. for (i = 0; i < 256; i++) {
  438. range_tbl[i] = 0;
  439. range_tbl[i + 256] = (uchar) i;
  440. range_tbl[i + 512] = 255;
  441. }
  442. for (i = 0; i < 256; i++) {
  443. dith_max_tbl[i] = -DITHER_MAX;
  444. dith_max_tbl[i + 256] = DITHER_MAX;
  445. }
  446. for (i = -DITHER_MAX; i <= DITHER_MAX; i++)
  447. dith_max_tbl[i + 256] = (schar)i;
  448. for (i = 0 ; i < height; i++) {
  449. if (odd_scanline) {
  450. dir = -1;
  451. in  += (width - 1) * 3;
  452. out += (width - 1);
  453. thisrowerr = orowerr + 3;
  454. nextrowerr = erowerr + width * 3;
  455. } else {
  456. dir = 1;
  457. thisrowerr = erowerr + 3;
  458. nextrowerr = orowerr + width * 3;
  459. }
  460. nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
  461. for (j = 0; j < width; j++) {
  462. #ifdef DITHER2
  463. r_pix = range[(thisrowerr[0] >> 1) + in[0]];
  464. g_pix = range[(thisrowerr[1] >> 1) + in[1]];
  465. b_pix = range[(thisrowerr[2] >> 1) + in[2]];
  466. #else
  467. r_pix = range[((thisrowerr[0] + 8) >> 4) + in[0]];
  468. g_pix = range[((thisrowerr[1] + 8) >> 4) + in[1]];
  469. b_pix = range[((thisrowerr[2] + 8) >> 4) + in[2]];
  470. #endif
  471. offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
  472. if (lookup[offset] < 0)
  473. lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
  474. *out = (BYTE)lookup[offset];
  475. r_pix = dith_max[r_pix - palette[0][lookup[offset]]];
  476. g_pix = dith_max[g_pix - palette[1][lookup[offset]]];
  477. b_pix = dith_max[b_pix - palette[2][lookup[offset]]];
  478. #ifdef DITHER2
  479. nextrowerr[0  ]  = (short)r_pix;
  480. thisrowerr[0+3] += (short)r_pix;
  481. nextrowerr[1  ]  = (short)g_pix;
  482. thisrowerr[1+3] += (short)g_pix;
  483. nextrowerr[2  ]  = (short)b_pix;
  484. thisrowerr[2+3] += (short)b_pix;
  485. #else
  486. two_val = r_pix * 2;
  487. nextrowerr[0-3]  = r_pix;
  488. r_pix += two_val;
  489. nextrowerr[0+3] += r_pix;
  490. r_pix += two_val;
  491. nextrowerr[0  ] += r_pix;
  492. r_pix += two_val;
  493. thisrowerr[0+3] += r_pix;
  494. two_val = g_pix * 2;
  495. nextrowerr[1-3]  = g_pix;
  496. g_pix += two_val;
  497. nextrowerr[1+3] += g_pix;
  498. g_pix += two_val;
  499. nextrowerr[1  ] += g_pix;
  500. g_pix += two_val;
  501. thisrowerr[1+3] += g_pix;
  502. two_val = b_pix * 2;
  503. nextrowerr[2-3]  = b_pix;
  504. b_pix += two_val;
  505. nextrowerr[2+3] += b_pix;
  506. b_pix += two_val;
  507. nextrowerr[2  ] += b_pix;
  508. b_pix += two_val;
  509. thisrowerr[2+3] += b_pix;
  510. #endif
  511. thisrowerr += 3;
  512. nextrowerr -= 3;
  513. in  += dir * 3;
  514. out += dir;
  515. }
  516. if ((i % 2) == 1) {
  517. in  += (width + 1) * 3;
  518. out += (width + 1);
  519. }
  520. odd_scanline = !odd_scanline;
  521. }
  522. free(range_tbl);
  523. free(lookup);
  524. free(erowerr);
  525. free(orowerr);
  526. free(dith_max_tbl);
  527. #else
  528. slong i =0; 
  529. slong j=0; 
  530. slong r_pix=0;
  531. slong g_pix=0;
  532. slong b_pix=0;
  533. slong r_err=0;
  534. slong g_err=0;
  535. slong b_err=0;
  536. slong offset=0;
  537. uchar *range_tbl = (BYTE*)malloc(3 * 256), *range = range_tbl + 256;
  538. sshort *lookup = (sshort *)malloc(sizeof(short) * 32768);
  539. if (range_tbl == NULL || lookup == NULL) {
  540. if (range_tbl != NULL)
  541. free(range_tbl);
  542. if (lookup != NULL)
  543. free(lookup);
  544. return 0;
  545. }
  546. for (i = 0; i < 32768; i++)
  547. lookup[i] = -1;
  548. for (i = 0; i < 256; i++) {
  549. range_tbl[i] = 0;
  550. range_tbl[i + 256] = (uchar) i;
  551. range_tbl[i + 512] = 255;
  552. }
  553. for (i = 0; i < height; i++) {
  554. r_err = g_err = b_err = 0;
  555. for (j = width - 1; j >= 0; j--) {
  556. r_pix = range[(r_err >> 1) + in[0]];
  557. g_pix = range[(g_err >> 1) + in[1]];
  558. b_pix = range[(b_err >> 1) + in[2]];
  559. offset = (r_pix&248) << 7 | (g_pix&248) << 2 | b_pix >> 3;
  560. if (lookup[offset] < 0)
  561. lookup[offset] = bestcolor(r_pix, g_pix, b_pix);
  562. *out++ = (BYTE)lookup[offset];
  563. r_err = r_pix - palette[0][lookup[offset]];
  564. g_err = g_pix - palette[1][lookup[offset]];
  565. b_err = b_pix - palette[2][lookup[offset]];
  566. in += 3;
  567. }
  568. }
  569. free(range_tbl);
  570. free(lookup);
  571. #endif
  572.     }
  573.     return 1;
  574. }
  575. LOCAL int bestcolor(int r, int g, int b) 
  576. {
  577.     ulong i=0;
  578. ulong bestcolor=0;
  579. ulong curdist=0;
  580. ulong mindist=0;
  581.     slong rdist=0;
  582. slong gdist=0;
  583. slong bdist=0;
  584.     r = (r & 248) + 4;
  585.     g = (g & 248) + 4;
  586.     b = (b & 248) + 4;
  587.     mindist = 200000;
  588. for (i = 0; i < (ulong)tot_colors; i++) {
  589. rdist = palette[0][i] - r;
  590. gdist = palette[1][i] - g;
  591. bdist = palette[2][i] - b;
  592. curdist = squares[rdist] + squares[gdist] + squares[bdist];
  593. if (curdist < mindist) {
  594. mindist = curdist;
  595. bestcolor = i;
  596. }
  597. }
  598.     return bestcolor;
  599. }
  600. #ifdef __cplusplus
  601. }
  602. #endif