]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
BC++/16-bit support now working, but without resource system
[wxWidgets.git] / src / common / image.cpp
index f57881dcb660f2bc3a2941f0a8047f453272220e..148059fb992776b0d53c6a98341a15ac101cf9e2 100644 (file)
 #endif
 
 #include "wx/image.h"
+#include "wx/bitmap.h"
 #include "wx/debug.h"
 #include "wx/log.h"
 #include "../png/png.h"
 #include "wx/filefn.h"
 
+#ifdef __WXGTK__
+#include "gdk/gdkprivate.h"
+#include "gdk/gdkx.h"
+#endif
+
 //-----------------------------------------------------------------------------
 // wxImage
 //-----------------------------------------------------------------------------
@@ -118,6 +124,99 @@ void wxImage::Destroy()
     UnRef();
 }
 
+wxImage wxImage::Scale( int width, int height )
+{
+    wxImage image;
+    
+    wxCHECK_MSG( Ok(), image, "invlaid image" );
+    
+    wxCHECK_MSG( (width > 0) && (height > 0), image, "invalid image size" );
+    
+    image.Create( width, height );
+    
+    char unsigned *data = image.GetData();
+    
+    wxCHECK_MSG( data, image, "unable to create image" );
+    
+    if (M_IMGDATA->m_hasMask)
+        image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
+    
+    double xscale = (double)width / (double)M_IMGDATA->m_width;
+    double yscale = (double)height / (double)M_IMGDATA->m_height;
+    
+    for (int j = 0; j < height; j++)
+    {
+        for (int i = 0; i < width; i++)
+       {
+           int new_pos = 3*(j*width + i);
+           int old_pos = 3*((long)(j/yscale)*M_IMGDATA->m_width + (long)(i/xscale));
+           data[ new_pos   ] = M_IMGDATA->m_data[ old_pos   ];
+           data[ new_pos+1 ] = M_IMGDATA->m_data[ old_pos+1 ];
+           data[ new_pos+2 ] = M_IMGDATA->m_data[ old_pos+2 ];
+       }
+    }
+    
+    return image;
+}
+  
+void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
+{
+    wxCHECK_RET( Ok(), "invalid image" );
+    
+    int w = M_IMGDATA->m_width;
+    int h = M_IMGDATA->m_height;
+    
+    wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), "invalid image index" );
+    
+    long pos = (y * w + x) * 3;
+    
+    M_IMGDATA->m_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, "invalid image" );
+    
+    int w = M_IMGDATA->m_width;
+    int h = M_IMGDATA->m_height;
+    
+    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
+    
+    long pos = (y * w + x) * 3;
+    
+    return M_IMGDATA->m_data[pos];
+}
+
+unsigned char wxImage::GetGreen( int x, int y )
+{
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
+    
+    int w = M_IMGDATA->m_width;
+    int h = M_IMGDATA->m_height;
+    
+    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
+    
+    long pos = (y * w + x) * 3;
+    
+    return M_IMGDATA->m_data[pos+1];
+}
+
+unsigned char wxImage::GetBlue( int x, int y )
+{
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
+    
+    int w = M_IMGDATA->m_width;
+    int h = M_IMGDATA->m_height;
+    
+    wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, "invalid image index" );
+    
+    long pos = (y * w + x) * 3;
+    
+    return M_IMGDATA->m_data[pos+2];
+}
+  
 bool wxImage::Ok() const 
 { 
     return (M_IMGDATA && M_IMGDATA->m_ok); 
@@ -125,18 +224,19 @@ bool wxImage::Ok() const
 
 char unsigned *wxImage::GetData() const
 {
-    if (!Ok()) return (char unsigned *)NULL;
+    wxCHECK_MSG( Ok(), (char unsigned *)NULL, "invalid image" );
   
     return M_IMGDATA->m_data;
 }
 
 void wxImage::SetData( char unsigned *WXUNUSED(data) )
 {
+    wxCHECK_RET( Ok(), "invalid image" );
 }
 
 void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
 {
-    if (!Ok()) return;
+    wxCHECK_RET( Ok(), "invalid image" );
   
     M_IMGDATA->m_maskRed = r;
     M_IMGDATA->m_maskGreen = g;
@@ -146,47 +246,51 @@ void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
 
 unsigned char wxImage::GetMaskRed() const
 {
-    if (!Ok()) return 0;
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
   
     return M_IMGDATA->m_maskRed;
 }
 
 unsigned char wxImage::GetMaskGreen() const
 {
-    if (!Ok()) return 0;
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
    
     return M_IMGDATA->m_maskGreen;
 }
 
 unsigned char wxImage::GetMaskBlue() const
 {
-    if (!Ok()) return 0;
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
   
     return M_IMGDATA->m_maskBlue;
 }
   
 void wxImage::SetMask( bool mask )
 {
-    if (!Ok()) return;
+    wxCHECK_RET( Ok(), "invalid image" );
   
     M_IMGDATA->m_hasMask = mask;
 }
 
 bool wxImage::HasMask() const
 {
-    if (!Ok()) return FALSE;
+    wxCHECK_MSG( Ok(), FALSE, "invalid image" );
   
     return M_IMGDATA->m_hasMask;
 }
 
 int wxImage::GetWidth() const 
 { 
-    return (M_IMGDATA ? M_IMGDATA->m_width : 0); 
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
+    
+    return M_IMGDATA->m_width; 
 }
 
 int wxImage::GetHeight() const 
 { 
-    return (M_IMGDATA ? M_IMGDATA->m_height : 0); 
+    wxCHECK_MSG( Ok(), 0, "invalid image" );
+    
+    return M_IMGDATA->m_height; 
 }
 
 bool wxImage::LoadFile( const wxString& filename, long type )
@@ -216,6 +320,8 @@ bool wxImage::LoadFile( const wxString& filename, long type )
 
 bool wxImage::SaveFile( const wxString& filename, int type )
 {
+    wxCHECK_MSG( Ok(), FALSE, "invalid image" );
+    
     wxImageHandler *handler = FindHandler(type);
 
     if (handler == NULL) 
@@ -568,7 +674,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
    unsigned char      *data, *ptr;
    int                 done, i, bpp, planes, comp, ncolors, line, column,
                        linesize, linepos, rshift = 0, gshift = 0, bshift = 0;
-   unsigned char       byte;
+   unsigned char       aByte;
    short int           word;
    long int            dbuf[4], dword, rmask = 0, gmask = 0, bmask = 0, offset,
                        size;
@@ -582,6 +688,9 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
 #define BI_RGB       0
 #define BI_RLE8      1
 #define BI_RLE4      2
+#endif
+
+#ifndef BI_BITFIELDS
 #define BI_BITFIELDS 3
 #endif
 
@@ -762,14 +871,14 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
                  int                 index;
 
                  linepos++;
-                 byte = getc(file);
+                 aByte = getc(file);
                  if (bpp == 1)
                    {
                       int                 bit = 0;
 
                       for (bit = 0; bit < 8; bit++)
                         {
-                           index = ((byte & (0x80 >> bit)) ? 1 : 0);
+                           index = ((aByte & (0x80 >> bit)) ? 1 : 0);
                            ptr[poffset] = cmap[index].r;
                            ptr[poffset + 1] = cmap[index].g;
                            ptr[poffset + 2] = cmap[index].b;
@@ -791,7 +900,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
 
                            for (nibble = 0; nibble < 2; nibble++)
                              {
-                                index = ((byte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
+                                index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
                                 if (index >= 16)
                                    index = 15;
                                 ptr[poffset] = cmap[index].r;
@@ -807,51 +916,51 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
                         {
                            unsigned char       first;
 
-                           first = byte;
-                           byte = getc(file);
+                           first = aByte;
+                           aByte = getc(file);
                            if (first == 0)
                              {
-                                if (byte == 0)
+                                if (aByte == 0)
                                   {
 /*                                    column = width; */
                                   }
-                                else if (byte == 1)
+                                else if (aByte == 1)
                                   {
                                      column = width;
                                      line = -1;
                                   }
-                                else if (byte == 2)
+                                else if (aByte == 2)
                                   {
-                                     byte = getc(file);
-                                     column += byte;
+                                     aByte = getc(file);
+                                     column += aByte;
                                      linepos = column * bpp / 8;
-                                     byte = getc(file);
-                                     line += byte;
+                                     aByte = getc(file);
+                                     line += aByte;
                                   }
                                 else
                                   {
-                                     int                 absolute = byte;
+                                     int                 absolute = aByte;
 
                                      for (i = 0; i < absolute; i++)
                                        {
-                                          +linepos++;
-                                          byte = getc(file);
-                                          ptr[poffset] = cmap[byte].r;
-                                          ptr[poffset + 1] = cmap[byte].g;
-                                          ptr[poffset + 2] = cmap[byte].b;
+                                          linepos++;
+                                          aByte = getc(file);
+                                          ptr[poffset] = cmap[aByte].r;
+                                          ptr[poffset + 1] = cmap[aByte].g;
+                                          ptr[poffset + 2] = cmap[aByte].b;
                                           column++;
                                        }
                                      if (absolute & 0x01)
-                                        byte = getc(file);
+                                        aByte = getc(file);
                                   }
                              }
                            else
                              {
                                 for (i = 0; i < first; i++)
                                   {
-                                     ptr[poffset] = cmap[byte].r;
-                                     ptr[poffset + 1] = cmap[byte].g;
-                                     ptr[poffset + 2] = cmap[byte].b;
+                                     ptr[poffset] = cmap[aByte].r;
+                                     ptr[poffset + 1] = cmap[aByte].g;
+                                     ptr[poffset + 2] = cmap[aByte].b;
                                      column++;
                                      linepos++;
                                   }
@@ -859,9 +968,9 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
                         }
                       else
                         {
-                           ptr[poffset] = cmap[byte].r;
-                           ptr[poffset + 1] = cmap[byte].g;
-                           ptr[poffset + 2] = cmap[byte].b;
+                           ptr[poffset] = cmap[aByte].r;
+                           ptr[poffset + 1] = cmap[aByte].g;
+                           ptr[poffset + 2] = cmap[aByte].b;
                            column++;
                            linepos += size;
                         }
@@ -904,7 +1013,7 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
          }
        while ((linepos < linesize) && (comp != 1) && (comp != 2))
          {
-            int                 temp = fread(&byte, 1, 1, file);
+            int                 temp = fread(&aByte, 1, 1, file);
 
             linepos += temp;
             if (!temp)
@@ -919,3 +1028,470 @@ bool wxBMPHandler::LoadFile( wxImage *image, const wxString& name )
    return TRUE;
 }
 
+#ifdef __WXMSW__
+
+wxBitmap wxImage::ConvertToBitmap() const
+{
+  
+  wxBitmap bitmap;
+  wxCHECK_MSG( Ok(), bitmap, "invalid image" );
+  int width = GetWidth();
+  int height = GetHeight();
+  bitmap.SetWidth( width );
+  bitmap.SetHeight( height );
+  bitmap.SetDepth( wxDisplayDepth() );
+
+  int headersize = sizeof(BITMAPINFOHEADER);
+  LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
+  wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" );
+
+// Fill in the DIB header
+  lpDIBh->bmiHeader.biSize = headersize;
+  lpDIBh->bmiHeader.biWidth = width;
+  lpDIBh->bmiHeader.biHeight = -height;
+  lpDIBh->bmiHeader.biSizeImage = width * height * 3;
+
+  lpDIBh->bmiHeader.biPlanes = 1;
+  lpDIBh->bmiHeader.biBitCount = 24;
+  lpDIBh->bmiHeader.biCompression = BI_RGB;
+  lpDIBh->bmiHeader.biClrUsed = 0;
+
+// These seem not needed for our purpose here.
+//  lpDIBh->bmiHeader.biClrImportant = 0;
+//  lpDIBh->bmiHeader.biXPelsPerMeter = 0;
+//  lpDIBh->bmiHeader.biYPelsPerMeter = 0;
+
+  unsigned char *lpBits = (unsigned char *) malloc( width*height*3 );
+  if( !lpBits )
+  {
+      wxFAIL_MSG( "could not allocate memory for DIB" );
+      free( lpDIBh );
+      return bitmap;
+  }
+
+  unsigned char *data = GetData();
+
+  unsigned char *ptdata = data, *ptbits = lpBits;
+  for( int i=0; i<width*height; i++ )
+  {
+    *(ptbits++) = *(ptdata+2);
+    *(ptbits++) = *(ptdata+1);
+    *(ptbits++) = *(ptdata  );
+    ptdata += 3;
+  }
+  HDC hdc = ::GetDC(NULL);
+
+  HBITMAP hbitmap;
+  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 );
+
+  if( HasMask() )
+  {
+    unsigned char r = GetMaskRed();
+    unsigned char g = GetMaskGreen();
+    unsigned char b = GetMaskBlue();
+    unsigned char zero = 0, one = 255;
+    ptdata = data;
+    ptbits = lpBits;
+    for( int i=0; i<width*height; i++ )
+    {
+      if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
+      {
+        *(ptbits++) = one;
+        *(ptbits++) = one;
+        *(ptbits++) = one;
+      }
+      else
+      {
+        *(ptbits++) = zero;
+        *(ptbits++) = zero;
+        *(ptbits++) = zero;
+      }
+    }
+    hbitmap = ::CreateBitmap( (WORD)width, (WORD)height, 1, 1, NULL );
+    ::SetDIBits( hdc, hbitmap, 0, (WORD)height, lpBits, lpDIBh, DIB_RGB_COLORS);
+    wxMask *mask = new wxMask();
+    mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
+    bitmap.SetMask( mask );
+
+/* 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 );
+*/
+  }
+
+  ::ReleaseDC(NULL, hdc);   
+  free(lpDIBh);
+  free(lpBits);
+
+  if( bitmap.GetHBITMAP() )
+    bitmap.SetOk( TRUE );
+  else
+    bitmap.SetOk( FALSE );
+   
+  return bitmap;
+}
+
+
+wxImage::wxImage( const wxBitmap &bitmap )
+{
+  if( !bitmap.Ok() )
+  {
+      wxFAIL_MSG( "invalid bitmap" );
+      return;
+  }
+
+  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;
+  }
+    
+  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 = width * height * 3;
+
+  lpDIBh->bmiHeader.biPlanes = 1;
+  lpDIBh->bmiHeader.biBitCount = 24;
+  lpDIBh->bmiHeader.biCompression = BI_RGB;
+  lpDIBh->bmiHeader.biClrUsed = 0;
+
+// These seem not needed for our purpose here.
+//    lpDIBh->bmiHeader.biClrImportant = 0;
+//    lpDIBh->bmiHeader.biXPelsPerMeter = 0;
+//    lpDIBh->bmiHeader.biYPelsPerMeter = 0;
+
+  unsigned char *lpBits = (unsigned char *) malloc( width*height*3 );
+  if( !lpBits )
+  {
+      wxFAIL_MSG( "could not allocate data for DIB" );
+      free( data );
+      free( lpDIBh );
+      return;
+  }
+    
+  HBITMAP hbitmap;
+  hbitmap = (HBITMAP) bitmap.GetHBITMAP();
+  HDC hdc = ::GetDC(NULL);
+  ::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
+       
+  unsigned char *ptdata = data, *ptbits = lpBits;
+  for( int i=0; i<width*height; i++ )
+  {
+    *(ptdata++) = *(ptbits+2);
+    *(ptdata++) = *(ptbits+1);
+    *(ptdata++) = *(ptbits  );
+    ptbits += 3;
+  }    
+      
+  if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
+  {
+    hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
+    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 ); 
+    unsigned char r=16, g=16, b=16;  // background set to RGB(16,16,16)
+    ptdata = data;
+    ptbits = lpBits;
+    for( int i=0; i<width*height; i++ )
+    {
+      if( *ptbits != 0 )
+      {
+        *(ptdata++)  = r;
+        *(ptdata++)  = g;
+        *(ptdata++)  = b;
+      }
+      ptbits += 3;
+    }       
+    SetMaskColour( r, g, b );
+  }    
+      
+  ::ReleaseDC(NULL, hdc);   
+  free(lpDIBh);
+  free(lpBits);
+}
+
+#endif
+
+#ifdef __WXGTK__
+
+wxBitmap wxImage::ConvertToBitmap() const
+{
+    wxBitmap bitmap;
+
+    wxCHECK_MSG( Ok(), bitmap, "invalid image" );
+
+    int width = GetWidth();
+    int height = GetHeight();
+
+    bitmap.SetHeight( height );
+    bitmap.SetWidth( width );
+
+    // Create picture
+
+    GdkImage *data_image =
+      gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), width, height );
+
+    bitmap.SetPixmap( gdk_pixmap_new( (GdkWindow*)&gdk_root_parent, width, height, -1 ) );
+
+    // 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
+
+    GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
+    if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
+    int bpp = visual->depth;
+    if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
+    if (bpp < 8) bpp = 8;
+
+    // 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 );
+           }
+
+           switch (bpp)
+           {
+               case 8:
+               {
+                   GdkColormap *cmap = gtk_widget_get_default_colormap();
+                    GdkColor *colors = cmap->colors;
+                    int max = 3 * (65536);
+                    int index = -1;
+
+                    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) { index = i; max = sum; }
+                    }
+
+                   gdk_image_put_pixel( data_image, x, y, index );
+
+                   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(), "invalid bitmap" );
+
+    GdkImage *gdk_image = gdk_image_get( bitmap.GetPixmap(),
+                                         0, 0,
+                                        bitmap.GetWidth(), bitmap.GetHeight() );
+
+    wxCHECK_RET( gdk_image, "couldn't create image" );
+
+    Create( bitmap.GetWidth(), bitmap.GetHeight() );
+    char unsigned *data = GetData();
+
+    if (!data)
+    {
+        gdk_image_destroy( gdk_image );
+        wxFAIL_MSG( "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
+    }
+
+    GdkVisual *visual = gdk_window_get_visual( bitmap.GetPixmap() );
+    if (visual == NULL) visual = gdk_window_get_visual( (GdkWindow*) &gdk_root_parent );
+    int bpp = visual->depth;
+    if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
+
+    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++)
+        {
+            int pixel = gdk_image_get_pixel( gdk_image, i, j );
+            if (bpp <= 8)
+            {
+                data[pos] = cmap->colors[pixel].red >> 8;
+                data[pos+1] = cmap->colors[pixel].green >> 8;
+                data[pos+2] = cmap->colors[pixel].blue >> 8;
+            } else if (bpp == 15)
+            {
+                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;
+        }
+    }
+
+    gdk_image_destroy( gdk_image );
+    if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
+}
+
+#endif