X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ad81651f00edc6f489d9b6a0839d316a964fd521..674ac8b919eecbc201b5f23b470a567cd0565e10:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index 1eaadf02e2..2f167850fc 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 ); } @@ -224,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") ); @@ -382,7 +405,7 @@ bool wxImage::LoadFile( const wxString& filename, long type ) wxBufferedInputStream bstream( stream ); return LoadFile(bstream, type); } - else + else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); @@ -402,7 +425,7 @@ bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype ) wxBufferedInputStream bstream( stream ); return LoadFile(bstream, mimetype); } - else + else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); @@ -747,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; @@ -939,7 +962,7 @@ wxImage::wxImage( const wxBitmap &bitmap ) // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); - LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); + BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); if( !lpDIBh ) { wxFAIL_MSG( wxT("could not allocate data for DIB header") ); @@ -1054,31 +1077,31 @@ wxBitmap wxImage::ConvertToBitmap() const int height = GetHeight(); // Create picture - + wxBitmap bitmap( width , height , wxDisplayDepth() ) ; - + // Create mask - + 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 ); */ } - + // Render - + int r_mask = GetMaskRed(); int g_mask = GetMaskGreen(); int b_mask = GetMaskBlue(); - + CGrafPtr origPort ; GDHandle origDevice ; @@ -1086,7 +1109,7 @@ wxBitmap wxImage::ConvertToBitmap() const SetGWorld( bitmap.GetHBITMAP() , NULL ) ; register unsigned char* data = GetData(); - + int index = 0; for (int y = 0; y < height; y++) { @@ -1102,7 +1125,7 @@ wxBitmap wxImage::ConvertToBitmap() const 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 ; @@ -1136,9 +1159,9 @@ wxBitmap wxImage::ConvertToBitmap() const } // for height SetGWorld( origPort , origDevice ) ; - + return bitmap; - + } wxImage::wxImage( const wxBitmap &bitmap ) @@ -1149,11 +1172,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 ) @@ -1161,18 +1184,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 ); @@ -1205,13 +1228,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; @@ -1227,7 +1250,7 @@ wxImage::wxImage( const wxBitmap &bitmap ) } ptbits += padding; } - + // similarly, set data according to the possible mask bitmap if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() ) { @@ -1237,9 +1260,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; idepth; - if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15; + if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent ); + bpp = visual->depth; + if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15; + } + if (bitmap.GetBitmap()) + { + bpp = 1; + } GdkColormap *cmap = gtk_widget_get_default_colormap(); @@ -1559,7 +1586,21 @@ 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) + 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 (bpp <= 8) { data[pos] = cmap->colors[pixel].red >> 8; data[pos+1] = cmap->colors[pixel].green >> 8; @@ -1629,6 +1670,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 ) +{ + this->size = 0; + this->colors = (XColor*) NULL; + this->color = (unsigned int *) NULL; + this->entry = (int*) NULL; + + this->bottom = 0; + this->top = 0; +} + +wxSearchColor::wxSearchColor( int size, XColor *colors ) +{ + int i; + this->size = size; + this->colors = colors; + this->color = new unsigned int[size]; + this->entry = new int [size]; + + for (i = 0; i < this->size; i++ ) { + this->entry[i] = -1; + } + + this->bottom = this->top = ( size >> 1 ); +} + +wxSearchColor::~wxSearchColor( void ) +{ + if ( this->color ) delete this->color; + if ( this->entry ) delete this->entry; +} + +int wxSearchColor::SearchColor( int r, int g, int b ) +{ + unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b; + int begin = this->bottom; + int end = this->top; + int middle; + + while ( begin <= end ) { + + middle = ( begin + end ) >> 1; + + if ( value == this->color[middle] ) { + return( this->entry[middle] ); + } else if ( value < this->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 ( this->entry[pos] < 0 ) { + this->color[pos] = value; + this->entry[pos] = pixel; + } else if ( value < this->color[pos] ) { + + if ( this->bottom > 0 ) { + for ( i = this->bottom; i < pos; i++ ) { + this->color[i-1] = this->color[i]; + this->entry[i-1] = this->entry[i]; + } + this->bottom--; + this->color[pos-1] = value; + this->entry[pos-1] = pixel; + } else if ( this->top < this->size-1 ) { + for ( i = this->top; i >= pos; i-- ) { + this->color[i+1] = this->color[i]; + this->entry[i+1] = this->entry[i]; + } + this->top++; + this->color[pos] = value; + this->entry[pos] = pixel; + } + + } else { + + if ( this->top < this->size-1 ) { + for ( i = this->top; i > pos; i-- ) { + this->color[i+1] = this->color[i]; + this->entry[i+1] = this->entry[i]; + } + this->top++; + this->color[pos+1] = value; + this->entry[pos+1] = pixel; + } else if ( this->bottom > 0 ) { + for ( i = this->bottom; i < pos; i++ ) { + this->color[i-1] = this->color[i]; + this->entry[i-1] = this->entry[i]; + } + this->bottom--; + this->color[pos] = value; + this->entry[pos] = pixel; + } + + } + + return( pixel ); +} + wxBitmap wxImage::ConvertToBitmap() const { wxBitmap bitmap; @@ -1719,6 +1933,7 @@ wxBitmap wxImage::ConvertToBitmap() const XQueryColors( dpy, cmap, colors, 256 ); } + wxSearchColor scolor( 256, colors ); unsigned char* data = GetData(); int index = 0; @@ -1747,6 +1962,7 @@ wxBitmap wxImage::ConvertToBitmap() const { case 8: { +#if 0 // Old, slower code int pixel = -1; /* if (wxTheApp->m_colorCube) @@ -1769,6 +1985,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; } @@ -2297,3 +2517,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; +} + +