]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
1. coloured buttons seem to work
[wxWidgets.git] / src / common / image.cpp
index 3679c78d0377ece78988b8a3e4a9be95072ca5b2..fcdc3d34e90107196ffd805d09d9b7a3f0fcce0f 100644 (file)
@@ -45,7 +45,6 @@
 
 class wxImageRefData: public wxObjectRefData
 {
-
 public:
     wxImageRefData();
     ~wxImageRefData();
@@ -72,7 +71,8 @@ wxImageRefData::wxImageRefData()
 
 wxImageRefData::~wxImageRefData()
 {
-    if (m_data) free( m_data );
+    if (m_data)
+        free( m_data );
 }
 
 wxList wxImage::sm_handlers;
@@ -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()
 {
@@ -195,8 +193,8 @@ wxImage wxImage::GetSubImage( const wxRect &rect ) const
 
     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") );
+    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();
@@ -381,11 +379,12 @@ bool wxImage::LoadFile( const wxString& filename, long type )
     if (wxFileExists(filename))
     {
         wxFileInputStream stream(filename);
-        return LoadFile(stream, type);
+       wxBufferedInputStream bstream( stream );
+        return LoadFile(bstream, type);
     }
-
-    else {
-        wxLogError( wxT("Can't load image from file '%s': file does not exist."), filename.c_str() );
+    else
+    {
+        wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
 
         return FALSE;
     }
@@ -400,11 +399,12 @@ bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype )
     if (wxFileExists(filename))
     {
         wxFileInputStream stream(filename);
-        return LoadFile(stream, mimetype);
+       wxBufferedInputStream bstream( stream );
+        return LoadFile(bstream, mimetype);
     }
-
-    else {
-        wxLogError( wxT("Can't load image from file '%s': file does not exist."), filename.c_str() );
+    else
+    {
+        wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
 
         return FALSE;
     }
@@ -419,7 +419,10 @@ bool wxImage::SaveFile( const wxString& filename, int type )
     wxFileOutputStream stream(filename);
 
     if ( stream.LastError() == wxStream_NOERROR )
-        return SaveFile(stream, type);
+    {
+       wxBufferedOutputStream bstream( stream );
+        return SaveFile(bstream, type);
+    }
     else
 #endif // wxUSE_STREAMS
         return FALSE;
@@ -431,14 +434,41 @@ bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype )
     wxFileOutputStream stream(filename);
 
     if ( stream.LastError() == wxStream_NOERROR )
-        return SaveFile(stream, mimetype);
+    {
+       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();
@@ -459,7 +489,7 @@ bool wxImage::LoadFile( wxInputStream& stream, long type )
 
         }
 
-        wxLogWarning( wxT("No handler found for this image.") );
+        wxLogWarning( _("No handler found for image type.") );
         return FALSE;
     }
 
@@ -467,7 +497,7 @@ bool wxImage::LoadFile( wxInputStream& stream, long type )
 
     if (handler == NULL)
     {
-        wxLogWarning( wxT("No image handler for type %d defined."), type );
+        wxLogWarning( _("No image handler for type %d defined."), type );
 
         return FALSE;
     }
@@ -485,7 +515,7 @@ bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype )
 
     if (handler == NULL)
     {
-        wxLogWarning( wxT("No image handler for type %s defined."), mimetype.GetData() );
+        wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
 
         return FALSE;
     }
@@ -501,7 +531,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, int type )
 
     if (handler == NULL)
     {
-        wxLogWarning( wxT("No image handler for type %d defined."), type );
+        wxLogWarning( _("No image handler for type %d defined."), type );
 
         return FALSE;
     }
@@ -517,7 +547,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype )
 
     if (handler == NULL)
     {
-        wxLogWarning( wxT("No image handler for type %s defined."), mimetype.GetData() );
+        wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
 
         return FALSE;
     }
@@ -627,12 +657,10 @@ 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) )
+bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
 {
     return FALSE;
 }
