///////////////////////////////////////////////////////////////////////////// // Name: image.cpp // Purpose: wxImage // Author: Robert Roebling // RCS-ID: $Id$ // Copyright: (c) Robert Roebling // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "image.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "wx/image.h" #include "wx/bitmap.h" #include "wx/debug.h" #include "wx/log.h" #include "wx/app.h" #include "wx/filefn.h" #include "wx/wfstream.h" #include "wx/intl.h" #include "wx/module.h" // For memcpy #include #ifdef __SALFORDC__ #undef FAR #endif #ifdef __WXMSW__ #include "wx/msw/private.h" #endif //----------------------------------------------------------------------------- // wxImage //----------------------------------------------------------------------------- class wxImageRefData: public wxObjectRefData { public: wxImageRefData(); ~wxImageRefData(); int m_width; int m_height; unsigned char *m_data; bool m_hasMask; unsigned char m_maskRed,m_maskGreen,m_maskBlue; bool m_ok; }; wxImageRefData::wxImageRefData() { m_width = 0; m_height = 0; m_data = (unsigned char*) NULL; m_ok = FALSE; m_maskRed = 0; m_maskGreen = 0; m_maskBlue = 0; m_hasMask = FALSE; } wxImageRefData::~wxImageRefData() { if (m_data) free( m_data ); } wxList wxImage::sm_handlers; //----------------------------------------------------------------------------- #define M_IMGDATA ((wxImageRefData *)m_refData) IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) wxImage::wxImage() { } wxImage::wxImage( int width, int height ) { Create( width, height ); } wxImage::wxImage( const wxString& name, long type ) { LoadFile( name, type ); } wxImage::wxImage( const wxString& name, const wxString& mimetype ) { LoadFile( name, mimetype ); } #if wxUSE_STREAMS wxImage::wxImage( wxInputStream& stream, long type ) { LoadFile( stream, type ); } wxImage::wxImage( wxInputStream& stream, const wxString& mimetype ) { LoadFile( stream, mimetype ); } #endif // wxUSE_STREAMS wxImage::wxImage( const wxImage& image ) { Ref(image); } wxImage::wxImage( const wxImage* image ) { if (image) Ref(*image); } void wxImage::Create( int width, int height ) { m_refData = new wxImageRefData(); M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 ); if (M_IMGDATA->m_data) { for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0; M_IMGDATA->m_width = width; M_IMGDATA->m_height = height; M_IMGDATA->m_ok = TRUE; } else { UnRef(); } } void wxImage::Destroy() { UnRef(); } wxImage wxImage::Scale( int width, int height ) const { wxImage image; wxCHECK_MSG( Ok(), image, wxT("invalid image") ); wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") ); image.Create( width, height ); char unsigned *data = image.GetData(); wxCHECK_MSG( data, image, wxT("unable to create image") ); if (M_IMGDATA->m_hasMask) image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); long old_height = M_IMGDATA->m_height; long old_width = M_IMGDATA->m_width; char unsigned *source_data = M_IMGDATA->m_data; char unsigned *target_data = data; for (long j = 0; j < height; j++) { long y_offset = (j * old_height / height) * old_width; for (long i = 0; i < width; i++) { memcpy( target_data, source_data + 3*(y_offset + ((i * old_width )/ width)), 3 ); target_data += 3; } } return image; } wxImage wxImage::GetSubImage( const wxRect &rect ) const { wxImage image; wxCHECK_MSG( Ok(), image, wxT("invalid image") ); wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), image, wxT("invalid subimage size") ); int subwidth=rect.GetWidth(); const int subheight=rect.GetHeight(); image.Create( subwidth, subheight ); char unsigned *subdata = image.GetData(), *data=GetData(); wxCHECK_MSG( subdata, image, wxT("unable to create image") ); if (M_IMGDATA->m_hasMask) image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); const int subleft=3*rect.GetLeft(); const int width=3*GetWidth(); subwidth*=3; data+=rect.GetTop()*width+subleft; for (long j = 0; j < subheight; ++j) { memcpy( subdata, data, subwidth); subdata+=subwidth; data+=width; } 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") ); int w = M_IMGDATA->m_width; int h = M_IMGDATA->m_height; wxCHECK_RET( (x>=0) && (y>=0) && (xm_data[ pos ] = r; M_IMGDATA->m_data[ pos+1 ] = g; M_IMGDATA->m_data[ pos+2 ] = b; } unsigned char wxImage::GetRed( int x, int y ) { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); int w = M_IMGDATA->m_width; int h = M_IMGDATA->m_height; wxCHECK_MSG( (x>=0) && (y>=0) && (xm_data[pos]; } unsigned char wxImage::GetGreen( int x, int y ) { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); int w = M_IMGDATA->m_width; int h = M_IMGDATA->m_height; wxCHECK_MSG( (x>=0) && (y>=0) && (xm_data[pos+1]; } unsigned char wxImage::GetBlue( int x, int y ) { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); int w = M_IMGDATA->m_width; int h = M_IMGDATA->m_height; wxCHECK_MSG( (x>=0) && (y>=0) && (xm_data[pos+2]; } bool wxImage::Ok() const { return (M_IMGDATA && M_IMGDATA->m_ok); } char unsigned *wxImage::GetData() const { wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") ); return M_IMGDATA->m_data; } void wxImage::SetData( char unsigned *data ) { wxCHECK_RET( Ok(), wxT("invalid image") ); wxImageRefData *newRefData = new wxImageRefData(); newRefData->m_width = M_IMGDATA->m_width; newRefData->m_height = M_IMGDATA->m_height; newRefData->m_data = data; newRefData->m_ok = TRUE; newRefData->m_maskRed = M_IMGDATA->m_maskRed; newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; newRefData->m_hasMask = M_IMGDATA->m_hasMask; UnRef(); m_refData = newRefData; } void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) { wxCHECK_RET( Ok(), wxT("invalid image") ); M_IMGDATA->m_maskRed = r; M_IMGDATA->m_maskGreen = g; M_IMGDATA->m_maskBlue = b; M_IMGDATA->m_hasMask = TRUE; } unsigned char wxImage::GetMaskRed() const { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); return M_IMGDATA->m_maskRed; } unsigned char wxImage::GetMaskGreen() const { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); return M_IMGDATA->m_maskGreen; } unsigned char wxImage::GetMaskBlue() const { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); return M_IMGDATA->m_maskBlue; } void wxImage::SetMask( bool mask ) { wxCHECK_RET( Ok(), wxT("invalid image") ); M_IMGDATA->m_hasMask = mask; } bool wxImage::HasMask() const { wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") ); return M_IMGDATA->m_hasMask; } int wxImage::GetWidth() const { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); return M_IMGDATA->m_width; } int wxImage::GetHeight() const { wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); return M_IMGDATA->m_height; } bool wxImage::LoadFile( const wxString& filename, long type ) { #if wxUSE_STREAMS if (wxFileExists(filename)) { wxFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); return LoadFile(bstream, type); } else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); return FALSE; } #else // !wxUSE_STREAMS return FALSE; #endif // wxUSE_STREAMS } bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype ) { #if wxUSE_STREAMS if (wxFileExists(filename)) { wxFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); return LoadFile(bstream, mimetype); } else { wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); return FALSE; } #else // !wxUSE_STREAMS return FALSE; #endif // wxUSE_STREAMS } bool wxImage::SaveFile( const wxString& filename, int type ) { #if wxUSE_STREAMS wxFileOutputStream stream(filename); if ( stream.LastError() == wxStream_NOERROR ) { wxBufferedOutputStream bstream( stream ); return SaveFile(bstream, type); } else #endif // wxUSE_STREAMS return FALSE; } bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) { #if wxUSE_STREAMS wxFileOutputStream stream(filename); if ( stream.LastError() == wxStream_NOERROR ) { wxBufferedOutputStream bstream( stream ); return SaveFile(bstream, mimetype); } else #endif // wxUSE_STREAMS return FALSE; } bool wxImage::CanRead( const wxString &name ) { #if wxUSE_STREAMS wxFileInputStream stream(name); return CanRead(stream); #else return FALSE; #endif } #if wxUSE_STREAMS bool wxImage::CanRead( wxInputStream &stream ) { wxList &list=GetHandlers(); for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) { wxImageHandler *handler=(wxImageHandler*)node->GetData(); if (handler->CanRead( stream )) return TRUE; } return FALSE; } bool wxImage::LoadFile( wxInputStream& stream, long type ) { UnRef(); m_refData = new wxImageRefData; wxImageHandler *handler; if (type==wxBITMAP_TYPE_ANY) { wxList &list=GetHandlers(); for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) { handler=(wxImageHandler*)node->GetData(); if (handler->CanRead( stream )) return handler->LoadFile( this, stream ); } wxLogWarning( _("No handler found for image type.") ); return FALSE; } handler = FindHandler(type); if (handler == NULL) { wxLogWarning( _("No image handler for type %d defined."), type ); return FALSE; } return handler->LoadFile( this, stream ); } bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype ) { UnRef(); m_refData = new wxImageRefData; wxImageHandler *handler = FindHandlerMime(mimetype); if (handler == NULL) { wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); return FALSE; } return handler->LoadFile( this, stream ); } bool wxImage::SaveFile( wxOutputStream& stream, int type ) { wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") ); wxImageHandler *handler = FindHandler(type); if (handler == NULL) { wxLogWarning( _("No image handler for type %d defined."), type ); return FALSE; } return handler->SaveFile( this, stream ); } bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) { wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") ); wxImageHandler *handler = FindHandlerMime(mimetype); if (handler == NULL) { wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); return FALSE; } return handler->SaveFile( this, stream ); } #endif // wxUSE_STREAMS void wxImage::AddHandler( wxImageHandler *handler ) { // make sure that the memory will be freed at the program end sm_handlers.DeleteContents(TRUE); sm_handlers.Append( handler ); } void wxImage::InsertHandler( wxImageHandler *handler ) { // make sure that the memory will be freed at the program end sm_handlers.DeleteContents(TRUE); sm_handlers.Insert( handler ); } bool wxImage::RemoveHandler( const wxString& name ) { wxImageHandler *handler = FindHandler(name); if (handler) { sm_handlers.DeleteObject(handler); return TRUE; } else return FALSE; } wxImageHandler *wxImage::FindHandler( const wxString& name ) { wxNode *node = sm_handlers.First(); while (node) { wxImageHandler *handler = (wxImageHandler*)node->Data(); if (handler->GetName().Cmp(name) == 0) return handler; node = node->Next(); } return (wxImageHandler *)NULL; } wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) { wxNode *node = sm_handlers.First(); while (node) { wxImageHandler *handler = (wxImageHandler*)node->Data(); if ( (handler->GetExtension().Cmp(extension) == 0) && (bitmapType == -1 || handler->GetType() == bitmapType) ) return handler; node = node->Next(); } return (wxImageHandler*)NULL; } wxImageHandler *wxImage::FindHandler( long bitmapType ) { wxNode *node = sm_handlers.First(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->Data(); if (handler->GetType() == bitmapType) return handler; node = node->Next(); } return NULL; } wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) { wxNode *node = sm_handlers.First(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->Data(); if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler; node = node->Next(); } return NULL; } void wxImage::InitStandardHandlers() { AddHandler( new wxBMPHandler ); } void wxImage::CleanUpHandlers() { wxNode *node = sm_handlers.First(); while (node) { wxImageHandler *handler = (wxImageHandler *)node->Data(); wxNode *next = node->Next(); delete handler; delete node; node = next; } } //----------------------------------------------------------------------------- // wxImageHandler //----------------------------------------------------------------------------- IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) #if wxUSE_STREAMS bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) { return FALSE; } bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) ) { return FALSE; } int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) ) { return 1; } bool wxImageHandler::CanRead( const wxString& name ) { if (wxFileExists(name)) { wxFileInputStream stream(name); return CanRead(stream); } else { wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); return FALSE; } // return FALSE; } #endif // wxUSE_STREAMS //----------------------------------------------------------------------------- // MSW conversion routines //----------------------------------------------------------------------------- #ifdef __WXMSW__ wxBitmap wxImage::ConvertToBitmap() const { if ( !Ok() ) return wxNullBitmap; // sizeLimit is the MS upper limit for the DIB size #ifdef WIN32 int sizeLimit = 1024*768*3; #else int sizeLimit = 0x7fff ; #endif // width and height of the device-dependent bitmap int width = GetWidth(); int bmpHeight = GetHeight(); // calc the number of bytes per scanline and padding int bytePerLine = width*3; int sizeDWORD = sizeof( DWORD ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // calc the number of DIBs and heights of DIBs int numDIB = 1; int hRemain = 0; int height = sizeLimit/bytePerLine; if( height >= bmpHeight ) height = bmpHeight; else { numDIB = bmpHeight / height; hRemain = bmpHeight % height; if( hRemain >0 ) numDIB++; } // set bitmap parameters wxBitmap bitmap; wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") ); bitmap.SetWidth( width ); bitmap.SetHeight( bmpHeight ); bitmap.SetDepth( wxDisplayDepth() ); // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); 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; lpDIBh->bmiHeader.biWidth = (DWORD)width; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; // the general formula for biSizeImage: // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate memory for DIB") ); free( lpDIBh ); return bitmap; } // create and set the device-dependent bitmap HDC hdc = ::GetDC(NULL); HDC memdc = ::CreateCompatibleDC( hdc ); HBITMAP hbitmap; hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight ); ::SelectObject( memdc, hbitmap); // copy image data into DIB data and then into DDB (in a loop) unsigned char *data = GetData(); int i, j, n; int origin = 0; unsigned char *ptdata = data; unsigned char *ptbits; for( n=0; n 1 && n == numDIB-1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( j=0; jbmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS ); // The above line is equivalent to the following two lines. // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS); // or the following lines // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // HDC memdc = ::CreateCompatibleDC( hdc ); // ::SelectObject( memdc, hbitmap); // ::SetDIBitsToDevice( memdc, 0, 0, width, height, // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS); // ::SelectObject( memdc, 0 ); // ::DeleteDC( memdc ); } bitmap.SetHBITMAP( (WXHBITMAP) hbitmap ); // similarly, created an mono-bitmap for the possible mask if( HasMask() ) { hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL ); ::SelectObject( memdc, hbitmap); if( numDIB == 1 ) height = bmpHeight; else height = sizeLimit/bytePerLine; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; origin = 0; unsigned char r = GetMaskRed(); unsigned char g = GetMaskGreen(); unsigned char b = GetMaskBlue(); unsigned char zero = 0, one = 255; ptdata = data; for( n=0; n 1 && n == numDIB - 1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( int j=0; jSetMaskBitmap( (WXHBITMAP) hbitmap ); bitmap.SetMask( mask ); // It will be deleted when the wxBitmap object is deleted (as of 01/1999) /* The following can also be used but is slow to run wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue()); wxMask *mask = new wxMask( bitmap, colour ); bitmap.SetMask( mask ); */ } // free allocated resources ::SelectObject( memdc, 0 ); ::DeleteDC( memdc ); ::ReleaseDC(NULL, hdc); free(lpDIBh); free(lpBits); #if WXWIN_COMPATIBILITY_2 // check the wxBitmap object bitmap.GetBitmapData()->SetOk(); #endif // WXWIN_COMPATIBILITY_2 return bitmap; } wxImage::wxImage( const wxBitmap &bitmap ) { // check the bitmap if( !bitmap.Ok() ) { wxFAIL_MSG( wxT("invalid bitmap") ); return; } // create an wxImage object int width = bitmap.GetWidth(); int height = bitmap.GetHeight(); Create( width, height ); unsigned char *data = GetData(); if( !data ) { wxFAIL_MSG( wxT("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 ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize ); if( !lpDIBh ) { wxFAIL_MSG( wxT("could not allocate data for DIB header") ); free( data ); return; } // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biSizeImage = bytePerLine * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate data for DIB") ); free( data ); 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; unsigned char *ptbits = lpBits; for( i=0; iGetMaskBitmap() ) { hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap(); // memory DC created, color set, data copied, and memory DC deleted HDC memdc = ::CreateCompatibleDC( hdc ); ::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::DeleteDC( memdc ); // background color set to RGB(16,16,16) in consistent with wxGTK unsigned char r=16, g=16, b=16; ptdata = data; ptbits = lpBits; for( i=0; i extern CTabHandle wxMacCreateColorTable( int numColors ) ; extern void wxMacDestroyColorTable( CTabHandle colors ) ; extern void wxMacSetColorTableEntry( CTabHandle newColors , int index , int red , int green , int blue ) ; extern GWorldPtr wxMacCreateGWorld( int height , int width , int depth ) ; extern void wxMacDestroyGWorld( GWorldPtr gw ) ; wxBitmap wxImage::ConvertToBitmap() const { // width and height of the device-dependent bitmap int width = GetWidth(); 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 ; 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 } // for height SetGWorld( origPort , origDevice ) ; return bitmap; } wxImage::wxImage( const wxBitmap &bitmap ) { // check the bitmap if( !bitmap.Ok() ) { wxFAIL_MSG( "invalid bitmap" ); return; } // create an wxImage object int width = bitmap.GetWidth(); int height = bitmap.GetHeight(); Create( width, height ); /* unsigned char *data = GetData(); if( !data ) { 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 ) { padding = sizeDWORD - lineBoundary.rem; bytePerLine += padding; } // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); if( !lpDIBh ) { wxFAIL_MSG( "could not allocate data for DIB header" ); free( data ); return; } // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biSizeImage = bytePerLine * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( "could not allocate data for DIB" ); free( data ); 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; unsigned char *ptbits = lpBits; for( i=0; iGetMaskBitmap() ) { hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap(); // memory DC created, color set, data copied, and memory DC deleted HDC memdc = ::CreateCompatibleDC( hdc ); ::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::DeleteDC( memdc ); // background color set to RGB(16,16,16) in consistent with wxGTK unsigned char r=16, g=16, b=16; ptdata = data; ptbits = lpBits; for( i=0; i #include #include #if (GTK_MINOR_VERSION > 0) #include #endif wxBitmap wxImage::ConvertToBitmap() const { wxBitmap bitmap; wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") ); int width = GetWidth(); int height = GetHeight(); bitmap.SetHeight( height ); bitmap.SetWidth( width ); bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) ); // Retrieve depth GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() ); if (visual == NULL) visual = gdk_visual_get_system(); int bpp = visual->depth; bitmap.SetDepth( bpp ); if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15; if (bpp < 8) bpp = 8; #if (GTK_MINOR_VERSION > 0) if (!HasMask() && (bpp > 8)) { static bool s_hasInitialized = FALSE; if (!s_hasInitialized) { gdk_rgb_init(); s_hasInitialized = TRUE; } GdkGC *gc = gdk_gc_new( bitmap.GetPixmap() ); gdk_draw_rgb_image( bitmap.GetPixmap(), gc, 0, 0, width, height, GDK_RGB_DITHER_NONE, GetData(), width*3 ); gdk_gc_unref( gc ); return bitmap; } #endif // Create picture image GdkImage *data_image = gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), 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 ); } // Render enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR }; byte_order b_o = RGB; if (bpp >= 24) { GdkVisual *visual = gdk_visual_get_system(); if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB; else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RGB; else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG; else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR; else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB; else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR; } 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 (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: { int pixel = -1; if (wxTheApp->m_colorCube) { pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ]; } else { GdkColormap *cmap = gtk_widget_get_default_colormap(); GdkColor *colors = cmap->colors; int max = 3 * (65536); for (int i = 0; i < cmap->size; i++) { int rdiff = (r << 8) - colors[i].red; int gdiff = (g << 8) - colors[i].green; int bdiff = (b << 8) - colors[i].blue; int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff); if (sum < max) { pixel = i; max = sum; } } } gdk_image_put_pixel( data_image, x, y, pixel ); break; } case 15: { guint32 pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); gdk_image_put_pixel( data_image, x, y, pixel ); break; } case 16: { guint32 pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); gdk_image_put_pixel( data_image, x, y, pixel ); break; } case 32: case 24: { guint32 pixel = 0; switch (b_o) { case RGB: pixel = (r << 16) | (g << 8) | b; break; case RBG: pixel = (r << 16) | (b << 8) | g; break; case BRG: pixel = (b << 16) | (r << 8) | g; break; case BGR: pixel = (b << 16) | (g << 8) | r; break; case GRB: pixel = (g << 16) | (r << 8) | b; break; case GBR: pixel = (g << 16) | (b << 8) | r; break; } gdk_image_put_pixel( data_image, x, y, pixel ); } default: break; } } // for } // for // Blit picture GdkGC *data_gc = gdk_gc_new( bitmap.GetPixmap() ); gdk_draw_image( bitmap.GetPixmap(), 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; } wxImage::wxImage( const wxBitmap &bitmap ) { wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") ); GdkImage *gdk_image = (GdkImage*) NULL; if (bitmap.GetPixmap()) { gdk_image = gdk_image_get( bitmap.GetPixmap(), 0, 0, bitmap.GetWidth(), bitmap.GetHeight() ); } else if (bitmap.GetBitmap()) { gdk_image = gdk_image_get( bitmap.GetBitmap(), 0, 0, bitmap.GetWidth(), bitmap.GetHeight() ); } else { wxFAIL_MSG( wxT("Ill-formed bitmap") ); } wxCHECK_RET( gdk_image, wxT("couldn't create image") ); Create( bitmap.GetWidth(), bitmap.GetHeight() ); char unsigned *data = GetData(); if (!data) { gdk_image_destroy( gdk_image ); wxFAIL_MSG( wxT("couldn't create image") ); return; } GdkImage *gdk_image_mask = (GdkImage*) NULL; if (bitmap.GetMask()) { gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(), 0, 0, bitmap.GetWidth(), bitmap.GetHeight() ); SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable } int bpp = -1; if (bitmap.GetPixmap()) { 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) && (visual->red_mask != 0xf800)) bpp = 15; } if (bitmap.GetBitmap()) { bpp = 1; } GdkColormap *cmap = gtk_widget_get_default_colormap(); long pos = 0; for (int j = 0; j < bitmap.GetHeight(); j++) { for (int i = 0; i < bitmap.GetWidth(); i++) { wxInt32 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 (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) { #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) { #if (wxBYTE_ORDER == wxBIG_ENDIAN) // ? #endif data[pos] = (pixel >> 8) & 0xf8; data[pos+1] = (pixel >> 3) & 0xfc; data[pos+2] = (pixel << 3) & 0xf8; } 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 } if (gdk_image_mask) { int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j ); if (mask_pixel == 0) { data[pos] = 16; data[pos+1] = 16; data[pos+2] = 16; } } pos += 3; } } gdk_image_destroy( gdk_image ); if (gdk_image_mask) gdk_image_destroy( gdk_image_mask ); } #endif //----------------------------------------------------------------------------- // Motif conversion routines //----------------------------------------------------------------------------- #ifdef __WXMOTIF__ #ifdef __VMS__ #pragma message disable nosimpint #endif #include #ifdef __VMS__ #pragma message enable nosimpint #endif #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; wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") ); int width = GetWidth(); int height = GetHeight(); bitmap.SetHeight( height ); bitmap.SetWidth( width ); Display *dpy = (Display*) wxGetDisplay(); Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) ); int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) ); // Create image XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 ); data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height ); bitmap.Create( width, height, bpp ); /* // Create mask 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 ); } */ // Retrieve depth info XVisualInfo vinfo_template; XVisualInfo *vi; vinfo_template.visual = vis; vinfo_template.visualid = XVisualIDFromVisual( vis ); vinfo_template.depth = bpp; int nitem = 0; vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem ); wxCHECK_MSG( vi, wxNullBitmap, wxT("no visual") ); XFree( vi ); if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15; if (bpp < 8) bpp = 8; // Render enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR }; byte_order b_o = RGB; if (bpp >= 24) { if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB; else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB; else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG; else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR; else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB; else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR; } /* int r_mask = GetMaskRed(); int g_mask = GetMaskGreen(); int b_mask = GetMaskBlue(); */ XColor colors[256]; if (bpp == 8) { Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy ); for (int i = 0; i < 256; i++) colors[i].pixel = i; XQueryColors( dpy, cmap, colors, 256 ); } wxSearchColor scolor( 256, colors ); 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 ); } */ switch (bpp) { case 8: { #if 0 // Old, slower code int pixel = -1; /* if (wxTheApp->m_colorCube) { pixel = wxTheApp->m_colorCube [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ]; } else { */ int max = 3 * (65536); for (int i = 0; i < 256; i++) { int rdiff = (r << 8) - colors[i].red; int gdiff = (g << 8) - colors[i].green; int bdiff = (b << 8) - colors[i].blue; int sum = abs (rdiff) + abs (gdiff) + abs (bdiff); if (sum < max) { pixel = i; max = sum; } } /* } */ #endif // And this is all to get the 'right' color... int pixel = scolor.SearchColor( r, g, b ); XPutPixel( data_image, x, y, pixel ); break; } case 15: { int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); XPutPixel( data_image, x, y, pixel ); break; } case 16: { int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); XPutPixel( data_image, x, y, pixel ); break; } case 32: case 24: { int pixel = 0; switch (b_o) { case RGB: pixel = (r << 16) | (g << 8) | b; break; case RBG: pixel = (r << 16) | (b << 8) | g; break; case BRG: pixel = (b << 16) | (r << 8) | g; break; case BGR: pixel = (b << 16) | (g << 8) | r; break; case GRB: pixel = (g << 16) | (r << 8) | b; break; case GBR: pixel = (g << 16) | (b << 8) | r; break; } XPutPixel( data_image, x, y, pixel ); } default: break; } } // for } // for // Blit picture XGCValues gcvalues; gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) ); GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues ); XPutImage( dpy, (Drawable)bitmap.GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height ); XDestroyImage( data_image ); XFreeGC( dpy, 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; } wxImage::wxImage( const wxBitmap &bitmap ) { wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") ); Display *dpy = (Display*) wxGetDisplay(); Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) ); int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) ); XImage *ximage = XGetImage( dpy, (Drawable)bitmap.GetPixmap(), 0, 0, bitmap.GetWidth(), bitmap.GetHeight(), AllPlanes, ZPixmap ); wxCHECK_RET( ximage, wxT("couldn't create image") ); Create( bitmap.GetWidth(), bitmap.GetHeight() ); char unsigned *data = GetData(); if (!data) { XDestroyImage( ximage ); wxFAIL_MSG( wxT("couldn't create image") ); return; } /* GdkImage *gdk_image_mask = (GdkImage*) NULL; if (bitmap.GetMask()) { gdk_image_mask = gdk_image_get( bitmap.GetMask()->GetBitmap(), 0, 0, bitmap.GetWidth(), bitmap.GetHeight() ); SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable } */ // Retrieve depth info XVisualInfo vinfo_template; XVisualInfo *vi; vinfo_template.visual = vis; vinfo_template.visualid = XVisualIDFromVisual( vis ); vinfo_template.depth = bpp; int nitem = 0; vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem ); wxCHECK_RET( vi, wxT("no visual") ); if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15; XFree( vi ); XColor colors[256]; if (bpp == 8) { Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy ); for (int i = 0; i < 256; i++) colors[i].pixel = i; XQueryColors( dpy, cmap, colors, 256 ); } long pos = 0; for (int j = 0; j < bitmap.GetHeight(); j++) { for (int i = 0; i < bitmap.GetWidth(); i++) { int pixel = XGetPixel( ximage, i, j ); if (bpp <= 8) { data[pos] = colors[pixel].red >> 8; data[pos+1] = colors[pixel].green >> 8; data[pos+2] = colors[pixel].blue >> 8; } else if (bpp == 15) { data[pos] = (pixel >> 7) & 0xf8; data[pos+1] = (pixel >> 2) & 0xf8; data[pos+2] = (pixel << 3) & 0xf8; } else if (bpp == 16) { data[pos] = (pixel >> 8) & 0xf8; data[pos+1] = (pixel >> 3) & 0xfc; data[pos+2] = (pixel << 3) & 0xf8; } else { data[pos] = (pixel >> 16) & 0xff; data[pos+1] = (pixel >> 8) & 0xff; data[pos+2] = pixel & 0xff; } /* if (gdk_image_mask) { int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j ); if (mask_pixel == 0) { data[pos] = 16; data[pos+1] = 16; data[pos+2] = 16; } } */ pos += 3; } } XDestroyImage( ximage ); /* if (gdk_image_mask) gdk_image_destroy( gdk_image_mask ); */ } #endif #ifdef __WXPM__ // OS/2 Presentation manager conversion routings wxBitmap wxImage::ConvertToBitmap() const { if ( !Ok() ) return wxNullBitmap; wxBitmap bitmap; // remove // TODO: /* int sizeLimit = 1024*768*3; // width and height of the device-dependent bitmap int width = GetWidth(); int bmpHeight = GetHeight(); // calc the number of bytes per scanline and padding int bytePerLine = width*3; int sizeDWORD = sizeof( DWORD ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // calc the number of DIBs and heights of DIBs int numDIB = 1; int hRemain = 0; int height = sizeLimit/bytePerLine; if( height >= bmpHeight ) height = bmpHeight; else { numDIB = bmpHeight / height; hRemain = bmpHeight % height; if( hRemain >0 ) numDIB++; } // set bitmap parameters wxBitmap bitmap; wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") ); bitmap.SetWidth( width ); bitmap.SetHeight( bmpHeight ); bitmap.SetDepth( wxDisplayDepth() ); // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); LPBITMAPINFO 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; lpDIBh->bmiHeader.biWidth = (DWORD)width; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; // the general formula for biSizeImage: // ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate memory for DIB") ); free( lpDIBh ); return bitmap; } // create and set the device-dependent bitmap HDC hdc = ::GetDC(NULL); HDC memdc = ::CreateCompatibleDC( hdc ); HBITMAP hbitmap; hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight ); ::SelectObject( memdc, hbitmap); // copy image data into DIB data and then into DDB (in a loop) unsigned char *data = GetData(); int i, j, n; int origin = 0; unsigned char *ptdata = data; unsigned char *ptbits; for( n=0; n 1 && n == numDIB-1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( j=0; jbmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS ); // The above line is equivalent to the following two lines. // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS); // or the following lines // hbitmap = ::CreateCompatibleBitmap( hdc, width, height ); // HDC memdc = ::CreateCompatibleDC( hdc ); // ::SelectObject( memdc, hbitmap); // ::SetDIBitsToDevice( memdc, 0, 0, width, height, // 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS); // ::SelectObject( memdc, 0 ); // ::DeleteDC( memdc ); } bitmap.SetHBITMAP( (WXHBITMAP) hbitmap ); // similarly, created an mono-bitmap for the possible mask if( HasMask() ) { hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL ); ::SelectObject( memdc, hbitmap); if( numDIB == 1 ) height = bmpHeight; else height = sizeLimit/bytePerLine; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; origin = 0; unsigned char r = GetMaskRed(); unsigned char g = GetMaskGreen(); unsigned char b = GetMaskBlue(); unsigned char zero = 0, one = 255; ptdata = data; for( n=0; n 1 && n == numDIB - 1 && hRemain > 0 ) { // redefine height and size of the (possibly) last smaller DIB // memory is not reallocated height = hRemain; lpDIBh->bmiHeader.biHeight = (DWORD)(-height); lpDIBh->bmiHeader.biSizeImage = bytePerLine*height; } ptbits = lpBits; for( int j=0; jSetMaskBitmap( (WXHBITMAP) hbitmap ); bitmap.SetMask( mask ); } // free allocated resources ::SelectObject( memdc, 0 ); ::DeleteDC( memdc ); ::ReleaseDC(NULL, hdc); free(lpDIBh); free(lpBits); // check the wxBitmap object if( bitmap.GetHBITMAP() ) bitmap.SetOk( TRUE ); else bitmap.SetOk( FALSE ); */ return bitmap; } wxImage::wxImage( const wxBitmap &bitmap ) { // check the bitmap if( !bitmap.Ok() ) { wxFAIL_MSG( wxT("invalid bitmap") ); return; } // create an wxImage object int width = bitmap.GetWidth(); int height = bitmap.GetHeight(); Create( width, height ); unsigned char *data = GetData(); if( !data ) { wxFAIL_MSG( wxT("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 ); int lineBoundary = bytePerLine % sizeDWORD; int padding = 0; if( lineBoundary > 0 ) { padding = sizeDWORD - lineBoundary; bytePerLine += padding; } // TODO: /* // create a DIB header int headersize = sizeof(BITMAPINFOHEADER); LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize ); if( !lpDIBh ) { wxFAIL_MSG( wxT("could not allocate data for DIB header") ); free( data ); return; } // Fill in the DIB header lpDIBh->bmiHeader.biSize = headersize; lpDIBh->bmiHeader.biWidth = width; lpDIBh->bmiHeader.biHeight = -height; lpDIBh->bmiHeader.biSizeImage = bytePerLine * height; lpDIBh->bmiHeader.biPlanes = 1; lpDIBh->bmiHeader.biBitCount = 24; lpDIBh->bmiHeader.biCompression = BI_RGB; lpDIBh->bmiHeader.biClrUsed = 0; // These seem not really needed for our purpose here. lpDIBh->bmiHeader.biClrImportant = 0; lpDIBh->bmiHeader.biXPelsPerMeter = 0; lpDIBh->bmiHeader.biYPelsPerMeter = 0; // memory for DIB data unsigned char *lpBits; lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage ); if( !lpBits ) { wxFAIL_MSG( wxT("could not allocate data for DIB") ); free( data ); 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; unsigned char *ptbits = lpBits; for( i=0; iGetMaskBitmap() ) { hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap(); // memory DC created, color set, data copied, and memory DC deleted HDC memdc = ::CreateCompatibleDC( hdc ); ::SetTextColor( memdc, RGB( 0, 0, 0 ) ); ::SetBkColor( memdc, RGB( 255, 255, 255 ) ); ::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS ); ::DeleteDC( memdc ); // background color set to RGB(16,16,16) in consistent with wxGTK unsigned char r=16, g=16, b=16; ptdata = data; ptbits = lpBits; for( i=0; iGetData(); 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; }