]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/image.cpp
postscript Blit()
[wxWidgets.git] / src / common / image.cpp
index 414ea15c251084dc93be573d7c2c2e85ef996dad..1f0cc7de58680a543ac2f602d31fdb4724424e3c 100644 (file)
 #include "wx/debug.h"
 #include "wx/log.h"
 #include "wx/app.h"
-#ifdef wxUSE_LIBPNG
+#if wxUSE_LIBPNG
 #include "../png/png.h"
 #endif
+#if wxUSE_LIBJPEG
+extern "C" {
+#include <jpeglib.h>
+}
+#endif
 #include "wx/filefn.h"
 #include "wx/wfstream.h"
 #include "wx/intl.h"
 
+#ifdef __SALFORDC__
+#ifdef FAR
+#undef FAR
+#endif
+#endif
+
 #ifdef __WXMSW__
 #include <windows.h>
 #endif
@@ -94,10 +105,12 @@ wxImage::wxImage( const wxString& name, long type )
     LoadFile( name, type );
 }
 
+#if wxUSE_STREAMS
 wxImage::wxImage( wxInputStream& stream, long type )
 {
     LoadFile( stream, type );
 }
+#endif // wxUSE_STREAMS
 
 wxImage::wxImage( const wxImage& image )
 {
@@ -150,18 +163,22 @@ wxImage wxImage::Scale( int width, int height )
     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;
+    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 (int j = 0; j < height; j++)
+    for (long j = 0; j < height; j++)
     {
-        for (int i = 0; i < width; i++)
+        long y_offset = (j * old_height / height) * old_width;
+       
+        for (long 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 ];
+           memcpy( target_data, 
+                   source_data + 3*(y_offset + ((i * old_width )/ width)), 
+                   3 );
+            target_data += 3;
         }
     }
 
@@ -304,6 +321,7 @@ int wxImage::GetHeight() const
 
 bool wxImage::LoadFile( const wxString& filename, long type )
 {
+#if wxUSE_STREAMS
     if (wxFileExists(filename))
     {
         wxFileInputStream stream(filename);
@@ -311,12 +329,28 @@ bool wxImage::LoadFile( const wxString& filename, long type )
     }
 
     else {
-        wxLogWarning( "Image file does not exist." );
+        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 )
+        return SaveFile(stream, type);
+    else
+#endif // wxUSE_STREAMS
+        return FALSE;
+}
+
+#if wxUSE_STREAMS
 bool wxImage::LoadFile( wxInputStream& stream, long type )
 {
     UnRef();
@@ -335,16 +369,6 @@ bool wxImage::LoadFile( wxInputStream& stream, long type )
     return handler->LoadFile( this, stream );
 }
 
-bool wxImage::SaveFile( const wxString& filename, int type )
-{
-    wxFileOutputStream stream(filename);
-
-    if ( stream.LastError() == wxStream_NOERROR )
-        return SaveFile(stream, type);
-    else
-        return FALSE;
-}
-
 bool wxImage::SaveFile( wxOutputStream& stream, int type )
 {
     wxCHECK_MSG( Ok(), FALSE, "invalid image" );
@@ -360,6 +384,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, int type )
 
     return handler->SaveFile( this, stream );
 }
+#endif // wxUSE_STREAMS
 
 void wxImage::AddHandler( wxImageHandler *handler )
 {
@@ -395,7 +420,8 @@ wxImageHandler *wxImage::FindHandler( const wxString& name )
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler*)node->Data();
-        if (handler->GetName() == name) return handler;
+        if (handler->GetName().Cmp(name) == 0) return handler;
+
         node = node->Next();
     }
     return (wxImageHandler *)NULL;
@@ -407,7 +433,7 @@ wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType
     while (node)
     {
         wxImageHandler *handler = (wxImageHandler*)node->Data();
-        if ( handler->GetExtension() == extension &&
+        if ( (handler->GetExtension().Cmp(extension) == 0) &&
             (bitmapType == -1 || handler->GetType() == bitmapType) )
         return handler;
         node = node->Next();
@@ -430,7 +456,7 @@ wxImageHandler *wxImage::FindHandler( long bitmapType )
 void wxImage::InitStandardHandlers()
 {
     AddHandler( new wxBMPHandler );
-#ifdef wxUSE_LIBPNG
+#if wxUSE_LIBPNG
     AddHandler( new wxPNGHandler );
 #endif
 }
@@ -456,6 +482,7 @@ void wxImage::CleanUpHandlers()
 IMPLEMENT_DYNAMIC_CLASS(wxImageHandler,wxObject)
 #endif
 
+#if wxUSE_STREAMS
 bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream) )
 {
     return FALSE;
@@ -465,18 +492,20 @@ bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSE
 {
     return FALSE;
 }
+#endif // wxUSE_STREAMS
 
 //-----------------------------------------------------------------------------
 // wxPNGHandler
 //-----------------------------------------------------------------------------
 
-#ifdef wxUSE_LIBPNG
+#if wxUSE_LIBPNG
 
 #if !USE_SHARED_LIBRARIES
 IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler)
 #endif
 
 