@@ -642,9 +670,13 @@ bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSE
     return FALSE;
 }
 
+int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
+{
+    return 1;
+}
+
 bool wxImageHandler::CanRead( const wxString& name )
 {
-#if wxUSE_STREAMS
     if (wxFileExists(name))
     {
         wxFileInputStream stream(name);
@@ -652,17 +684,13 @@ bool wxImageHandler::CanRead( const wxString& name )
     }
 
     else {
-        wxLogError( wxT("Can't check image format of file '%s': file does not exist."), name.c_str() );
+        wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
 
         return FALSE;
     }
-#else // !wxUSE_STREAMS
-    return FALSE;
-#endif // wxUSE_STREAMS
+//    return FALSE;
 }
 
-
-
 #endif // wxUSE_STREAMS
 
 //-----------------------------------------------------------------------------
@@ -719,7 +747,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;
@@ -870,11 +898,10 @@ wxBitmap wxImage::ConvertToBitmap() const
     free(lpDIBh);
     free(lpBits);
 
+#if WXWIN_COMPATIBILITY_2
     // check the wxBitmap object
-    if( bitmap.GetHBITMAP() )
-        bitmap.SetOk( TRUE );
-    else
-        bitmap.SetOk( FALSE );
+    bitmap.GetBitmapData()->SetOk();
+#endif // WXWIN_COMPATIBILITY_2
 
     return bitmap;
 }
@@ -912,7 +939,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") );
@@ -1010,18 +1037,255 @@ wxImage::wxImage( const wxBitmap &bitmap )
 
 #endif
 
+#ifdef __WXMAC__
+
+#include <PictUtils.h>
+
+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; i<height; i++ )
+    {
+        for( j=0; j<width; j++ )
+        {
+            *(ptdata++) = *(ptbits+2);
+            *(ptdata++) = *(ptbits+1);
+            *(ptdata++) = *(ptbits  );
+            ptbits += 3;
+        }
+        ptbits += padding;
+    }  
+
+    // similarly, set data according to the possible mask bitmap
+    if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
+    {
+        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<height; i++ )
+        {
+            for( j=0; j<width; j++ )
+            {
+                if( *ptbits != 0 )
+                    ptdata += 3;
+                else
+                {
+                    *(ptdata++)  = r;
+                    *(ptdata++)  = g;
+                    *(ptdata++)  = b;
+                }
+                ptbits += 3;
+            }
+            ptbits += padding;
+        }
+        SetMaskColour( r, g, b );
+        SetMask( TRUE );
+    }
+    else
+    {
+        SetMask( FALSE );
+    }
+    // free allocated resources
+    ::ReleaseDC(NULL, hdc);
+    free(lpDIBh);
+    free(lpBits);
+    */
+}
+
+#endif
+
 //-----------------------------------------------------------------------------
 // GTK conversion routines
 //-----------------------------------------------------------------------------
 
 #ifdef __WXGTK__
 
-#include "gtk/gtk.h"
-#include "gdk/gdk.h"
-#include "gdk/gdkx.h"
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
 
 #if (GTK_MINOR_VERSION > 0)
-#include "gdk/gdkrgb.h"
+#include <gdk/gdkrgb.h>
 #endif
 
 wxBitmap wxImage::ConvertToBitmap() const
@@ -1295,7 +1559,6 @@ wxImage::wxImage( const wxBitmap &bitmap )
         for (int i = 0; i < bitmap.GetWidth(); i++)
         {
             wxInt32 pixel = gdk_image_get_pixel( gdk_image, i, j );
-            // pixel = wxINT32_SWAP_ON_BE( pixel );
             if (bpp <= 8)
             {
                 data[pos] = cmap->colors[pixel].red >> 8;
@@ -1303,19 +1566,31 @@ wxImage::wxImage( const wxBitmap &bitmap )
                 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)
@@ -1344,8 +1619,13 @@ wxImage::wxImage( const wxBitmap &bitmap )
 //-----------------------------------------------------------------------------
 
 #ifdef __WXMOTIF__
-
+#ifdef __VMS__
+#pragma message disable nosimpint
+#endif
 #include <Xm/Xm.h>
+#ifdef __VMS__
+#pragma message enable nosimpint
+#endif
 #include "wx/utils.h"
 #include <math.h>
 
@@ -1668,17 +1948,442 @@ wxImage::wxImage( const wxBitmap &bitmap )
 }
 #endif
 
