1 /* libppm3.c - ppm utility library part 3
2 **
3 ** Colormap routines.
4 **
5 ** Copyright (C) 1989, 1991 by Jef Poskanzer.
6 **
7 ** Permission to use, copy, modify, and distribute this software and its
8 ** documentation for any purpose and without fee is hereby granted, provided
9 ** that the above copyright notice appear in all copies and that both that
10 ** copyright notice and this permission notice appear in supporting
11 ** documentation. This software is provided "as is" without express or
12 ** implied warranty.
13 */
14
15 #include "netpbm/pm_config.h"
16 #include "netpbm/pm_c_util.h"
17 #include "netpbm/nstring.h"
18 #include "netpbm/mallocvar.h"
19 #include "ppm.h"
20 #include "ppmcmap.h"
21
22 #define HASH_SIZE 20023
23
24
25
26 static __inline__ unsigned int
ppm_hashpixel(pixel const p)27 ppm_hashpixel(pixel const p) {
28
29 return (unsigned int) (PPM_GETR(p) * 33 * 33
30 + PPM_GETG(p) * 33
31 + PPM_GETB(p)) % HASH_SIZE;
32 }
33
34
35
36 colorhist_vector
ppm_computecolorhist(pixel ** const pixels,const int cols,const int rows,const int maxcolors,int * const colorsP)37 ppm_computecolorhist( pixel ** const pixels,
38 const int cols, const int rows, const int maxcolors,
39 int * const colorsP ) {
40 /*----------------------------------------------------------------------------
41 Compute a color histogram for the image described by 'pixels',
42 'cols', and 'rows'. I.e. a colorhist_vector containing an entry
43 for each color in the image and for each one the number of pixels
44 of that color (i.e. a color histogram).
45
46 If 'maxcolors' is zero, make the output have 5 spare slots at the end
47 for expansion.
48
49 If 'maxcolors' is nonzero, make the output have 'maxcolors' slots in
50 it, and if there are more colors than that in the image, don't return
51 anything except a NULL pointer.
52 -----------------------------------------------------------------------------*/
53 colorhash_table cht;
54 colorhist_vector chv;
55
56 cht = ppm_computecolorhash(pixels, cols, rows, maxcolors, colorsP);
57 if (cht == NULL)
58 chv = NULL;
59 else {
60 chv = ppm_colorhashtocolorhist(cht, maxcolors);
61 ppm_freecolorhash(cht);
62 }
63 return chv;
64 }
65
66
67
68 colorhist_vector
ppm_computecolorhist2(FILE * const ifP,int const cols,int const rows,pixval const maxval,int const format,int const maxcolorCt,int * const colorCtP)69 ppm_computecolorhist2(FILE * const ifP,
70 int const cols,
71 int const rows,
72 pixval const maxval,
73 int const format,
74 int const maxcolorCt,
75 int * const colorCtP ) {
76
77 colorhist_vector retval;
78 colorhash_table cht;
79
80 cht = ppm_computecolorhash2(ifP, cols, rows, maxval, format,
81 maxcolorCt, colorCtP);
82 if (cht ==NULL)
83 retval = NULL;
84 else {
85 retval = ppm_colorhashtocolorhist(cht, maxcolorCt);
86
87 ppm_freecolorhash(cht);
88 }
89
90 return retval;
91 }
92
93
94
95 void
ppm_addtocolorhist(colorhist_vector chv,int * const colorsP,const int maxcolors,const pixel * const colorP,const int value,const int position)96 ppm_addtocolorhist( colorhist_vector chv,
97 int * const colorsP, const int maxcolors,
98 const pixel * const colorP,
99 const int value, const int position ) {
100 int i, j;
101
102 /* Search colorhist for the color. */
103 for ( i = 0; i < *colorsP; ++i )
104 if ( PPM_EQUAL( chv[i].color, *colorP ) ) {
105 /* Found it - move to new slot. */
106 if ( position > i ) {
107 for ( j = i; j < position; ++j )
108 chv[j] = chv[j + 1];
109 } else if ( position < i ) {
110 for ( j = i; j > position; --j )
111 chv[j] = chv[j - 1];
112 }
113 chv[position].color = *colorP;
114 chv[position].value = value;
115 return;
116 }
117 if ( *colorsP < maxcolors ) {
118 /* Didn't find it, but there's room to add it; so do so. */
119 for ( i = *colorsP; i > position; --i )
120 chv[i] = chv[i - 1];
121 chv[position].color = *colorP;
122 chv[position].value = value;
123 ++(*colorsP);
124 }
125 }
126
127
128
129 static colorhash_table
alloccolorhash(void)130 alloccolorhash(void) {
131 colorhash_table cht;
132 int i;
133
134 MALLOCARRAY(cht, HASH_SIZE);
135 if (cht) {
136 for (i = 0; i < HASH_SIZE; ++i)
137 cht[i] = NULL;
138 }
139 return cht;
140 }
141
142
143
144 colorhash_table
ppm_alloccolorhash(void)145 ppm_alloccolorhash(void) {
146 colorhash_table cht;
147
148 cht = alloccolorhash();
149
150 if (cht == NULL)
151 pm_error( "out of memory allocating hash table" );
152
153 return cht;
154 }
155
156
157
158 static void
readppmrow(FILE * const fileP,pixel * const pixelrow,int const cols,pixval const maxval,int const format,const char ** const errorP)159 readppmrow(FILE * const fileP,
160 pixel * const pixelrow,
161 int const cols,
162 pixval const maxval,
163 int const format,
164 const char ** const errorP) {
165
166 jmp_buf jmpbuf;
167 jmp_buf * origJmpbufP;
168
169 if (setjmp(jmpbuf) != 0) {
170 pm_setjmpbuf(origJmpbufP);
171 pm_asprintf(errorP, "Failed to read row of image.");
172 } else {
173 pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
174
175 ppm_readppmrow(fileP, pixelrow, cols, maxval, format);
176
177 *errorP = NULL; /* Would have longjmped if anything went wrong */
178
179 pm_setjmpbuf(origJmpbufP);
180 }
181 }
182
183
184
185 static void
buildHashTable(FILE * const ifP,pixel ** const pixels,unsigned int const cols,unsigned int const rows,pixval const maxval,int const format,unsigned int const maxcolors,colorhash_table const cht,pixel * const rowbuffer,int * const nColorsP,bool * const tooManyColorsP,const char ** const errorP)186 buildHashTable(FILE * const ifP,
187 pixel ** const pixels,
188 unsigned int const cols,
189 unsigned int const rows,
190 pixval const maxval,
191 int const format,
192 unsigned int const maxcolors,
193 colorhash_table const cht,
194 pixel * const rowbuffer,
195 int * const nColorsP,
196 bool * const tooManyColorsP,
197 const char ** const errorP) {
198 /*----------------------------------------------------------------------------
199 Look at all the colors in the file *ifP or array pixels[][] and add
200 them to the hash table 'cht'.
201
202 Even if we fail, we may add some colors to 'cht'.
203
204 As soon as we've seen more that 'maxcolors' colors, we quit. In that
205 case, only, we return *tooManyColorsP == true. That is not a failure.
206 'maxcolors' == 0 means infinity.
207 -----------------------------------------------------------------------------*/
208 unsigned int row;
209 unsigned int nColors;
210
211 nColors = 0; /* initial value */
212 *tooManyColorsP = FALSE; /* initial value */
213 *errorP = NULL; /* initial value */
214
215 /* Go through the entire image, building a hash table of colors. */
216 for (row = 0; row < rows && !*tooManyColorsP && !*errorP; ++row) {
217 unsigned int col;
218 pixel * pixelrow; /* The row of pixels we are processing */
219
220 if (ifP) {
221 readppmrow(ifP, rowbuffer, cols, maxval, format, errorP);
222 pixelrow = rowbuffer;
223 } else
224 pixelrow = pixels[row];
225
226 for (col = 0; col < cols && !*tooManyColorsP && !*errorP; ++col) {
227 const pixel apixel = pixelrow[col];
228 const int hash = ppm_hashpixel(apixel);
229 colorhist_list chl;
230
231 for (chl = cht[hash];
232 chl && !PPM_EQUAL(chl->ch.color, apixel);
233 chl = chl->next);
234
235 if (chl)
236 ++chl->ch.value;
237 else {
238 /* It's not in the hash yet, so add it (if allowed) */
239 ++nColors;
240 if (maxcolors > 0 && nColors > maxcolors)
241 *tooManyColorsP = TRUE;
242 else {
243 MALLOCVAR(chl);
244 if (chl == NULL)
245 pm_asprintf(errorP,
246 "out of memory computing hash table");
247 chl->ch.color = apixel;
248 chl->ch.value = 1;
249 chl->next = cht[hash];
250 cht[hash] = chl;
251 }
252 }
253 }
254 }
255 *nColorsP = nColors;
256 }
257
258
259
260 static void
computecolorhash(pixel ** const pixels,unsigned int const cols,unsigned int const rows,unsigned int const maxcolors,int * const nColorsP,FILE * const ifP,pixval const maxval,int const format,colorhash_table * const chtP,const char ** const errorP)261 computecolorhash(pixel ** const pixels,
262 unsigned int const cols,
263 unsigned int const rows,
264 unsigned int const maxcolors,
265 int * const nColorsP,
266 FILE * const ifP,
267 pixval const maxval,
268 int const format,
269 colorhash_table * const chtP,
270 const char ** const errorP) {
271 /*----------------------------------------------------------------------------
272 Compute a color histogram from an image. The input is one of two types:
273
274 1) a two-dimensional array of pixels 'pixels'; In this case, 'pixels'
275 is non-NULL and 'ifP' is NULL.
276
277 2) an open file, positioned to the image data. In this case,
278 'pixels' is NULL and 'ifP' is non-NULL. ifP is the stream
279 descriptor for the input file, and 'maxval' and 'format' are
280 parameters of the image data in it.
281
282 We return with the file still open and its position undefined.
283
284 In either case, the image is 'cols' by 'rows'.
285
286 Return the number of colors found as *colorsP.
287
288 However, if 'maxcolors' is nonzero and the number of colors is
289 greater than 'maxcolors', return a null return value and *colorsP
290 undefined.
291 -----------------------------------------------------------------------------*/
292 pixel * rowbuffer; /* malloc'ed */
293 /* Buffer for a row read from the input file; undefined (but still
294 allocated) if input is not from a file.
295 */
296
297 MALLOCARRAY(rowbuffer, cols);
298
299 if (rowbuffer == NULL)
300 pm_asprintf(errorP, "Unable to allocate %u-column row buffer.", cols);
301 else {
302 colorhash_table cht;
303 bool tooManyColors;
304
305 cht = alloccolorhash();
306
307 if (cht == NULL)
308 pm_asprintf(errorP, "Unable to allocate color hash.");
309 else {
310 buildHashTable(ifP, pixels, cols, rows, maxval, format, maxcolors,
311 cht, rowbuffer,
312 nColorsP, &tooManyColors, errorP);
313
314 if (tooManyColors) {
315 ppm_freecolorhash(cht);
316 *chtP = NULL;
317 } else
318 *chtP = cht;
319
320 if (*errorP)
321 ppm_freecolorhash(cht);
322 }
323 free(rowbuffer);
324 }
325 }
326
327
328
329 colorhash_table
ppm_computecolorhash(pixel ** const pixels,int const cols,int const rows,int const maxcolors,int * const colorsP)330 ppm_computecolorhash(pixel ** const pixels,
331 int const cols,
332 int const rows,
333 int const maxcolors,
334 int * const colorsP) {
335
336 colorhash_table cht;
337 const char * error;
338
339 computecolorhash(pixels, cols, rows, maxcolors, colorsP,
340 NULL, 0, 0, &cht, &error);
341
342 if (error) {
343 pm_errormsg("%s", error);
344 pm_strfree(error);
345 pm_longjmp();
346 }
347 return cht;
348 }
349
350
351
352 colorhash_table
ppm_computecolorhash2(FILE * const ifP,int const cols,int const rows,pixval const maxval,int const format,int const maxcolors,int * const colorsP)353 ppm_computecolorhash2(FILE * const ifP,
354 int const cols,
355 int const rows,
356 pixval const maxval,
357 int const format,
358 int const maxcolors,
359 int * const colorsP ) {
360
361 colorhash_table cht;
362 const char * error;
363
364 computecolorhash(NULL, cols, rows, maxcolors, colorsP,
365 ifP, maxval, format, &cht, &error);
366
367 if (error) {
368 pm_errormsg("%s", error);
369 pm_strfree(error);
370 pm_longjmp();
371 }
372 return cht;
373 }
374
375
376
377 int
ppm_addtocolorhash(colorhash_table const cht,const pixel * const colorP,int const value)378 ppm_addtocolorhash(colorhash_table const cht,
379 const pixel * const colorP,
380 int const value) {
381 /*----------------------------------------------------------------------------
382 Add color *colorP to the color hash 'cht' with associated value 'value'.
383
384 Assume the color is not already in the hash.
385 -----------------------------------------------------------------------------*/
386 int retval;
387 colorhist_list chl;
388
389 MALLOCVAR(chl);
390 if (chl == NULL)
391 retval = -1;
392 else {
393 int const hash = ppm_hashpixel(*colorP);
394
395 chl->ch.color = *colorP;
396 chl->ch.value = value;
397 chl->next = cht[hash];
398 cht[hash] = chl;
399 retval = 0;
400 }
401 return retval;
402 }
403
404
405
406 void
ppm_delfromcolorhash(colorhash_table const cht,const pixel * const colorP)407 ppm_delfromcolorhash(colorhash_table const cht,
408 const pixel * const colorP) {
409 /*----------------------------------------------------------------------------
410 Delete the color *colorP from the colorhahs 'cht', if it's there.
411 -----------------------------------------------------------------------------*/
412 int hash;
413 colorhist_list * chlP;
414
415 hash = ppm_hashpixel(*colorP);
416 for (chlP = &cht[hash]; *chlP; chlP = &(*chlP)->next) {
417 if (PPM_EQUAL((*chlP)->ch.color, *colorP)) {
418 /* chlP points to a pointer to the hash chain element we want
419 to remove.
420 */
421 colorhist_list const chl = *chlP;
422 *chlP = chl->next;
423 free(chl);
424 return;
425 }
426 }
427 }
428
429
430
431 static unsigned int
colorHashSize(colorhash_table const cht)432 colorHashSize(colorhash_table const cht) {
433 /*----------------------------------------------------------------------------
434 Return the number of colors in the colorhash table 'cht'
435 -----------------------------------------------------------------------------*/
436 unsigned int nColors;
437 /* Number of colors found so far */
438 int i;
439 /* Loop through the hash table. */
440 nColors = 0;
441 for (i = 0; i < HASH_SIZE; ++i) {
442 colorhist_list chl;
443 for (chl = cht[i]; chl; chl = chl->next)
444 ++nColors;
445 }
446 return nColors;
447 }
448
449
450
451 colorhist_vector
ppm_colorhashtocolorhist(colorhash_table const cht,int const maxcolors)452 ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) {
453
454 colorhist_vector chv;
455 colorhist_list chl;
456 unsigned int chvSize;
457
458 if (maxcolors == 0)
459 /* We leave space for 5 more colors so caller can add in special
460 colors like background color and transparent color.
461 */
462 chvSize = colorHashSize(cht) + 5;
463 else
464 /* Caller is responsible for making sure there are no more
465 than 'maxcolors' colors in the colorhash table. NOTE:
466 Before March 2002, the maxcolors == 0 invocation didn't
467 exist.
468 */
469 chvSize = maxcolors;
470
471 /* Collate the hash table into a simple colorhist array. */
472 MALLOCARRAY(chv, chvSize);
473 if (chv == NULL)
474 pm_error("out of memory generating histogram");
475
476 {
477 int i, j;
478 /* Loop through the hash table. */
479 j = 0;
480 for (i = 0; i < HASH_SIZE; ++i)
481 for (chl = cht[i]; chl; chl = chl->next) {
482 /* Add the new entry. */
483 chv[j] = chl->ch;
484 ++j;
485 }
486 }
487 return chv;
488 }
489
490
491
492 colorhash_table
ppm_colorhisttocolorhash(colorhist_vector const chv,int const colors)493 ppm_colorhisttocolorhash(colorhist_vector const chv,
494 int const colors) {
495
496 colorhash_table retval;
497 colorhash_table cht;
498 const char * error;
499
500 cht = alloccolorhash( ); /* Initializes to NULLs */
501 if (cht == NULL)
502 pm_asprintf(&error, "Unable to allocate color hash");
503 else {
504 unsigned int i;
505
506 for (i = 0, error = NULL; i < colors && !error; ++i) {
507 pixel const color = chv[i].color;
508 int const hash = ppm_hashpixel(color);
509
510 colorhist_list chl;
511
512 for (chl = cht[hash]; chl && !error; chl = chl->next)
513 if (PPM_EQUAL(chl->ch.color, color))
514 pm_asprintf(&error, "same color found twice: (%u %u %u)",
515 PPM_GETR(color),
516 PPM_GETG(color),
517 PPM_GETB(color));
518 MALLOCVAR(chl);
519 if (chl == NULL)
520 pm_asprintf(&error, "out of memory");
521 else {
522 chl->ch.color = color;
523 chl->ch.value = i;
524 chl->next = cht[hash];
525 cht[hash] = chl;
526 }
527 }
528 if (error)
529 ppm_freecolorhash(cht);
530 }
531 if (error) {
532 pm_errormsg("%s", error);
533 pm_strfree(error);
534 pm_longjmp();
535 } else
536 retval = cht;
537
538 return retval;
539 }
540
541
542
543 int
ppm_lookupcolor(colorhash_table const cht,const pixel * const colorP)544 ppm_lookupcolor(colorhash_table const cht,
545 const pixel * const colorP) {
546 int hash;
547 colorhist_list chl;
548
549 hash = ppm_hashpixel(*colorP);
550 for (chl = cht[hash]; chl; chl = chl->next)
551 if (PPM_EQUAL(chl->ch.color, *colorP))
552 return chl->ch.value;
553
554 return -1;
555 }
556
557
558
559 void
ppm_freecolorhist(colorhist_vector const chv)560 ppm_freecolorhist(colorhist_vector const chv) {
561 free(chv);
562 }
563
564
565
566 void
ppm_freecolorhash(colorhash_table const cht)567 ppm_freecolorhash(colorhash_table const cht) {
568
569 int i;
570 colorhist_list chl, chlnext;
571
572 for (i = 0; i < HASH_SIZE; ++i)
573 for (chl = cht[i]; chl != (colorhist_list) 0; chl = chlnext) {
574 chlnext = chl->next;
575 free(chl);
576 }
577 free(cht);
578 }
579
580
581 /*****************************************************************************
582 The following "color row" routines are taken from Ingo Wilken's ilbm
583 package, dated December 1994. Since they're only used by ppmtoilbm
584 and ilbmtoppm today, they aren't documented or well maintained, but
585 they seem pretty useful and ought to be used in other programs.
586
587 -Bryan 2001.03.10
588 ****************************************************************************/
589
590 /* libcmap2.c - support routines for color rows
591 **
592 ** Copyright (C) 1994 Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
593 **
594 ** Permission to use, copy, modify, and distribute this software and its
595 ** documentation for any purpose and without fee is hereby granted, provided
596 ** that the above copyright notice appear in all copies and that both that
597 ** copyright notice and this permission notice appear in supporting
598 ** documentation. This software is provided "as is" without express or
599 ** implied warranty.
600 */
601
602 colorhash_table
ppm_colorrowtocolorhash(colorrow,ncolors)603 ppm_colorrowtocolorhash(colorrow, ncolors)
604 pixel *colorrow;
605 int ncolors;
606 {
607 colorhash_table cht;
608 int i;
609
610 cht = ppm_alloccolorhash();
611 for( i = 0; i < ncolors; i++ ) {
612 if( ppm_lookupcolor(cht, &colorrow[i]) < 0 ) {
613 if( ppm_addtocolorhash(cht, &colorrow[i], i) < 0 )
614 pm_error("out of memory adding to hash table");
615 }
616 }
617 return cht;
618 }
619
620
621 pixel *
ppm_computecolorrow(pixels,cols,rows,maxcolors,ncolorsP)622 ppm_computecolorrow(pixels, cols, rows, maxcolors, ncolorsP)
623 pixel **pixels;
624 int cols, rows, maxcolors;
625 int *ncolorsP;
626 {
627 int ncolors, row, col;
628 colorhash_table cht;
629 pixel *pixrow;
630
631 pixrow = ppm_allocrow(maxcolors);
632 cht = ppm_alloccolorhash(); ncolors = 0;
633 for( row = 0; row < rows; row++ ) {
634 for( col = 0; col < cols; col++ ) {
635 if( ppm_lookupcolor(cht, &pixels[row][col]) < 0 ) {
636 if( ncolors >= maxcolors ) {
637 ppm_freerow(pixrow);
638 pixrow = (pixel *)0;
639 ncolors = -1;
640 goto fail;
641 }
642 if( ppm_addtocolorhash(cht, &pixels[row][col], ncolors) < 0 )
643 pm_error("out of memory adding to hash table");
644 pixrow[ncolors] = pixels[row][col];
645 ++ncolors;
646 }
647 }
648 }
649 fail:
650 ppm_freecolorhash(cht);
651
652 *ncolorsP = ncolors;
653 return pixrow;
654 }
655
656
657 pixel *
ppm_mapfiletocolorrow(file,maxcolors,ncolorsP,maxvalP)658 ppm_mapfiletocolorrow(file, maxcolors, ncolorsP, maxvalP)
659 FILE *file;
660 int maxcolors;
661 int *ncolorsP;
662 pixval *maxvalP;
663 {
664 int cols, rows, format, row, col, ncolors;
665 pixel *pixrow, *temprow;
666 colorhash_table cht;
667
668 pixrow = ppm_allocrow(maxcolors);
669
670 ppm_readppminit(file, &cols, &rows, maxvalP, &format);
671 temprow = ppm_allocrow(cols);
672 cht = ppm_alloccolorhash(); ncolors = 0;
673 for( row = 0; row < rows; row++ ) {
674 ppm_readppmrow(file, temprow, cols, *maxvalP, format);
675 for( col = 0; col < cols; col++ ) {
676 if( ppm_lookupcolor(cht, &temprow[col]) < 0 ) {
677 if( ncolors >= maxcolors ) {
678 ppm_freerow(pixrow);
679 pixrow = (pixel *)0;
680 ncolors = -1;
681 goto fail;
682 }
683 if( ppm_addtocolorhash(cht, &temprow[col], ncolors) < 0 )
684 pm_error("out of memory adding to hash table");
685 pixrow[ncolors] = temprow[col];
686 ++ncolors;
687 }
688 }
689 }
690 fail:
691 ppm_freecolorhash(cht);
692 ppm_freerow(temprow);
693
694 *ncolorsP = ncolors;
695 return pixrow;
696 }
697
698
699
700 static int (*customCmp)(pixel *, pixel *);
701
702 #ifndef LITERAL_FN_DEF_MATCH
703 static qsort_comparison_fn customStub;
704 #endif
705
706 static int
customStub(const void * const a,const void * const b)707 customStub(const void * const a,
708 const void * const b) {
709
710 return (*customCmp)((pixel *)a, (pixel *)b);
711 }
712
713
714
715 #ifndef LITERAL_FN_DEF_MATCH
716 static qsort_comparison_fn pixelCmp;
717 #endif
718
719 static int
pixelCmp(const void * const a,const void * const b)720 pixelCmp(const void * const a,
721 const void * const b) {
722
723 const pixel * const p1 = (const pixel *)a;
724 const pixel * const p2 = (const pixel *)b;
725
726 int diff;
727
728 diff = PPM_GETR(*p1) - PPM_GETR(*p2);
729 if( diff == 0 ) {
730 diff = PPM_GETG(*p1) - PPM_GETG(*p2);
731 if( diff == 0 )
732 diff = PPM_GETB(*p1) - PPM_GETB(*p2);
733 }
734 return diff;
735 }
736
737
738
739 void
ppm_sortcolorrow(pixel * const colorrow,int const ncolors,int (* cmpfunc)(pixel *,pixel *))740 ppm_sortcolorrow(pixel * const colorrow,
741 int const ncolors,
742 int (*cmpfunc)(pixel *, pixel *)) {
743
744 if (cmpfunc) {
745 customCmp = cmpfunc;
746 qsort((void *)colorrow, ncolors, sizeof(pixel), customStub);
747 } else
748 qsort((void *)colorrow, ncolors, sizeof(pixel), pixelCmp);
749 }
750
751
752
753 int
ppm_addtocolorrow(colorrow,ncolorsP,maxcolors,pixelP)754 ppm_addtocolorrow(colorrow, ncolorsP, maxcolors, pixelP)
755 pixel *colorrow;
756 int *ncolorsP;
757 int maxcolors;
758 pixel *pixelP;
759 {
760 int i;
761 pixval r, g, b;
762
763 r = PPM_GETR(*pixelP);
764 g = PPM_GETG(*pixelP);
765 b = PPM_GETB(*pixelP);
766
767 for( i = 0; i < *ncolorsP; i++ ) {
768 if( PPM_GETR(colorrow[i]) == r &&
769 PPM_GETG(colorrow[i]) == g &&
770 PPM_GETB(colorrow[i]) == b )
771 return i;
772 }
773
774 i = *ncolorsP;
775 if( i >= maxcolors )
776 return -1;
777 colorrow[i] = *pixelP;
778 ++*ncolorsP;
779 return i;
780 }
781
782
783 int
ppm_findclosestcolor(const pixel * const colormap,int const ncolors,const pixel * const pP)784 ppm_findclosestcolor(const pixel * const colormap,
785 int const ncolors,
786 const pixel * const pP) {
787
788 /* Search colormap for closest match. */
789
790 int i;
791 int ind;
792 unsigned int bestDist;
793
794 bestDist = UINT_MAX;
795 ind = -1;
796
797 for(i = 0; i < ncolors && bestDist > 0; ++i) {
798 unsigned int const dist = PPM_DISTANCE(*pP, colormap[i]);
799
800 if (dist < bestDist ) {
801 ind = i;
802 bestDist = dist;
803 }
804 }
805 return ind;
806 }
807
808
809 void
ppm_colorrowtomapfile(FILE * ofp,pixel * colormap,int ncolors,pixval maxval)810 ppm_colorrowtomapfile(FILE *ofp, pixel *colormap, int ncolors, pixval maxval)
811 {
812 int i;
813
814 ppm_writeppminit(ofp, ncolors, 1, maxval, 1);
815 for( i = 0; i < ncolors; i++ )
816 ppm_writeppmrow(ofp, &colormap[i], 1, maxval, 1);
817 }
818
819
820
821