+#if wxUSE_STREAMS
 static void _PNG_stream_reader( png_structp png_ptr, png_bytep data, png_size_t length )
 {
    ((wxInputStream*) png_get_io_ptr( png_ptr )) -> Read(data, length);
@@ -491,11 +520,12 @@ bool wxPNGHandler::LoadFile( wxImage *image, wxInputStream& stream )
 {
     // VZ: as this function uses setjmp() the only fool proof error handling
     //     method is to use goto (setjmp is not really C++ dtors friendly...)
-    image->Destroy();
-
+    
+    unsigned char **lines = (unsigned char **) NULL;
     unsigned int i;
-    unsigned char **lines = NULL;
-    png_infop info_ptr = NULL;
+    png_infop info_ptr = (png_infop) NULL;
+    
+    image->Destroy();
 
     png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                                                   (voidp) NULL,
@@ -728,11 +758,226 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
   }
   return TRUE;
 }
+#endif // wxUSE_STREAMS
 
 #endif
 
   // wxUSE_LIBPNG
 
+
+//-----------------------------------------------------------------------------
+// wxJPEGHandler
+//-----------------------------------------------------------------------------
+
+#if wxUSE_LIBJPEG
+
+#if !USE_SHARED_LIBRARIES
+IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler)
+#endif
+
+#if wxUSE_STREAMS
+
+
+//------------- JPEG Data Source Manager
+
+typedef struct {
+  struct jpeg_source_mgr pub;   /* public fields */
+
+  JOCTET* buffer;               /* start of buffer */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+METHODDEF(void) my_init_source ( j_decompress_ptr cinfo )
+{
+}
+
+METHODDEF(boolean) my_fill_input_buffer ( j_decompress_ptr cinfo )
+{
+  return TRUE;
+}
+
+METHODDEF(void) my_skip_input_data ( j_decompress_ptr cinfo, long num_bytes )
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+
+  src->pub.next_input_byte += (size_t) num_bytes;
+  src->pub.bytes_in_buffer -= (size_t) num_bytes;
+}
+
+METHODDEF(void) my_term_source ( j_decompress_ptr cinfo )
+{
+  my_src_ptr src = (my_src_ptr) cinfo->src;
+
+  free (src->buffer);
+}
+
+void jpeg_wxio_src( j_decompress_ptr cinfo, wxInputStream& infile )
+{
+  my_src_ptr src;
+
+  if (cinfo->src == NULL) {    /* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                 sizeof(my_source_mgr));
+    src = (my_src_ptr) cinfo->src;
+  }
+  src = (my_src_ptr) cinfo->src;
+  src->pub.bytes_in_buffer = infile.StreamSize(); /* forces fill_input_buffer on first read */
+  src->buffer = (JOCTET *) malloc (infile.StreamSize());
+  src->pub.next_input_byte = src->buffer; /* until buffer loaded */
+  infile.Read(src->buffer, infile.StreamSize());
+
+  src->pub.init_source = my_init_source;
+  src->pub.fill_input_buffer = my_fill_input_buffer;
+  src->pub.skip_input_data = my_skip_input_data;
+  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->pub.term_source = my_term_source;
+}
+
+
+
+bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream )
+{
+    struct jpeg_decompress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    JSAMPARRAY tempbuf;
+    unsigned char *ptr;
+    unsigned stride;
+
+    image->Destroy();
+    cinfo.err = jpeg_std_error( &jerr );
+    jpeg_create_decompress( &cinfo );
+    jpeg_wxio_src( &cinfo, stream );
+    jpeg_read_header( &cinfo, TRUE );
+    cinfo.out_color_space = JCS_RGB;
+    jpeg_start_decompress( &cinfo );
+
+    image->Create( cinfo.image_width, cinfo.image_height );
+    if (!image->Ok()) {
+      jpeg_finish_decompress( &cinfo );
+      jpeg_destroy_decompress( &cinfo );
+      return FALSE;
+    }
+    image->SetMask( FALSE );
+    ptr = image->GetData();
+    stride = cinfo.output_width * 3;
+    tempbuf = (*cinfo.mem->alloc_sarray)
+               ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 );
+
+    while ( cinfo.output_scanline < cinfo.output_height ) {
+      jpeg_read_scanlines( &cinfo, tempbuf, 1 );
+      memcpy( ptr, tempbuf[0], stride );
+      ptr += stride;
+    }
+    jpeg_finish_decompress( &cinfo );
+    jpeg_destroy_decompress( &cinfo );
+    return TRUE;
+}
+
+
+
+
+
+typedef struct {
+  struct jpeg_destination_mgr pub;
+
+  wxOutputStream *stream;
+  JOCTET * buffer;
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE  4096  /* choose an efficiently fwrite'able size */
+
+METHODDEF(void) init_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+  /* Allocate the output buffer --- it will be released when done with image */
+  dest->buffer = (JOCTET *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+                                 OUTPUT_BUF_SIZE * sizeof(JOCTET));
+  dest->pub.next_output_byte = dest->buffer;
+  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+  dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE);
+  dest->pub.next_output_byte = dest->buffer;
+  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+  return TRUE;
+}
+
+METHODDEF(void) term_destination (j_compress_ptr cinfo)
+{
+  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+  size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+  /* Write any data remaining in the buffer */
+  if (datacount > 0)
+    dest->stream->Write(dest->buffer, datacount);
+}
+
+GLOBAL(void) jpeg_wxio_dest (j_compress_ptr cinfo, wxOutputStream& outfile)
+{
+  my_dest_ptr dest;
+
+  if (cinfo->dest == NULL) {   /* first time for this JPEG object? */
+    cinfo->dest = (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                 sizeof(my_destination_mgr));
+  }
+
+  dest = (my_dest_ptr) cinfo->dest;
+  dest->pub.init_destination = init_destination;
+  dest->pub.empty_output_buffer = empty_output_buffer;
+  dest->pub.term_destination = term_destination;
+  dest->stream = &outfile;
+}
+
+
+
+bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
+{
+  struct jpeg_compress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPROW row_pointer[1];     /* pointer to JSAMPLE row[s] */
+  JSAMPLE *image_buffer;
+  int stride;                  /* physical row width in image buffer */
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_compress(&cinfo);
+  jpeg_wxio_dest(&cinfo, stream);
+
+  cinfo.image_width = image->GetWidth();
+  cinfo.image_height = image->GetHeight();
+  cinfo.input_components = 3;
+  cinfo.in_color_space = JCS_RGB;
+  jpeg_set_defaults(&cinfo);
+  jpeg_start_compress(&cinfo, TRUE);
+
+  stride = cinfo.image_width * 3;      /* JSAMPLEs per row in image_buffer */
+  image_buffer = image->GetData();
+  while (cinfo.next_scanline < cinfo.image_height) {
+    row_pointer[0] = &image_buffer[cinfo.next_scanline * stride];
+    jpeg_write_scanlines( &cinfo, row_pointer, 1 );
+  }
+  jpeg_finish_compress(&cinfo);
+  jpeg_destroy_compress(&cinfo);
+
+  return TRUE;
+}
+#endif // wxUSE_STREAMS
+
+#endif
+
+  // wxUSE_LIBJPEG
+
+
+
 //-----------------------------------------------------------------------------
 // wxBMPHandler
 //-----------------------------------------------------------------------------
