1 // File: AlienImage_GIFLZWDict.cxx
2 // Created: Quebex 23 October 1998
4 // Notes: Most of code is taken from Xw_save_gif_image.c file (ZOV)
6 // Copyright: MatraDatavision 1998
8 #include <AlienImage_GIFLZWDict.hxx>
11 const Handle(Standard_Type)& STANDARD_TYPE(AlienImage_GIFLZWDict)
13 static Handle(Standard_Type) _atype =
14 new Standard_Type ("AlienImage_GIFLZWDict", sizeof (AlienImage_GIFLZWDict));
18 //=============================================================================
19 // Functions to write GIF image to file.
20 //=============================================================================
22 //===================== Static definitions ===================
23 static AlienImage_GIFLZWDict* dict;
24 static int startBits, codeBits, nextCode, bumpCode, rack, mask, putIdx,
25 ClearCode, EOFCode, FreeCode;
27 static void _init_dict (void);
28 static int _find_child (int, int);
29 static BOOL _put_bits (BYTE *, ULONG, UINT, OSD_File&);
30 static BOOL _flush_bits (BYTE *, OSD_File&);
33 //=============================================================================
34 int _lzw_encode (OSD_File& file, const BYTE* pData, int width, int height, int inc)
37 BYTE byte, OutBuff [BUFF_SIZE];
41 dict = (AlienImage_GIFLZWDict*) malloc (sizeof (AlienImage_GIFLZWDict)*TBL_SIZE);
53 ClearCode = 1 << startBits;
54 EOFCode = ClearCode + 1;
55 FreeCode = EOFCode + 1;
61 file.Write (&byte, sizeof(byte));
65 strCode = pLine[ x++ ];
67 if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file))
74 i = _find_child ( strCode, chr );
76 if ( dict[ i ].code != UNUSED )
77 strCode = dict[ i ].code;
80 dict[ i ].code = nextCode++;
81 dict[ i ].prnt = strCode;
84 if (!_put_bits (OutBuff, (ULONG) strCode, codeBits, file))
89 if (nextCode > MAX_CODE) {
90 if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file))
95 else if (nextCode > bumpCode) {
108 if (!_put_bits (OutBuff, (ULONG) strCode, codeBits, file)) goto _ExitError;
109 if (!_put_bits (OutBuff, (ULONG) EOFCode, codeBits, file)) goto _ExitError;
110 if (!_flush_bits (OutBuff, file)) goto _ExitError;
123 //====================================================================
124 static void _init_dict ()
126 memset (dict, UNUSED, sizeof (AlienImage_GIFLZWDict)*TBL_SIZE);
128 codeBits = startBits + 1;
129 bumpCode = 1 << codeBits;
132 //====================================================================
133 static int _find_child (int prntCode, int chr)
137 idx = ( chr << ( NBITS - 8 ) ) ^ prntCode;
138 offset = idx ? TBL_SIZE - idx : 1;
142 if (dict[ idx ].code == UNUSED ||
143 dict[ idx ].prnt == prntCode && dict[ idx ].byte == ( BYTE )chr)
146 idx = ( idx >= offset ) ? idx - offset : idx + TBL_SIZE - offset;
150 //====================================================================
151 static BOOL _put_bits (BYTE *OutBuff, ULONG code, UINT nBits, OSD_File& file)
158 while (msk != (ULONG) (1 << nBits)) {
163 if ((mask & 0xFF) == 0) {
164 OutBuff[ putIdx++ ] = rack;
167 if (putIdx == BUFF_SIZE) {
168 file.Write (OutBuff, BUFF_SIZE);
169 if (file.Failed ()) {
184 //====================================================================
185 static BOOL _flush_bits (BYTE* OutBuff, OSD_File& file)
190 if ( mask != 0x01 ) {
191 OutBuff[ putIdx++ ] = rack;
196 file.Write (OutBuff, putIdx);
203 file.Write (&byte, 1);
210 //=============================================================================
211 // Functions to convert from 24 to 8 color image
212 //=============================================================================
213 static int __fastcall quick_check ( PBYTE, int, int, PBYTE, LPRGBQUAD );
214 //static int __fastcall quick_quant ( PBYTE, int, int, PBYTE, LPRGBQUAD );
215 static int __fastcall ppm_quant ( PBYTE, int, int, PBYTE, LPRGBQUAD );
217 BOOL __fastcall _convert24to8 (
218 LPRGBQUAD cTable, PBYTE pData24, PBYTE pData8,
224 if ( quick_check ( pData24, w, h, pData8, cTable ) ) {
228 } else if ( ppm_quant ( pData24, w, h, pData8, cTable ) != -1 ) {
230 for ( int i = 0; i < 256; ++i ) {
231 BYTE b = cTable[ i ].rgbRed;
232 cTable[ i ].rgbRed = cTable[ i ].rgbBlue;
233 cTable[ i ].rgbBlue = b;
241 } // end _convert24to8
243 //*************************************************************************//
244 //* The following code based on code from the 'pbmplus' package written by //
246 //*************************************************************************//
248 #define MAXCOLORS 32767
250 #define PPM_GETR( p ) ( ( p ).r )
251 #define PPM_GETG( p ) ( ( p ).g )
252 #define PPM_GETB( p ) ( ( p ).b )
254 #define PPM_ASSIGN( p, red, grn, blu ) \
255 { ( p ).r = ( red ); ( p ).g = ( grn ); ( p ).b = ( blu ); }
257 #define PPM_EQUAL( p, q ) \
258 ( ( p ).r == ( q ).r && ( p ).g == ( q ).g && ( p ).b == ( q ).b )
261 #define PPM_DEPTH( newp, p, oldmaxval, newmaxval ) \
264 ( ( int )PPM_GETR( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ), \
265 ( ( int )PPM_GETG( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ), \
266 ( ( int )PPM_GETB( p ) ) * ( ( int )newmaxval ) / ( ( int )oldmaxval ) \
270 #define HASH_SIZE 6553
272 #define ppm_hashpixel( p ) \
273 ( ( ( ( int )PPM_GETR( p ) * 33023 + \
274 ( int )PPM_GETG( p ) * 30013 + \
275 ( int )PPM_GETB( p ) * 27011 \
280 #define PPM_LUMIN( p ) \
281 ( 77 * PPM_GETR( p ) + 150 * PPM_GETG( p ) + 29 * PPM_GETB( p ) )
283 typedef struct { BYTE r, g, b; } pixel;
290 typedef struct chist_item* chist_vec;
292 typedef struct chist_list_item* chist_list;
293 typedef chist_list* chash_table;
295 struct chist_list_item {
296 struct chist_item ch;
306 typedef struct box* box_vector;
308 static chist_vec __fastcall ppm_computechist ( pixel**, int, int, int, PINT );
309 static void __fastcall ppm_freechist ( chist_vec );
310 static chist_vec __fastcall mediancut ( chist_vec, int, int, int, int );
311 static chash_table ppm_allocchash ( void );
312 static void __fastcall ppm_freechash ( chash_table );
313 static chash_table __fastcall ppm_computechash ( pixel**, int, int, int, PINT );
314 static chist_vec __fastcall ppm_chashtochist ( chash_table, int );
316 static int redcompare ( const void*, const void* );
317 static int greencompare ( const void*, const void* );
318 static int bluecompare ( const void*, const void* );
319 static int sumcompare ( const void*, const void* );
321 static int __fastcall ppm_quant (
322 PBYTE pic24, int cols, int rows, PBYTE pic8, LPRGBQUAD rgbmap
330 BYTE maxval, newmaxval;
333 chist_vec chv, colormap;
342 // pad = PAD( cols * 3 );
345 pixels = ( pixel** )MALLOC( rows * sizeof ( pixel* ) );
347 if ( pixels == NULL ) return -1;
349 for ( row = 0; row < rows; ++row ) {
351 pixels[ row ] = ( pixel* )MALLOC( cols * sizeof ( pixel ) );
353 if ( pixels[ row ] == NULL ) {
355 while ( --row >= 0 ) FREE( pixels[ row ] );
363 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) {
377 chv = ppm_computechist ( pixels, cols, rows, MAXCOLORS, &colors );
379 if ( chv != ( chist_vec )0 ) break;
381 newmaxval = maxval / 2;
383 for ( row = 0; row < rows; ++row )
385 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP )
387 PPM_DEPTH( *pP, *pP, maxval, newmaxval );
393 colormap = mediancut ( chv, colors, rows * cols, maxval, 256 );
395 if ( colormap == ( chist_vec )NULL ) {
397 ppm_freechist ( chv );
403 ppm_freechist ( chv );
405 cht = ppm_allocchash ();
409 for ( row = 0; row < rows; ++row ) {
420 hash = ppm_hashpixel ( *pP );
422 for ( chl = cht[ hash ]; chl; chl = chl -> next )
424 if ( PPM_EQUAL( chl -> ch.color, *pP ) ) {
426 index = chl -> ch.value;
433 int i, r1, g1, b1, r2, g2, b2;
436 r1 = PPM_GETR( *pP );
437 g1 = PPM_GETG( *pP );
438 b1 = PPM_GETB( *pP );
441 for ( i = 0; i < 256; ++i ) {
443 r2 = PPM_GETR( colormap[ i ].color );
444 g2 = PPM_GETG( colormap[ i ].color );
445 b2 = PPM_GETB( colormap[ i ].color );
447 newdist = ( r1 - r2 ) * ( r1 - r2 ) +
448 ( g1 - g2 ) * ( g1 - g2 ) +
449 ( b1 - b2 ) * ( b1 - b2 );
451 if ( newdist < dist ) {
460 hash = ppm_hashpixel( *pP );
461 chl = ( chist_list )MALLOC( sizeof ( struct chist_list_item ) );
465 ppm_freechash ( cht );
470 chl -> ch.color = *pP;
471 chl -> ch.value = index;
472 chl -> next = cht[ hash ];
481 } while ( col != limitcol );
485 for ( i = 0, pRGB = rgbmap; i < 256; ++i, ++pRGB ) {
487 PPM_DEPTH( colormap[ i ].color, colormap[ i ].color, maxval, 255 );
489 pRGB -> rgbRed = PPM_GETR( colormap[ i ].color );
490 pRGB -> rgbGreen = PPM_GETG( colormap[ i ].color );
491 pRGB -> rgbBlue = PPM_GETB( colormap[ i ].color );
495 for ( i = 0; i < rows; ++i ) FREE( pixels[ i ] );
499 ppm_freechist ( colormap );
500 ppm_freechash ( cht );
506 static void __fastcall ppm_freechist ( chist_vec chv ) {
508 FREE( ( LPVOID )chv );
510 } // end ppm_freechist
512 static chist_vec __fastcall mediancut (
513 chist_vec chv, int colors, int sum,
514 int maxval, int newcolors
522 bv = ( box_vector )MALLOC( sizeof( struct box ) * newcolors );
524 if ( bv == NULL ) return ( chist_vec )NULL;
526 colormap = ( chist_vec )MALLOC( sizeof( struct chist_item ) * newcolors );
528 if ( colormap == NULL ) {
531 return ( chist_vec )NULL;
535 for ( i = 0; i < newcolors; ++i ) PPM_ASSIGN( colormap[ i ].color, 0, 0, 0 );
538 bv[ 0 ].colors = colors;
542 while ( boxes < newcolors ) {
546 int minr, maxr, ming, maxg, minb, maxb, v;
547 int halfsum, lowersum;
549 for ( bi = 0; bv[ bi ].colors < 2 && bi < boxes; ++bi );
551 if ( bi == boxes ) break;
553 indx = bv[ bi ].index;
554 clrs = bv[ bi ].colors;
557 minr = maxr = PPM_GETR( chv[ indx ].color );
558 ming = maxg = PPM_GETG( chv[ indx ].color );
559 minb = maxb = PPM_GETB( chv[ indx ].color );
561 for ( i = 1; i < clrs; ++i ) {
563 v = PPM_GETR( chv[ indx + i ].color );
565 if ( v < minr ) minr = v;
566 if ( v > maxr ) maxr = v;
568 v = PPM_GETG( chv[ indx + i ].color );
570 if ( v < ming ) ming = v;
571 if ( v > maxg ) maxg = v;
573 v = PPM_GETB( chv[ indx + i ].color );
575 if ( v < minb ) minb = v;
576 if ( v > maxb ) maxb = v;
580 { // begin local block
585 PPM_ASSIGN( p, maxr - minr, 0, 0 );
588 PPM_ASSIGN( p, 0, maxg - ming, 0 );
591 PPM_ASSIGN( p, 0, 0, maxb - minb );
594 if ( rl >= gl && rl >= bl )
597 ( char* )&chv[ indx ], ( size_t )clrs,
598 sizeof ( struct chist_item ), redcompare
604 ( char* )&chv[ indx ], ( size_t )clrs,
605 sizeof ( struct chist_item ), greencompare
611 ( char* )&chv[ indx ], ( size_t )clrs,
612 sizeof ( struct chist_item ), bluecompare
617 lowersum = chv[ indx ].value;
620 for ( i = 1; i < clrs - 1; ++i) {
622 if ( lowersum >= halfsum ) break;
624 lowersum += chv[ indx + i ].value;
629 bv[ bi ].sum = lowersum;
631 bv[ boxes ].index = indx + i;
632 bv[ boxes ].colors = clrs - i;
633 bv[ boxes++ ].sum = sm - lowersum;
636 ( char* )bv, ( size_t )boxes, sizeof ( struct box ), sumcompare
641 for ( bi = 0; bi < boxes; ++bi ) {
643 int indx = bv[ bi ].index;
644 int clrs = bv[ bi ].colors;
645 long r = 0, g = 0, b = 0, sum = 0;
647 for ( i = 0; i < clrs; ++i ) {
649 r += PPM_GETR( chv[ indx + i ].color ) * chv[ indx + i ].value;
650 g += PPM_GETG( chv[ indx + i ].color ) * chv[ indx + i ].value;
651 b += PPM_GETB( chv[ indx + i ].color ) * chv[ indx + i ].value;
653 sum += chv[ indx + i ].value;
655 } // end for ( i . . . )
657 r = r / sum; if ( r > maxval ) r = maxval;
658 g = g / sum; if ( g > maxval ) g = maxval;
659 b = b / sum; if ( b > maxval ) b = maxval;
661 PPM_ASSIGN( colormap[ bi ].color, ( BYTE )r, ( BYTE )g, ( BYTE )b );
663 } // end for ( bi . . . )
671 static int redcompare ( const void* p1, const void* p2 ) {
673 return ( int )PPM_GETR( ( ( chist_vec )p1 ) -> color ) -
674 ( int )PPM_GETR( ( ( chist_vec )p2 ) -> color );
678 static int greencompare ( const void* p1, const void* p2 ) {
680 return ( int )PPM_GETG( ( ( chist_vec )p1 ) -> color ) -
681 ( int )PPM_GETG( ( ( chist_vec )p2 ) -> color );
683 } // end greencompare
685 static int bluecompare ( const void* p1, const void* p2 ) {
687 return ( int )PPM_GETB( ( ( chist_vec )p1 ) -> color ) -
688 ( int )PPM_GETB( ( ( chist_vec )p2 ) -> color );
692 static int sumcompare ( const void* p1, const void* p2 ) {
694 return ( ( box_vector )p2 ) -> sum - ( ( box_vector )p1 ) -> sum;
698 static chash_table ppm_allocchash ( void ) {
702 cht = ( chash_table )MALLOC( HASH_SIZE * sizeof ( chist_list ) );
706 } // end ppm_allocchash
708 static chist_vec __fastcall ppm_computechist (
709 pixel** pixels, int cols, int rows, int maxcolors,
716 cht = ppm_computechash ( pixels, cols, rows, maxcolors, colorsP );
718 if ( cht == NULL ) return ( chist_vec )NULL;
720 chv = ppm_chashtochist ( cht, maxcolors );
722 ppm_freechash ( cht );
726 } // end ppm_computechist
728 static chash_table __fastcall ppm_computechash (
729 pixel** pixels, int cols, int rows, int maxcolors,
738 cht = ppm_allocchash ();
741 for ( row = 0; row < rows; ++row )
743 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) {
745 hash = ppm_hashpixel ( *pP );
747 for ( chl = cht[ hash ]; chl != ( chist_list )0; chl = chl -> next )
749 if ( PPM_EQUAL( chl -> ch.color, *pP ) ) break;
751 if ( chl != ( chist_list)0 )
757 if ( ( *colorsP )++ > maxcolors ) {
759 ppm_freechash ( cht );
761 return ( chash_table )NULL;
765 chl = ( chist_list )MALLOC( sizeof( struct chist_list_item ) );
767 if ( chl == NULL ) return ( chash_table )NULL;
769 chl -> ch.color = *pP;
771 chl -> next = cht[ hash ];
780 } // end ppm_computechash
782 static chist_vec __fastcall ppm_chashtochist ( chash_table cht, int maxcolors ) {
788 chv = ( chist_vec )MALLOC( maxcolors * sizeof ( struct chist_item ) );
790 if ( chv == NULL) return chv;
794 for ( i = 0; i < HASH_SIZE; ++i )
796 for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chl -> next ) {
798 chv[ j ] = chl -> ch;
805 } // end ppm_chashtochist
807 static void __fastcall ppm_freechash ( chash_table cht ) {
810 chist_list chl, chlnext;
812 for ( i = 0; i < HASH_SIZE; ++i )
814 for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chlnext ) {
816 chlnext = chl -> next;
823 } // end ppm_freechash
825 static int __fastcall quick_check (
826 PBYTE pic24, int w, int h, PBYTE pic8, LPRGBQUAD rgbmap
829 unsigned long colors[ 256 ], col;
830 int i, j, nc, low, high, mid, pad;
835 // pad = PAD( w * 3 );
838 for ( i = 0, p = pic24; i < h; ++i ) {
840 for ( j = 0; j < w; ++j ) {
842 col = ( ( ( unsigned long )*p++ ) << 16 );
843 col += ( ( ( unsigned long )*p++ ) << 8 );
844 col += ( ( ( unsigned long )*p++ ) << 0 );
846 low = 0; high = nc - 1;
848 while ( low <= high ) {
850 mid = ( low + high ) / 2;
852 if ( col < colors[ mid ] )
856 else if ( col > colors[ mid ] )
866 if ( nc >= 256 ) return FALSE;
869 ( char* )&colors[ low + 1 ], ( char* )&colors[ low ],
870 ( nc - low ) * sizeof ( unsigned long )
878 } // end for ( j . . . )
882 } // end for ( i . . . )
884 for ( i = 0, p = pic24, pix = pic8; i < h; ++i ) {
886 for ( j = 0; j < w; ++j ) {
888 col = ( ( ( unsigned long )*p++ ) << 16 );
889 col += ( ( ( unsigned long )*p++ ) << 8 );
892 low = 0; high = nc - 1;
894 while ( low <= high ) {
896 mid = ( low + high ) / 2;
898 if ( col < colors[ mid ] )
902 else if ( col > colors[ mid ] )
912 } // end for ( j . . . )
916 } // end for ( i . . . )
918 for ( i = 0; i < nc; ++i, ++rgbmap ) {
920 rgbmap -> rgbRed = ( BYTE )( colors[ i ] >> 0 ) & 0xFF;
921 rgbmap -> rgbGreen = ( BYTE )( colors[ i ] >> 8 ) & 0xFF;
922 rgbmap -> rgbBlue = ( BYTE )( colors[ i ] >> 16 ) & 0xFF;
930 #ifdef BSHIFT //HPUX COMPATIBILLITY
939 #define RANGE( a, b, c ) { if ( a < b ) a = b; if ( a > c ) a = c; }
941 //static int __fastcall quick_quant (
942 // PBYTE p24, int w, int h, PBYTE p8, LPRGBQUAD rgbmap
947 // PINT thisline, nextline, thisptr, nextptr, tmpptr;
948 // int i, j, val, pwide3;
952 //// pad = PAD( w * 3 );
960 // for ( i = 0; i < 256; ++i ) {
962 // rgbmap[ i ].rgbRed = ( ( ( i << RSHIFT ) & RMASK ) * 255 + RMASK / 2 ) / RMASK;
963 // rgbmap[ i ].rgbGreen = ( ( ( i << GSHIFT ) & GMASK ) * 255 + GMASK / 2 ) / GMASK;
964 // rgbmap[ i ].rgbBlue = ( ( ( i << BSHIFT ) & BMASK ) * 255 + BMASK / 2 ) / BMASK;
968 // thisline = ( PINT )MALLOC( pwide3 * sizeof ( int ) );
970 // if ( thisline == NULL ) return 1;
972 // nextline = ( PINT )MALLOC( pwide3 * sizeof ( int ) );
974 // if ( nextline == NULL ) {
981 // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;
985 // for ( i = 0; i < h; ++i ) {
987 // tmpptr = thisline;
988 // thisline = nextline;
989 // nextline = tmpptr;
991 // if ( i != imax ) {
993 // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;
999 // for ( j = 0, thisptr = thisline, nextptr = nextline; j < w; ++j, ++pp ) {
1002 // RANGE( r1, 0, 255 );
1010 // val = ( ( ( r1 & RMASK ) >> RSHIFT ) |
1011 // ( ( g1 & GMASK ) >> GSHIFT ) |
1012 // ( ( b1 & BMASK ) >> BSHIFT ) );
1015 // r1 -= rgbmap[ val ].rgbRed;
1016 // g1 -= rgbmap[ val ].rgbGreen;
1017 // b1 -= rgbmap[ val ].rgbBlue;
1019 // if ( j != jmax ) {
1021 // thisptr[ 0 ] += ( r1 * 7 ) / 16;
1022 // thisptr[ 1 ] += ( g1 * 7 ) / 16;
1023 // thisptr[ 2 ] += ( b1 * 7 ) / 16;
1027 // if ( i != imax ) {
1029 // nextptr[ 0 ] += ( r1 * 5 ) / 16;
1030 // nextptr[ 1 ] += ( g1 * 5 ) / 16;
1031 // nextptr[ 2 ] += ( b1 * 5 ) / 16;
1035 // nextptr[ -3 ] += ( r1 * 3 ) / 16;
1036 // nextptr[ -2 ] += ( g1 * 3 ) / 16;
1037 // nextptr[ -1 ] += ( b1 * 3 ) / 16;
1041 // if ( j != jmax ) {
1043 // nextptr[ 3 ] += ( r1 ) / 16;
1044 // nextptr[ 4 ] += ( g1 ) / 16;
1045 // nextptr[ 5 ] += ( b1 ) / 16;
1053 // } // end for ( j . . . )
1055 // } // end for ( i . . . )
1057 // FREE( thisline );
1058 // FREE( nextline );
1062 //} // end quick_quant
1064 //*************************************************************************//