home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / image.cpp < prev    next >
C/C++ Source or Header  |  2002-06-04  |  47KB  |  1,695 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        image.cpp
  3. // Purpose:     wxImage
  4. // Author:      Robert Roebling
  5. // RCS-ID:      $Id: image.cpp,v 1.147 2002/05/22 23:14:47 VZ 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.LastError() == wxStream_NOERROR )
  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.LastError() == wxStream_NOERROR )
  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.   return GetImageCount(stream, type);
  1009. #else
  1010.   return 0;
  1011. #endif
  1012. }
  1013.  
  1014. #if wxUSE_STREAMS
  1015.  
  1016. bool wxImage::CanRead( wxInputStream &stream )
  1017. {
  1018.     const wxList& list = GetHandlers();
  1019.  
  1020.     for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
  1021.     {
  1022.         wxImageHandler *handler=(wxImageHandler*)node->GetData();
  1023.         if (handler->CanRead( stream ))
  1024.             return TRUE;
  1025.     }
  1026.  
  1027.     return FALSE;
  1028. }
  1029.  
  1030. int wxImage::GetImageCount( wxInputStream &stream, long type )
  1031. {
  1032.     wxImageHandler *handler;
  1033.  
  1034.     if ( type == wxBITMAP_TYPE_ANY )
  1035.     {
  1036.         wxList &list=GetHandlers();
  1037.  
  1038.         for (wxList::Node *node = list.GetFirst(); node; node = node->GetNext())
  1039.         {
  1040.              handler=(wxImageHandler*)node->GetData();
  1041.              if ( handler->CanRead(stream) )
  1042.                  return handler->GetImageCount(stream);
  1043.  
  1044.         }
  1045.  
  1046.         wxLogWarning(_("No handler found for image type."));
  1047.         return 0;
  1048.     }
  1049.  
  1050.     handler = FindHandler(type);
  1051.  
  1052.     if ( !handler )
  1053.     {
  1054.         wxLogWarning(_("No image handler for type %d defined."), type);
  1055.         return FALSE;
  1056.     }
  1057.  
  1058.     if ( handler->CanRead(stream) )
  1059.     {
  1060.         return handler->GetImageCount(stream);
  1061.     }
  1062.     else
  1063.     {
  1064.         wxLogError(_("Image file is not of type %d."), type);
  1065.         return 0;
  1066.     }
  1067. }
  1068.  
  1069. bool wxImage::LoadFile( wxInputStream& stream, long type, int index )
  1070. {
  1071.     UnRef();
  1072.  
  1073.     m_refData = new wxImageRefData;
  1074.  
  1075.     wxImageHandler *handler;
  1076.  
  1077.     if ( type == wxBITMAP_TYPE_ANY )
  1078.     {
  1079.         wxList &list=GetHandlers();
  1080.  
  1081.         for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() )
  1082.         {
  1083.              handler=(wxImageHandler*)node->GetData();
  1084.              if ( handler->CanRead(stream) )
  1085.                  return handler->LoadFile(this, stream, TRUE/*verbose*/, index);
  1086.  
  1087.         }
  1088.  
  1089.         wxLogWarning( _("No handler found for image type.") );
  1090.         return FALSE;
  1091.     }
  1092.  
  1093.     handler = FindHandler(type);
  1094.  
  1095.     if (handler == NULL)
  1096.     {
  1097.         wxLogWarning( _("No image handler for type %d defined."), type );
  1098.  
  1099.         return FALSE;
  1100.     }
  1101.  
  1102.     return handler->LoadFile(this, stream, TRUE/*verbose*/, index);
  1103. }
  1104.  
  1105. bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index )
  1106. {
  1107.     UnRef();
  1108.  
  1109.     m_refData = new wxImageRefData;
  1110.  
  1111.     wxImageHandler *handler = FindHandlerMime(mimetype);
  1112.  
  1113.     if (handler == NULL)
  1114.     {
  1115.         wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
  1116.  
  1117.         return FALSE;
  1118.     }
  1119.  
  1120.     return handler->LoadFile( this, stream, TRUE/*verbose*/, index );
  1121. }
  1122.  
  1123. bool wxImage::SaveFile( wxOutputStream& stream, int type ) const
  1124. {
  1125.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  1126.  
  1127.     wxImageHandler *handler = FindHandler(type);
  1128.  
  1129.     if (handler == NULL)
  1130.     {
  1131.         wxLogWarning( _("No image handler for type %d defined."), type );
  1132.  
  1133.         return FALSE;
  1134.     }
  1135.  
  1136.     return handler->SaveFile( (wxImage*)this, stream );
  1137. }
  1138.  
  1139. bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const
  1140. {
  1141.     wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") );
  1142.  
  1143.     wxImageHandler *handler = FindHandlerMime(mimetype);
  1144.  
  1145.     if (handler == NULL)
  1146.     {
  1147.         wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() );
  1148.  
  1149.         return FALSE;
  1150.     }
  1151.  
  1152.     return handler->SaveFile( (wxImage*)this, stream );
  1153. }
  1154. #endif // wxUSE_STREAMS
  1155.  
  1156. void wxImage::AddHandler( wxImageHandler *handler )
  1157. {
  1158.     // make sure that the memory will be freed at the program end
  1159.     sm_handlers.DeleteContents(TRUE);
  1160.  
  1161.     sm_handlers.Append( handler );
  1162. }
  1163.  
  1164. void wxImage::InsertHandler( wxImageHandler *handler )
  1165. {
  1166.     // make sure that the memory will be freed at the program end
  1167.     sm_handlers.DeleteContents(TRUE);
  1168.  
  1169.     sm_handlers.Insert( handler );
  1170. }
  1171.  
  1172. bool wxImage::RemoveHandler( const wxString& name )
  1173. {
  1174.     wxImageHandler *handler = FindHandler(name);
  1175.     if (handler)
  1176.     {
  1177.         sm_handlers.DeleteObject(handler);
  1178.         return TRUE;
  1179.     }
  1180.     else
  1181.         return FALSE;
  1182. }
  1183.  
  1184. wxImageHandler *wxImage::FindHandler( const wxString& name )
  1185. {
  1186.     wxNode *node = sm_handlers.First();
  1187.     while (node)
  1188.     {
  1189.         wxImageHandler *handler = (wxImageHandler*)node->Data();
  1190.         if (handler->GetName().Cmp(name) == 0) return handler;
  1191.  
  1192.         node = node->Next();
  1193.     }
  1194.     return (wxImageHandler *)NULL;
  1195. }
  1196.  
  1197. wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType )
  1198. {
  1199.     wxNode *node = sm_handlers.First();
  1200.     while (node)
  1201.     {
  1202.         wxImageHandler *handler = (wxImageHandler*)node->Data();
  1203.         if ( (handler->GetExtension().Cmp(extension) == 0) &&
  1204.             (bitmapType == -1 || handler->GetType() == bitmapType) )
  1205.             return handler;
  1206.         node = node->Next();
  1207.     }
  1208.     return (wxImageHandler*)NULL;
  1209. }
  1210.  
  1211. wxImageHandler *wxImage::FindHandler( long bitmapType )
  1212. {
  1213.     wxNode *node = sm_handlers.First();
  1214.     while (node)
  1215.     {
  1216.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1217.         if (handler->GetType() == bitmapType) return handler;
  1218.         node = node->Next();
  1219.     }
  1220.     return NULL;
  1221. }
  1222.  
  1223. wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype )
  1224. {
  1225.     wxNode *node = sm_handlers.First();
  1226.     while (node)
  1227.     {
  1228.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1229.         if (handler->GetMimeType().IsSameAs(mimetype, FALSE)) return handler;
  1230.         node = node->Next();
  1231.     }
  1232.     return NULL;
  1233. }
  1234.  
  1235. void wxImage::InitStandardHandlers()
  1236. {
  1237. #if wxUSE_STREAMS
  1238.     AddHandler(new wxBMPHandler);
  1239. #endif // wxUSE_STREAMS
  1240.  
  1241. #if wxUSE_XPM && !defined(__WXGTK__) && !defined(__WXMOTIF__)
  1242.     AddHandler(new wxXPMHandler);
  1243. #endif
  1244. }
  1245.  
  1246. void wxImage::CleanUpHandlers()
  1247. {
  1248.     wxNode *node = sm_handlers.First();
  1249.     while (node)
  1250.     {
  1251.         wxImageHandler *handler = (wxImageHandler *)node->Data();
  1252.         wxNode *next = node->Next();
  1253.         delete handler;
  1254.         delete node;
  1255.         node = next;
  1256.     }
  1257. }
  1258.  
  1259. //-----------------------------------------------------------------------------
  1260. // wxImageHandler
  1261. //-----------------------------------------------------------------------------
  1262.  
  1263. IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject)
  1264.  
  1265. #if wxUSE_STREAMS
  1266. bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) )
  1267. {
  1268.     return FALSE;
  1269. }
  1270.  
  1271. bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) )
  1272. {
  1273.     return FALSE;
  1274. }
  1275.  
  1276. int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) )
  1277. {
  1278.     return 1;
  1279. }
  1280.  
  1281. bool wxImageHandler::CanRead( const wxString& name )
  1282. {
  1283.     if (wxFileExists(name))
  1284.     {
  1285.         wxFileInputStream stream(name);
  1286.         return CanRead(stream);
  1287.     }
  1288.  
  1289.     wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() );
  1290.  
  1291.     return FALSE;
  1292. }
  1293.  
  1294. bool wxImageHandler::CallDoCanRead(wxInputStream& stream)
  1295. {
  1296.     off_t posOld = stream.TellI();
  1297.     if ( posOld == wxInvalidOffset )
  1298.     {
  1299.         // can't test unseekable stream
  1300.         return FALSE;
  1301.     }
  1302.  
  1303.     bool ok = DoCanRead(stream);
  1304.  
  1305.     // restore the old position to be able to test other formats and so on
  1306.     if ( stream.SeekI(posOld) == wxInvalidOffset )
  1307.     {
  1308.         wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!"));
  1309.  
  1310.         // reading would fail anyhow as we're not at the right position
  1311.         return FALSE;
  1312.     }
  1313.  
  1314.     return ok;
  1315. }
  1316.  
  1317. #endif // wxUSE_STREAMS
  1318.  
  1319.  
  1320.  
  1321. //-----------------------------------------------------------------------------
  1322. // Deprecated wxBitmap convertion routines
  1323. //-----------------------------------------------------------------------------
  1324.  
  1325. #if WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
  1326.  
  1327. #ifdef __WXGTK__
  1328. wxBitmap wxImage::ConvertToMonoBitmap( unsigned char red, unsigned char green, unsigned char blue ) const
  1329. {
  1330.     wxImage mono = this->ConvertToMono( red, green, blue );
  1331.     wxBitmap bitmap( mono, 1 );
  1332.     return bitmap;
  1333. }
  1334. #endif
  1335.  
  1336. wxBitmap wxImage::ConvertToBitmap() const
  1337. {
  1338.     wxBitmap bitmap( *this );
  1339.     return bitmap;
  1340. }
  1341.  
  1342. wxImage::wxImage( const wxBitmap &bitmap )
  1343. {
  1344.     *this = bitmap.ConvertToImage();
  1345. }
  1346.  
  1347. #endif // WXWIN_COMPATIBILITY_2_2 && wxUSE_GUI
  1348.  
  1349.  
  1350. //-----------------------------------------------------------------------------
  1351.  
  1352. // GRG, Dic/99
  1353. // Counts and returns the number of different colours. Optionally stops
  1354. // when it exceeds 'stopafter' different colours. This is useful, for
  1355. // example, to see if the image can be saved as 8-bit (256 colour or
  1356. // less, in this case it would be invoked as CountColours(256)). Default
  1357. // value for stopafter is -1 (don't care).
  1358. //
  1359. unsigned long wxImage::CountColours( unsigned long stopafter ) const
  1360. {
  1361.     wxHashTable h;
  1362.     wxObject dummy;
  1363.     unsigned char r, g, b;
  1364.     unsigned char *p;
  1365.     unsigned long size, nentries, key;
  1366.  
  1367.     p = GetData();
  1368.     size = GetWidth() * GetHeight();
  1369.     nentries = 0;
  1370.  
  1371.     for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++)
  1372.     {
  1373.         r = *(p++);
  1374.         g = *(p++);
  1375.         b = *(p++);
  1376.         key = (r << 16) | (g << 8) | b;
  1377.  
  1378.         if (h.Get(key) == NULL)
  1379.         {
  1380.             h.Put(key, &dummy);
  1381.             nentries++;
  1382.         }
  1383.     }
  1384.  
  1385.     return nentries;
  1386. }
  1387.  
  1388.  
  1389. unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const
  1390. {
  1391.     unsigned char r, g, b;
  1392.     unsigned char *p;
  1393.     unsigned long size, nentries, key;
  1394.  
  1395.     h.clear();
  1396.  
  1397.     p = GetData();
  1398.     size = GetWidth() * GetHeight();
  1399.     nentries = 0;
  1400.  
  1401.     for (unsigned long j = 0; j < size; j++)
  1402.     {
  1403.         r = *(p++);
  1404.         g = *(p++);
  1405.         b = *(p++);
  1406.         key = (r << 16) | (g << 8) | b;
  1407.  
  1408.         wxImageHistogramEntry& entry = h[key];
  1409.         if ( entry.value++ == 0 )
  1410.             entry.index = nentries++;
  1411.     }
  1412.  
  1413.     return nentries;
  1414. }
  1415.  
  1416. /*
  1417.  * Rotation code by Carlos Moreno
  1418.  */
  1419.  
  1420. // GRG: I've removed wxRotationPoint - we already have wxRealPoint which
  1421. //      does exactly the same thing. And I also got rid of wxRotationPixel
  1422. //      bacause of potential problems in architectures where alignment
  1423. //      is an issue, so I had to rewrite parts of the code.
  1424.  
  1425. static const double gs_Epsilon = 1e-10;
  1426.  
  1427. static inline int wxCint (double x)
  1428. {
  1429.     return (x > 0) ? (int) (x + 0.5) : (int) (x - 0.5);
  1430. }
  1431.  
  1432.  
  1433. // Auxiliary function to rotate a point (x,y) with respect to point p0
  1434. // make it inline and use a straight return to facilitate optimization
  1435. // also, the function receives the sine and cosine of the angle to avoid
  1436. // repeating the time-consuming calls to these functions -- sin/cos can
  1437. // be computed and stored in the calling function.
  1438.  
  1439. inline wxRealPoint rotated_point (const wxRealPoint & p, double cos_angle, double sin_angle, const wxRealPoint & p0)
  1440. {
  1441.     return wxRealPoint (p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle,
  1442.                         p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle);
  1443. }
  1444.  
  1445. inline wxRealPoint rotated_point (double x, double y, double cos_angle, double sin_angle, const wxRealPoint & p0)
  1446. {
  1447.     return rotated_point (wxRealPoint(x,y), cos_angle, sin_angle, p0);
  1448. }
  1449.  
  1450. wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const
  1451. {
  1452.     int i;
  1453.     angle = -angle;     // screen coordinates are a mirror image of "real" coordinates
  1454.  
  1455.     // Create pointer-based array to accelerate access to wxImage's data
  1456.     unsigned char ** data = new unsigned char * [GetHeight()];
  1457.  
  1458.     data[0] = GetData();
  1459.  
  1460.     for (i = 1; i < GetHeight(); i++)
  1461.         data[i] = data[i - 1] + (3 * GetWidth());
  1462.  
  1463.     // precompute coefficients for rotation formula
  1464.     // (sine and cosine of the angle)
  1465.     const double cos_angle = cos(angle);
  1466.     const double sin_angle = sin(angle);
  1467.  
  1468.     // Create new Image to store the result
  1469.     // First, find rectangle that covers the rotated image;  to do that,
  1470.     // rotate the four corners
  1471.  
  1472.     const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y);
  1473.  
  1474.     wxRealPoint p1 = rotated_point (0, 0, cos_angle, sin_angle, p0);
  1475.     wxRealPoint p2 = rotated_point (0, GetHeight(), cos_angle, sin_angle, p0);
  1476.     wxRealPoint p3 = rotated_point (GetWidth(), 0, cos_angle, sin_angle, p0);
  1477.     wxRealPoint p4 = rotated_point (GetWidth(), GetHeight(), cos_angle, sin_angle, p0);
  1478.  
  1479.     int x1 = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x)));
  1480.     int y1 = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y)));
  1481.     int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
  1482.     int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
  1483.  
  1484.     wxImage rotated (x2 - x1 + 1, y2 - y1 + 1);
  1485.  
  1486.     if (offset_after_rotation != NULL)
  1487.     {
  1488.         *offset_after_rotation = wxPoint (x1, y1);
  1489.     }
  1490.  
  1491.     // GRG: The rotated (destination) image is always accessed
  1492.     //      sequentially, so there is no need for a pointer-based
  1493.     //      array here (and in fact it would be slower).
  1494.     //
  1495.     unsigned char * dst = rotated.GetData();
  1496.  
  1497.     // GRG: if the original image has a mask, use its RGB values
  1498.     //      as the blank pixel, else, fall back to default (black).
  1499.     //
  1500.     unsigned char blank_r = 0;
  1501.     unsigned char blank_g = 0;
  1502.     unsigned char blank_b = 0;
  1503.  
  1504.     if (HasMask())
  1505.     {
  1506.         blank_r = GetMaskRed();
  1507.         blank_g = GetMaskGreen();
  1508.         blank_b = GetMaskBlue();
  1509.         rotated.SetMaskColour( blank_r, blank_g, blank_b );
  1510.     }
  1511.  
  1512.     // Now, for each point of the rotated image, find where it came from, by
  1513.     // performing an inverse rotation (a rotation of -angle) and getting the
  1514.     // pixel at those coordinates
  1515.  
  1516.     // GRG: I've taken the (interpolating) test out of the loops, so that
  1517.     //      it is done only once, instead of repeating it for each pixel.
  1518.  
  1519.     int x;
  1520.     if (interpolating)
  1521.     {
  1522.         for (int y = 0; y < rotated.GetHeight(); y++)
  1523.         {
  1524.             for (x = 0; x < rotated.GetWidth(); x++)
  1525.             {
  1526.                 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
  1527.  
  1528.                 if (-0.25 < src.x && src.x < GetWidth() - 0.75 &&
  1529.                     -0.25 < src.y && src.y < GetHeight() - 0.75)
  1530.                 {
  1531.                     // interpolate using the 4 enclosing grid-points.  Those
  1532.                     // points can be obtained using floor and ceiling of the
  1533.                     // exact coordinates of the point
  1534.                         // C.M. 2000-02-17:  when the point is near the border, special care is required.
  1535.  
  1536.                     int x1, y1, x2, y2;
  1537.  
  1538.                     if (0 < src.x && src.x < GetWidth() - 1)
  1539.                     {
  1540.                         x1 = wxCint(floor(src.x));
  1541.                         x2 = wxCint(ceil(src.x));
  1542.                     }
  1543.                     else    // else means that x is near one of the borders (0 or width-1)
  1544.                     {
  1545.                         x1 = x2 = wxCint (src.x);
  1546.                     }
  1547.  
  1548.                     if (0 < src.y && src.y < GetHeight() - 1)
  1549.                     {
  1550.                         y1 = wxCint(floor(src.y));
  1551.                         y2 = wxCint(ceil(src.y));
  1552.                     }
  1553.                     else
  1554.                     {
  1555.                         y1 = y2 = wxCint (src.y);
  1556.                     }
  1557.  
  1558.                     // get four points and the distances (square of the distance,
  1559.                     // for efficiency reasons) for the interpolation formula
  1560.  
  1561.                     // GRG: Do not calculate the points until they are
  1562.                     //      really needed -- this way we can calculate
  1563.                     //      just one, instead of four, if d1, d2, d3
  1564.                     //      or d4 are < gs_Epsilon
  1565.  
  1566.                     const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1);
  1567.                     const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1);
  1568.                     const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2);
  1569.                     const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2);
  1570.  
  1571.                     // Now interpolate as a weighted average of the four surrounding
  1572.                     // points, where the weights are the distances to each of those points
  1573.  
  1574.                     // If the point is exactly at one point of the grid of the source
  1575.                     // image, then don't interpolate -- just assign the pixel
  1576.  
  1577.                     if (d1 < gs_Epsilon)        // d1,d2,d3,d4 are positive -- no need for abs()
  1578.                     {
  1579.                         unsigned char *p = data[y1] + (3 * x1);
  1580.                         *(dst++) = *(p++);
  1581.                         *(dst++) = *(p++);
  1582.                         *(dst++) = *(p++);
  1583.                     }
  1584.                     else if (d2 < gs_Epsilon)
  1585.                     {
  1586.                         unsigned char *p = data[y1] + (3 * x2);
  1587.                         *(dst++) = *(p++);
  1588.                         *(dst++) = *(p++);
  1589.                         *(dst++) = *(p++);
  1590.                     }
  1591.                     else if (d3 < gs_Epsilon)
  1592.                     {
  1593.                         unsigned char *p = data[y2] + (3 * x2);
  1594.                         *(dst++) = *(p++);
  1595.                         *(dst++) = *(p++);
  1596.                         *(dst++) = *(p++);
  1597.                     }
  1598.                     else if (d4 < gs_Epsilon)
  1599.                     {
  1600.                         unsigned char *p = data[y2] + (3 * x1);
  1601.                         *(dst++) = *(p++);
  1602.                         *(dst++) = *(p++);
  1603.                         *(dst++) = *(p++);
  1604.                     }
  1605.                     else
  1606.                     {
  1607.                         // weights for the weighted average are proportional to the inverse of the distance
  1608.                         unsigned char *v1 = data[y1] + (3 * x1);
  1609.                         unsigned char *v2 = data[y1] + (3 * x2);
  1610.                         unsigned char *v3 = data[y2] + (3 * x2);
  1611.                         unsigned char *v4 = data[y2] + (3 * x1);
  1612.  
  1613.                         const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4;
  1614.  
  1615.                         // GRG: Unrolled.
  1616.  
  1617.                         *(dst++) = (unsigned char)
  1618.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1619.                                w3 * *(v3++) + w4 * *(v4++)) /
  1620.                               (w1 + w2 + w3 + w4) );
  1621.                         *(dst++) = (unsigned char)
  1622.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1623.                                w3 * *(v3++) + w4 * *(v4++)) /
  1624.                               (w1 + w2 + w3 + w4) );
  1625.                         *(dst++) = (unsigned char)
  1626.                             ( (w1 * *(v1++) + w2 * *(v2++) +
  1627.                                w3 * *(v3++) + w4 * *(v4++)) /
  1628.                               (w1 + w2 + w3 + w4) );
  1629.                     }
  1630.                 }
  1631.                 else
  1632.                 {
  1633.                     *(dst++) = blank_r;
  1634.                     *(dst++) = blank_g;
  1635.                     *(dst++) = blank_b;
  1636.                 }
  1637.             }
  1638.         }
  1639.     }
  1640.     else    // not interpolating
  1641.     {
  1642.         for (int y = 0; y < rotated.GetHeight(); y++)
  1643.         {
  1644.             for (x = 0; x < rotated.GetWidth(); x++)
  1645.             {
  1646.                 wxRealPoint src = rotated_point (x + x1, y + y1, cos_angle, -sin_angle, p0);
  1647.  
  1648.                 const int xs = wxCint (src.x);      // wxCint rounds to the
  1649.                 const int ys = wxCint (src.y);      // closest integer
  1650.  
  1651.                 if (0 <= xs && xs < GetWidth() &&
  1652.                     0 <= ys && ys < GetHeight())
  1653.                 {
  1654.                     unsigned char *p = data[ys] + (3 * xs);
  1655.                     *(dst++) = *(p++);
  1656.                     *(dst++) = *(p++);
  1657.                     *(dst++) = *(p++);
  1658.                 }
  1659.                 else
  1660.                 {
  1661.                     *(dst++) = blank_r;
  1662.                     *(dst++) = blank_g;
  1663.                     *(dst++) = blank_b;
  1664.                 }
  1665.             }
  1666.         }
  1667.     }
  1668.  
  1669.     delete [] data;
  1670.  
  1671.     return rotated;
  1672. }
  1673.  
  1674.  
  1675.  
  1676.  
  1677.  
  1678. // A module to allow wxImage initialization/cleanup
  1679. // without calling these functions from app.cpp or from
  1680. // the user's application.
  1681.  
  1682. class wxImageModule: public wxModule
  1683. {
  1684. DECLARE_DYNAMIC_CLASS(wxImageModule)
  1685. public:
  1686.     wxImageModule() {}
  1687.     bool OnInit() { wxImage::InitStandardHandlers(); return TRUE; };
  1688.     void OnExit() { wxImage::CleanUpHandlers(); };
  1689. };
  1690.  
  1691. IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule)
  1692.  
  1693.  
  1694. #endif // wxUSE_IMAGE
  1695.