@@ -741,6 +986,7 @@ bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream )
 IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler)
 #endif
 
+#if wxUSE_STREAMS
 bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
 {
    unsigned char      *data, *ptr;
@@ -1090,220 +1336,339 @@ bool wxBMPHandler::LoadFile( wxImage *image, wxInputStream& stream )
 
    return TRUE;
 }
+#endif // wxUSE_STREAMS
 
 #ifdef __WXMSW__
 
 wxBitmap wxImage::ConvertToBitmap() const
 {
+// sizeLimit is the MS upper limit for the DIB size
+    int sizeLimit = 1024*768*3; 
 
-  wxBitmap bitmap;
-  wxCHECK_MSG( Ok(), bitmap, "invalid image" );
-  int width = GetWidth();
-  int height = GetHeight();
-  bitmap.SetWidth( width );
-  bitmap.SetHeight( height );
-  bitmap.SetDepth( wxDisplayDepth() );
+// 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 );
+    div_t lineBoundary = div( bytePerLine, sizeDWORD );
+    int padding = 0;
+    if( lineBoundary.rem > 0 )  
+    {
+        padding = sizeDWORD - lineBoundary.rem;
+        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
+    {
+        div_t result = div( bmpHeight, height );
+        numDIB = result.quot;
+       hRemain = result.rem;
+       if( hRemain >0 )  numDIB++;
+    }
 
-  int headersize = sizeof(BITMAPINFOHEADER);
-  LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
-  wxCHECK_MSG( lpDIBh, bitmap, "could not allocate memory for DIB header" );
+// set bitmap parameters
+    wxBitmap bitmap;
+    wxCHECK_MSG( Ok(), bitmap, "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, "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 );
+    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( "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);
+//    ::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;
-      }
+//         0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
+//    ::SelectObject( memdc, 0 ); 
+//    ::DeleteDC( memdc ); 
     }
-    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 );
+    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( int 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 );
+// 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 );
+        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 );
+// free allocated resources  
+    ::SelectObject( memdc, 0 ); 
+    ::DeleteDC( memdc ); 
+    ::ReleaseDC(NULL, hdc);   
+    free(lpDIBh);
+    free(lpBits);
 
