2 // Copyright (c) 1998-1999 Matra Datavision
3 // Copyright (c) 1999-2012 OPEN CASCADE SAS
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.
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.
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.
20 // Notes: Most of code is taken from Xw_save_gif_image.c file (ZOV)
22 #include <AlienImage_GIFLZWDict.hxx>
25 const Handle(Standard_Type)& STANDARD_TYPE(AlienImage_GIFLZWDict)
27 static Handle(Standard_Type) _atype =
28 new Standard_Type ("AlienImage_GIFLZWDict", sizeof (AlienImage_GIFLZWDict));
32 //=============================================================================
33 // Functions to write GIF image to file.
34 //=============================================================================
36 //===================== Static definitions ===================
37 static AlienImage_GIFLZWDict* dict;
38 static int startBits, codeBits, nextCode, bumpCode, rack, mask, putIdx,
39 ClearCode, EOFCode, FreeCode;
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&);
47 //=============================================================================
48 int _lzw_encode (OSD_File& file, const BYTE* pData, int width, int height, int inc)
51 BYTE byte, OutBuff [BUFF_SIZE];
55 dict = (AlienImage_GIFLZWDict*) malloc (sizeof (AlienImage_GIFLZWDict)*TBL_SIZE);
67 ClearCode = 1 << startBits;
68 EOFCode = ClearCode + 1;
69 FreeCode = EOFCode + 1;
75 file.Write (&byte, sizeof(byte));
79 strCode = pLine[ x++ ];
81 if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file))
88 i = _find_child ( strCode, chr );
90 if ( dict[ i ].code != UNUSED )
91 strCode = dict[ i ].code;
94 dict[ i ].code = nextCode++;
95 dict[ i ].prnt = strCode;
98 if (!_put_bits (OutBuff, (ULONG) strCode, codeBits, file))
103 if (nextCode > MAX_CODE) {
104 if (!_put_bits (OutBuff, (ULONG) ClearCode, codeBits, file))
109 else if (nextCode > bumpCode) {
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;
137 //====================================================================
138 static void _init_dict ()
140 memset (dict, UNUSED, sizeof (AlienImage_GIFLZWDict)*TBL_SIZE);
142 codeBits = startBits + 1;
143 bumpCode = 1 << codeBits;
146 //====================================================================
147 static int _find_child (int prntCode, int chr)
151 idx = ( chr << ( NBITS - 8 ) ) ^ prntCode;
152 offset = idx ? TBL_SIZE - idx : 1;
156 if (dict[ idx ].code == UNUSED ||
157 dict[ idx ].prnt == prntCode && dict[ idx ].byte == ( BYTE )chr)
160 idx = ( idx >= offset ) ? idx - offset : idx + TBL_SIZE - offset;
164 //====================================================================
165 static BOOL _put_bits (BYTE *OutBuff, ULONG code, UINT nBits, OSD_File& file)
172 while (msk != (ULONG) (1 << nBits)) {
177 if ((mask & 0xFF) == 0) {
178 OutBuff[ putIdx++ ] = rack;
181 if (putIdx == BUFF_SIZE) {
182 file.Write (OutBuff, BUFF_SIZE);
183 if (file.Failed ()) {
198 //====================================================================
199 static BOOL _flush_bits (BYTE* OutBuff, OSD_File& file)
204 if ( mask != 0x01 ) {
205 OutBuff[ putIdx++ ] = rack;
210 file.Write (OutBuff, putIdx);
217 file.Write (&byte, 1);
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 );
231 BOOL __fastcall _convert24to8 (
232 LPRGBQUAD cTable, PBYTE pData24, PBYTE pData8,
238 if ( quick_check ( pData24, w, h, pData8, cTable ) ) {
242 } else if ( ppm_quant ( pData24, w, h, pData8, cTable ) != -1 ) {
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;
255 } // end _convert24to8
257 //*************************************************************************//
258 //* The following code based on code from the 'pbmplus' package written by //
260 //*************************************************************************//
262 #define MAXCOLORS 32767
264 #define PPM_GETR( p ) ( ( p ).r )
265 #define PPM_GETG( p ) ( ( p ).g )
266 #define PPM_GETB( p ) ( ( p ).b )
268 #define PPM_ASSIGN( p, red, grn, blu ) \
269 { ( p ).r = ( red ); ( p ).g = ( grn ); ( p ).b = ( blu ); }
271 #define PPM_EQUAL( p, q ) \
272 ( ( p ).r == ( q ).r && ( p ).g == ( q ).g && ( p ).b == ( q ).b )
275 #define PPM_DEPTH( newp, p, oldmaxval, newmaxval ) \
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 ) \
284 #define HASH_SIZE 6553
286 #define ppm_hashpixel( p ) \
287 ( ( ( ( int )PPM_GETR( p ) * 33023 + \
288 ( int )PPM_GETG( p ) * 30013 + \
289 ( int )PPM_GETB( p ) * 27011 \
294 #define PPM_LUMIN( p ) \
295 ( 77 * PPM_GETR( p ) + 150 * PPM_GETG( p ) + 29 * PPM_GETB( p ) )
297 typedef struct { BYTE r, g, b; } pixel;
304 typedef struct chist_item* chist_vec;
306 typedef struct chist_list_item* chist_list;
307 typedef chist_list* chash_table;
309 struct chist_list_item {
310 struct chist_item ch;
320 typedef struct box* box_vector;
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 );
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* );
335 static int __fastcall ppm_quant (
336 PBYTE pic24, int cols, int rows, PBYTE pic8, LPRGBQUAD rgbmap
344 BYTE maxval, newmaxval;
347 chist_vec chv, colormap;
356 // pad = PAD( cols * 3 );
359 pixels = ( pixel** )MALLOC( rows * sizeof ( pixel* ) );
361 if ( pixels == NULL ) return -1;
363 for ( row = 0; row < rows; ++row ) {
365 pixels[ row ] = ( pixel* )MALLOC( cols * sizeof ( pixel ) );
367 if ( pixels[ row ] == NULL ) {
369 while ( --row >= 0 ) FREE( pixels[ row ] );
377 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) {
391 chv = ppm_computechist ( pixels, cols, rows, MAXCOLORS, &colors );
393 if ( chv != ( chist_vec )0 ) break;
395 newmaxval = maxval / 2;
397 for ( row = 0; row < rows; ++row )
399 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP )
401 PPM_DEPTH( *pP, *pP, maxval, newmaxval );
407 colormap = mediancut ( chv, colors, rows * cols, maxval, 256 );
409 if ( colormap == ( chist_vec )NULL ) {
411 ppm_freechist ( chv );
417 ppm_freechist ( chv );
419 cht = ppm_allocchash ();
423 for ( row = 0; row < rows; ++row ) {
434 hash = ppm_hashpixel ( *pP );
436 for ( chl = cht[ hash ]; chl; chl = chl -> next )
438 if ( PPM_EQUAL( chl -> ch.color, *pP ) ) {
440 index = chl -> ch.value;
447 int i, r1, g1, b1, r2, g2, b2;
450 r1 = PPM_GETR( *pP );
451 g1 = PPM_GETG( *pP );
452 b1 = PPM_GETB( *pP );
455 for ( i = 0; i < 256; ++i ) {
457 r2 = PPM_GETR( colormap[ i ].color );
458 g2 = PPM_GETG( colormap[ i ].color );
459 b2 = PPM_GETB( colormap[ i ].color );
461 newdist = ( r1 - r2 ) * ( r1 - r2 ) +
462 ( g1 - g2 ) * ( g1 - g2 ) +
463 ( b1 - b2 ) * ( b1 - b2 );
465 if ( newdist < dist ) {
474 hash = ppm_hashpixel( *pP );
475 chl = ( chist_list )MALLOC( sizeof ( struct chist_list_item ) );
479 ppm_freechash ( cht );
484 chl -> ch.color = *pP;
485 chl -> ch.value = index;
486 chl -> next = cht[ hash ];
495 } while ( col != limitcol );
499 for ( i = 0, pRGB = rgbmap; i < 256; ++i, ++pRGB ) {
501 PPM_DEPTH( colormap[ i ].color, colormap[ i ].color, maxval, 255 );
503 pRGB -> rgbRed = PPM_GETR( colormap[ i ].color );
504 pRGB -> rgbGreen = PPM_GETG( colormap[ i ].color );
505 pRGB -> rgbBlue = PPM_GETB( colormap[ i ].color );
509 for ( i = 0; i < rows; ++i ) FREE( pixels[ i ] );
513 ppm_freechist ( colormap );
514 ppm_freechash ( cht );
520 static void __fastcall ppm_freechist ( chist_vec chv ) {
522 FREE( ( LPVOID )chv );
524 } // end ppm_freechist
526 static chist_vec __fastcall mediancut (
527 chist_vec chv, int colors, int sum,
528 int maxval, int newcolors
536 bv = ( box_vector )MALLOC( sizeof( struct box ) * newcolors );
538 if ( bv == NULL ) return ( chist_vec )NULL;
540 colormap = ( chist_vec )MALLOC( sizeof( struct chist_item ) * newcolors );
542 if ( colormap == NULL ) {
545 return ( chist_vec )NULL;
549 for ( i = 0; i < newcolors; ++i ) PPM_ASSIGN( colormap[ i ].color, 0, 0, 0 );
552 bv[ 0 ].colors = colors;
556 while ( boxes < newcolors ) {
560 int minr, maxr, ming, maxg, minb, maxb, v;
561 int halfsum, lowersum;
563 for ( bi = 0; bv[ bi ].colors < 2 && bi < boxes; ++bi );
565 if ( bi == boxes ) break;
567 indx = bv[ bi ].index;
568 clrs = bv[ bi ].colors;
571 minr = maxr = PPM_GETR( chv[ indx ].color );
572 ming = maxg = PPM_GETG( chv[ indx ].color );
573 minb = maxb = PPM_GETB( chv[ indx ].color );
575 for ( i = 1; i < clrs; ++i ) {
577 v = PPM_GETR( chv[ indx + i ].color );
579 if ( v < minr ) minr = v;
580 if ( v > maxr ) maxr = v;
582 v = PPM_GETG( chv[ indx + i ].color );
584 if ( v < ming ) ming = v;
585 if ( v > maxg ) maxg = v;
587 v = PPM_GETB( chv[ indx + i ].color );
589 if ( v < minb ) minb = v;
590 if ( v > maxb ) maxb = v;
594 { // begin local block
599 PPM_ASSIGN( p, maxr - minr, 0, 0 );
602 PPM_ASSIGN( p, 0, maxg - ming, 0 );
605 PPM_ASSIGN( p, 0, 0, maxb - minb );
608 if ( rl >= gl && rl >= bl )
611 ( char* )&chv[ indx ], ( size_t )clrs,
612 sizeof ( struct chist_item ), redcompare
618 ( char* )&chv[ indx ], ( size_t )clrs,
619 sizeof ( struct chist_item ), greencompare
625 ( char* )&chv[ indx ], ( size_t )clrs,
626 sizeof ( struct chist_item ), bluecompare
631 lowersum = chv[ indx ].value;
634 for ( i = 1; i < clrs - 1; ++i) {
636 if ( lowersum >= halfsum ) break;
638 lowersum += chv[ indx + i ].value;
643 bv[ bi ].sum = lowersum;
645 bv[ boxes ].index = indx + i;
646 bv[ boxes ].colors = clrs - i;
647 bv[ boxes++ ].sum = sm - lowersum;
650 ( char* )bv, ( size_t )boxes, sizeof ( struct box ), sumcompare
655 for ( bi = 0; bi < boxes; ++bi ) {
657 int indx = bv[ bi ].index;
658 int clrs = bv[ bi ].colors;
659 long r = 0, g = 0, b = 0, sum = 0;
661 for ( i = 0; i < clrs; ++i ) {
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;
667 sum += chv[ indx + i ].value;
669 } // end for ( i . . . )
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;
675 PPM_ASSIGN( colormap[ bi ].color, ( BYTE )r, ( BYTE )g, ( BYTE )b );
677 } // end for ( bi . . . )
685 static int redcompare ( const void* p1, const void* p2 ) {
687 return ( int )PPM_GETR( ( ( chist_vec )p1 ) -> color ) -
688 ( int )PPM_GETR( ( ( chist_vec )p2 ) -> color );
692 static int greencompare ( const void* p1, const void* p2 ) {
694 return ( int )PPM_GETG( ( ( chist_vec )p1 ) -> color ) -
695 ( int )PPM_GETG( ( ( chist_vec )p2 ) -> color );
697 } // end greencompare
699 static int bluecompare ( const void* p1, const void* p2 ) {
701 return ( int )PPM_GETB( ( ( chist_vec )p1 ) -> color ) -
702 ( int )PPM_GETB( ( ( chist_vec )p2 ) -> color );
706 static int sumcompare ( const void* p1, const void* p2 ) {
708 return ( ( box_vector )p2 ) -> sum - ( ( box_vector )p1 ) -> sum;
712 static chash_table ppm_allocchash ( void ) {
716 cht = ( chash_table )MALLOC( HASH_SIZE * sizeof ( chist_list ) );
720 } // end ppm_allocchash
722 static chist_vec __fastcall ppm_computechist (
723 pixel** pixels, int cols, int rows, int maxcolors,
730 cht = ppm_computechash ( pixels, cols, rows, maxcolors, colorsP );
732 if ( cht == NULL ) return ( chist_vec )NULL;
734 chv = ppm_chashtochist ( cht, maxcolors );
736 ppm_freechash ( cht );
740 } // end ppm_computechist
742 static chash_table __fastcall ppm_computechash (
743 pixel** pixels, int cols, int rows, int maxcolors,
752 cht = ppm_allocchash ();
755 for ( row = 0; row < rows; ++row )
757 for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) {
759 hash = ppm_hashpixel ( *pP );
761 for ( chl = cht[ hash ]; chl != ( chist_list )0; chl = chl -> next )
763 if ( PPM_EQUAL( chl -> ch.color, *pP ) ) break;
765 if ( chl != ( chist_list)0 )
771 if ( ( *colorsP )++ > maxcolors ) {
773 ppm_freechash ( cht );
775 return ( chash_table )NULL;
779 chl = ( chist_list )MALLOC( sizeof( struct chist_list_item ) );
781 if ( chl == NULL ) return ( chash_table )NULL;
783 chl -> ch.color = *pP;
785 chl -> next = cht[ hash ];
794 } // end ppm_computechash
796 static chist_vec __fastcall ppm_chashtochist ( chash_table cht, int maxcolors ) {
802 chv = ( chist_vec )MALLOC( maxcolors * sizeof ( struct chist_item ) );
804 if ( chv == NULL) return chv;
808 for ( i = 0; i < HASH_SIZE; ++i )
810 for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chl -> next ) {
812 chv[ j ] = chl -> ch;
819 } // end ppm_chashtochist
821 static void __fastcall ppm_freechash ( chash_table cht ) {
824 chist_list chl, chlnext;
826 for ( i = 0; i < HASH_SIZE; ++i )
828 for ( chl = cht[ i ]; chl != ( chist_list )0; chl = chlnext ) {
830 chlnext = chl -> next;
837 } // end ppm_freechash
839 static int __fastcall quick_check (
840 PBYTE pic24, int w, int h, PBYTE pic8, LPRGBQUAD rgbmap
843 unsigned long colors[ 256 ], col;
844 int i, j, nc, low, high, mid, pad;
849 // pad = PAD( w * 3 );
852 for ( i = 0, p = pic24; i < h; ++i ) {
854 for ( j = 0; j < w; ++j ) {
856 col = ( ( ( unsigned long )*p++ ) << 16 );
857 col += ( ( ( unsigned long )*p++ ) << 8 );
858 col += ( ( ( unsigned long )*p++ ) << 0 );
860 low = 0; high = nc - 1;
862 while ( low <= high ) {
864 mid = ( low + high ) / 2;
866 if ( col < colors[ mid ] )
870 else if ( col > colors[ mid ] )
880 if ( nc >= 256 ) return FALSE;
883 ( char* )&colors[ low + 1 ], ( char* )&colors[ low ],
884 ( nc - low ) * sizeof ( unsigned long )
892 } // end for ( j . . . )
896 } // end for ( i . . . )
898 for ( i = 0, p = pic24, pix = pic8; i < h; ++i ) {
900 for ( j = 0; j < w; ++j ) {
902 col = ( ( ( unsigned long )*p++ ) << 16 );
903 col += ( ( ( unsigned long )*p++ ) << 8 );
906 low = 0; high = nc - 1;
908 while ( low <= high ) {
910 mid = ( low + high ) / 2;
912 if ( col < colors[ mid ] )
916 else if ( col > colors[ mid ] )
926 } // end for ( j . . . )
930 } // end for ( i . . . )
932 for ( i = 0; i < nc; ++i, ++rgbmap ) {
934 rgbmap -> rgbRed = ( BYTE )( colors[ i ] >> 0 ) & 0xFF;
935 rgbmap -> rgbGreen = ( BYTE )( colors[ i ] >> 8 ) & 0xFF;
936 rgbmap -> rgbBlue = ( BYTE )( colors[ i ] >> 16 ) & 0xFF;
944 #ifdef BSHIFT //HPUX COMPATIBILLITY
953 #define RANGE( a, b, c ) { if ( a < b ) a = b; if ( a > c ) a = c; }
955 //static int __fastcall quick_quant (
956 // PBYTE p24, int w, int h, PBYTE p8, LPRGBQUAD rgbmap
961 // PINT thisline, nextline, thisptr, nextptr, tmpptr;
962 // int i, j, val, pwide3;
966 //// pad = PAD( w * 3 );
974 // for ( i = 0; i < 256; ++i ) {
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;
982 // thisline = ( PINT )MALLOC( pwide3 * sizeof ( int ) );
984 // if ( thisline == NULL ) return 1;
986 // nextline = ( PINT )MALLOC( pwide3 * sizeof ( int ) );
988 // if ( nextline == NULL ) {
995 // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;
999 // for ( i = 0; i < h; ++i ) {
1001 // tmpptr = thisline;
1002 // thisline = nextline;
1003 // nextline = tmpptr;
1005 // if ( i != imax ) {
1007 // for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;
1013 // for ( j = 0, thisptr = thisline, nextptr = nextline; j < w; ++j, ++pp ) {
1016 // RANGE( r1, 0, 255 );
1024 // val = ( ( ( r1 & RMASK ) >> RSHIFT ) |
1025 // ( ( g1 & GMASK ) >> GSHIFT ) |
1026 // ( ( b1 & BMASK ) >> BSHIFT ) );
1029 // r1 -= rgbmap[ val ].rgbRed;
1030 // g1 -= rgbmap[ val ].rgbGreen;
1031 // b1 -= rgbmap[ val ].rgbBlue;
1033 // if ( j != jmax ) {
1035 // thisptr[ 0 ] += ( r1 * 7 ) / 16;
1036 // thisptr[ 1 ] += ( g1 * 7 ) / 16;
1037 // thisptr[ 2 ] += ( b1 * 7 ) / 16;
1041 // if ( i != imax ) {
1043 // nextptr[ 0 ] += ( r1 * 5 ) / 16;
1044 // nextptr[ 1 ] += ( g1 * 5 ) / 16;
1045 // nextptr[ 2 ] += ( b1 * 5 ) / 16;
1049 // nextptr[ -3 ] += ( r1 * 3 ) / 16;
1050 // nextptr[ -2 ] += ( g1 * 3 ) / 16;
1051 // nextptr[ -1 ] += ( b1 * 3 ) / 16;
1055 // if ( j != jmax ) {
1057 // nextptr[ 3 ] += ( r1 ) / 16;
1058 // nextptr[ 4 ] += ( g1 ) / 16;
1059 // nextptr[ 5 ] += ( b1 ) / 16;
1067 // } // end for ( j . . . )
1069 // } // end for ( i . . . )
1071 // FREE( thisline );
1072 // FREE( nextline );
1076 //} // end quick_quant
1078 //*************************************************************************//