wxImage
Official Classes | Archive • Containers • Controls • Data Structures • Database • Date & Time • Debug • Device Contexts • Dialogs • Document & Views • Drag & Drop • Events • Filesystem • Frames • Graphics • Grid Cell • Help • HTML • Logging • Miscellaneous • Networking • Printing • Sizers • Streams • Threading • Windows |
This class encapsulates a platform-independent image.
An image can be created from data, or using wxBitmap::ConvertToImage. An image can be loaded from a file in a variety of formats, and is extensible to new formats via image format handlers. Functions are available to set and get image bits, so it can be used for basic image manipulation.
A wxImage cannot (currently) be drawn directly to a wxDC. Instead, a platform-specific wxBitmap object must be created from it using the wxBitmap::wxBitmap(wxImage,int depth) constructor. This bitmap can then be drawn in a device context, using wxDC::DrawBitmap.
More on the difference between wxImage and wxBitmap: wxImage is just a buffer of RGB bytes with an optional buffer for the alpha bytes. It is all generic, platform independent and image file format independent code. It includes generic code for scaling, resizing, clipping, and other manipulations of the image data. OTOH, wxBitmap is intended to be a wrapper of whatever is the native image format that is quickest/easiest to draw to a DC or to be the target of the drawing operations performed on a wxMemoryDC. By splitting the responsibilities between wxImage/wxBitmap like this then it's easier to use generic code shared by all platforms and image types for generic operations and platform specific code where performance or compatibility is needed.
One colour value of the image may be used as a mask colour which will lead to the automatic creation of a wxMask object associated to the bitmap object.
Gotchas
If you're opening a file and get: 'Warning: No image handler for type xx defined.', you probably forgot to add the image handler and/or initialise all handlers. See wxImage and wxImageHandler.
The default compression algorithm for the TIFF image handler's SaveFile method is LZW. This algorithm is patented by Unisys Corporation. Unisys is currently enforcing its patent, so software which uses LZW may be held liable. For more information see http://www.unisys.com/about__unisys/lzw. In particular, this patent is no longer enforceable in Canada, France, Germany, Italy, Japan, the United Kingdom and the United States of America - but it remains enforceable in other countries.
wxBasic implementation
This short example shows how to use wxImage to resize an image:
dim Path_img = "immagine.bmp" ' ******* CHANGE NAME HERE!!! ******
frame = new wxFrame( Null, -1, "Using wxImage", wxPoint(20, 20), wxSize(320, 200 + 25))
panel = new wxPanel( frame, -1, wxPoint(0, 200), wxSize(320, 200))
panel2 = new wxPanel( frame, -1, wxPoint(-1, -1), wxSize(0, 0))
bmp = new wxEmptyImage(0, 0) ' Create an empty Image. Size does NOT matter...
img = new wxEmptyBitmap(0, 0) ' Create empty bitmap
bmp2DC = wxMemoryDC() ' Allocate memory: this space will be used to store the bitmap.
if(bmp.LoadFile(Path_img, wxBITMAP_TYPE_BMP)) then 'Load image
wxMessageBox("image loaded correctly")
end if
'resize l'immagine
wxMessageBox("Original size(X,Y) = (" & bmp.GetWidth() & "," & bmp.GetHeight() & ")")
bmp = bmp.Scale(60,60) ' Change image size
wxMessageBox("Size(X,Y) after resize = (" & bmp.GetWidth() & "," & bmp.GetHeight() & ")")
bmp2 = bmp.ConvertToBitmap() 'convert image into bmp
wxMessageBox("convert image into bitmap")
Sub onPaint( event )
dc = wxPaintDC( frame )
dc.BeginDrawing()
dc.DrawBitmap(bmp2, 1, 1, FALSE) 'draw converted image
dc.EndDrawing()
End Sub
Connect( frame, -1, wxEVT_PAINT, "onPaint" )
frame.Show(True)
You can find wxBasic at this address. The language is under development, so the above source may require minor adjustment on some wxBasic versions.
Creating Standalone Copy of wxImage
The wxImage copy constructor doesn't seem to create a new copy of the image object. I used this code to do so:
wxImage* m_pOldImg = new wxImage( "image.bmp", wxBITMAP_TYPE_BMP, -1 );
int dataSize = m_pOldImg->GetWidth() * m_pOldImg->GetHeight() * 3;
unsigned char* NewImgData = ( unsigned char* ) malloc( dataSize );
unsigned char* OldImgData = m_pOldImg->GetData();
memcpy( NewImgData, OldImgData, dataSize );
wxImage* m_pNewImg = new wxImage( m_pOldImg->GetWidth(), m_pOldImg->GetHeight(), NewImgData );
A neater way would be to use wxImage::Copy, but at the time of writing (jan 2006), you need to copy the Alpha channel manually (GetAlphaData(), memcpy, SetAlphaData()).
Supported image formats
I have the following code snippet in an app to find out what image formats are available for use:
#include <wx/list.h>
WX_DECLARE_LIST(wxImageHandler, HandlerList);
#include <wx/listimpl.cpp>
WX_DEFINE_LIST(HandlerList);
wxChoice *formatchoice = new wxChoice( this, -1 );
wxImageHandler* handler;
wxInitAllImageHandlers();
HandlerList& handlers = (HandlerList&)wxImage::GetHandlers();
HandlerList::Node *node = handlers.GetFirst();
while(node) {
wxString extn;
handler = (wxImageHandler *)node->GetData();
extn = handler->GetExtension();
if(extn.Len() > 0) formatchoice->Append(handler->GetExtension(), (void *)handler);
/* If you want to use this for saving, add these checks to the if statement. */
/* && extn != "cur" // Format not good for general-purpose writing
&& extn != "ico" // Format not good for general-purpose writing
&& extn != "iff" // wx Doesn't support writing to this
&& extn != "gif" // wx Doesn't support writing to this
&& extn != "ani" // wx Doesn't support writing to this
*/
node = node->GetNext();
}
/* Use the wxChoice however you want */
const wxString mimetype = ((wxImageHandler *)formatchoice->GetClientData(formatchoice->GetSelection()))->GetMimeType();
if(image.SaveFile(filename->GetValue(), mimetype ) == TRUE) {
/* Image saved successfully */
} else {
/* Image not saved successfully */
}
Basic function to automatically crop 'whitespace' surrounding an image
Very simplistic/slow - only for example purposes:
wxImage AutoCropWhiteSpace(const wxImage& InputImage)
{
int nHeight=InputImage.GetHeight();
int nWidth=InputImage.GetWidth();
unsigned char nR=InputImage.GetRed(0,0);
unsigned char nG=InputImage.GetGreen(0,0);
unsigned char nB=InputImage.GetBlue(0,0);
int nCloseness=15;
wxRect ClipRect;
//Calculate top clip
for(int y=0;y<nHeight;y++)
{
for(int x=0;x<nWidth;x++)
{
if(std::abs(InputImage.GetRed(x,y)-nR)>nCloseness||std::abs(InputImage.GetGreen(x,y)-nG)>nCloseness||std::abs(InputImage.GetBlue(x,y)-nB)>nCloseness)
{
ClipRect.y=std::max(y-1,0);
goto bottom;
}
}
}
bottom:
//Calculate bottom clip
for(int y=nHeight-1;y>=0; y--)
{
for(int x=0;x<nWidth;x++)
{
if(std::abs(InputImage.GetRed(x,y)-nR)>nCloseness||std::abs(InputImage.GetGreen(x,y)-nG)>nCloseness||std::abs(InputImage.GetBlue(x,y)-nB)>nCloseness)
{
ClipRect.height=std::min(y+1,nHeight)-ClipRect.y;
goto left;
}
}
}
left:
//Calculate left clip
for(int x=0;x<nWidth; x++)
{
for(int y=ClipRect.y;y<ClipRect.y+ClipRect.height;y++)
{
if(std::abs(InputImage.GetRed(x,y)-nR)>nCloseness||std::abs(InputImage.GetGreen(x,y)-nG)>nCloseness||std::abs(InputImage.GetBlue(x,y)-nB)>nCloseness)
{
ClipRect.x=std::max(x-1,0);
goto right;
}
}
}
right:
//Calculate right clip
for(int x=nWidth-1;x>=0; x--)
{
for(int y=ClipRect.y;y<ClipRect.y+ClipRect.height;y++)
{
if(std::abs(InputImage.GetRed(x,y)-nR)>nCloseness||std::abs(InputImage.GetGreen(x,y)-nG)>nCloseness||std::abs(InputImage.GetBlue(x,y)-nB)>nCloseness)
{
ClipRect.width=std::min(x+1,nWidth)-ClipRect.x;
goto crop;
}
}
}
crop:
//Create new cropped image
return InputImage.GetSubImage(ClipRect);
}
Correct SetData Documentation
The docs don't correctly document the SetData method. The actual methods for SetImage are:
void SetData( unsigned char *data, bool static_data=false ); void SetData( unsigned char *data, int new_width, int new_height, bool static_data=false );
The most important part is the "static_data" parameter. If you pass true, then wxImage will not try to free the memory. It's also important to note that if you pass "false", thereby indicating that you wish wxImage to delete the data in its own destructor that the memory used for the data was allocated with "malloc()" (i.e. NOT "new" or "new <type>[]) as wxImage's destructor will destroy the data with "free()"