b311480e |
1 | // Created by: DCB |
2 | // Copyright (c) 1998-1999 Matra Datavision |
3 | // Copyright (c) 1999-2012 OPEN CASCADE SAS |
4 | // |
5 | // The content of this file is subject to the Open CASCADE Technology Public |
6 | // License Version 6.5 (the "License"). You may not use the content of this file |
7 | // except in compliance with the License. Please obtain a copy of the License |
8 | // at http://www.opencascade.org and read it completely before using this file. |
9 | // |
10 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its |
11 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. |
7fd59977 |
12 | // |
b311480e |
13 | // The Original Code and all software distributed under the License is |
14 | // distributed on an "AS IS" basis, without warranty of any kind, and the |
15 | // Initial Developer hereby disclaims all such warranties, including without |
16 | // limitation, any warranties of merchantability, fitness for a particular |
17 | // purpose or non-infringement. Please see the License for the specific terms |
18 | // and conditions governing the rights and limitations under the License. |
19 | |
20 | // Notes: Most of code is taken from Xw_save_gif_image.c file (ZOV) |
7fd59977 |
21 | |
22 | #include <AlienImage_GIFLZWDict.hxx> |
23 | #include <stdio.h> |
24 | |
25 | const Handle(Standard_Type)& STANDARD_TYPE(AlienImage_GIFLZWDict) |
26 | { |
27 | static Handle(Standard_Type) _atype = |
28 | new Standard_Type ("AlienImage_GIFLZWDict", sizeof (AlienImage_GIFLZWDict)); |
29 | return _atype; |
30 | } |
31 | |
32 | //============================================================================= |
33 | // Functions to write GIF image to file. |
34 | //============================================================================= |
35 | |
36 | //===================== Static definitions =================== |
37 | static AlienImage_GIFLZWDict* dict; |
38 | static int startBits, codeBits, nextCode, bumpCode, rack, mask, putIdx, |
39 | ClearCode, EOFCode, FreeCode; |
40 | |
41 | static void _init_dict (void); |
42 | static int _find_child (int, int); |
43 | static BOOL _put_bits (BYTE *, ULONG, UINT, OSD_File&); |
44 | static BOOL _flush_bits (BYTE *, OSD_File&); |
45 | |
46 | |
47 | //============================================================================= |
48 | int _lzw_encode (OSD_File& file, const BYTE* pData, int width, int height, int inc) |
49 | { |
50 | int i, x, y; |
51 | BYTE byte, OutBuff [BUFF_SIZE]; |
52 | const BYTE *pLine; |
53 | int strCode, chr; |
54 | |
55 | dict = (AlienImage_GIFLZWDict*) malloc (sizeof (AlienImage_GIFLZWDict)*TBL_SIZE); |
56 | if (dict == NULL) |
57 | goto _ExitError; |
58 | |
59 | x = y = 0; |
60 | pLine = pData; |
61 | |
62 | OutBuff[ 0 ] = 0; |
63 | putIdx = 1; |
64 | mask = 0x01; |
65 | rack = 0; |
66 | startBits = 8; |
67 | ClearCode = 1 << startBits; |
68 | EOFCode = ClearCode + 1; |
69 | FreeCode = EOFCode + 1; |
70 | |
71 | _init_dict (); |
72 | |
73 | byte = startBits; |
74 | |
75 | file.Write (&byte, sizeof(byte)); |
76 | if (file.Failed ()) |
77 | goto _ExitError; |
78 | |
79 | strCode = pLine[ x++ ]; |
80 | |
81 | if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file)) |
82 | goto _ExitError; |
83 | |
84 | while (y < height) { |
85 | |
86 | chr = pLine[ x++ ]; |
87 | |
88 | i = _find_child ( strCode, chr ); |
89 | |
90 | if ( dict[ i ].code != UNUSED ) |
91 | strCode = dict[ i ].code; |
92 | |
93 | else { |
94 | dict[ i ].code = nextCode++; |
95 | dict[ i ].prnt = strCode; |
96 | dict[ i ].byte = chr; |
97 | |
98 | if (!_put_bits (OutBuff, (ULONG) strCode, codeBits, file)) |
99 | goto _ExitError; |
100 | |
101 | strCode = chr; |
102 | |
103 | if (nextCode > MAX_CODE) { |
104 | if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file)) |
105 | goto _ExitError; |
106 | |
107 | _init_dict (); |
108 | } |
109 | else if (nextCode > bumpCode) { |
110 | ++codeBits; |
111 | bumpCode <<= 1; |
112 | } |
113 | } |
114 | |
115 | if (x == width) { |
116 | x = 0; |
117 | ++y; |
118 | pLine += inc; |
119 | } |
120 | } |
121 | |
122 | if (!_put_bits (OutBuff, (ULONG) strCode, codeBits, file)) goto _ExitError; |
123 | if (!_put_bits (OutBuff, (ULONG) EOFCode, codeBits, file)) goto _ExitError; |
124 | if (!_flush_bits (OutBuff, file)) goto _ExitError; |
125 | |
126 | if (dict) |
127 | free (dict); |
128 | return TRUE; |
129 | |
130 | |
131 | _ExitError: |
132 | if (dict) |
133 | free (dict); |
134 | return FALSE; |
135 | } |
136 | |
137 | //==================================================================== |
138 | static void _init_dict () |
139 | { |
140 | memset (dict, UNUSED, sizeof (AlienImage_GIFLZWDict)*TBL_SIZE); |
141 | nextCode = FreeCode; |
142 | codeBits = startBits + 1; |
143 | bumpCode = 1 << codeBits; |
144 | } |
145 | |
146 | //==================================================================== |
147 | static int _find_child (int prntCode, int chr) |
148 | { |
149 | int idx, offset; |
150 | |
151 | idx = ( chr << ( NBITS - 8 ) ) ^ prntCode; |
152 | offset = idx ? TBL_SIZE - idx : 1; |
153 | |
154 | for (;;) { |
155 | |
156 | if (dict[ idx ].code == UNUSED || |
157 | dict[ idx ].prnt == prntCode && dict[ idx ].byte == ( BYTE )chr) |
158 | return idx; |
159 | |
160 | idx = ( idx >= offset ) ? idx - offset : idx + TBL_SIZE - offset; |
161 | } |
162 | } |
163 | |
164 | //==================================================================== |
165 | static BOOL _put_bits (BYTE *OutBuff, ULONG code, UINT nBits, OSD_File& file) |
166 | { |
167 | BOOL retVal = TRUE; |
168 | ULONG msk; |
169 | |
170 | msk = 1; |
171 | |
172 | while (msk != (ULONG) (1 << nBits)) { |
173 | if ( msk & code ) |
174 | rack |= mask; |
175 | mask <<= 1; |
176 | |
177 | if ((mask & 0xFF) == 0) { |
178 | OutBuff[ putIdx++ ] = rack; |
179 | ++OutBuff[ 0 ]; |
180 | |
181 | if (putIdx == BUFF_SIZE) { |
182 | file.Write (OutBuff, BUFF_SIZE); |
183 | if (file.Failed ()) { |
184 | retVal = FALSE; |
185 | break; |
186 | } |
187 | putIdx = 1; |
188 | OutBuff[ 0 ] = 0; |
189 | } |
190 | rack = 0; |
191 | mask = 0x01; |
192 | } |
193 | msk <<= 1; |
194 | } |
195 | return retVal; |
196 | } |
197 | |
198 | //==================================================================== |
199 | static BOOL _flush_bits (BYTE* OutBuff, OSD_File& file) |
200 | { |
201 | BOOL retVal = TRUE; |
202 | BYTE byte; |
203 | |
204 | if ( mask != 0x01 ) { |
205 | OutBuff[ putIdx++ ] = rack; |
206 | ++OutBuff[ 0 ]; |
207 | } |
208 | |
209 | if (putIdx != 1) { |
210 | file.Write (OutBuff, putIdx); |
211 | if (file.Failed ()) |
212 | retVal = FALSE; |
213 | } |
214 | |
215 | if (retVal) { |
216 | byte = 0; |
217 | file.Write (&byte, 1); |
218 | if (file.Failed ()) |
219 | retVal = FALSE; |
220 | } |
221 | return retVal; |
222 | } |
223 | |
224 | //============================================================================= |
225 | // Functions to convert from 24 to 8 color image |
226 | //============================================================================= |
227 | static int __fastcall quick_check ( PBYTE, int, int, PBYTE, LPRGBQUAD ); |
228 | //static int __fastcall quick_quant ( PBYTE, int, int, PBYTE, LPRGBQUAD ); |
229 | static int __fastcall ppm_quant ( PBYTE, int, int, PBYTE, LPRGBQUAD ); |
230 | |
231 | BOOL __fastcall _convert24to8 ( |
232 | LPRGBQUAD cTable, PBYTE pData24, PBYTE pData8, |
233 | int w, int h |
234 | ) |
235 | { |
236 | BOOL retVal = FALSE; |
237 | while ( 1 ) { |
238 | if ( quick_check ( pData24, w, h, pData8, cTable ) ) { |
239 | okRet: |
240 | retVal = TRUE; |
241 | break; |
242 | } else if ( ppm_quant ( pData24, w, h, pData8, cTable ) != -1 ) { |
243 | //////////////////// |
244 | for ( int i = 0; i < 256; ++i ) { |
245 | BYTE b = cTable[ i ].rgbRed; |
246 | cTable[ i ].rgbRed = cTable[ i ].rgbBlue; |
247 | cTable[ i ].rgbBlue = b; |
248 | } // end for |
249 | //////////////////// |
250 | goto okRet; |
251 | } // end if |
252 | break; |
253 | } // end while |
254 | return retVal; |
255 | } // end _convert24to8 |
256 | |
257 | //*************************************************************************// |
258 | //* The following code based on code from the 'pbmplus' package written by // |
259 | //* Jef Poskanzer // |
260 | //*************************************************************************// |
261 | //***// |
262 | #define MAXCOLORS 32767 |
263 | |
264 | #define PPM_GETR( p ) ( ( p ).r ) |
265 | #define PPM_GETG( p ) ( ( p ).g ) |
266 | #define PPM_GETB( p ) ( ( p ).b ) |
267 | |
268 | #define PPM_ASSIGN( p, red, grn, blu ) \ |
269 | { ( p ).r = ( red ); ( p ).g = ( grn ); ( p ).b = ( blu ); } |
270 | |
271 | #define PPM_EQUAL( p, q ) \ |
272 | ( ( p ).r == ( q ).r && ( p ).g == ( q ).g && ( p ).b == ( q ).b ) |
273 | |
274 | |
275 | #define PPM_DEPTH( newp, p, oldmaxval, newmaxval ) \ |
276 | PPM_ASSIGN( \ |
277 | ( newp ), \ |
278 | ( ( int )PPM_GETR( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ), \ |
279 | ( ( int )PPM_GETG( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ), \ |
280 | ( ( int )PPM_GETB( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ) \ |
281 | ) |
282 | |
283 | |
284 | #define HASH_SIZE 6553 |
285 | |
286 | #define ppm_hashpixel( p ) \ |
287 | ( ( ( ( int )PPM_GETR( p ) * 33023 + \ |
288 | ( int )PPM_GETG( p ) * 30013 + \ |
289 | ( int )PPM_GETB( p ) * 27011 \ |
290 | ) & 0x7fffffff \ |
291 | ) % HASH_SIZE \ |
292 | ) |
293 | |
294 | #define PPM_LUMIN( p ) \ |
295 | ( 77 * PPM_GETR( p ) + 150 * PPM_GETG( p ) + 29 * PPM_GETB( p ) ) |
296 | |
297 | typedef struct { BYTE r, g, b; } pixel; |
298 | |
299 | struct chist_item { |
300 | pixel color; |
301 | int value; |
302 | }; |
303 | |
304 | typedef struct chist_item* chist_vec; |
305 | |
306 | typedef struct chist_list_item* chist_list; |
307 | typedef chist_list* chash_table; |
308 | |
309 | struct chist_list_item { |
310 | struct chist_item ch; |
311 | chist_list next; |
312 | }; |
313 | |
314 | struct box { |
315 | int index; |
316 | int colors; |
317 | int sum; |
318 | }; |
319 | |
320 | typedef struct box* box_vector; |
321 | |
322 | static chist_vec __fastcall ppm_computechist ( pixel**, int, int, int, PINT ); |
323 | static void __fastcall ppm_freechist ( chist_vec ); |
324 | static chist_vec __fastcall mediancut ( chist_vec, int, int, int, int ); |
325 | static chash_table ppm_allocchash ( void ); |
326 | static void __fastcall ppm_freechash ( chash_table ); |
327 | static chash_table __fastcall ppm_computechash ( pixel**, int, int, int, PINT ); |
328 | static chist_vec __fastcall ppm_chashtochist ( chash_table, int ); |
329 | |
330 | static int redcompare ( const void*, const void* ); |
331 | static int greencompare ( const void*, const void* ); |
332 | static int bluecompare ( const void*, const void* ); |
333 | static int sumcompare ( const void*, const void* ); |
334 | |
335 | static int __fastcall ppm_quant ( |
336 | PBYTE pic24, int cols, int rows, PBYTE pic8, LPRGBQUAD rgbmap |
337 | ) { |
338 | |
339 | |
340 | pixel** pixels; |
341 | pixel* pP; |
342 | int row; |
343 | int col, limitcol; |
344 | BYTE maxval, newmaxval; |
345 | int colors; |
346 | int index; |
347 | chist_vec chv, colormap; |
348 | chash_table cht; |
349 | int i; |
350 | PBYTE picptr; |
351 | LPRGBQUAD pRGB; |
352 | int pad; |
353 | |
354 | index = 0; |
355 | maxval = 255; |
356 | // pad = PAD( cols * 3 ); |
357 | pad = 0; |
358 | |
359 | pixels = ( pixel** )MALLOC( rows * sizeof ( pixel* ) ); |
360 | |
361 | if ( pixels == NULL ) return -1; |
362 | |
363 | for ( row = 0; row < rows; ++row ) { |
364 | |
365 | pixels[ row ] = ( pixel* )MALLOC( cols * sizeof ( pixel ) ); |
366 | |
367 | if ( pixels[ row ] == NULL ) { |
368 | freeMemory: |
369 | while ( --row >= 0 ) FREE( pixels[ row ] ); |
370 | |
371 | FREE( pixels ); |
372 | |
373 | return -1; |
374 | |
375 | } // end if |
376 | |
377 | for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) { |
378 | |
379 | pP -> r = *pic24++; |
380 | pP -> g = *pic24++; |
381 | pP -> b = *pic24++; |
382 | |
383 | } // end for |
384 | |
385 | pic24 += pad; |
386 | |
387 | } // end for |
388 | |
389 | for ( ;; ) { |
390 | |
391 | chv = ppm_computechist ( pixels, cols, rows, MAXCOLORS, &colors ); |
392 | |
393 | if ( chv != ( chist_vec )0 ) break; |
394 | |
395 | newmaxval = maxval / 2; |
396 | |
397 | for ( row = 0; row < rows; ++row ) |
398 | |
399 | for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) |
400 | |
401 | PPM_DEPTH( *pP, *pP, maxval, newmaxval ); |
402 | |
403 | maxval = newmaxval; |
404 | |
405 | } // end for |
406 | |
407 | colormap = mediancut ( chv, colors, rows * cols, maxval, 256 ); |
408 | |
409 | if ( colormap == ( chist_vec )NULL ) { |
410 | freeMemory_1: |
411 | ppm_freechist ( chv ); |
412 | row = rows; |
413 | goto freeMemory; |
414 | |
415 | } // end if |
416 | |
417 | ppm_freechist ( chv ); |
418 | |
419 | cht = ppm_allocchash (); |
420 | |
421 | picptr = pic8; |
422 | |
423 | for ( row = 0; row < rows; ++row ) { |
424 | |
425 | col = 0; |
426 | limitcol = cols; |
427 | pP = pixels[ row ]; |
428 | |
429 | do { |
430 | |
431 | int hash; |
432 | chist_list chl; |
433 | |
434 | hash = ppm_hashpixel ( *pP ); |
435 | |
436 | for ( chl = cht[ hash ]; chl; chl = chl -> next ) |
437 | |
438 | if ( PPM_EQUAL( chl -> ch.color, *pP ) ) { |
439 | |
440 | index = chl -> ch.value; |
441 | break; |
442 | |
443 | } // end if |
444 | |
445 | if ( !chl ) { |
446 | |
447 | int i, r1, g1, b1, r2, g2, b2; |
448 | long dist, newdist; |
449 | |
450 | r1 = PPM_GETR( *pP ); |
451 | g1 = PPM_GETG( *pP ); |
452 | b1 = PPM_GETB( *pP ); |
453 | dist = 2000000000; |
454 | |
455 | for ( i = 0; i < 256; ++i ) { |
456 | |
457 | r2 = PPM_GETR( colormap[ i ].color ); |
458 | g2 = PPM_GETG( colormap[ i ].color ); |
459 | b2 = PPM_GETB( colormap[ i ].color ); |
460 | |
461 | newdist = ( r1 - r2 ) * ( r1 - r2 ) + |
462 | ( g1 - g2 ) * ( g1 - g2 ) + |
463 | ( b1 - b2 ) * ( b1 - b2 ); |
464 | |
465 | if ( newdist < dist ) { |
466 | |
467 | index = i; |
468 | dist = newdist; |
469 | |
470 | } // end if |
471 | |
472 | } // end for |
473 | |
474 | hash = ppm_hashpixel( *pP ); |
475 | chl = ( chist_list )MALLOC( sizeof ( struct chist_list_item ) ); |
476 | |
477 | if ( chl == NULL ) { |
478 | |
479 | ppm_freechash ( cht ); |
480 | goto freeMemory_1; |
481 | |
482 | } // end if |
483 | |
484 | chl -> ch.color = *pP; |
485 | chl -> ch.value = index; |
486 | chl -> next = cht[ hash ]; |
487 | cht[ hash ] = chl; |
488 | |
489 | } // end if |
490 | |
491 | *picptr++ = index; |
492 | ++col; |
493 | ++pP; |
494 | |
495 | } while ( col != limitcol ); |
496 | |
497 | } // end for |
498 | |
499 | for ( i = 0, pRGB = rgbmap; i < 256; ++i, ++pRGB ) { |
500 | |
501 | PPM_DEPTH( colormap[ i ].color, colormap[ i ].color, maxval, 255 ); |
502 | |
503 | pRGB -> rgbRed = PPM_GETR( colormap[ i ].color ); |
504 | pRGB -> rgbGreen = PPM_GETG( colormap[ i ].color ); |
505 | pRGB -> rgbBlue = PPM_GETB( colormap[ i ].color ); |
506 | |
507 | } // end for |
508 | |
509 | for ( i = 0; i < rows; ++i ) FREE( pixels[ i ] ); |
510 | |
511 | FREE( pixels ); |
512 | |
513 | ppm_freechist ( colormap ); |
514 | ppm_freechash ( cht ); |
515 | |
516 | return 0; |
517 | |
518 | } // end ppm_quant |
519 | |
520 | static void __fastcall ppm_freechist ( chist_vec chv ) { |
521 | |
522 | FREE( ( LPVOID )chv ); |
523 | |
524 | } // end ppm_freechist |
525 | |
526 | static chist_vec __fastcall mediancut ( |
527 | chist_vec chv, int colors, int sum, |
528 | int maxval, int newcolors |
529 | ) { |
530 | |
531 | chist_vec colormap; |
532 | box_vector bv; |
533 | int bi, i; |
534 | int boxes; |
535 | |
536 | bv = ( box_vector )MALLOC( sizeof( struct box ) * newcolors ); |
537 | |
538 | if ( bv == NULL ) return ( chist_vec )NULL; |
539 | |
540 | colormap = ( chist_vec )MALLOC( sizeof( struct chist_item ) * newcolors ); |
541 | |
542 | if ( colormap == NULL ) { |
543 | |
544 | FREE( bv ); |
545 | return ( chist_vec )NULL; |
546 | |
547 | } // end if |
548 | |
549 | for ( i = 0; i < newcolors; ++i ) PPM_ASSIGN( colormap[ i ].color, 0, 0, 0 ); |
550 | |
551 | bv[ 0 ].index = 0; |
552 | bv[ 0 ].colors = colors; |
553 | bv[ 0 ].sum = sum; |
554 | boxes = 1; |
555 | |
556 | while ( boxes < newcolors ) { |
557 | |
558 | int indx, clrs; |
559 | int sm; |
560 | int minr, maxr, ming, maxg, minb, maxb, v; |
561 | int halfsum, lowersum; |
562 | |
563 | for ( bi = 0; bv[ bi ].colors < 2 && bi < boxes; ++bi ); |
564 | |
565 | if ( bi == boxes ) break; |
566 | |
567 | indx = bv[ bi ].index; |
568 | clrs = bv[ bi ].colors; |
569 | sm = bv[ bi ].sum; |
570 | |
571 | minr = maxr = PPM_GETR( chv[ indx ].color ); |
572 | ming = maxg = PPM_GETG( chv[ indx ].color ); |
573 | minb = maxb = PPM_GETB( chv[ indx ].color ); |
574 | |
575 | for ( i = 1; i < clrs; ++i ) { |
576 | |
577 | v = PPM_GETR( chv[ indx + i ].color ); |
578 | |
579 | if ( v < minr ) minr = v; |
580 | if ( v > maxr ) maxr = v; |
581 | |
582 | v = PPM_GETG( chv[ indx + i ].color ); |
583 | |
584 | if ( v < ming ) ming = v; |
585 | if ( v > maxg ) maxg = v; |
586 | |
587 | v = PPM_GETB( chv[ indx + i ].color ); |
588 | |
589 | if ( v < minb ) minb = v; |
590 | if ( v > maxb ) maxb = v; |
591 | |
592 | } // end for |
593 | |
594 | { // begin local block |
595 | |
596 | pixel p; |
597 | int rl, gl, bl; |
598 | |
599 | PPM_ASSIGN( p, maxr - minr, 0, 0 ); |
600 | rl = PPM_LUMIN( p ); |
601 | |
602 | PPM_ASSIGN( p, 0, maxg - ming, 0 ); |
603 | gl = PPM_LUMIN( p ); |
604 | |
605 | PPM_ASSIGN( p, 0, 0, maxb - minb ); |
606 | bl = PPM_LUMIN( p ); |
607 | |
608 | if ( rl >= gl && rl >= bl ) |
609 | |
610 | qsort ( |
611 | ( char* )&chv[ indx ], ( size_t )clrs, |
612 | sizeof ( struct chist_item ), redcompare |
613 | ); |
614 | |
615 | else if ( gl >= bl ) |
616 | |
617 | qsort ( |
618 | ( char* )&chv[ indx ], ( size_t )clrs, |
619 | sizeof ( struct chist_item ), greencompare |
620 | ); |
621 | |
622 | else |
623 | |
624 | qsort ( |
625 | ( char* )&chv[ indx ], ( size_t )clrs, |
626 | sizeof ( struct chist_item ), bluecompare |
627 | ); |
628 | |
629 | } // end local block |
630 | |
631 | lowersum = chv[ indx ].value; |
632 | halfsum = sm / 2; |
633 | |
634 | for ( i = 1; i < clrs - 1; ++i) { |
635 | |
636 | if ( lowersum >= halfsum ) break; |
637 | |
638 | lowersum += chv[ indx + i ].value; |
639 | |
640 | } // end for |
641 | |
642 | bv[ bi ].colors = i; |
643 | bv[ bi ].sum = lowersum; |
644 | |
645 | bv[ boxes ].index = indx + i; |
646 | bv[ boxes ].colors = clrs - i; |
647 | bv[ boxes++ ].sum = sm - lowersum; |
648 | |
649 | qsort ( |
650 | ( char* )bv, ( size_t )boxes, sizeof ( struct box ), sumcompare |
651 | ); |
652 | |
653 | } // end while |
654 | |
655 | for ( bi = 0; bi < boxes; ++bi ) { |
656 | |
657 | int indx = bv[ bi ].index; |
658 | int clrs = bv[ bi ].colors; |
659 | long r = 0, g = 0, b = 0, sum = 0; |
660 | |
661 | for ( i = 0; i < clrs; ++i ) { |
662 | |
663 | r += PPM_GETR( chv[ indx + i ].color ) * chv[ indx + i ].value; |
664 | g += PPM_GETG( chv[ indx + i ].color ) * chv[ indx + i ].value; |
665 | b += PPM_GETB( chv[ indx + i ].color ) * chv[ indx + i ].value; |
666 | |
667 | sum += chv[ indx + i ].value; |
668 | |
669 | } // end for ( i . . . ) |
670 | |
671 | r = r / sum; if ( r > maxval ) r = maxval; |
672 | g = g / sum; if ( g > maxval ) g = maxval; |
673 | b = b / sum; if ( b > maxval ) b = maxval; |
674 | |
675 | PPM_ASSIGN( colormap[ bi ].color, ( BYTE )r, ( BYTE )g, ( BYTE )b ); |
676 | |
677 | } // end for ( bi . . . ) |
678 | |
679 | FREE( bv ); |
680 | |
681 | return colormap; |
682 | |
683 | } // end mediancut |
684 | |
685 | static int redcompare ( const void* p1, const void* p2 ) { |
686 | |
687 | return ( int )PPM_GETR( ( ( chist_vec )p1 ) -> color ) - |
688 | ( int )PPM_GETR( ( ( chist_vec )p2 ) -> color ); |
689 | |
690 | } // end redcompare |
691 | |
692 | static int greencompare ( const void* p1, const void* p2 ) { |
693 | |
694 | return ( int )PPM_GETG( ( ( chist_vec )p1 ) -> color ) - |
695 | ( int )PPM_GETG( ( ( chist_vec )p2 ) -> color ); |
696 | |
697 | } // end greencompare |
698 | |
699 | static int bluecompare ( const void* p1, const void* p2 ) { |
700 | |
701 | return ( int )PPM_GETB( ( ( chist_vec )p1 ) -> color ) - |
702 | ( int )PPM_GETB( ( ( chist_vec )p2 ) -> color ); |
703 | |
704 | } // end bluecompare |
705 | |
706 | static int sumcompare ( const void* p1, const void* p2 ) { |
707 | |
708 | return ( ( box_vector )p2 ) -> sum - ( ( box_vector )p1 ) -> sum; |
709 | |
710 | } // end sumcompare |
711 | |
712 | static chash_table ppm_allocchash ( void ) { |
713 | |
714 | chash_table cht; |
715 | |
716 | cht = ( chash_table )MALLOC( HASH_SIZE * sizeof ( chist_list ) ); |
717 | |
718 | return cht; |
719 | |
720 | } // end ppm_allocchash |
721 | |
722 | static chist_vec __fastcall ppm_computechist ( |
723 | pixel** pixels, int cols, int rows, int maxcolors, |
724 | PINT colorsP |
725 | ) { |
726 | |
727 | chash_table cht; |
728 | chist_vec chv; |
729 | |
730 | cht = ppm_computechash ( pixels, cols, rows, maxcolors, colorsP ); |
731 | |
732 | if ( cht == NULL ) return ( chist_vec )NULL; |
733 | |
734 | chv = ppm_chashtochist ( cht, maxcolors ); |
735 | |
736 | ppm_freechash ( cht ); |
737 | |
738 | return chv; |
739 | |
740 | } // end ppm_computechist |
741 | |
742 | static chash_table __fastcall ppm_computechash ( |
743 | pixel** pixels, int cols, int rows, int maxcolors, |
744 | PINT colorsP |
745 | ) { |
746 | |
747 | chash_table cht; |
748 | register pixel* pP; |
749 | chist_list chl; |
750 | int col, row, hash; |
751 | |
752 | cht = ppm_allocchash (); |
753 | *colorsP = 0; |
754 | |
755 | for ( row = 0; row < rows; ++row ) |
756 | |
757 | for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) { |
758 | |
759 | hash = ppm_hashpixel ( *pP ); |
760 | |
761 | for ( chl = cht[ hash ]; chl != ( chist_list )0; chl = chl -> next ) |
762 | |
763 | if ( PPM_EQUAL( chl -> ch.color, *pP ) ) break; |
764 | |
765 | if ( chl != ( chist_list)0 ) |
766 | |
767 | ++( chl->ch.value ); |
768 | |
769 | else { |
770 | |
771 | if ( ( *colorsP )++ > maxcolors ) { |
772 | |
773 | ppm_freechash ( cht ); |
774 | |
775 | return ( chash_table )NULL; |
776 | |
777 | } // end if |
778 | |
779 | chl = ( chist_list )MALLOC( sizeof( struct chist_list_item ) ); |
780 | |
781 | if ( chl == NULL ) return ( chash_table )NULL; |
782 | |
783 | chl -> ch.color = *pP; |
784 | chl -> ch.value = 1; |
785 | chl -> next = cht[ hash ]; |
786 | cht[ hash ] = chl; |
787 | |
788 | } // end else |
789 | |
790 | } // end for |
791 | |
792 | return cht; |
793 | |
794 | } // end ppm_computechash |
795 | |
796 | static chist_vec __fastcall ppm_chashtochist ( chash_table cht, int maxcolors ) { |
797 | |
798 | chist_vec chv; |
799 | chist_list chl; |
800 | int i, j; |
801 | |
802 | chv = ( chist_vec )MALLOC( maxcolors * sizeof ( struct chist_item ) ); |
803 | |
804 | if ( chv == NULL) return chv; |
805 | |
806 | j = 0; |
807 | |
808 | for ( i = 0; i < HASH_SIZE; ++i ) |
809 | |
810 | for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chl -> next ) { |
811 | |
812 | chv[ j ] = chl -> ch; |
813 | ++j; |
814 | |
815 | } // end for |
816 | |
817 | return chv; |
818 | |
819 | } // end ppm_chashtochist |
820 | |
821 | static void __fastcall ppm_freechash ( chash_table cht ) { |
822 | |
823 | int i; |
824 | chist_list chl, chlnext; |
825 | |
826 | for ( i = 0; i < HASH_SIZE; ++i ) |
827 | |
828 | for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chlnext ) { |
829 | |
830 | chlnext = chl -> next; |
831 | FREE( chl ); |
832 | |
833 | } // end for |
834 | |
835 | FREE( cht ); |
836 | |
837 | } // end ppm_freechash |
838 | |
839 | static int __fastcall quick_check ( |
840 | PBYTE pic24, int w, int h, PBYTE pic8, LPRGBQUAD rgbmap |
841 | ) { |
842 | |
843 | unsigned long colors[ 256 ], col; |
844 | int i, j, nc, low, high, mid, pad; |
845 | PBYTE p, pix; |
846 | |
847 | nc = 0; |
848 | mid = 0; |
849 | // pad = PAD( w * 3 ); |
850 | pad = 0; |
851 | |
852 | for ( i = 0, p = pic24; i < h; ++i ) { |
853 | |
854 | for ( j = 0; j < w; ++j ) { |
855 | |
856 | col = ( ( ( unsigned long )*p++ ) << 16 ); |
857 | col += ( ( ( unsigned long )*p++ ) << 8 ); |
858 | col += ( ( ( unsigned long )*p++ ) << 0 ); |
859 | |
860 | low = 0; high = nc - 1; |
861 | |
862 | while ( low <= high ) { |
863 | |
864 | mid = ( low + high ) / 2; |
865 | |
866 | if ( col < colors[ mid ] ) |
867 | |
868 | high = mid - 1; |
869 | |
870 | else if ( col > colors[ mid ] ) |
871 | |
872 | low = mid + 1; |
873 | |
874 | else break; |
875 | |
876 | } // end while |
877 | |
878 | if ( high < low ) { |
879 | |
880 | if ( nc >= 256 ) return FALSE; |
881 | |
882 | memcpy ( |
883 | ( char* )&colors[ low + 1 ], ( char* )&colors[ low ], |
884 | ( nc - low ) * sizeof ( unsigned long ) |
885 | ); |
886 | |
887 | colors[ low ] = col; |
888 | ++nc; |
889 | |
890 | } // end if |
891 | |
892 | } // end for ( j . . . ) |
893 | |
894 | p += pad; |
895 | |
896 | } // end for ( i . . . ) |
897 | |
898 | for ( i = 0, p = pic24, pix = pic8; i < h; ++i ) { |
899 | |
900 | for ( j = 0; j < w; ++j ) { |
901 | |
902 | col = ( ( ( unsigned long )*p++ ) << 16 ); |
903 | col += ( ( ( unsigned long )*p++ ) << 8 ); |
904 | col += *p++; |
905 | |
906 | low = 0; high = nc - 1; |
907 | |
908 | while ( low <= high ) { |
909 | |
910 | mid = ( low + high ) / 2; |
911 | |
912 | if ( col < colors[ mid ] ) |
913 | |
914 | high = mid - 1; |
915 | |
916 | else if ( col > colors[ mid ] ) |
917 | |
918 | low = mid + 1; |
919 | |
920 | else break; |
921 | |
922 | } // end while |
923 | |
924 | *pix++ = mid; |
925 | |
926 | } // end for ( j . . . ) |
927 | |
928 | p += pad; |
929 | |
930 | } // end for ( i . . . ) |
931 | |
932 | for ( i = 0; i < nc; ++i, ++rgbmap ) { |
933 | |
934 | rgbmap -> rgbRed = ( BYTE )( colors[ i ] >> 0 ) & 0xFF; |
935 | rgbmap -> rgbGreen = ( BYTE )( colors[ i ] >> 8 ) & 0xFF; |
936 | rgbmap -> rgbBlue = ( BYTE )( colors[ i ] >> 16 ) & 0xFF; |
937 | |
938 | } // end for |
939 | |
940 | return nc; |
941 | |
942 | } // end quick_check |
943 | |
944 | #ifdef BSHIFT //HPUX COMPATIBILLITY |
945 | #undef BSHIFT |
946 | #endif |
947 | #define RMASK 0xE0 |
948 | #define RSHIFT 0 |
949 | #define GMASK 0xE0 |
950 | #define GSHIFT 3 |
951 | #define BMASK 0xC0 |
952 | #define BSHIFT 6 |
953 | #define RANGE( a, b, c ) { if ( a < b ) a = b; if ( a > c ) a = c; } |
954 | |
955 | //static int __fastcall quick_quant ( |
956 | // PBYTE p24, int w, int h, PBYTE p8, LPRGBQUAD rgbmap |
957 | // ) { |
958 | |
959 | // PBYTE pp; |
960 | // int r1, g1, b1; |
961 | // PINT thisline, nextline, thisptr, nextptr, tmpptr; |
962 | // int i, j, val, pwide3; |
963 | // int imax, jmax; |
964 | // int pad; |
965 | |
966 | //// pad = PAD( w * 3 ); |
967 | // pad = 0; |
968 | |
969 | // pp = p8; |
970 | // pwide3 = w * 3; |
971 | // imax = h - 1; |
972 | // jmax = w - 1; |
973 | |
974 | // for ( i = 0; i < 256; ++i ) { |
975 | |
976 | // rgbmap[ i ].rgbRed = ( ( ( i << RSHIFT ) & RMASK ) * 255 + RMASK / 2 ) / RMASK; |
977 | // rgbmap[ i ].rgbGreen = ( ( ( i << GSHIFT ) & GMASK ) * 255 + GMASK / 2 ) / GMASK; |
978 | // rgbmap[ i ].rgbBlue = ( ( ( i << BSHIFT ) & BMASK ) * 255 + BMASK / 2 ) / BMASK; |
979 | |
980 | // } // end for |
981 | |
982 | // thisline = ( PINT )MALLOC( pwide3 * sizeof ( int ) ); |
983 | |
984 | // if ( thisline == NULL ) return 1; |
985 | |
986 | // nextline = ( PINT )MALLOC( pwide3 * sizeof ( int ) ); |
987 | |
988 | // if ( nextline == NULL ) { |
989 | |
990 | // FREE( thisline ); |
991 | // return 1; |
992 | |
993 | // } // end if |
994 | |
995 | // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++; |
996 | |
997 | // p24 += pad; |
998 | |
999 | // for ( i = 0; i < h; ++i ) { |
1000 | |
1001 | // tmpptr = thisline; |
1002 | // thisline = nextline; |
1003 | // nextline = tmpptr; |
1004 | // |
1005 | // if ( i != imax ) { |
1006 | |
1007 | // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++; |
1008 | // |
1009 | // p24 += pad; |
1010 | |
1011 | // } // end if |
1012 | |
1013 | // for ( j = 0, thisptr = thisline, nextptr = nextline; j < w; ++j, ++pp ) { |
1014 | |
1015 | // r1 = *thisptr++; |
1016 | // RANGE( r1, 0, 255 ); |
1017 | |
1018 | // g1 = *thisptr++; |
1019 | // RANGE(g1,0,255); |
1020 | |
1021 | // b1 = *thisptr++; |
1022 | // RANGE(b1,0,255); |
1023 | |
1024 | // val = ( ( ( r1 & RMASK ) >> RSHIFT ) | |
1025 | // ( ( g1 & GMASK ) >> GSHIFT ) | |
1026 | // ( ( b1 & BMASK ) >> BSHIFT ) ); |
1027 | // *pp = val; |
1028 | |
1029 | // r1 -= rgbmap[ val ].rgbRed; |
1030 | // g1 -= rgbmap[ val ].rgbGreen; |
1031 | // b1 -= rgbmap[ val ].rgbBlue; |
1032 | |
1033 | // if ( j != jmax ) { |
1034 | |
1035 | // thisptr[ 0 ] += ( r1 * 7 ) / 16; |
1036 | // thisptr[ 1 ] += ( g1 * 7 ) / 16; |
1037 | // thisptr[ 2 ] += ( b1 * 7 ) / 16; |
1038 | |
1039 | // } // end if |
1040 | |
1041 | // if ( i != imax ) { |
1042 | |
1043 | // nextptr[ 0 ] += ( r1 * 5 ) / 16; |
1044 | // nextptr[ 1 ] += ( g1 * 5 ) / 16; |
1045 | // nextptr[ 2 ] += ( b1 * 5 ) / 16; |
1046 | |
1047 | // if ( j > 0 ) { |
1048 | |
1049 | // nextptr[ -3 ] += ( r1 * 3 ) / 16; |
1050 | // nextptr[ -2 ] += ( g1 * 3 ) / 16; |
1051 | // nextptr[ -1 ] += ( b1 * 3 ) / 16; |
1052 | |
1053 | // } // end if |
1054 | |
1055 | // if ( j != jmax ) { |
1056 | |
1057 | // nextptr[ 3 ] += ( r1 ) / 16; |
1058 | // nextptr[ 4 ] += ( g1 ) / 16; |
1059 | // nextptr[ 5 ] += ( b1 ) / 16; |
1060 | |
1061 | // } // end if |
1062 | |
1063 | // nextptr += 3; |
1064 | |
1065 | // } // end if |
1066 | |
1067 | // } // end for ( j . . . ) |
1068 | |
1069 | // } // end for ( i . . . ) |
1070 | |
1071 | // FREE( thisline ); |
1072 | // FREE( nextline ); |
1073 | |
1074 | // return 0; |
1075 | |
1076 | //} // end quick_quant |
1077 | //***// |
1078 | //*************************************************************************// |
1079 | |