X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c96ea65713a8dd58ae40b10718723b5c92a303e3..2e09dc2dc80d5dd5c42a559c4dd4738ed006a276:/src/common/image.cpp diff --git a/src/common/image.cpp b/src/common/image.cpp index c19e9da9d7..2c5ba9758d 100644 --- a/src/common/image.cpp +++ b/src/common/image.cpp @@ -58,7 +58,9 @@ public: unsigned char m_maskRed,m_maskGreen,m_maskBlue; bool m_ok; bool m_static; +#if wxUSE_PALETTE wxPalette m_palette; +#endif // wxUSE_PALETTE wxArrayString m_optionNames; wxArrayString m_optionValues; }; @@ -106,25 +108,25 @@ wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) Create( width, height, data, static_data ); } -wxImage::wxImage( const wxString& name, long type ) +wxImage::wxImage( const wxString& name, long type, int index ) { - LoadFile( name, type ); + LoadFile( name, type, index ); } -wxImage::wxImage( const wxString& name, const wxString& mimetype ) +wxImage::wxImage( const wxString& name, const wxString& mimetype, int index ) { - LoadFile( name, mimetype ); + LoadFile( name, mimetype, index ); } #if wxUSE_STREAMS -wxImage::wxImage( wxInputStream& stream, long type ) +wxImage::wxImage( wxInputStream& stream, long type, int index ) { - LoadFile( stream, type ); + LoadFile( stream, type, index ); } -wxImage::wxImage( wxInputStream& stream, const wxString& mimetype ) +wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) { - LoadFile( stream, mimetype ); + LoadFile( stream, mimetype, index ); } #endif // wxUSE_STREAMS @@ -210,7 +212,14 @@ wxImage wxImage::Scale( int width, int height ) const wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - wxCHECK_MSG( (width > 0) && (height > 0), image, wxT("invalid image size") ); + // can't scale to/from 0 size + wxCHECK_MSG( (width > 0) && (height > 0), image, + wxT("invalid new image size") ); + + long old_height = M_IMGDATA->m_height, + old_width = M_IMGDATA->m_width; + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, + wxT("invalid old image size") ); image.Create( width, height ); @@ -219,14 +228,39 @@ wxImage wxImage::Scale( int width, int height ) const wxCHECK_MSG( data, image, wxT("unable to create image") ); if (M_IMGDATA->m_hasMask) - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - - long old_height = M_IMGDATA->m_height; - long old_width = M_IMGDATA->m_width; + { + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } char unsigned *source_data = M_IMGDATA->m_data; char unsigned *target_data = data; +#if 0 + // This is nonsense, RR. + + // We do (x, y) -> (x, y)*oldSize/newSize but the valid values of x and y + // are from 0 to size-1, hence all decrement the sizes + long old_old_width = old_width; + old_height--; + old_width--; + height--; + width--; + for ( long j = 0; j <= height; j++ ) + { + // don't crash for images with height == 1 + long y_offset = height ? (j * old_height / height)* old_old_width : 0; + + for ( long i = 0; i <= width; i++ ) + { + long x_offset = width ? (i * old_width) / width : 0; + + memcpy( target_data, source_data + 3*(y_offset + x_offset), 3 ); + target_data += 3; + } + } +#else for (long j = 0; j < height; j++) { long y_offset = (j * old_height / height) * old_width; @@ -239,6 +273,15 @@ wxImage wxImage::Scale( int width, int height ) const target_data += 3; } } +#endif + + // In case this is a cursor, make sure the hotspot is scalled accordingly: + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height); return image; } @@ -414,31 +457,31 @@ void wxImage::Paste( const wxImage &image, int x, int y ) } return; } - + if (!HasMask() && image.HasMask()) { unsigned char r = image.GetMaskRed(); unsigned char g = image.GetMaskGreen(); unsigned char b = image.GetMaskBlue(); - + width *= 3; unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); int source_step = image.GetWidth()*3; unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; int target_step = M_IMGDATA->m_width*3; - + for (int j = 0; j < height; j++) { for (int i = 0; i < width; i+=3) { - if ((source_data[i] != r) && - (source_data[i+1] != g) && + if ((source_data[i] != r) && + (source_data[i+1] != g) && (source_data[i+2] != b)) { memcpy( target_data+i, source_data+i, 3 ); } - } + } source_data += source_step; target_data += target_step; } @@ -685,6 +728,100 @@ int wxImage::GetHeight() const return M_IMGDATA->m_height; } + +bool wxImage::FindFirstUnusedColour( + unsigned char *r, unsigned char *g, unsigned char *b, + unsigned char startR, unsigned char startG, unsigned char startB) const +{ + wxImageHistogram histogram; + unsigned long key; + + ComputeHistogram(histogram); + + unsigned char r2 = startR; + unsigned char g2 = startG; + unsigned char b2 = startB; + + key = (r2 << 16) | (g2 << 8) | b2; + + while ( histogram.find(key) != histogram.end() ) + { + // color already used + r2++; + if ( r2 >= 255 ) + { + r2 = 0; + g2++; + if ( g2 >= 255 ) + { + g2 = 0; + b2++; + if ( b2 >= 255 ) + { + wxLogError( _("GetUnusedColour:: No Unused Color in image ") ); + return FALSE; + } + } + } + + key = (r2 << 16) | (g2 << 8) | b2; + } + + if (r) *r = r2; + if (g) *g = g2; + if (b) *b = b2; + + return TRUE; +} + + +bool wxImage::SetMaskFromImage(const wxImage& mask, + unsigned char mr, unsigned char mg, unsigned char mb) +{ + // check that the images are the same size + if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) ) + { + wxLogError( _("Image and Mask have different sizes") ); + return FALSE; + } + + // find unused colour + unsigned char r,g,b ; + if (!FindFirstUnusedColour(&r, &g, &b)) + { + wxLogError( _("No Unused Color in image being masked") ); + return FALSE ; + } + + char unsigned *imgdata = GetData(); + char unsigned *maskdata = mask.GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb)) + { + imgdata[0] = r; + imgdata[1] = g; + imgdata[2] = b; + } + imgdata += 3; + maskdata += 3; + } + } + + SetMaskColour(r, g, b); + SetMask(TRUE); + + return TRUE; +} + +#if wxUSE_PALETTE + // Palette functions bool wxImage::HasPalette() const @@ -709,6 +846,8 @@ void wxImage::SetPalette(const wxPalette& palette) M_IMGDATA->m_palette = palette; } +#endif // wxUSE_PALETTE + // Option functions (arbitrary name/value mapping) void wxImage::SetOption(const wxString& name, const wxString& value) { @@ -759,14 +898,14 @@ bool wxImage::HasOption(const wxString& name) const return (M_IMGDATA->m_optionNames.Index(name, FALSE) != wxNOT_FOUND); } -bool wxImage::LoadFile( const wxString& filename, long type ) +bool wxImage::LoadFile( const wxString& filename, long type, int index ) { #if wxUSE_STREAMS if (wxFileExists(filename)) { wxFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, type); + return LoadFile(bstream, type, index); } else { @@ -779,14 +918,14 @@ bool wxImage::LoadFile( const wxString& filename, long type ) #endif // wxUSE_STREAMS } -bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype ) +bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype, int index ) { #if wxUSE_STREAMS if (wxFileExists(filename)) { wxFileInputStream stream(filename); wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, mimetype); + return LoadFile(bstream, mimetype, index); } else { @@ -799,9 +938,11 @@ bool wxImage::LoadFile( const wxString& filename, const wxString& mimetype ) #endif // wxUSE_STREAMS } -bool wxImage::SaveFile( const wxString& filename, int type ) +bool wxImage::SaveFile( const wxString& filename, int type ) const { #if wxUSE_STREAMS + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + wxFileOutputStream stream(filename); if ( stream.LastError() == wxStream_NOERROR ) @@ -814,9 +955,11 @@ bool wxImage::SaveFile( const wxString& filename, int type ) return FALSE; } -bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) +bool wxImage::SaveFile( const wxString& filename, const wxString& mimetype ) const { #if wxUSE_STREAMS + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + wxFileOutputStream stream(filename); if ( stream.LastError() == wxStream_NOERROR ) @@ -839,23 +982,72 @@ bool wxImage::CanRead( const wxString &name ) #endif } +int wxImage::GetImageCount( const wxString &name, long type ) +{ +#if wxUSE_STREAMS + wxFileInputStream stream(name); + return GetImageCount(stream, type); +#else + return 0; +#endif +} + #if wxUSE_STREAMS bool wxImage::CanRead( wxInputStream &stream ) { - wxList &list=GetHandlers(); + wxList &list=GetHandlers(); - for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) + for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) { - wxImageHandler *handler=(wxImageHandler*)node->GetData(); - if (handler->CanRead( stream )) - return TRUE; + wxImageHandler *handler=(wxImageHandler*)node->GetData(); + if (handler->CanRead( stream )) + return TRUE; } - return FALSE; + return FALSE; +} + +int wxImage::GetImageCount( wxInputStream &stream, long type ) +{ + wxImageHandler *handler; + + if ( type == wxBITMAP_TYPE_ANY ) + { + wxList &list=GetHandlers(); + + for (wxList::Node *node = list.GetFirst(); node; node = node->GetNext()) + { + handler=(wxImageHandler*)node->GetData(); + if ( handler->CanRead(stream) ) + return handler->GetImageCount(stream); + + } + + wxLogWarning(_("No handler found for image type.")); + return 0; + } + + handler = FindHandler(type); + + if ( !handler ) + { + wxLogWarning(_("No image handler for type %d defined."), type); + return FALSE; + } + + if ( handler->CanRead(stream) ) + { + return handler->GetImageCount(stream); + } + else + { + wxLogError(_("Image file is not of type %d."), type); + return 0; + } } -bool wxImage::LoadFile( wxInputStream& stream, long type ) +bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) { UnRef(); @@ -863,15 +1055,15 @@ bool wxImage::LoadFile( wxInputStream& stream, long type ) wxImageHandler *handler; - if (type==wxBITMAP_TYPE_ANY) + if ( type == wxBITMAP_TYPE_ANY ) { wxList &list=GetHandlers(); for ( wxList::Node *node = list.GetFirst(); node; node = node->GetNext() ) { handler=(wxImageHandler*)node->GetData(); - if (handler->CanRead( stream )) - return handler->LoadFile( this, stream ); + if ( handler->CanRead(stream) ) + return handler->LoadFile(this, stream, TRUE/*verbose*/, index); } @@ -888,10 +1080,10 @@ bool wxImage::LoadFile( wxInputStream& stream, long type ) return FALSE; } - return handler->LoadFile( this, stream ); + return handler->LoadFile(this, stream, TRUE/*verbose*/, index); } -bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype ) +bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) { UnRef(); @@ -906,10 +1098,10 @@ bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype ) return FALSE; } - return handler->LoadFile( this, stream ); + return handler->LoadFile( this, stream, TRUE/*verbose*/, index ); } -bool wxImage::SaveFile( wxOutputStream& stream, int type ) +bool wxImage::SaveFile( wxOutputStream& stream, int type ) const { wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") ); @@ -922,10 +1114,10 @@ bool wxImage::SaveFile( wxOutputStream& stream, int type ) return FALSE; } - return handler->SaveFile( this, stream ); + return handler->SaveFile( (wxImage*)this, stream ); } -bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) +bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const { wxCHECK_MSG( Ok(), FALSE, wxT("invalid image") ); @@ -938,7 +1130,7 @@ bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) return FALSE; } - return handler->SaveFile( this, stream ); + return handler->SaveFile( (wxImage*)this, stream ); } #endif // wxUSE_STREAMS @@ -1023,7 +1215,13 @@ wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) void wxImage::InitStandardHandlers() { - AddHandler( new wxBMPHandler ); +#if wxUSE_STREAMS + AddHandler(new wxBMPHandler); +#endif // wxUSE_STREAMS + +#if wxUSE_XPM && !defined(__WXGTK__) && !defined(__WXMOTIF__) + AddHandler(new wxXPMHandler); +#endif } void wxImage::CleanUpHandlers() @@ -1136,11 +1334,12 @@ IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) // less, in this case it would be invoked as CountColours(256)). Default // value for stopafter is -1 (don't care). // -unsigned long wxImage::CountColours( unsigned long stopafter ) +unsigned long wxImage::CountColours( unsigned long stopafter ) const { wxHashTable h; wxObject dummy; - unsigned char r, g, b, *p; + unsigned char r, g, b; + unsigned char *p; unsigned long size, nentries, key; p = GetData(); @@ -1165,18 +1364,13 @@ unsigned long wxImage::CountColours( unsigned long stopafter ) } -// GRG, Dic/99 -// Computes the histogram of the image and fills a hash table, indexed -// with integer keys built as 0xRRGGBB, containing wxHNode objects. Each -// wxHNode contains an 'index' (useful to build a palette with the image -// colours) and a 'value', which is the number of pixels in the image with -// that colour. -// -unsigned long wxImage::ComputeHistogram( wxHashTable &h ) +unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const { - unsigned char r, g, b, *p; + unsigned char r, g, b; + unsigned char *p; unsigned long size, nentries, key; - wxHNode *hnode; + + h.clear(); p = GetData(); size = GetWidth() * GetHeight(); @@ -1189,18 +1383,9 @@ unsigned long wxImage::ComputeHistogram( wxHashTable &h ) b = *(p++); key = (r << 16) | (g << 8) | b; - hnode = (wxHNode *) h.Get(key); - - if (hnode) - hnode->value++; - else - { - hnode = new wxHNode(); - hnode->index = nentries++; - hnode->value = 1; - - h.Put(key, (wxObject *)hnode); - } + wxImageHistogramEntry& entry = h[key]; + if ( entry.value++ == 0 ) + entry.index = nentries++; } return nentries;