-// A module to allow wxImage initialization/cleanup
-// without calling these functions from app.cpp or from
-// the user's application.
+#ifdef __WXPM__
+// OS/2 Presentation manager conversion routings
 
-class wxImageModule: public wxModule
+wxBitmap wxImage::ConvertToBitmap() const
 {
-DECLARE_DYNAMIC_CLASS(wxImageModule)
-public:
-    wxImageModule() {}
-    bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
-    void OnExit() { wxImage::CleanUpHandlers(); };
-};
+    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<numDIB; n++ )
+    {
+        if( numDIB > 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; j<height; j++ )
+        {
+            for( i=0; i<width; i++ )
+            {
+                *(ptbits++) = *(ptdata+2);
+                *(ptbits++) = *(ptdata+1);
+                *(ptbits++) = *(ptdata  );
+                ptdata += 3;
+            }
+            for( i=0; i< padding; i++ )   *(ptbits++) = 0;
+        }
+        ::StretchDIBits( memdc, 0, origin, width, height,\
+            0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
+        origin += height;
+        // if numDIB = 1,  lines below can also be used
+        //    hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), 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<numDIB; n++ )
+        {
+            if( numDIB > 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; j<height; j++ )
+            {
+                for(i=0; i<width; i++ )
+                {
+                    if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
+                    {
+                        *(ptbits++) = one;
+                        *(ptbits++) = one;
+                        *(ptbits++) = one;
+                    }
+                    else
+                    {
+                        *(ptbits++) = zero;
+                        *(ptbits++) = zero;
+                        *(ptbits++) = zero;
+                    }
+                }
+                for( i=0; i< padding; i++ )   *(ptbits++) = zero;
+            }
+            ::StretchDIBits( memdc, 0, origin, width, height,\
+                0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
+            origin += height;
+        }
+        // create a wxMask object
+        wxMask *mask = new wxMask();
+        mask->SetMaskBitmap( (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; i<height; i++ )
+    {
+        for( j=0; j<width; j++ )
+        {
+            *(ptdata++) = *(ptbits+2);
+            *(ptdata++) = *(ptbits+1);
+            *(ptdata++) = *(ptbits  );
+            ptbits += 3;
+        }
+        ptbits += padding;
+    }
+
+    // similarly, set data according to the possible mask bitmap
+    if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
+    {
+        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<height; i++ )
+        {
+            for( j=0; j<width; j++ )
+            {
+                if( *ptbits != 0 )
+                    ptdata += 3;
+                else
+                {
+                    *(ptdata++)  = r;
+                    *(ptdata++)  = g;
+                    *(ptdata++)  = b;
+                }
+                ptbits += 3;
+            }
+            ptbits += padding;
+        }
+        SetMaskColour( r, g, b );
+        SetMask( TRUE );
+    }
+    else
+    {
+        SetMask( FALSE );
+    }
+    // free allocated resources
+    ::ReleaseDC(NULL, hdc);
+    free(lpDIBh);
+    free(lpBits);
+*/
+}
+
+#endif
+
+// A module to allow wxImage initialization/cleanup
+// without calling these functions from app.cpp or from
+// the user's application.
+
+class wxImageModule: public wxModule
+{
+DECLARE_DYNAMIC_CLASS(wxImageModule)
+public:
+    wxImageModule() {}
+    bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
+    void OnExit() { wxImage::CleanUpHandlers(); };
+};
+
+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;
+}
+
 
-IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)