X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/68874acfedbd7dbe1aa9d17a5ccc389c7a721131..7818b39874176b529be814fdfdfb773d8b211d3a:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index 5931d63cb1..38d807f19e 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -71,7 +71,7 @@ wxImageRefData::wxImageRefData() wxImageRefData::~wxImageRefData() { - if (m_data) + if (m_data) free( m_data ); } @@ -81,9 +81,7 @@ wxList wxImage::sm_handlers; #define M_IMGDATA ((wxImageRefData *)m_refData) -#if !USE_SHARED_LIBRARIES IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) -#endif wxImage::wxImage() { @@ -226,6 +224,29 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const return image; } +void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, + unsigned char r2, unsigned char g2, unsigned char b2 ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + char unsigned *data = GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + { + if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1)) + { + data[0] = r2; + data[1] = g2; + data[2] = b2; + } + data += 3; + } +} + void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b ) { wxCHECK_RET( Ok(), wxT("invalid image") ); @@ -381,10 +402,10 @@ bool wxImage::LoadFile( const wxString& filename, long type ) if (wxFileExists(filename)) { wxFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); + wxBufferedInputStream bstream( stream ); return LoadFile(bstream, type); } - else + else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); @@ -401,10 +422,10 @@ bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype ) if (wxFileExists(filename)) { wxFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); + wxBufferedInputStream bstream( stream ); return LoadFile(bstream, mimetype); } - else + else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); @@ -422,7 +443,7 @@ bool wxImage::SaveFile( const wxString& filename, int type ) if ( stream.LastError() == wxStream_NOERROR ) { - wxBufferedOutputStream bstream( stream ); + wxBufferedOutputStream bstream( stream ); return SaveFile(bstream, type); } else @@ -437,7 +458,7 @@ bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) if ( stream.LastError() == wxStream_NOERROR ) { - wxBufferedOutputStream bstream( stream ); + wxBufferedOutputStream bstream( stream ); return SaveFile(bstream, mimetype); } else @@ -465,7 +486,7 @@ bool wxImage::CanRead( wxInputStream &stream ) { wxImageHandler *handler=(wxImageHandler*)node->GetData(); if (handler->CanRead( stream )) - return TRUE; + return TRUE; } return FALSE; @@ -659,9 +680,7 @@ void wxImage::CleanUpHandlers() // wxImageHandler //----------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARIES IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) -#endif #if wxUSE_STREAMS bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) @@ -751,7 +770,7 @@ wxBitmap wxImage::ConvertToBitmap() const // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); - LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); + BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") ); // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; @@ -864,7 +883,12 @@ wxBitmap wxImage::ConvertToBitmap() const { for(i=0; i> 3)+8) * height ); - + mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height ); - + wxMask *mask = new wxMask(); mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 ); - + bitmap.SetMask( mask ); */ } - + // Render - + int r_mask = GetMaskRed(); int g_mask = GetMaskGreen(); int b_mask = GetMaskBlue(); - - CGrafPtr origPort ; - GDHandle origDevice ; - - GetGWorld( &origPort , &origDevice ) ; - SetGWorld( bitmap.GetHBITMAP() , NULL ) ; + + CGrafPtr origPort ; + GDHandle origDevice ; + + GetGWorld( &origPort , &origDevice ) ; + SetGWorld( bitmap.GetHBITMAP() , NULL ) ; register unsigned char* data = GetData(); - + int index = 0; for (int y = 0; y < height; y++) { -#if 0 - unsigned char lastr = 0 ; - unsigned char lastg = 0 ; - unsigned char lastb = 0 ; - RGBColor lastcolor ; - - MoveTo( 0 , y ) ; for (int x = 0; x < width; x++) { - unsigned char r = data[index++]; - unsigned char g = data[index++]; - unsigned char b = data[index++]; - - if ( r != lastr || g != lastg || b != lastb ) - { - lastcolor.red = ( lastr << 8 ) + lastr ; - lastcolor.green = ( lastg << 8 ) + lastg ; - lastcolor.blue = ( lastb << 8 ) + lastb ; - RGBForeColor( &lastcolor ) ; - LineTo( x , y ) ; - lastr = r ; - lastg = g ; - lastb = b ; - } - } // for width - lastcolor.red = ( lastr << 8 ) + lastr ; - lastcolor.green = ( lastg << 8 ) + lastg ; - lastcolor.blue = ( lastb << 8 ) + lastb ; - RGBForeColor( &lastcolor ) ; - LineTo( width - 1 , y ) ; -#else - for (int x = 0; x < width; x++) - { - unsigned char r = data[index++]; - unsigned char g = data[index++]; - unsigned char b = data[index++]; - RGBColor color ; - color.red = ( r << 8 ) + r ; - color.green = ( g << 8 ) + g ; - color.blue = ( b << 8 ) + b ; - SetCPixel( x , y , &color ) ; - } -#endif + unsigned char r = data[index++]; + unsigned char g = data[index++]; + unsigned char b = data[index++]; + RGBColor color ; + color.red = ( r << 8 ) + r ; + color.green = ( g << 8 ) + g ; + color.blue = ( b << 8 ) + b ; + SetCPixel( x , y , &color ) ; + } } // for height - SetGWorld( origPort , origDevice ) ; - + SetGWorld( origPort , origDevice ) ; + + if ( HasMask() ) + { + wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue()); + wxMask *mask = new wxMask( bitmap, colour ); + bitmap.SetMask( mask ); + } return bitmap; - + } wxImage::wxImage( const wxBitmap &bitmap ) @@ -1153,11 +1151,11 @@ wxImage::wxImage( const wxBitmap &bitmap ) wxFAIL_MSG( "invalid bitmap" ); return; } - + // create an wxImage object int width = bitmap.GetWidth(); int height = bitmap.GetHeight(); - Create( width, height ); + Create( width, height ); /* unsigned char *data = GetData(); if( !data ) @@ -1165,18 +1163,18 @@ wxImage::wxImage( const wxBitmap &bitmap ) wxFAIL_MSG( "could not allocate data for image" ); return; } - + // calc the number of bytes per scanline and padding in the DIB int bytePerLine = width*3; int sizeDWORD = sizeof( DWORD ); div_t lineBoundary = div( bytePerLine, sizeDWORD ); int padding = 0; - if( lineBoundary.rem > 0 ) + if( lineBoundary.rem > 0 ) { padding = sizeDWORD - lineBoundary.rem; bytePerLine += padding; } - + // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); @@ -1209,13 +1207,13 @@ wxImage::wxImage( const wxBitmap &bitmap ) free( lpDIBh ); return; } - + // copy data from the device-dependent bitmap to the DIB HDC hdc = ::GetDC(NULL); HBITMAP hbitmap; hbitmap = (HBITMAP) bitmap.GetHBITMAP(); ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); - + // copy DIB data into the wxImage object int i, j; unsigned char *ptdata = data; @@ -1230,8 +1228,8 @@ wxImage::wxImage( const wxBitmap &bitmap ) ptbits += 3; } ptbits += padding; - } - + } + // similarly, set data according to the possible mask bitmap if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() ) { @@ -1241,9 +1239,9 @@ wxImage::wxImage( const wxBitmap &bitmap ) ::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); - ::DeleteDC( memdc ); + ::DeleteDC( memdc ); // background color set to RGB(16,16,16) in consistent with wxGTK - unsigned char r=16, g=16, b=16; + unsigned char r=16, g=16, b=16; ptdata = data; ptbits = lpBits; for( i=0; i #endif +wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue ) +{ + wxBitmap bitmap; + + wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") ); + + int width = GetWidth(); + int height = GetHeight(); + + bitmap.SetHeight( height ); + bitmap.SetWidth( width ); + + bitmap.SetBitmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 ) ); + + bitmap.SetDepth( 1 ); + + // Create picture image + + unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height ); + + GdkImage *data_image = + gdk_image_new_bitmap( gdk_visual_get_system(), data_data, width, height ); + + // Create mask image + + GdkImage *mask_image = (GdkImage*) NULL; + + if (HasMask()) + { + unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height ); + + mask_image = gdk_image_new_bitmap( gdk_visual_get_system(), mask_data, width, height ); + + wxMask *mask = new wxMask(); + mask->m_bitmap = gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, 1 ); + + bitmap.SetMask( mask ); + } + + int r_mask = GetMaskRed(); + int g_mask = GetMaskGreen(); + int b_mask = GetMaskBlue(); + + unsigned char* data = GetData(); + + int index = 0; + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + int r = data[index]; + index++; + int g = data[index]; + index++; + int b = data[index]; + index++; + + if (HasMask()) + { + if ((r == r_mask) && (b == b_mask) && (g == g_mask)) + gdk_image_put_pixel( mask_image, x, y, 1 ); + else + gdk_image_put_pixel( mask_image, x, y, 0 ); + } + + if ((r == red) && (b == blue) && (g == green)) + gdk_image_put_pixel( data_image, x, y, 1 ); + else + gdk_image_put_pixel( data_image, x, y, 0 ); + + } // for + } // for + + // Blit picture + + GdkGC *data_gc = gdk_gc_new( bitmap.GetBitmap() ); + + gdk_draw_image( bitmap.GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height ); + + gdk_image_destroy( data_image ); + gdk_gc_unref( data_gc ); + + // Blit mask + + if (HasMask()) + { + GdkGC *mask_gc = gdk_gc_new( bitmap.GetMask()->GetBitmap() ); + + gdk_draw_image( bitmap.GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height ); + + gdk_image_destroy( mask_image ); + gdk_gc_unref( mask_gc ); + } + + return bitmap; +} + + wxBitmap wxImage::ConvertToBitmap() const { wxBitmap bitmap; @@ -1409,14 +1505,6 @@ wxBitmap wxImage::ConvertToBitmap() const gdk_image_put_pixel( mask_image, x, y, 0 ); } - if (HasMask()) - { - if ((r == r_mask) && (b == b_mask) && (g == g_mask)) - gdk_image_put_pixel( mask_image, x, y, 1 ); - else - gdk_image_put_pixel( mask_image, x, y, 0 ); - } - switch (bpp) { case 8: @@ -1545,16 +1633,37 @@ wxImage::wxImage( const wxBitmap &bitmap ) SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable } - GdkVisual *visual = (GdkVisual*) NULL; + int bpp = -1; + int red_shift_right = 0; + int green_shift_right = 0; + int blue_shift_right = 0; + int red_shift_left = 0; + int green_shift_left = 0; + int blue_shift_left = 0; + bool use_shift = FALSE; + if (bitmap.GetPixmap()) - visual = gdk_window_get_visual( bitmap.GetPixmap() ); - else - visual = gdk_window_get_visual( bitmap.GetBitmap() ); - - if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent ); - int bpp = visual->depth; - if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15; + { + GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() ); + + if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent ); + bpp = visual->depth; + if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec; + red_shift_right = visual->red_shift; + red_shift_left = 8-visual->red_prec; + green_shift_right = visual->green_shift; + green_shift_left = 8-visual->green_prec; + blue_shift_right = visual->blue_shift; + blue_shift_left = 8-visual->blue_prec; + + use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR); + } + if (bitmap.GetBitmap()) + { + bpp = 1; + } + GdkColormap *cmap = gtk_widget_get_default_colormap(); long pos = 0; @@ -1562,40 +1671,38 @@ wxImage::wxImage( const wxBitmap &bitmap ) { for (int i = 0; i < bitmap.GetWidth(); i++) { - wxInt32 pixel = gdk_image_get_pixel( gdk_image, i, j ); - if (bpp <= 8) - { - data[pos] = cmap->colors[pixel].red >> 8; - data[pos+1] = cmap->colors[pixel].green >> 8; - data[pos+2] = cmap->colors[pixel].blue >> 8; - } else if (bpp == 15) + wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j ); + if (bpp == 1) + { + if (pixel == 0) + { + data[pos] = 0; + data[pos+1] = 0; + data[pos+2] = 0; + } + else + { + data[pos] = 255; + data[pos+1] = 255; + data[pos+2] = 255; + } + } + else if (use_shift) { -#if (wxBYTE_ORDER == wxBIG_ENDIAN) - // ? -#endif - data[pos] = (pixel >> 7) & 0xf8; - data[pos+1] = (pixel >> 2) & 0xf8; - data[pos+2] = (pixel << 3) & 0xf8; - } else if (bpp == 16) + data[pos] = (pixel >> red_shift_right) << red_shift_left; + data[pos+1] = (pixel >> green_shift_right) << green_shift_left; + data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left; + } + else if (cmap->colors) { -#if (wxBYTE_ORDER == wxBIG_ENDIAN) - // ? -#endif - data[pos] = (pixel >> 8) & 0xf8; - data[pos+1] = (pixel >> 3) & 0xfc; - data[pos+2] = (pixel << 3) & 0xf8; - } else + data[pos] = cmap->colors[pixel].red >> 8; + data[pos+1] = cmap->colors[pixel].green >> 8; + data[pos+2] = cmap->colors[pixel].blue >> 8; + } + else { -#if (wxBYTE_ORDER == wxBIG_ENDIAN) - data[pos] = (pixel) & 0xff; // Red - data[pos+1] = (pixel >> 8) & 0xff; // Green - data[pos+2] = (pixel >> 16) & 0xff; // Blue -#else - data[pos] = (pixel >> 16) & 0xff; - data[pos+1] = (pixel >> 8) & 0xff; - data[pos+2] = pixel & 0xff; -#endif - } + wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") ); + } if (gdk_image_mask) { @@ -1633,6 +1740,179 @@ wxImage::wxImage( const wxBitmap &bitmap ) #include "wx/utils.h" #include +/* + +Date: Wed, 05 Jan 2000 11:45:40 +0100 +From: Frits Boel +To: julian.smart@ukonline.co.uk +Subject: Patch for Motif ConvertToBitmap + +Hi Julian, + +I've been working on a wxWin application for image processing. From the +beginning, I was surprised by the (lack of) speed of ConvertToBitmap, +till I looked in the source code of image.cpp. I saw that converting a +wxImage to a bitmap with 8-bit pixels is done with comparing every pixel +to the 256 colors of the palet. A very time-consuming piece of code! + +Because I wanted a faster application, I've made a 'patch' for this. In +short: every pixel of the image is compared to a sorted list with +colors. If the color is found in the list, the palette entry is +returned; if the color is not found, the color palette is searched and +then the palette entry is returned and the color added to the sorted +list. + +Maybe there is another method for this, namely changing the palette +itself (if the colors are known, as is the case with tiffs with a +colormap). I did not look at this, maybe someone else did? + +The code of the patch is attached, have a look on it, and maybe you will +ship it with the next release of wxMotif? + +Regards, + +Frits Boel +Software engineer at Hubrecht Laboratory, The Netherlands. + +*/ + +class wxSearchColor +{ +public: + wxSearchColor( void ); + wxSearchColor( int size, XColor *colors ); + ~wxSearchColor( void ); + + int SearchColor( int r, int g, int b ); +private: + int AddColor( unsigned int value, int pos ); + + int size; + XColor *colors; + unsigned int *color; + int *entry; + + int bottom; + int top; +}; + +wxSearchColor::wxSearchColor( void ) +{ + size = 0; + colors = (XColor*) NULL; + color = (unsigned int *) NULL; + entry = (int*) NULL; + + bottom = 0; + top = 0; +} + +wxSearchColor::wxSearchColor( int size_, XColor *colors_ ) +{ + int i; + size = size_; + colors = colors_; + color = new unsigned int[size]; + entry = new int [size]; + + for (i = 0; i < size; i++ ) { + entry[i] = -1; + } + + bottom = top = ( size >> 1 ); +} + +wxSearchColor::~wxSearchColor( void ) +{ + if ( color ) delete color; + if ( entry ) delete entry; +} + +int wxSearchColor::SearchColor( int r, int g, int b ) +{ + unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b; + int begin = bottom; + int end = top; + int middle; + + while ( begin <= end ) { + + middle = ( begin + end ) >> 1; + + if ( value == color[middle] ) { + return( entry[middle] ); + } else if ( value < color[middle] ) { + end = middle - 1; + } else { + begin = middle + 1; + } + + } + + return AddColor( value, middle ); +} + +int wxSearchColor::AddColor( unsigned int value, int pos ) +{ + int i; + int pixel = -1; + int max = 3 * (65536); + for ( i = 0; i < 256; i++ ) { + int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red; + int gdiff = ((value ) & 0xFF00 ) - colors[i].green; + int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue; + int sum = abs (rdiff) + abs (gdiff) + abs (bdiff); + if (sum < max) { pixel = i; max = sum; } + } + + if ( entry[pos] < 0 ) { + color[pos] = value; + entry[pos] = pixel; + } else if ( value < color[pos] ) { + + if ( bottom > 0 ) { + for ( i = bottom; i < pos; i++ ) { + color[i-1] = color[i]; + entry[i-1] = entry[i]; + } + bottom--; + color[pos-1] = value; + entry[pos-1] = pixel; + } else if ( top < size-1 ) { + for ( i = top; i >= pos; i-- ) { + color[i+1] = color[i]; + entry[i+1] = entry[i]; + } + top++; + color[pos] = value; + entry[pos] = pixel; + } + + } else { + + if ( top < size-1 ) { + for ( i = top; i > pos; i-- ) { + color[i+1] = color[i]; + entry[i+1] = entry[i]; + } + top++; + color[pos+1] = value; + entry[pos+1] = pixel; + } else if ( bottom > 0 ) { + for ( i = bottom; i < pos; i++ ) { + color[i-1] = color[i]; + entry[i-1] = entry[i]; + } + bottom--; + color[pos] = value; + entry[pos] = pixel; + } + + } + + return( pixel ); +} + wxBitmap wxImage::ConvertToBitmap() const { wxBitmap bitmap; @@ -1723,6 +2003,7 @@ wxBitmap wxImage::ConvertToBitmap() const XQueryColors( dpy, cmap, colors, 256 ); } + wxSearchColor scolor( 256, colors ); unsigned char* data = GetData(); int index = 0; @@ -1751,6 +2032,7 @@ wxBitmap wxImage::ConvertToBitmap() const { case 8: { +#if 0 // Old, slower code int pixel = -1; /* if (wxTheApp->m_colorCube) @@ -1773,6 +2055,10 @@ wxBitmap wxImage::ConvertToBitmap() const /* } */ +#endif + + // And this is all to get the 'right' color... + int pixel = scolor.SearchColor( r, g, b ); XPutPixel( data_image, x, y, pixel ); break; } @@ -2301,3 +2587,93 @@ public: }; IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) + + +//----------------------------------------------------------------------------- + +// GRG, Dic/99 +// Counts and returns the number of different colours. Optionally stops +// when it exceeds 'stopafter' different colours. This is useful, for +// example, to see if the image can be saved as 8-bit (256 colour or +// less, in this case it would be invoked as CountColours(256)). Default +// value for stopafter is -1 (don't care). +// +unsigned long wxImage::CountColours( unsigned long stopafter ) +{ + wxHashTable h; + wxNode *node; + wxHNode *hnode; + unsigned char r, g, b, *p; + unsigned long size, nentries, key; + + p = GetData(); + size = GetWidth() * GetHeight(); + nentries = 0; + + for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++) + { + r = *(p++); + g = *(p++); + b = *(p++); + key = (r << 16) | (g << 8) | b; + + hnode = (wxHNode *) h.Get(key); + + if (!hnode) + { + h.Put(key, (wxObject *)(new wxHNode)); + nentries++; + } + } + + // delete all HNodes + h.BeginFind(); + while ((node = h.Next()) != NULL) + delete (wxHNode *)node->GetData(); + + return nentries; +} + + +// GRG, Dic/99 +// Computes the histogram of the image and fills a hash table, indexed +// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each +// wxHNode contains an 'index' (useful to build a palette with the image +// colours) and a 'value', which is the number of pixels in the image with +// that colour. +// +unsigned long wxImage::ComputeHistogram( wxHashTable &h ) +{ + unsigned char r, g, b, *p; + unsigned long size, nentries, key; + wxHNode *hnode; + + p = GetData(); + size = GetWidth() * GetHeight(); + nentries = 0; + + for (unsigned long j = 0; j < size; j++) + { + r = *(p++); + g = *(p++); + b = *(p++); + key = (r << 16) | (g << 8) | b; + + hnode = (wxHNode *) h.Get(key); + + if (hnode) + hnode->value++; + else + { + hnode = new wxHNode(); + hnode->index = nentries++; + hnode->value = 1; + + h.Put(key, (wxObject *)hnode); + } + } + + return nentries; +} + +