home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / image.cpp < prev    next >
C/C++ Source or Header  |  2002-12-05  |  48KB  |  1,725 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        image.cpp
  3. // Purpose:     wxImage
  4. // Author:      Robert Roebling
  5. // RCS-ID:      $Id: image.cpp,v 1.147.2.4 2002/12/05 10:09:58 JS Exp $
  6. // Copyright:   (c) Robert Roebling
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. #ifdef __GNUG__
  11. #pragma implementation "image.h"
  12. #endif
  13.  
  14. // For compilers that support precompilation, includes "wx.h".
  15. #include "wx/wxprec.h"
  16.  
  17. #ifdef __BORLANDC__
  18.     #pragma hdrstop
  19. #endif
  20.  
  21. #include "wx/defs.h"
  22.  
  23. #if wxUSE_IMAGE
  24.  
  25. #include "wx/image.h"
  26. #include "wx/bitmap.h"
  27. #include "wx/debug.h"
  28. #include "wx/log.h"
  29. #include "wx/app.h"
  30. #include "wx/filefn.h"
  31. #include "wx/wfstream.h"
  32. #include "wx/intl.h"
  33. #include "wx/module.h"
  34.  
  35. // For memcpy
  36. #include <string.h>
  37. #include <math.h>
  38.  
  39. #ifdef __SALFORDC__
  40.     #undef FAR
  41. #endif
  42.  
  43.  
  44. //-----------------------------------------------------------------------------
  45. // wxImage
  46. //-----------------------------------------------------------------------------
  47.  
  48. class wxImageRefData: public wxObjectRefData
  49. {
  50. public:
  51.     wxImageRefData();
  52.     ~wxImageRefData();
  53.  
  54.     int             m_width;
  55.     int             m_height;
  56.     unsigned char  *m_data;
  57.     bool            m_hasMask;
  58.     unsigned char   m_maskRed,m_maskGreen,m_maskBlue;
  59.     bool            m_ok;
  60.     bool            m_static;
  61. #if wxUSE_PALETTE
  62.     wxPalette       m_palette;
  63. #endif // wxUSE_PALETTE
  64.     wxArrayString   m_optionNames;
  65.     wxArrayString   m_optionValues;
  66. };
  67.  
  68. wxImageRefData::wxImageRefData()
  69. {
  70.     m_width = 0;
  71.     m_height = 0;
  72.     m_data = (unsigned char*) NULL;
  73.     m_ok = FALSE;
  74.     m_maskRed = 0;
  75.     m_maskGreen = 0;
  76.     m_maskBlue = 0;
  77.     m_hasMask = FALSE;
  78.     m_static = FALSE;
  79. }
  80.  
  81. wxImageRefData::~wxImageRefData()
  82. {
  83.     if (m_data && !m_static)
  84.         free( m_data );
  85. }
  86.  
  87. wxList wxImage::sm_handlers;
  88.  
  89. wxImage wxNullImage;
  90.  
  91. //-----------------------------------------------------------------------------
  92.  
  93. #define M_IMGDATA ((wxImageRefData *)m_refData)
  94.  
  95. IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
  96.  
  97. wxImage::wxImage()
  98. {
  99. }
  100.  
  101. wxImage::wxImage( int width, int height )
  102. {
  103.     Create( width, height );
  104. }
  105.  
  106. wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
  107. {
  108.     Create( width, height, data, static_data );
  109. }
  110.  
  111. wxImage::wxImage( const wxString& name, long type, int index )
  112. {
  113.     LoadFile( name, type, index );
  114. }
  115.  
  116. wxImage::wxImage( const wxString& name, const wxString& mimetype, int index )
  117. {
  118.     LoadFile( name, mimetype, index );
  119. }
  120.  
  121. #if wxUSE_STREAMS
  122. wxImage::wxImage( wxInputStream& stream, long type, int index )
  123. {
  124.     LoadFile( stream, type, index );
  125. }
  126.  
  127. wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index )
  128. {
  129.     LoadFile( stream, mimetype, index );
  130. }
  131. #endif // wxUSE_STREAMS
  132.  
  133. wxImage::wxImage( const wxImage& image )
  134.     : wxObject()
  135. {
  136.     Ref(image);
  137. }
  138.  
  139. wxImage::wxImage( const wxImage* image )
  140. {
  141.     if (image) Ref(*image);
  142. }
  143.  
  144. void wxImage::Create( int width, int height )
  145. {
  146.     UnRef();
  147.  
  148.     m_refData = new wxImageRefData();
  149.  
  150.     M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
  151.     if (M_IMGDATA->m_data)
  152.     {
  153.         for (int l = 0; l < width*height*3; l++) M_IMGDATA->m_data[l] = 0;
  154.  
  155.         M_IMGDATA->m_width = width;
  156.         M_IMGDATA->m_height = height;
  157.         M_IMGDATA->m_ok = TRUE;
  158.     }
  159.     else
  160.     {
  161.         UnRef();
  162.     }
  163. }
  164.  
  165. void wxImage::Create( int width, int height, unsigned char* data, bool static_data )
  166. {
  167.     UnRef();
  168.  
  169.     m_refData = new wxImageRefData();
  170.  
  171.     M_IMGDATA->m_data = data;
  172.     if (M_IMGDATA->m_data)
  173.     {
  174.         M_IMGDATA->m_width = width;
  175.         M_IMGDATA->m_height = height;
  176.         M_IMGDATA->m_ok = TRUE;
  177.         M_IMGDATA->m_static = static_data;
  178.     }
  179.     else
  180.     {
  181.         UnRef();
  182.     }
  183. }
  184.  
  185. void wxImage::Destroy()
  186. {
  187.     UnRef();
  188. }
  189.  
  190. wxImage wxImage::Copy() const
  191. {
  192.     wxImage image;
  193.  
  194.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  195.  
  196.     image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
  197.  
  198.     char unsigned *data = image.GetData();
  199.  
  200.     wxCHECK_MSG( data, image, wxT("unable to create image") );
  201.  
  202.     image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
  203.     image.SetMask( M_IMGDATA->m_hasMask );
  204.  
  205.     memcpy( data, GetData(), M_IMGDATA->m_width*M_IMGDATA->m_height*3 );
  206.  
  207.     return image;
  208. }
  209.  
  210. wxImage wxImage::Scale( int width, int height ) const
  211. {
  212.     wxImage image;
  213.  
  214.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  215.  
  216.     // can't scale to/from 0 size
  217.     wxCHECK_MSG( (width > 0) && (height > 0), image,
  218.                  wxT("invalid new image size") );
  219.  
  220.     long old_height = M_IMGDATA->m_height,
  221.          old_width  = M_IMGDATA->m_width;
  222.     wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
  223.                  wxT("invalid old image size") );
  224.  
  225.     image.Create( width, height );
  226.  
  227.     char unsigned *data = image.GetData();
  228.  
  229.     wxCHECK_MSG( data, image, wxT("unable to create image") );
  230.  
  231.     if (M_IMGDATA->m_hasMask)
  232.     {
  233.         image.SetMaskColour( M_IMGDATA->m_maskRed,
  234.                              M_IMGDATA->m_maskGreen,
  235.                              M_IMGDATA->m_maskBlue );
  236.     }
  237.  
  238.     char unsigned *source_data = M_IMGDATA->m_data;
  239.     char unsigned *target_data = data;
  240.  
  241. #if 0
  242.     // This is nonsense, RR.
  243.  
  244.     // We do (x, y) -> (x, y)*oldSize/newSize but the valid values of x and y
  245.     // are from 0 to size-1, hence all decrement the sizes
  246.     long old_old_width = old_width;
  247.     old_height--;
  248.     old_width--;
  249.     height--;
  250.     width--;
  251.     for ( long j = 0; j <= height; j++ )
  252.     {
  253.         // don't crash for images with height == 1
  254.         long y_offset = height ? (j * old_height / height)* old_old_width : 0;
  255.  
  256.         for ( long i = 0; i <= width; i++ )
  257.         {
  258.             long x_offset = width ? (i * old_width) / width : 0;
  259.  
  260.             memcpy( target_data, source_data + 3*(y_offset + x_offset), 3 );
  261.             target_data += 3;
  262.         }
  263.     }
  264. #else
  265.     for (long j = 0; j < height; j++)
  266.     {
  267.         long y_offset = (j * old_height / height) * old_width;
  268.  
  269.         for (long i = 0; i < width; i++)
  270.         {
  271.             memcpy( target_data,
  272.                 source_data + 3*(y_offset + ((i * old_width )/ width)),
  273.                 3 );
  274.             target_data += 3;
  275.         }
  276.     }
  277. #endif
  278.  
  279.     // In case this is a cursor, make sure the hotspot is scalled accordingly:
  280.     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) )
  281.         image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,
  282.                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width);
  283.     if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) )
  284.         image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,
  285.                 (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height);
  286.  
  287.     return image;
  288. }
  289.  
  290. wxImage wxImage::Rotate90( bool clockwise ) const
  291. {
  292.     wxImage image;
  293.  
  294.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  295.  
  296.     image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width );
  297.  
  298.     char unsigned *data = image.GetData();
  299.  
  300.     wxCHECK_MSG( data, image, wxT("unable to create image") );
  301.  
  302.     if (M_IMGDATA->m_hasMask)
  303.         image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
  304.  
  305.     long height = M_IMGDATA->m_height;
  306.     long width  = M_IMGDATA->m_width;
  307.  
  308.     char unsigned *source_data = M_IMGDATA->m_data;
  309.     char unsigned *target_data;
  310.  
  311.     for (long j = 0; j < height; j++)
  312.     {
  313.         for (long i = 0; i < width; i++)
  314.         {
  315.             if (clockwise)
  316.                 target_data = data + (((i+1)*height) - j - 1)*3;
  317.             else
  318.                 target_data = data + ((height*(width-1)) + j - (i*height))*3;
  319.             memcpy( target_data, source_data, 3 );
  320.             source_data += 3;
  321.         }
  322.     }
  323.  
  324.     return image;
  325. }
  326.  
  327. wxImage wxImage::Mirror( bool horizontally ) const
  328. {
  329.     wxImage image;
  330.  
  331.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  332.  
  333.     image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
  334.  
  335.     char unsigned *data = image.GetData();
  336.  
  337.     wxCHECK_MSG( data, image, wxT("unable to create image") );
  338.  
  339.     if (M_IMGDATA->m_hasMask)
  340.         image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
  341.  
  342.     long height = M_IMGDATA->m_height;
  343.     long width  = M_IMGDATA->m_width;
  344.  
  345.     char unsigned *source_data = M_IMGDATA->m_data;
  346.     char unsigned *target_data;
  347.  
  348.     if (horizontally)
  349.     {
  350.         for (long j = 0; j < height; j++)
  351.         {
  352.             data += width*3;
  353.             target_data = data-3;
  354.             for (long i = 0; i < width; i++)
  355.             {
  356.                 memcpy( target_data, source_data, 3 );
  357.                 source_data += 3;
  358.                 target_data -= 3;
  359.             }
  360.         }
  361.     }
  362.     else
  363.     {
  364.         for (long i = 0; i < height; i++)
  365.         {
  366.             target_data = data + 3*width*(height-1-i);
  367.             memcpy( target_data, source_data, (size_t)3*width );
  368.             source_data += 3*width;
  369.         }
  370.     }
  371.  
  372.     return image;
  373. }
  374.  
  375. wxImage wxImage::GetSubImage( const wxRect &rect ) const
  376. {
  377.     wxImage image;
  378.  
  379.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  380.  
  381.     wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()),
  382.                  image, wxT("invalid subimage size") );
  383.  
  384.     int subwidth=rect.GetWidth();
  385.     const int subheight=rect.GetHeight();
  386.  
  387.     image.Create( subwidth, subheight );
  388.  
  389.     char unsigned *subdata = image.GetData(), *data=GetData();
  390.  
  391.     wxCHECK_MSG( subdata, image, wxT("unable to create image") );
  392.  
  393.     if (M_IMGDATA->m_hasMask)
  394.         image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
  395.  
  396.     const int subleft=3*rect.GetLeft();
  397.     const int width=3*GetWidth();
  398.     subwidth*=3;
  399.  
  400.     data+=rect.GetTop()*width+subleft;
  401.  
  402.     for (long j = 0; j < subheight; ++j)
  403.     {
  404.         memcpy( subdata, data, subwidth);
  405.         subdata+=subwidth;
  406.         data+=width;
  407.     }
  408.  
  409.     return image;
  410. }
  411.  
  412. void wxImage::Paste( const wxImage &image, int x, int y )
  413. {
  414.     wxCHECK_RET( Ok(), wxT("invalid image") );
  415.     wxCHECK_RET( image.Ok(), wxT("invalid image") );
  416.  
  417.     int xx = 0;
  418.     int yy = 0;
  419.     int width = image.GetWidth();
  420.     int height = image.GetHeight();
  421.  
  422.     if (x < 0)
  423.     {
  424.         xx = -x;
  425.         width += x;
  426.     }
  427.     if (y < 0)
  428.     {
  429.         yy = -y;
  430.         height += y;
  431.     }
  432.  
  433.     if ((x+xx)+width > M_IMGDATA->m_width)
  434.         width = M_IMGDATA->m_width - (x+xx);
  435.     if ((y+yy)+height > M_IMGDATA->m_height)
  436.         height = M_IMGDATA->m_height - (y+yy);
  437.  
  438.     if (width < 1) return;
  439.     if (height < 1) return;
  440.  
  441.     if ((!HasMask() && !image.HasMask()) ||
  442.        ((HasMask() && image.HasMask() &&
  443.          (GetMaskRed()==image.GetMaskRed()) &&
  444.          (GetMaskGreen()==image.GetMaskGreen()) &&
  445.          (GetMaskBlue()==image.GetMaskBlue()))))
  446.     {
  447.         width *= 3;
  448.         unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
  449.         int source_step = image.GetWidth()*3;
  450.  
  451.         unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
  452.         int target_step = M_IMGDATA->m_width*3;
  453.         for (int j = 0; j < height; j++)
  454.         {
  455.             memcpy( target_data, source_data, width );
  456.             source_data += source_step;
  457.             target_data += target_step;
  458.         }
  459.         return;
  460.     }
  461.  
  462.     if (!HasMask() && image.HasMask())
  463.     {
  464.         unsigned char r = image.GetMaskRed();
  465.         unsigned char g = image.GetMaskGreen();
  466.         unsigned char b = image.GetMaskBlue();
  467.  
  468.         width *= 3;
  469.         unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth();
  470.         int source_step = image.GetWidth()*3;
  471.  
  472.         unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width;
  473.         int target_step = M_IMGDATA->m_width*3;
  474.  
  475.         for (int j = 0; j < height; j++)
  476.         {
  477.             for (int i = 0; i < width; i+=3)
  478.             {
  479.                 if ((source_data[i]   != r) &&
  480.                     (source_data[i+1] != g) &&
  481.                     (source_data[i+2] != b))
  482.                 {
  483.                     memcpy( target_data+i, source_data+i, 3 );
  484.                 }
  485.             }
  486.             source_data += source_step;
  487.             target_data += target_step;
  488.         }
  489.     }
  490. }
  491.  
  492. void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1,
  493.                        unsigned char r2, unsigned char g2, unsigned char b2 )
  494. {
  495.     wxCHECK_RET( Ok(), wxT("invalid image") );
  496.  
  497.     char unsigned *data = GetData();
  498.  
  499.     const int w = GetWidth();
  500.     const int h = GetHeight();
  501.  
  502.     for (int j = 0; j < h; j++)
  503.         for (int i = 0; i < w; i++)
  504.         {
  505.             if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1))
  506.             {
  507.                 data[0] = r2;
  508.                 data[1] = g2;
  509.                 data[2] = b2;
  510.             }
  511.             data += 3;
  512.         }
  513. }
  514.  
  515. wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const
  516. {
  517.     wxImage image;
  518.  
  519.     wxCHECK_MSG( Ok(), image, wxT("invalid image") );
  520.  
  521.     image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height );
  522.  
  523.     char unsigned *data = image.GetData();
  524.  
  525.     wxCHECK_MSG( data, image, wxT("unable to create image") );
  526.  
  527.     if (M_IMGDATA->m_hasMask)
  528.     {
  529.         if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g &&
  530.                                          M_IMGDATA->m_maskBlue == b)
  531.             image.SetMaskColour( 255, 255, 255 );
  532.         else
  533.             image.SetMaskColour( 0, 0, 0 );
  534.     }
  535.  
  536.     long size = M_IMGDATA->m_height * M_IMGDATA->m_width;
  537.  
  538.     char unsigned *srcd = M_IMGDATA->m_data;
  539.     char unsigned *tard = image.GetData();
  540.  
  541.     for ( long i = 0; i < size; i++, srcd += 3, tard += 3 )
  542.     {
  543.         if (srcd[0] == r && srcd[1] == g && srcd[2] == b)
  544.             tard[0] = tard[1] = tard[2] = 255;
  545.         else
  546.             tard[0] = tard[1] = tard[2] = 0;
  547.     }
  548.  
  549.     return image;
  550. }
  551.  
  552. void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b )
  553. {
  554.     wxCHECK_RET( Ok(), wxT("invalid image") );
  555.  
  556.     int w = M_IMGDATA->m_width;
  557.     int h = M_IMGDATA->m_height;
  558.  
  559.     wxCHECK_RET( (x>=0) && (y>=0) && (x<w) && (y<h), wxT("invalid image index") );
  560.  
  561.     long pos = (y * w + x) * 3;
  562.  
  563.     M_IMGDATA->m_data[ pos   ] = r;
  564.     M_IMGDATA->m_data[ pos+1 ] = g;
  565.     M_IMGDATA->m_data[ pos+2 ] = b;
  566. }
  567.  
  568. unsigned char wxImage::GetRed( int x, int y ) const
  569. {
  570.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  571.  
  572.     int w = M_IMGDATA->m_width;
  573.     int h = M_IMGDATA->m_height;
  574.  
  575.     wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
  576.  
  577.     long pos = (y * w + x) * 3;
  578.  
  579.     return M_IMGDATA->m_data[pos];
  580. }
  581.  
  582. unsigned char wxImage::GetGreen( int x, int y ) const
  583. {
  584.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  585.  
  586.     int w = M_IMGDATA->m_width;
  587.     int h = M_IMGDATA->m_height;
  588.  
  589.     wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
  590.  
  591.     long pos = (y * w + x) * 3;
  592.  
  593.     return M_IMGDATA->m_data[pos+1];
  594. }
  595.  
  596. unsigned char wxImage::GetBlue( int x, int y ) const
  597. {
  598.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  599.  
  600.     int w = M_IMGDATA->m_width;
  601.     int h = M_IMGDATA->m_height;
  602.  
  603.     wxCHECK_MSG( (x>=0) && (y>=0) && (x<w) && (y<h), 0, wxT("invalid image index") );
  604.  
  605.     long pos = (y * w + x) * 3;
  606.  
  607.     return M_IMGDATA->m_data[pos+2];
  608. }
  609.  
  610. bool wxImage::Ok() const
  611. {
  612.     // image of 0 width or height can't be considered ok - at least because it
  613.     // causes crashes in ConvertToBitmap() if we don't catch it in time
  614.     wxImageRefData *data = M_IMGDATA;
  615.     return data && data->m_ok && data->m_width && data->m_height;
  616. }
  617.  
  618. char unsigned *wxImage::GetData() const
  619. {
  620.     wxCHECK_MSG( Ok(), (char unsigned *)NULL, wxT("invalid image") );
  621.  
  622.     return M_IMGDATA->m_data;
  623. }
  624.  
  625. void wxImage::SetData( char unsigned *data )
  626. {
  627.     wxCHECK_RET( Ok(), wxT("invalid image") );
  628.  
  629.     wxImageRefData *newRefData = new wxImageRefData();
  630.  
  631.     newRefData->m_width = M_IMGDATA->m_width;
  632.     newRefData->m_height = M_IMGDATA->m_height;
  633.     newRefData->m_data = data;
  634.     newRefData->m_ok = TRUE;
  635.     newRefData->m_maskRed = M_IMGDATA->m_maskRed;
  636.     newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
  637.     newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
  638.     newRefData->m_hasMask = M_IMGDATA->m_hasMask;
  639.  
  640.     UnRef();
  641.  
  642.     m_refData = newRefData;
  643. }
  644.  
  645. void wxImage::SetData( char unsigned *data, int new_width, int new_height )
  646. {
  647.     wxImageRefData *newRefData = new wxImageRefData();
  648.  
  649.     if (m_refData)
  650.     {
  651.         newRefData->m_width = new_width;
  652.         newRefData->m_height = new_height;
  653.         newRefData->m_data = data;
  654.         newRefData->m_ok = TRUE;
  655.         newRefData->m_maskRed = M_IMGDATA->m_maskRed;
  656.         newRefData->m_maskGreen = M_IMGDATA->m_maskGreen;
  657.         newRefData->m_maskBlue = M_IMGDATA->m_maskBlue;
  658.         newRefData->m_hasMask = M_IMGDATA->m_hasMask;
  659.     }
  660.     else
  661.     {
  662.         newRefData->m_width = new_width;
  663.         newRefData->m_height = new_height;
  664.         newRefData->m_data = data;
  665.         newRefData->m_ok = TRUE;
  666.     }
  667.  
  668.     UnRef();
  669.  
  670.     m_refData = newRefData;
  671. }
  672.  
  673. void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b )
  674. {
  675.     wxCHECK_RET( Ok(), wxT("invalid image") );
  676.  
  677.     M_IMGDATA->m_maskRed = r;
  678.     M_IMGDATA->m_maskGreen = g;
  679.     M_IMGDATA->m_maskBlue = b;
  680.     M_IMGDATA->m_hasMask = TRUE;
  681. }
  682.  
  683. unsigned char wxImage::GetMaskRed() const
  684. {
  685.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  686.  
  687.     return M_IMGDATA->m_maskRed;
  688. }
  689.  
  690. unsigned char wxImage::GetMaskGreen() const
  691. {
  692.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  693.  
  694.     return M_IMGDATA->m_maskGreen;
  695. }
  696.  
  697. unsigned char wxImage::GetMaskBlue() const
  698. {
  699.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  700.  
  701.     return M_IMGDATA->m_maskBlue;
  702. }
  703.  
  704. void wxImage::SetMask( bool mask )
  705. {
  706.     wxCHECK_RET( Ok(), wxT("invalid image") );
  707.  
  708.     M_IMGDATA->m_hasMask = mask;
  709. }
  710.  
  711. bool wxImage::HasMask() const
  712. {
  713.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  714.  
  715.     return M_IMGDATA->m_hasMask;
  716. }
  717.  
  718. int wxImage::GetWidth() const
  719. {
  720.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  721.  
  722.     return M_IMGDATA->m_width;
  723. }
  724.  
  725. int wxImage::GetHeight() const
  726. {
  727.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  728.  
  729.     return M_IMGDATA->m_height;
  730. }
  731.  
  732.  
  733. bool wxImage::FindFirstUnusedColour(
  734.             unsigned char *r, unsigned char *g, unsigned char *b,
  735.             unsigned char startR, unsigned char startG, unsigned char startB) const
  736. {
  737.     wxImageHistogram histogram;
  738.     unsigned long key;
  739.    
  740.     ComputeHistogram(histogram);
  741.     
  742.     unsigned char r2 = startR;
  743.     unsigned char g2 = startG;
  744.     unsigned char b2 = startB;
  745.     
  746.     key = (r2 << 16) | (g2 << 8) | b2;
  747.  
  748.     while ( histogram.find(key) != histogram.end() )
  749.     {
  750.         // color already used
  751.         r2++;
  752.         if ( r2 >= 255 )
  753.         {
  754.             r2 = 0;
  755.             g2++;
  756.             if ( g2 >= 255 )
  757.             {
  758.                 g2 = 0;
  759.                 b2++;
  760.                 if ( b2 >= 255 )
  761.                 {
  762.                     wxLogError( _("GetUnusedColour:: No Unused Color in image ") );            
  763.                     return FALSE;                              
  764.                 }
  765.             }
  766.         }
  767.         
  768.         key = (r2 << 16) | (g2 << 8) | b2;
  769.     }
  770.     
  771.     if (r) *r = r2;
  772.     if (g) *g = g2;
  773.     if (b) *b = b2;
  774.     
  775.     return TRUE;
  776. }
  777.  
  778.  
  779. bool wxImage::SetMaskFromImage(const wxImage& mask, 
  780.                                unsigned char mr, unsigned char mg, unsigned char mb)
  781. {
  782.     // check that the images are the same size
  783.     if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) )
  784.     {
  785.         wxLogError( _("Image and Mask have different sizes") );            
  786.         return FALSE;
  787.     }
  788.     
  789.     // find unused colour
  790.     unsigned char r,g,b ;
  791.     if (!FindFirstUnusedColour(&r, &g, &b))
  792.     {
  793.         wxLogError( _("No Unused Color in image being masked") );            
  794.         return FALSE ;
  795.     }
  796.         
  797.     char unsigned *imgdata = GetData();
  798.     char unsigned *maskdata = mask.GetData();
  799.  
  800.     const int w = GetWidth();
  801.     const int h = GetHeight();
  802.  
  803.     for (int j = 0; j < h; j++)
  804.     {
  805.         for (int i = 0; i < w; i++)
  806.         {
  807.             if ((maskdata[0] == mr) && (maskdata[1]  == mg) && (maskdata[2] == mb))
  808.             {
  809.                 imgdata[0] = r;
  810.                 imgdata[1] = g;
  811.                 imgdata[2] = b;
  812.             }
  813.             imgdata  += 3;
  814.             maskdata += 3;
  815.         }
  816.     }
  817.  
  818.     SetMaskColour(r, g, b);
  819.     SetMask(TRUE);
  820.     
  821.     return TRUE;
  822. }
  823.  
  824. #if wxUSE_PALETTE
  825.  
  826. // Palette functions
  827.  
  828. bool wxImage::HasPalette() const
  829. {
  830.     if (!Ok())
  831.         return FALSE;
  832.  
  833.     return M_IMGDATA->m_palette.Ok();
  834. }
  835.  
  836. const wxPalette& wxImage::GetPalette() const
  837. {
  838.     wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") );
  839.  
  840.     return M_IMGDATA->m_palette;
  841. }
  842.  
  843. void wxImage::SetPalette(const wxPalette& palette)
  844. {
  845.     wxCHECK_RET( Ok(), wxT("invalid image") );
  846.  
  847.     M_IMGDATA->m_palette = palette;
  848. }
  849.  
  850. #endif // wxUSE_PALETTE
  851.  
  852. // Option functions (arbitrary name/value mapping)
  853. void wxImage::SetOption(const wxString& name, const wxString& value)
  854. {
  855.     wxCHECK_RET( Ok(), wxT("invalid image") );
  856.  
  857.     int idx = M_IMGDATA->m_optionNames.Index(name, FALSE);
  858.     if (idx == wxNOT_FOUND)
  859.     {
  860.         M_IMGDATA->m_optionNames.Add(name);
  861.         M_IMGDATA->m_optionValues.Add(value);
  862.     }
  863.     else
  864.     {
  865.         M_IMGDATA->m_optionNames[idx] = name;
  866.         M_IMGDATA->m_optionValues[idx] = value;
  867.     }
  868. }
  869.  
  870. void wxImage::SetOption(const wxString& name, int value)
  871. {
  872.     wxString valStr;
  873.     valStr.Printf(wxT("%d"), value);
  874.     SetOption(name, valStr);
  875. }
  876.  
  877. wxString wxImage::GetOption(const wxString& name) const
  878. {
  879.     wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") );
  880.  
  881.     int idx = M_IMGDATA->m_optionNames.Index(name, FALSE);
  882.     if (idx == wxNOT_FOUND)
  883.         return wxEmptyString;
  884.     else
  885.         return M_IMGDATA->m_optionValues[idx];
  886. }
  887.  
  888. int wxImage::GetOptionInt(const wxString& name) const
  889. {
  890.     wxCHECK_MSG( Ok(), 0, wxT("invalid image") );
  891.  
  892.     return wxAtoi(GetOption(name));
  893. }
  894.  
  895. bool wxImage::HasOption(const wxString& name) const
  896. {
  897.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  898.  
  899.     return (M_IMGDATA->m_optionNames.Index(name, FALSE) != wxNOT_FOUND);
  900. }
  901.  
  902. bool wxImage::LoadFile( const wxString& filename, long type, int index )
  903. {
  904. #if wxUSE_STREAMS
  905.     if (wxFileExists(filename))
  906.     {
  907.         wxFileInputStream stream(filename);
  908.         wxBufferedInputStream bstream( stream );
  909.         return LoadFile(bstream, type, index);
  910.     }
  911.     else
  912.     {
  913.         wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
  914.  
  915.         return FALSE;
  916.     }
  917. #else // !wxUSE_STREAMS
  918.     return FALSE;
  919. #endif // wxUSE_STREAMS
  920. }
  921.  
  922. bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype, int index )
  923. {
  924. #if wxUSE_STREAMS
  925.     if (wxFileExists(filename))
  926.     {
  927.         wxFileInputStream stream(filename);
  928.         wxBufferedInputStream bstream( stream );
  929.         return LoadFile(bstream, mimetype, index);
  930.     }
  931.     else
  932.     {
  933.         wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() );
  934.  
  935.         return FALSE;
  936.     }
  937. #else // !wxUSE_STREAMS
  938.     return FALSE;
  939. #endif // wxUSE_STREAMS
  940. }
  941.  
  942.  
  943.  
  944. bool wxImage::SaveFile( const wxString& filename ) const
  945. {
  946.     wxString ext = filename.AfterLast('.').Lower();
  947.     
  948.     wxImageHandler * pHandler = FindHandler(ext, -1);
  949.     if (pHandler)
  950.     {
  951.         SaveFile(filename, pHandler->GetType());
  952.         return TRUE;
  953.     }
  954.  
  955.     wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str());
  956.  
  957.     return FALSE;
  958. }
  959.  
  960. bool wxImage::SaveFile( const wxString& filename, int type ) const
  961. {
  962. #if wxUSE_STREAMS
  963.     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
  964.  
  965.     wxFileOutputStream stream(filename);
  966.  
  967.     if ( stream.IsOk() )
  968.     {
  969.         wxBufferedOutputStream bstream( stream );
  970.         return SaveFile(bstream, type);
  971.     }
  972. #endif // wxUSE_STREAMS
  973.  
  974.     return FALSE;
  975. }
  976.  
  977. bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) const
  978. {
  979. #if wxUSE_STREAMS
  980.     ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename);
  981.  
  982.     wxFileOutputStream stream(filename);
  983.  
  984.     if ( stream.IsOk() )
  985.     {
  986.         wxBufferedOutputStream bstream( stream );
  987.         return SaveFile(bstream, mimetype);
  988.     }
  989. #endif // wxUSE_STREAMS
  990.  
  991.     return FALSE;
  992. }
  993.  
  994. bool wxImage::CanRead( const wxString &name )
  995. {
  996. #if wxUSE_STREAMS
  997.   wxFileInputStream stream(name);
  998.   return CanRead(stream);
  999. #else
  1000.   return FALSE;
  1001. #endif
  1002. }
  1003.  
  1004. int wxImage::GetImageCount( const wxString &name, long type )
  1005. {
  1006. #if wxUSE_STREAMS
  1007.   wxFileInputStream stream(name);
  1008.   if (!stream.Ok())
  1009.       return 0;
  1010.   else
  1011.     return GetImageCount(stream, type);
  1012. #else
  1013.   return 0;
  1014. #endif
  1015. }
  1016.  
  1017. #if wxUSE_STREAMS
  1018.  
  1019. bool wxImage::CanRead( wxInputStream &stream )
  1020. {
  1021.     const wxList& list = GetHandlers();
  1022.  
  1023.     for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
  1024.     {
  1025.         wxImageHandler *handler=(wxImageHandler*)node->GetData();
  1026.         if (handler->CanRead( stream ))
  1027.             return TRUE;
  1028.     }
  1029.  
  1030.     return FALSE;
  1031. }
  1032.  
  1033. int wxImage::GetImageCount( wxInputStream &stream, long type )
  1034. {
  1035.     wxImageHandler *handler;
  1036.  
  1037.     if ( type == wxBITMAP_TYPE_ANY )
  1038.     {
  1039.         wxList &list=GetHandlers();
  1040.  
  1041.         for (wxList::Node *node = list.GetFirst(); node; node = node->GetNext())
  1042.         {
  1043.              handler=(wxImageHandler*)node->GetData();
  1044.              if ( handler->CanRead(stream) )
  1045.                  return handler->GetImageCount(stream);
  1046.  
  1047.         }
  1048.  
  1049.         wxLogWarning(_("No handler found for image type."));
  1050.         return 0;
  1051.     }
  1052.  
  1053.     handler = FindHandler(type);
  1054.  
  1055.     if ( !handler )
  1056.     {
  1057.         wxLogWarning(_("No image handler for type %d defined."), type);
  1058.         return FALSE;
  1059.     }
  1060.  
  1061.     if ( handler->CanRead(stream) )
  1062.     {
  1063.         return handler->GetImageCount(stream);
  1064.     }
  1065.     else
  1066.     {
  1067.         wxLogError(_("Image file is not of type %d."), type);
  1068.         return 0;
  1069.     }
  1070. }
  1071.  
  1072. bool wxImage::LoadFile( wxInputStream& stream, long type, int index )
  1073. {
  1074.     UnRef();
  1075.  
  1076.     m_refData = new wxImageRefData;
  1077.  
  1078.     wxImageHandler *handler;
  1079.  
  1080.     if ( type == wxBITMAP_TYPE_ANY )
  1081.     {
  1082.         wxList &list=GetHandlers();
  1083.  
  1084.         for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
  1085.         {
  1086.              handler=(wxImageHandler*)node->GetData();
  1087.              if ( handler->CanRead(stream) )
  1088.                  return handler->LoadFile(this, stream, TRUE/*verbose*/, index);
  1089.  
  1090.         }
  1091.  
  1092.         wxLogWarning( _("No handler found for image type.") );
  1093.         return FALSE;
  1094.     }
  1095.  
  1096.     handler = FindHandler(type);
  1097.  
  1098.     if (handler == 0)
  1099.     {
  1100.         wxLogWarning( _("No image handler for type %d defined."), type );
  1101.  
  1102.         return FALSE;
  1103.     }
  1104.  
  1105.     return handler->LoadFile(this, stream, TRUE/*verbose*/, index);
  1106. }
  1107.  
  1108. bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index )
  1109. {
  1110.     UnRef();
  1111.  
  1112.     m_refData = new wxImageRefData;
  1113.  
  1114.     wxImageHandler *handler = FindHandlerMime(mimetype);
  1115.  
  1116.     if (handler == 0)
  1117.     {
  1118.         wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
  1119.  
  1120.         return FALSE;
  1121.     }
  1122.  
  1123.     return handler->LoadFile( this, stream, TRUE/*verbose*/, index );
  1124. }
  1125.  
  1126. bool wxImage::SaveFile( wxOutputStream& stream, int type ) const
  1127. {
  1128.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  1129.  
  1130.     wxImageHandler *handler = FindHandler(type);
  1131.  
  1132.     if (handler == 0)
  1133.     {
  1134.         wxLogWarning( _("No image handler for type %d defined."), type );
  1135.  
  1136.         return FALSE;
  1137.     }
  1138.  
  1139.     return handler->SaveFile( (wxImage*)this, stream );
  1140. }
  1141.  
  1142. bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
  1143. {
  1144.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  1145.  
  1146.     wxImageHandler *handler = FindHandlerMime(mimetype);
  1147.  
  1148.     if (handler == 0)
  1149.     {
  1150.         wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
  1151.  
  1152.         return FALSE;
  1153.     }
  1154.  
  1155.     return handler->SaveFile( (wxImage*)this, stream );
  1156. }
  1157. #endif // wxUSE_STREAMS
  1158.  
  1159. void wxImage::AddHandler( wxImageHandler *handler )
  1160. {
  1161.     // make sure that the memory will be freed at the program end
  1162.     sm_handlers.DeleteContents(TRUE);
  1163.  
  1164.     // Check for an existing handler of the type being added.
  1165.     if (FindHandler( handler->GetType() ) == 0)
  1166.     {
  1167.         sm_handlers.Append( handler );
  1168.     }
  1169.     else
  1170.     {
  1171.         // This is not documented behaviour, merely the simplest 'fix'
  1172.         // for preventing duplicate additions.  If someone ever has
  1173.         // a good reason to add and remove duplicate handlers (and they
  1174.         // may) we should probably refcount the duplicates.
  1175.         //   also an issue in InsertHandler below.
  1176.  
  1177.         wxLogDebug( _T("Adding duplicate image handler for '%s'"),
  1178.                     handler->GetName().c_str() );
  1179.         delete handler;
  1180.     }
  1181. }
  1182.  
  1183. void wxImage::InsertHandler( wxImageHandler *handler )
  1184. {
  1185.     // make sure that the memory will be freed at the program end
  1186.     sm_handlers.DeleteContents(TRUE);
  1187.  
  1188.     // Check for an existing handler of the type being added.
  1189.     if (FindHandler( handler->GetType() ) == 0)
  1190.     {
  1191.         sm_handlers.Insert( handler );
  1192.     }
  1193.     else
  1194.     {
  1195.         // see AddHandler for additional comments.
  1196.         wxLogDebug( _T("Inserting duplicate image handler for '%s'"),
  1197.                     handler->GetName().c_str() );
  1198.         delete handler;
  1199.     }
  1200. }
  1201.  
  1202. bool wxImage::RemoveHandler( const wxString& name )
  1203. {
  1204.     wxImageHandler *handler = FindHandler(name);
  1205.     if (handler)
  1206.     {
  1207.         sm_handlers.DeleteObject(handler);
  1208.         return TRUE;
  1209.     }
  1210.     else
  1211.         return FALSE;
  1212. }
  1213.  
  1214. wxImageHandler *wxImage::FindHandler( const wxString& name )
  1215. {
  1216.     wxNode *node = sm_handlers.First();
  1217.     while (node)
  1218.     {
  1219.         wxImageHandler *handler = (wxImageHandler*)node->Data();
  1220.         if (handler->GetName().Cmp(name) == 0) return handler;
  1221.  
  1222.         node = node->Next();
  1223.     }
  1224.     return 0;
  1225. }
  1226.  
  1227. wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
  1228. {
  1229.     wxNode *node = sm_handlers.First();
  1230.     while (node)
  1231.     {
  1232.         wxImageHandler *handler = (wxImageHandler*)node->Data();
  1233.         if ( (handler->GetExtension().Cmp(extension) == 0) &&
  1234.             (bitmapType == -1 || handler->GetType() == bitmapType) )
  1235.             return handler;
  1236.         node = node->Next();
  1237.     }
  1238.     return 0;
  1239. }
  1240.  
  1241. wxImageHandler *wxImage::FindHandler( long bitmapType )
  1242. {
  1243.     wxNode *node = sm_handlers.First();
  1244.     while (node)
  1245.     {
  1246.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1247.         if (handler->GetType() == bitmapType) return handler;
  1248.         node = node->Next();
  1249.     }
  1250.     return 0;
  1251. }
  1252.  
  1253. wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
  1254. {
  1255.     wxNode *node = sm_handlers.First();
  1256.     while (node)
  1257.     {
  1258.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1259.         if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
  1260.         node = node->Next();
  1261.     }
  1262.     return 0;
  1263. }
  1264.  
  1265. void wxImage::InitStandardHandlers()
  1266. {
  1267. #if wxUSE_STREAMS
  1268.     AddHandler(new wxBMPHandler);
  1269. #endif // wxUSE_STREAMS
  1270.  
  1271. #if wxUSE_XPM && !defined(__WXGTK__) && !defined(__WXMOTIF__)
  1272.     AddHandler(new wxXPMHandler);
  1273. #endif
  1274. }
  1275.  
  1276. void wxImage::CleanUpHandlers()
  1277. {
  1278.     wxNode *node = sm_handlers.First();
  1279.     while (node)
  1280.     {
  1281.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1282.         wxNode *next = node->Next();
  1283.         delete handler;
  1284.         delete node;
  1285.         node = next;
  1286.     }
  1287. }
  1288.  
  1289. //-----------------------------------------------------------------------------
  1290. // wxImageHandler
  1291. //-----------------------------------------------------------------------------
  1292.  
  1293. IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
  1294.  
  1295. #if wxUSE_STREAMS
  1296. bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
  1297. {
  1298.     return FALSE;
  1299. }
  1300.  
  1301. bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
  1302. {
  1303.     return FALSE;
  1304. }
  1305.  
  1306. int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
  1307. {
  1308.     return 1;
  1309. }
  1310.  
  1311. bool wxImageHandler::CanRead( const wxString& name )
  1312. {
  1313.     if (wxFileExists(name))
  1314.     {
  1315.         wxFileInputStream stream(name);
  1316.         return CanRead(stream);
  1317.     }
  1318.  
  1319.     wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
  1320.  
  1321.     return FALSE;
  1322. }
  1323.  
  1324. bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
  1325. {
  1326.     off_t posOld = stream.TellI();
  1327.     if ( posOld == wxInvalidOffset )
  1328.     {
  1329.         // can't test unseekable stream
  1330.         return FALSE;
  1331.     }
  1332.  
  1333.     bool ok = DoCanRead(stream);
  1334.  
  1335.     // restore the old position to be able to test other formats and so on
  1336.     if ( stream.SeekI(posOld) == wxInvalidOffset )
  1337.     {
  1338.         wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!"));
  1339.  
  1340.         // reading would fail anyhow as we're not at the right position
  1341.         return FALSE;
  1342.     }
  1343.  
  1344.     return ok;
  1345. }
  1346.  
  1347. #endif // wxUSE_STREAMS
  1348.  
  1349.  
  1350.  
  1351. //-----------------------------------------------------------------------------
  1352. // Deprecated wxBitmap conversion routines
  1353. //-----------------------------------------------------------------------------
  1354.  
  1355. #if WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
  1356.  
  1357. #ifdef __WXGTK__
  1358. wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue ) const
  1359. {
  1360.     wxImage mono = this->ConvertToMono( red, green, blue );
  1361.     wxBitmap bitmap( mono, 1 );
  1362.     return bitmap;
  1363. }
  1364. #endif
  1365.  
  1366. wxBitmap wxImage::ConvertToBitmap() const
  1367. {
  1368.     wxBitmap bitmap( *this );
  1369.     return bitmap;
  1370. }
  1371.  
  1372. wxImage::wxImage( const wxBitmap &bitmap )
  1373. {
  1374.     *this = bitmap.ConvertToImage();
  1375. }
  1376.  
  1377. #endif // WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
  1378.  
  1379.  
  1380. //-----------------------------------------------------------------------------
  1381.  
  1382. // GRG, Dic/99
  1383. // Counts and returns the number of different colours. Optionally stops
  1384. // when it exceeds 'stopafter' different colours. This is useful, for
  1385. // example, to see if the image can be saved as 8-bit (256 colour or
  1386. // less, in this case it would be invoked as CountColours(256)). Default
  1387. // value for stopafter is -1 (don't care).
  1388. //
  1389. unsigned long wxImage::CountColours( unsigned long stopafter ) const
  1390. {
  1391.     wxHashTable h;
  1392.     wxObject dummy;
  1393.     unsigned char r, g, b;
  1394.     unsigned char *p;
  1395.     unsigned long size, nentries, key;
  1396.  
  1397.     p = GetData();
  1398.     size = GetWidth() * GetHeight();
  1399.     nentries = 0;
  1400.  
  1401.     for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
  1402.     {
  1403.         r = *(p++);
  1404.         g = *(p++);
  1405.         b = *(p++);
  1406.         key = (r << 16) | (g << 8) | b;
  1407.  
  1408.         if (h.Get(key) == NULL)
  1409.         {
  1410.             h.Put(key, &dummy);
  1411.             nentries++;
  1412.         }
  1413.     }
  1414.  
  1415.     return nentries;
  1416. }
  1417.  
  1418.  
  1419. unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const
  1420. {
  1421.     unsigned char r, g, b;
  1422.     unsigned char *p;
  1423.     unsigned long size, nentries, key;
  1424.  
  1425.     h.clear();
  1426.  
  1427.     p = GetData();
  1428.     size = GetWidth() * GetHeight();
  1429.     nentries = 0;
  1430.  
  1431.     for (unsigned long j = 0; j < size; j++)
  1432.     {
  1433.         r = *(p++);
  1434.         g = *(p++);
  1435.         b = *(p++);
  1436.         key = (r << 16) | (g << 8) | b;
  1437.  
  1438.         wxImageHistogramEntry& entry = h[key];
  1439.         if ( entry.value++ == 0 )
  1440.             entry.index = nentries++;
  1441.     }
  1442.  
  1443.     return nentries;
  1444. }
  1445.  
  1446. /*
  1447.  * Rotation code by Carlos Moreno
  1448.  */
  1449.  
  1450. // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
  1451. //      does exactly the same thing. And I also got rid of wxRotationPixel
  1452. //      bacause of potential problems in architectures where alignment
  1453. //      is an issue, so I had to rewrite parts of the code.
  1454.  
  1455. static const double gs_Epsilon = 1e-10;
  1456.  
  1457. static inline int wxCint (double x)
  1458. {
  1459.     return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
  1460. }
  1461.  
  1462.  
  1463. // Auxiliary function to rotate a point (x,y) with respect to point p0
  1464. // make it inline and use a straight return to facilitate optimization
  1465. // also, the function receives the sine and cosine of the angle to avoid
  1466. // repeating the time-consuming calls to these functions -- sin/cos can
  1467. // be computed and stored in the calling function.
  1468.  
  1469. inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
  1470. {
  1471.     return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
  1472.                         p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
  1473. }
  1474.  
  1475. inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
  1476. {
  1477.     return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
  1478. }
  1479.  
  1480. wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
  1481. {
  1482.     int i;
  1483.     angle = -angle;     // screen coordinates are a mirror image of "real" coordinates
  1484.  
  1485.     // Create pointer-based array to accelerate access to wxImage's data
  1486.     unsigned char ** data = new unsigned char * [GetHeight()];
  1487.  
  1488.     data[0] = GetData();
  1489.  
  1490.     for (i = 1; i < GetHeight(); i++)
  1491.         data[i] = data[i - 1] + (3 * GetWidth());
  1492.  
  1493.     // precompute coefficients for rotation formula
  1494.     // (sine and cosine of the angle)
  1495.     const double cos_angle = cos(angle);
  1496.     const double sin_angle = sin(angle);
  1497.  
  1498.     // Create new Image to store the result
  1499.     // First, find rectangle that covers the rotated image;  to do that,
  1500.     // rotate the four corners
  1501.  
  1502.     const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
  1503.  
  1504.     wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
  1505.     wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
  1506.     wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
  1507.     wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
  1508.  
  1509.     int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
  1510.     int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
  1511.     int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
  1512.     int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
  1513.  
  1514.     wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
  1515.  
  1516.     if (offset_after_rotation != NULL)
  1517.     {
  1518.         *offset_after_rotation = wxPoint (x1, y1);
  1519.     }
  1520.  
  1521.     // GRG: The rotated (destination) image is always accessed
  1522.     //      sequentially, so there is no need for a pointer-based
  1523.     //      array here (and in fact it would be slower).
  1524.     //
  1525.     unsigned char * dst = rotated.GetData();
  1526.  
  1527.     // GRG: if the original image has a mask, use its RGB values
  1528.     //      as the blank pixel, else, fall back to default (black).
  1529.     //
  1530.     unsigned char blank_r = 0;
  1531.     unsigned char blank_g = 0;
  1532.     unsigned char blank_b = 0;
  1533.  
  1534.     if (HasMask())
  1535.     {
  1536.         blank_r = GetMaskRed();
  1537.         blank_g = GetMaskGreen();
  1538.         blank_b = GetMaskBlue();
  1539.         rotated.SetMaskColour( blank_r, blank_g, blank_b );
  1540.     }
  1541.  
  1542.     // Now, for each point of the rotated image, find where it came from, by
  1543.     // performing an inverse rotation (a rotation of -angle) and getting the
  1544.     // pixel at those coordinates
  1545.  
  1546.     // GRG: I've taken the (interpolating) test out of the loops, so that
  1547.     //      it is done only once, instead of repeating it for each pixel.
  1548.  
  1549.     int x;
  1550.     if (interpolating)
  1551.     {
  1552.         for (int y = 0; y < rotated.GetHeight(); y++)
  1553.         {
  1554.             for (x = 0; x < rotated.GetWidth(); x++)
  1555.             {
  1556.                 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
  1557.  
  1558.                 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
  1559.                     -0.25 < src.y && src.y < GetHeight() - 0.75)
  1560.                 {
  1561.                     // interpolate using the 4 enclosing grid-points.  Those
  1562.                     // points can be obtained using floor and ceiling of the
  1563.                     // exact coordinates of the point
  1564.                         // C.M. 2000-02-17:  when the point is near the border, special care is required.
  1565.  
  1566.                     int x1, y1, x2, y2;
  1567.  
  1568.                     if (0 < src.x && src.x < GetWidth() - 1)
  1569.                     {
  1570.                         x1 = wxCint(floor(src.x));
  1571.                         x2 = wxCint(ceil(src.x));
  1572.                     }
  1573.                     else    // else means that x is near one of the borders (0 or width-1)
  1574.                     {
  1575.                         x1 = x2 = wxCint (src.x);
  1576.                     }
  1577.  
  1578.                     if (0 < src.y && src.y < GetHeight() - 1)
  1579.                     {
  1580.                         y1 = wxCint(floor(src.y));
  1581.                         y2 = wxCint(ceil(src.y));
  1582.                     }
  1583.                     else
  1584.                     {
  1585.                         y1 = y2 = wxCint (src.y);
  1586.                     }
  1587.  
  1588.                     // get four points and the distances (square of the distance,
  1589.                     // for efficiency reasons) for the interpolation formula
  1590.  
  1591.                     // GRG: Do not calculate the points until they are
  1592.                     //      really needed -- this way we can calculate
  1593.                     //      just one, instead of four, if d1, d2, d3
  1594.                     //      or d4 are < gs_Epsilon
  1595.  
  1596.                     const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
  1597.                     const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
  1598.                     const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
  1599.                     const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
  1600.  
  1601.                     // Now interpolate as a weighted average of the four surrounding
  1602.                     // points, where the weights are the distances to each of those points
  1603.  
  1604.                     // If the point is exactly at one point of the grid of the source
  1605.                     // image, then don't interpolate -- just assign the pixel
  1606.  
  1607.                     if (d1 < gs_Epsilon)        // d1,d2,d3,d4 are positive -- no need for abs()
  1608.                     {
  1609.                         unsigned char *p = data[y1] + (3 * x1);
  1610.                         *(dst++) = *(p++);
  1611.                         *(dst++) = *(p++);
  1612.                         *(dst++) = *(p++);
  1613.                     }
  1614.                     else if (d2 < gs_Epsilon)
  1615.                     {
  1616.                         unsigned char *p = data[y1] + (3 * x2);
  1617.                         *(dst++) = *(p++);
  1618.                         *(dst++) = *(p++);
  1619.                         *(dst++) = *(p++);
  1620.                     }
  1621.                     else if (d3 < gs_Epsilon)
  1622.                     {
  1623.                         unsigned char *p = data[y2] + (3 * x2);
  1624.                         *(dst++) = *(p++);
  1625.                         *(dst++) = *(p++);
  1626.                         *(dst++) = *(p++);
  1627.                     }
  1628.                     else if (d4 < gs_Epsilon)
  1629.                     {
  1630.                         unsigned char *p = data[y2] + (3 * x1);
  1631.                         *(dst++) = *(p++);
  1632.                         *(dst++) = *(p++);
  1633.                         *(dst++) = *(p++);
  1634.                     }
  1635.                     else
  1636.                     {
  1637.                         // weights for the weighted average are proportional to the inverse of the distance
  1638.                         unsigned char *v1 = data[y1] + (3 * x1);
  1639.                         unsigned char *v2 = data[y1] + (3 * x2);
  1640.                         unsigned char *v3 = data[y2] + (3 * x2);
  1641.                         unsigned char *v4 = data[y2] + (3 * x1);
  1642.  
  1643.                         const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
  1644.  
  1645.                         // GRG: Unrolled.
  1646.  
  1647.                         *(dst++) = (unsigned char)
  1648.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1649.                                w3 * *(v3++) + w4 * *(v4++)) /
  1650.                               (w1 + w2 + w3 + w4) );
  1651.                         *(dst++) = (unsigned char)
  1652.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1653.                                w3 * *(v3++) + w4 * *(v4++)) /
  1654.                               (w1 + w2 + w3 + w4) );
  1655.                         *(dst++) = (unsigned char)
  1656.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1657.                                w3 * *(v3++) + w4 * *(v4++)) /
  1658.                               (w1 + w2 + w3 + w4) );
  1659.                     }
  1660.                 }
  1661.                 else
  1662.                 {
  1663.                     *(dst++) = blank_r;
  1664.                     *(dst++) = blank_g;
  1665.                     *(dst++) = blank_b;
  1666.                 }
  1667.             }
  1668.         }
  1669.     }
  1670.     else    // not interpolating
  1671.     {
  1672.         for (int y = 0; y < rotated.GetHeight(); y++)
  1673.         {
  1674.             for (x = 0; x < rotated.GetWidth(); x++)
  1675.             {
  1676.                 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
  1677.  
  1678.                 const int xs = wxCint (src.x);      // wxCint rounds to the
  1679.                 const int ys = wxCint (src.y);      // closest integer
  1680.  
  1681.                 if (0 <= xs && xs < GetWidth() &&
  1682.                     0 <= ys && ys < GetHeight())
  1683.                 {
  1684.                     unsigned char *p = data[ys] + (3 * xs);
  1685.                     *(dst++) = *(p++);
  1686.                     *(dst++) = *(p++);
  1687.                     *(dst++) = *(p++);
  1688.                 }
  1689.                 else
  1690.                 {
  1691.                     *(dst++) = blank_r;
  1692.                     *(dst++) = blank_g;
  1693.                     *(dst++) = blank_b;
  1694.                 }
  1695.             }
  1696.         }
  1697.     }
  1698.  
  1699.     delete [] data;
  1700.  
  1701.     return rotated;
  1702. }
  1703.  
  1704.  
  1705.  
  1706.  
  1707.  
  1708. // A module to allow wxImage initialization/cleanup
  1709. // without calling these functions from app.cpp or from
  1710. // the user's application.
  1711.  
  1712. class wxImageModule: public wxModule
  1713. {
  1714. DECLARE_DYNAMIC_CLASS(wxImageModule)
  1715. public:
  1716.     wxImageModule() {}
  1717.     bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
  1718.     void OnExit() { wxImage::CleanUpHandlers(); };
  1719. };
  1720.  
  1721. IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
  1722.  
  1723.  
  1724. #endif // wxUSE_IMAGE
  1725.