wxWidgets is a great portable GUI library.
These contributions are published under wxWindows licence (based on L-GPL).
This is a tracker similar to the MFC CRectTracker. It is basically a selection rectangle with dragging capabilites, to set its size and position.
Documentation generated by Doxygen is provided.
Thus this class needs a little refactoring, it can be derivated easily, by example in another class wxLineTracker, which does the same thing, but with a line instead of a rectangle.
wxRectTracker is used in RPhoto and in wxCommander
wxConfigDialog is a basic configuration system, for developer who does not want to spend much time in building configuration dialogs. wxConfigDialog handles automatically :
Code example :
m_pConfig = new wxConfig(wxT("RPhoto")); m_pConfigDialog = new wxConfigDialog(*m_pConfig, this, -1, _("Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ); new wxConfigDialog_EntryCheck(*m_pConfigDialog, wxT("Main"), wxT("AutoSave"), _("Main"), _("Auto Save"), FALSE); new wxConfigDialog_EntryTextEdit(*m_pConfigDialog, wxT("JPEG"), wxT("JPEGTran"), _("JPEG"), _("JPEGTran's path"), wxT("jpegtran")); m_pConfigDialog->doLayout();
wxStr64 is a extension to wxString, to help using strings encoded in base64. It does not use the wxEncodingConverter style, because it was mainly developped to store data buffers which may contain the null char in wxString objects.
class wxStringBase64 : public wxString { public: wxStringBase64() : wxString() {}; wxStringBase64(wxString str) : wxString(str) {}; wxStringBase64(unsigned char * src, int size); void setBase64Data(unsigned char * src, int size); int getDataLength(); unsigned char * getBase64Data(); };
For instance, I use wxStringBase64 to store Exif data in wxString, which may contain null char. Storing these data in wxString avoid subclassing wxImage, what would be rather complicated.
Here are some “patchesâ€. Note : it is not regular patch, but more code snippets to solve the problem. I will probably soon submit them as regular patches to wxWidgets.
wxGenericDirCtrl did not accept multiple wildcards as in “Images (*.jpg;*.png;*.tif)â€.
Replace the existing code in wxGenericDirCtrl::ExpandDir
if (d.IsOpened()) { wxStringTokenizer strTok; wxString curFilter; strTok.SetString(m_currentFilterStr,wxT(";")); while(strTok.HasMoreTokens()) { curFilter = strTok.GetNextToken(); if (d.GetFirst(& eachFilename, curFilter, wxDIR_FILES)) { do { if ((eachFilename != wxT(".")) && (eachFilename != wxT(".."))) { filenames.Add(eachFilename); } } while (d.GetNext(& eachFilename)); } } }
This patch has been incorporated in wx2.6. If you use wx2.4 and do not want to recompile it, you can use wxFixedDirCtrl (and #define it) instead.
This is to display the drive label in the tree “(C:) WinXP†instead of only the drive letter “(C:)â€.
Insert the following snippet after the switch(driveType) in wxGenericDirCtrl::SetupSections()
TCHAR FileSysNameBuf[MAX_PATH]; if ((driveType == DRIVE_FIXED) || (driveType == DRIVE_REMOTE)) { GetVolumeInformation(path.c_str(), FileSysNameBuf, MAX_PATH, NULL, NULL, NULL, NULL, 0); name.Printf(wxT("(%c:) %s"), driveBuffer[i], FileSysNameBuf); }
Currently, wxGenericDirCtrl would not show IMG0001.JPG with the filter *.jpg .
If you load and save a jpeg file with the current JPEG handler, you will lose all additionnal informations like Exif, IPTC, comments… A solution is to store these additionnal info in options (see wxImage::SetOption()). The options will be name “APP1†for Exif, “COM†for comments, and “APP2â€..“APP15†for other info.Here are code snippets to solve this :
In wxJPEGHandler::LoadFile between jpeg_create_decompress and jpeg_read_header :
jpeg_save_markers(&cinfo, M_APP0, 32000); [...] jpeg_save_markers(&cinfo, M_APP15, 32000); jpeg_save_markers(&cinfo, M_COM, 32000);
and after jpeg_destroy_decompress :
jpeg_saved_marker_ptr curMarker; wxString markerName, markerValue; curMarker = cinfo.marker_list; while(curMarker != NULL) { switch(curMarker->marker) { case M_APP0: markerName = "APP0"; break; case M_APP1: markerName = "APP1"; break; [...] case M_APP15: markerName = "APP15"; break; case M_COM: markerName = "COM"; break; default: markerName = "UNKNOWN"; break; } markerValue = wxStringBase64(curMarker->data, curMarker->data_length); image->SetOption(markerName, markerValue); wxLogDebug("\n%s = %s", markerName, image->GetOption(markerName)); curMarker = curMarker->next; }
In wxJPEGHandler::SaveFile after jpeg_start_compress :
wxStringBase64 str64; unsigned char * buf; #define SAVE_OPTION(name, index) \ if (image->HasOption((name))) \ { \ wxLogDebug("%s", name); \ str64 = image->GetOption((name)); \ buf = str64.getBase64Data(); \ jpeg_write_marker(&cinfo, (index), buf, str64.getDataLength()); \ if (buf) free(buf); \ } SAVE_OPTION("APP0", M_APP0); SAVE_OPTION("APP1", M_APP1); [...] SAVE_OPTION("APP15", M_APP15); SAVE_OPTION("COM", M_COM); #undef SAVE_OPTION
You will need wxStringBase64. To help integration, I made a new handler wxEJPGHandler. Juste put the two files, and register it in your application OnInit()Â :
wxInitAllImageHandlers(); wxImage::RemoveHandler("JPEG file"); wxImage::InsertHandler(new wxEJPGHandler());
When copying or creating a new image from another, the current implementation of wxImage does not copy the options strings. Thus, all options will be lost when rotating, getting a sub image, and so on.
As wxImage is very hard to subclass (because of m_refData), I prefer a simple helper class (included in wxEJPGHandler::wxImageOpt), to use in applications. I will provide a wxImage patch later.
To use it, define somewhere in your application
static wxImageOpt imageOpts; #define BEGIN_IMAGE_MANIP(img) imageOpts.getImageOptions(img); #define END_IMAGE_MANIP(img) imageOpts.setImageOptions(img);
And before / after each image operation :
BEGIN_IMAGE_MANIP(img) // Image Operation : img = img.GetSubImage(...); END_IMAGE_MANIP(img)
Header :
class WXDLLEXPORT wxImageOpt { public: wxImageOpt(); wxImageOpt(const wxImage & img); getImageOptions(const wxImage & img); setImageOptions(wxImage & img, bool overwrite = false); public: wxArrayString idsToSave; protected: wxArrayString ids; wxArrayString values; };
Code :
wxImageOpt::wxImageOpt() { idsToSave.Add("APP0"); idsToSave.Add("APP1"); idsToSave.Add("APP2"); idsToSave.Add("APP3"); idsToSave.Add("APP4"); idsToSave.Add("APP5"); idsToSave.Add("APP6"); idsToSave.Add("APP7"); idsToSave.Add("APP8"); idsToSave.Add("APP9"); idsToSave.Add("APP10"); idsToSave.Add("APP11"); idsToSave.Add("APP12"); idsToSave.Add("APP13"); idsToSave.Add("APP14"); idsToSave.Add("APP15"); idsToSave.Add("COM"); } wxImageOpt::wxImageOpt(const wxImage & img) { wxImageOpt(); getImageOptions(img); } wxImageOpt::getImageOptions(const wxImage & img) { unsigned int i; ids.Clear(); values.Clear(); for (i = 0 ; i < idsToSave.Count() ; i++) { if (img.HasOption(idsToSave[i])) { ids.Add(idsToSave[i]); values.Add(img.GetOption(idsToSave[i])); } } } wxImageOpt::setImageOptions(wxImage & img, bool overwrite) { unsigned int i; for (i = 0 ; i < ids.Count() ; i++) { if ( (!img.HasOption(ids[i])) || overwrite ) { img.SetOption(ids[i], values[i]); } } }
These properties are in private scope (Grrr, use protected instead, to allow easy patch-subclassing !). It is so impossible to know which options are defined.
Patch TODOÂ : add GetOptions() which returns the wxList of keys.