-  return bitmap;
+// check the wxBitmap object
+    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;
-  }
+// check the 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;
-  }
+// 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;
+    }
 
-  int headersize = sizeof(BITMAPINFOHEADER);
-  LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
-  if( !lpDIBh )
-  {
-      wxFAIL_MSG( "could not allocate data for DIB header" );
-      free( data );
-      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 = 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++ )
+    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 )
     {
-      if( *ptbits != 0 )
-      {
-        *(ptdata++)  = r;
-        *(ptdata++)  = g;
-        *(ptdata++)  = b;
-      }
-      ptbits += 3;
+        wxFAIL_MSG( "could not allocate data for DIB" );
+        free( data );
+        free( lpDIBh );
+        return;
     }
-    SetMaskColour( r, g, b );
-  }
-
-  ::ReleaseDC(NULL, hdc);
-  free(lpDIBh);
-  free(lpBits);
+    
+// 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
@@ -1417,8 +1782,7 @@ wxBitmap wxImage::ConvertToBitmap() const
                     int pixel = -1;
                     if (wxTheApp->m_colorCube)
                     {
-                        pixel = wxTheApp->m_colorCube
-                           [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
+                        pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
                     }
                     else
                     {
@@ -1582,12 +1946,11 @@ wxImage::wxImage( const wxBitmap &bitmap )
 
 #endif
 
-// TODO
-
 #ifdef __WXMOTIF__
 
 #include <Xm/Xm.h>
 #include "wx/utils.h"
+#include <math.h>
 
 wxBitmap wxImage::ConvertToBitmap() const
 {
@@ -1630,8 +1993,6 @@ wxBitmap wxImage::ConvertToBitmap() const
     }
 */
 
-//    bitmap.SetDepth( bpp );
-    
     // Retrieve depth info
     
     XVisualInfo vinfo_template;
@@ -1650,6 +2011,8 @@ wxBitmap wxImage::ConvertToBitmap() const
         return wxNullBitmap;
     }
        
+    XFree( vi );
+
     if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
     if (bpp < 8) bpp = 8;
 
@@ -1674,6 +2037,15 @@ wxBitmap wxImage::ConvertToBitmap() const
     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 );
+    }
+
     unsigned char* data = GetData();
 
     int index = 0;
@@ -1702,8 +2074,8 @@ wxBitmap wxImage::ConvertToBitmap() const
            {
                case 8:
                {
-/*
                     int pixel = -1;
+/*
                    if (wxTheApp->m_colorCube)
                    {
                        pixel = wxTheApp->m_colorCube
@@ -1711,23 +2083,20 @@ wxBitmap wxImage::ConvertToBitmap() const
                     }              
                     else
                    {
-                       GdkColormap *cmap = gtk_widget_get_default_colormap();
-                        GdkColor *colors = cmap->colors;
+*/
                         int max = 3 * (65536);
-
-                        for (int i = 0; i < cmap->size; i++)
+                        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);
+                            int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
                             if (sum < max) { pixel = i; max = sum; }
                        }
-                    }
-
-                   gdk_image_put_pixel( data_image, x, y, pixel );
+/*
+                   }
 */
-
+                   XPutPixel( data_image, x, y, pixel );
                    break;
                }
                case 15:
@@ -1791,6 +2160,121 @@ wxBitmap wxImage::ConvertToBitmap() const
 
 wxImage::wxImage( const wxBitmap &bitmap )
 {
-  wxFAIL_MSG("Sorry, wxImage::wxImage(const wxBitmap&) isn't implemented for wxMotif yet.");
+    wxCHECK_RET( bitmap.Ok(), "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, "couldn't create image" );
+
+    Create( bitmap.GetWidth(), bitmap.GetHeight() );
+    char unsigned *data = GetData();
+
+    if (!data)
+    {
+        XDestroyImage( ximage );
+        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
+    }
+*/
+
+    // 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 );
+    
+    if (!vi) 
+    {
+        printf("no visual.\n" );
+        return;
+    }
+       
+    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