%% options copyright owner = Dirk Krause copyright year = 2012 license = bsd %% wx-gui type = frame icon = dkicon_bitmap menu bar = mbMain contents = mainSizer [wxMenuBar mbMain] contents = mFile contents = mExtras contents = mHelp [wxMenu mFile] contents = miOpen contents = miExit text = sTexts[1] [wxMenuItem miOpen] text = sTexts[49] id = DkWxImgsz_Open tip = sTexts[50] [wxMenuItem miExit] text = sTexts[2] id = DkWxImgsz_Quit tip = sTexts[19] [wxMenu mExtras] text = sTexts[38] contents = miOptions [wxMenuItem miOptions] text = sTexts[39] tip = sTexts[40] id = DkWxImgsz_Options [wxMenu mHelp] text = sTexts[27] contents = miHelpContents contents = miHelpAbout [wxMenuItem miHelpContents] text = sTexts[28] tip = sTexts[30] id = DkWxImgsz_Help [wxMenuItem miHelpAbout] text = sTexts[29] tip = sTexts[31] id = DkWxImgsz_About [wxBoxSizer mainSizer] direction = vertical contents = $space(10) contents = horizontalSizer contents = $space(10) contents = statusSizer contents = $space(10) [wxBoxSizer horizontalSizer] grow = yes proportion = 1 contents = $space(10) contents = inputDataSizer left top contents = $space(10) contents = bCalculate centered-x centered-y contents = $space(10) contents = outputDataSizer left top contents = $space(10) [wxGridBagSizer inputDataSizer] grid = 5 5 contents = lOriginalImage 0 0 1 2 left centered-y contents = lWidth +1 0 1 1 right centered-y contents = tWidth . +1 1 1 left centered-y contents = lHeight +1 0 1 1 right centered-y contents = tHeight . +1 1 1 left centered-y contents = $space(10) +1 0 1 1 left contents = lChangeType +1 0 1 2 left centered-y contents = lAction +1 0 1 1 right centered-y contents = cbAction . +1 1 1 left centered-y contents = lMinimum +1 0 1 1 right centered-y contents = tMinimum . +1 1 1 left centered-y contents = lMaximum +1 0 1 1 right centered-y contents = tMaximum . +1 1 1 left centered-y [wxStaticText lOriginalImage] text = sTexts[6] [wxStaticText lWidth] text = sTexts[8] [wxTextCtrl tWidth] tip = sTexts[20] text = sTexts[26] [wxStaticText lHeight] text = sTexts[9] [wxTextCtrl tHeight] tip = sTexts[21] text = sTexts[26] [wxStaticText lChangeType] text = sTexts[10] [wxStaticText lAction] text = sTexts[11] [wxChoice cbAction] choices = 3 saAction tip = sTexts[22] # grow = yes id = DkWxImgsz_Choice [wxStaticText lMinimum] text = sTexts[15] [wxTextCtrl tMinimum] tip = sTexts[23] text = sTexts[26] [wxStaticText lMaximum] text = sTexts[16] [wxTextCtrl tMaximum] tip = sTexts[24] text = sTexts[26] [wxBitmapButton bCalculate] # text = sTexts[17] bitmap = run2_bitmap tip = sTexts[25] id = DkWxImgsz_Run [wxGridBagSizer outputDataSizer] grid = 5 5 grow = yes proportion = 1 contents = lResults 0 0 1 2 left centered-y contents = dataGrid +1 0 2 2 left top growable row = 2 growable column = 1 [wxStaticText lResults] text = sTexts[7] [wxGrid dataGrid] text style = readonly column head = sTexts[3] column head = sTexts[4] column head = sTexts[5] column head = sTexts[18] rows = 16 minimum size = 300 200 grow = true proportion = 1 [wxBoxSizer statusSizer] contents = $space(10) contents = lStatus contents = $space(10) [wxStaticText lStatus] text = sTexts[18] %% header start %% class start /** Main window class for the wximgsz program. */ class DkWxImgszFrame : public DkWxFrame { private: /** Event table. */ DECLARE_EVENT_TABLE() protected: /** Localized message texts. */ wxChar const * const *sTexts; /** Red (used as background color). */ wxColour cRed; /** Red 127. */ wxColour cNotSoDarkRed; /** Green (used as background color). */ wxColour cGreen; /** Black (used as text color). */ wxColour cBlack; /** Dark red (used as text color). */ wxColour cDarkRed; /** Yellow (used as background color). */ wxColour cYellow; /** File dialog x position. */ int fdx; /** File dialog y position. */ int fdy; /** Options dialog x position. */ int odx; /** Options dialog y position. */ int ody; /** Flag: Use background colors to indicate scale factor quality. */ bool bUseColour; /** Current directory. */ wxString sCurrentDir; %% class end public: /** Constructor. */ DkWxImgszFrame( wxChar const *applicationName, wxChar const * const *localizedMessages, DkWxAppHelper *applicationHelper, DkWxHelpController *helpController, int wxid, int argc, wxChar **argv ); /** Destructor. */ ~DkWxImgszFrame(); /** Check whether we can close the window. @param isLast Flag: Last top level window. */ bool canClose(bool isLast); /** Event handler to open a file. @param event Event to process. */ void OnOpen(wxCommandEvent& WXUNUSED(event)); /** Event handler to quit application. @param event Event to process. */ void OnQuit(wxCommandEvent& WXUNUSED(event)); /** Event handler to show help contents. @param event Event to process. */ void OnHelp(wxCommandEvent& WXUNUSED(event)); /** Event handler to show version number. @param event Event to process. */ void OnAbout(wxCommandEvent& WXUNUSED(event)); /** Event handler: Run calculation. @param event Event to process. */ void OnRun(wxCommandEvent& WXUNUSED(event)); /** Event handler: Choice made. @param event Event to process. */ void OnChoice(wxCommandEvent & event); /** Event handler to set options. @param event Event to process. */ void OnOptions(wxCommandEvent& WXUNUSED(event)); protected: /** Save data entered into text fields. */ void saveData(); /** Restore data entered in text fields. */ void restoreData(); /** Enable/disable the lower text fields depending on the current choice selection. */ void enableDisableMinimumMaximum(); /** Calculate largest common divisor. @param aa One number. @param bb Other number. @return Largest common divisor of aa and bb. */ long gcd(long aa, long bb); /** Retrieve positive long number from text field. @param tf Text field to process. @param bShowErrors Flag: Show message boxes for errors. @return Positive number on success, 0L on error. */ long getTextCtrlContents(wxTextCtrl *tf, bool bShowErrors); /** Run calculation. */ void run(bool bShowErrors); /** Run for a set of numbers. @param w Width (or height, if inverted). @param h Height (or width, if inverted). @param min Minimum value. @param max maximum value. @param inverted Flag: w contains the hight, h the width. */ void runForNumbers(long w, long h, long min, long max, int inverted); /** Classify factor. @param n New value. @param o Old value. @return 2 for powers of 2, 1 for integer factors, 0 otherwise. */ int classifyFactor(long n, long o); /** Count bit number in a long value. @param v Value to check. @return Number of bits set. */ int countBits(long v); }; %% header end %% module start #include "wximgsz.h" #include "dkicon.xpm" #include "run2.xpm" $!trace-include /** Event table for the DkWxImgszFrame class. */ BEGIN_EVENT_TABLE(DkWxImgszFrame, wxFrame) EVT_MENU(DkWxImgsz_Quit, DkWxImgszFrame::OnQuit) EVT_MENU(DkWxImgsz_Help, DkWxImgszFrame::OnHelp) EVT_MENU(DkWxImgsz_About, DkWxImgszFrame::OnAbout) EVT_MENU(DkWxImgsz_Options, DkWxImgszFrame::OnOptions) EVT_MENU(DkWxImgsz_Open, DkWxImgszFrame::OnOpen) EVT_BUTTON(DkWxImgsz_Run, DkWxImgszFrame::OnRun) EVT_CHOICE(DkWxImgsz_Choice, DkWxImgszFrame::OnChoice) END_EVENT_TABLE() %% constructor start DkWxImgszFrame::DkWxImgszFrame( wxChar const *applicationName, wxChar const * const *localizedMessages, DkWxAppHelper *applicationHelper, DkWxHelpController *helpController, int wxid, int argc, wxChar **argv ) : DkWxFrame(applicationName, applicationHelper, helpController, wxid), cRed(255, 91, 91), cNotSoDarkRed(127, 0, 0), cGreen(127, 255, 127), cBlack(0, 0, 0), cDarkRed(63, 0, 0), cYellow(255, 255, 0), sCurrentDir(wxT("")) { /* Icon for main window. */ #if defined(__WXMSW__) wxIcon dkicon_bitmap(wxT("aaaaa")); #else wxIcon dkicon_bitmap(xpm_dkicon); #endif wxIcon run2_bitmap(xpm_run2); fdx = -1; fdy = -1; odx = -1; ody = -1; sTexts = localizedMessages; wxString saAction[] = { wxString(localizedMessages[12]), wxString(localizedMessages[13]), wxString(localizedMessages[14]) }; bUseColour = true; %% constructor end if (lOriginalImage) { lOriginalImage->SetForegroundColour(cNotSoDarkRed); } if (lChangeType) { lChangeType->SetForegroundColour(cNotSoDarkRed); } if (lResults) { lResults->SetForegroundColour(cNotSoDarkRed); } SetTitle(localizedMessages[0]); restorePosition(); restoreData(); enableDisableMinimumMaximum(); } %% module end void DkWxImgszFrame::OnHelp(wxCommandEvent& WXUNUSED(event)) { openHelp(); } static wxChar const wximgsz_version[] = { wxT("wximgsz (part of dkt-") }; static wxChar const wximgsz_versnumber[] = { DKT_WXCHAR_VERSION }; static wxChar const wximgsz_versend[] = { wxT(")") }; void DkWxImgszFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) { wxString sVersion(wximgsz_version); sVersion.Append(wximgsz_versnumber); sVersion.Append(wximgsz_versend); sVersion.Append(sTexts[53]); sVersion.Append(wxT("Copyright (c) 2013 Dirk Krause")); sVersion.Append(sTexts[53]); sVersion.Append(sTexts[53]); sVersion.Append(sTexts[54]); sVersion.Append(wxT("DK tools, wxWidgets, libpng, libjpeg, libtiff, zlib.")); sVersion.Append(sTexts[53]); sVersion.Append(sTexts[53]); sVersion.Append(sTexts[55]); sVersion.Append(wxT("http://dktools.sourceforge.net\n")); sVersion.Append(wxT("http://www.wxwidgets.org\n")); sVersion.Append(wxT("http://www.libpng.org/pub/png/libpng.html\n")); sVersion.Append(wxT("http://www.ijg.org\n")); sVersion.Append(wxT("http://www.remotesensing.org/libtiff\n")); sVersion.Append(wxT("http://www.zlib.org")); wxMessageBox(sVersion, sTexts[35]); } void DkWxImgszFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) { $? "+ DkWxImgszFrame::OnQuit" Show(false); Close(); $? "- DkWxBmepsFrame::OnQuit" } void DkWxImgszFrame::OnOpen(wxCommandEvent& WXUNUSED(event)) { wxString s(wxT("")); $? "+ DkWxImgszFrame::OnOpen" s.Append(wxT("BMP files (*.bmp)|*.bmp")); s.Append(wxT("|PNG files (*.png)|*.png")); s.Append(wxT("|JPEG files (*.jpg)|*.jpg|JPEG files (*.jpeg)|*.jpeg")); s.Append(wxT("|TIFF files (*.tif)|*.tif|TIFF files (*.tiff)|*.tiff")); s.Append(wxT("|XPM files (*.xpm)|*.xpm")); s.Append(wxT("|All files (*.*)|*.*")); #if wxCHECK_VERSION(2, 9, 0) wxFileDialog dlg(this, sTexts[48], sCurrentDir, wxT(""), s, wxFD_OPEN); #else wxFileDialog dlg(this, sTexts[48], sCurrentDir, wxT(""), s, wxOPEN); #endif pHelper->setRelatedPosition(this, &dlg, &fdx, &fdy); if(wxID_OK == dlg.ShowModal()) { wxString path = dlg.GetPath(); wxImage img; if(img.LoadFile(path)) { int w = img.GetWidth(); int h = img.GetHeight(); if((w > 0) && (h > 0)) { wxString sWidth; wxString sHeight; sWidth.Printf(wxT("%d"), w); sHeight.Printf(wxT("%d"), h); if((tWidth) && (tHeight)) { tWidth->SetValue(sWidth); tHeight->SetValue(sHeight); Refresh(); Update(); run(false); } } else { /* ERROR: Illegal image dimensions! */ wxMessageBox(sTexts[51], sTexts[52], (wxOK | wxICON_ERROR), this); } } else { /* ERROR: Failed to load file! */ wxMessageBox(sTexts[51], sTexts[52], (wxOK | wxICON_ERROR), this); } } dlg.GetPosition(&fdx, &fdy); $? "- DkWxBmepsFrame::OnOpen" } void DkWxImgszFrame::OnOptions(wxCommandEvent& WXUNUSED(event)) { $? "+ DkWxImgszFrame::OnOptions" DkWxImgszOptionsDialog dlg(this, sTexts[41], sTexts); pHelper->setRelatedPosition(this, &dlg, &odx, &ody); dlg.SetValue(bUseColour); if(dlg.ShowModal() == wxID_OK) { bUseColour = dlg.GetValue(); } dlg.GetPosition(&odx, &ody); $? "- DkWxBmepsFrame::OnOptions" } void DkWxImgszFrame::run(bool bShowErrors) { long w = 0L; long h = 0L; long min = 0L; long max = 0L; int action = 0; $? "+ DkWxImgszFrame::run" w = getTextCtrlContents(tWidth, bShowErrors); if(w > 0L) { h = getTextCtrlContents(tHeight, bShowErrors); if(h > 0L) { switch((action = cbAction->GetCurrentSelection())) { case 2: { min = getTextCtrlContents(tMinimum, bShowErrors); if(min > 0L) { max = getTextCtrlContents(tMaximum, bShowErrors); } } break; case 1: { min = getTextCtrlContents(tMinimum, bShowErrors); if(min > 0L) { max = getTextCtrlContents(tMaximum, bShowErrors); } } break; default: { min = 1L; max = w; action = 1; } break; } if((w > 0L) && (h > 0L) && (min > 0L) && (max > 0L)) { switch(action) { case 2: { runForNumbers(h, w, min, max, 1); } break; default: { runForNumbers(w, h, min, max, 0); } break; } } } } $? "- DkWxImgszFrame::run" } void DkWxImgszFrame::OnRun(wxCommandEvent& WXUNUSED(event)) { $? "+ DkWxImgszFrame::OnRun" run(true); $? "- DkWxImgszFrame::OnRun" } DkWxImgszFrame::~DkWxImgszFrame() { } bool DkWxImgszFrame::canClose(bool isLast) { $? "+ DkWxBmepsFrame::canClose %d", (isLast ? 1 : 0) if(isLast) { saveData(); } $? "- DkWxBmepsFrame::canClose 1" return true; } static wxChar const * const wximgsz_keys[] = { $!string-table macro=wxT wximgsz.width wximgsz.height wximgsz.selection wximgsz.minimum wximgsz.maximum wximgsz.colours $!end }; void DkWxImgszFrame::saveData() { long i[] = { 0L, // Width 0L, // Height 0L, // Selection 0L, // Minimum 0L, // Maximum 0L // bUseColour }; long l; if((tWidth->GetValue()).ToLong(&l)) { i[0] = l; } if((tHeight->GetValue()).ToLong(&l)) { i[1] = l; } i[2] = (long)(cbAction->GetCurrentSelection()); if(i[2] < 0L) i[2] = 0L; if((tMinimum->GetValue()).ToLong(&l)) { i[3] = l; } if((tMaximum->GetValue()).ToLong(&l)) { i[4] = l; } i[5] = ((bUseColour) ? 1L : 0L); if(pHelper) { pHelper->saveMultipleLongs(wximgsz_keys, i); } } void DkWxImgszFrame::restoreData() { wxString sWidth; wxString sHeight; wxString sMinimum; wxString sMaximum; long i[] = { 1024L, // Width 768L, // Height 0L, // Selection 200L, // Minimum 800L, // Maximum 1L // bUseColour }; if(pHelper) { pHelper->retrieveMultipleLongs(wximgsz_keys, i); sWidth.Printf(wxT("%ld"), i[0]); sHeight.Printf(wxT("%ld"), i[1]); sMinimum.Printf(wxT("%ld"), i[3]); sMaximum.Printf(wxT("%ld"), i[4]); tWidth->SetValue(sWidth); tHeight->SetValue(sHeight); tMinimum->SetValue(sMinimum); tMaximum->SetValue(sMaximum); cbAction->SetSelection((int)(i[2])); bUseColour = ((i[5]) ? true : false); } } void DkWxImgszFrame::enableDisableMinimumMaximum() { if(0 == cbAction->GetCurrentSelection()) { tMinimum->SetEditable(false); tMaximum->SetEditable(false); tMinimum->Enable(false); tMaximum->Enable(false); } else { tMinimum->SetEditable(true); tMaximum->SetEditable(true); tMinimum->Enable(true); tMaximum->Enable(true); } } void DkWxImgszFrame::OnChoice(wxCommandEvent & event) { enableDisableMinimumMaximum(); } long DkWxImgszFrame::gcd(long aa, long bb) { long back = 0L; long h = 0L; long a; long b; a = aa; b = bb; while(b > 0L) { h = a % b; a = b; b = h; } back = a; return back; } long DkWxImgszFrame::getTextCtrlContents(wxTextCtrl *tf, bool bShowErrors) { long back = 0L; long l = 0L; if((tf->GetValue()).ToLong(&l)) { back = l; } if(0 >= back) { if(bShowErrors) { tf->SetFocus(); wxMessageBox(sTexts[33], sTexts[32], (wxOK | wxICON_ERROR), this); } } return back; } void DkWxImgszFrame::runForNumbers(long w, long h, long min, long max, int inverted) { long gd; long w0; long h0; long nw; long nh; long i; long z; long n; long g2; int lineno; int cl; int rows; int found = 0; gd = gcd(w, h); if(gd > 0L) { /* Minimum rectangle. */ w0 = w / gd; h0 = h / gd; /* Remove all grid lines. */ rows = dataGrid->GetNumberRows(); dataGrid->DeleteRows(0, rows); /* Build and fill new grid. */ lineno = 0; i = 1; lStatus->SetForegroundColour(cBlack); lStatus->SetLabel(sTexts[18]); while((i * w0) <= max) { if((i * w0) >= min) { found = 1; nw = i * w0; nh = i * h0; /* Classify factor. */ cl = classifyFactor(nw, w); g2 = gcd(nw, w); z = nw / g2; n = w / g2; dataGrid->AppendRows(1); dataGrid->SetCellTextColour(lineno, 0, cBlack); dataGrid->SetCellTextColour(lineno, 1, cBlack); dataGrid->SetCellTextColour(lineno, 2, cBlack); switch(cl) { case 2: { if(bUseColour) { dataGrid->SetCellBackgroundColour(lineno, 2, cGreen); } else { dataGrid->SetCellValue(lineno, 3, sTexts[36]); } } break; case 1: { if(bUseColour) { dataGrid->SetCellBackgroundColour(lineno, 2, cYellow); } else { dataGrid->SetCellValue(lineno, 3, sTexts[37]); } } break; default: { if(bUseColour) { dataGrid->SetCellBackgroundColour(lineno, 2, cRed); } else { dataGrid->SetCellValue(lineno, 3, wxT("")); } } break; } if(bUseColour) { dataGrid->SetCellValue(lineno, 3, wxT("")); } { wxString sRowHead; wxString sFactor; wxString sWidth; wxString sHeight; sRowHead.Printf(wxT("%d"), (lineno + 1)); if(n > 1L) { sFactor.Printf(wxT("%ld / %d"), z, n); } else { sFactor.Printf(wxT("%ld"), z); } if(inverted) { sWidth.Printf(wxT("%ld"), nh); sHeight.Printf(wxT("%ld"), nw); } else { sWidth.Printf(wxT("%ld"), nw); sHeight.Printf(wxT("%ld"), nh); } dataGrid->SetRowLabelValue(lineno, sRowHead); dataGrid->SetCellValue(lineno, 0, sWidth); dataGrid->SetCellValue(lineno, 1, sHeight); dataGrid->SetCellValue(lineno, 2, sFactor); dataGrid->SetCellAlignment(lineno, 0, wxALIGN_CENTRE, wxALIGN_CENTRE); dataGrid->SetCellAlignment(lineno, 1, wxALIGN_CENTRE, wxALIGN_CENTRE); dataGrid->SetCellAlignment(lineno, 2, wxALIGN_CENTRE, wxALIGN_CENTRE); dataGrid->SetCellAlignment(lineno, 3, wxALIGN_CENTRE, wxALIGN_CENTRE); } lineno++; } i++; } dataGrid->AutoSizeColumns(); dataGrid->EnableDragColSize(true); if(0 == found) { lStatus->SetLabel(sTexts[34]); lStatus->SetForegroundColour(cDarkRed); } Refresh(); Update(); } } int DkWxImgszFrame::classifyFactor(long n, long o) { long max; long min; int back = 0; if(n > o) { max = n; min = o; } else { max = o; min = n; } if(max % min) { back = 0; } else { back = 1; max = max / min; if(countBits(max) == 1) { back = 2; } } return back; } int DkWxImgszFrame::countBits(long v) { long bitmask = 0x4000L; int attempts = 15; int back = 0; /* Better solution below, does not produce a warning about constant too large for data type. */ #if 0 if(sizeof(long) > 2) { if(sizeof(long) > 4) { /* 2014-06-05 The next line causes a warning on 32 bit systems. Due to the if(sizeof(long) > 4) condition test above this line is not reached if the data type long is too short, so the warning is harmless. */ bitmask = 0x4000000000000000L; attempts = 63; } else { bitmask = 0x40000000L; attempts = 31; } } #endif #if DK3_SIZEOF_LONG > 2 bitmask = 0x40000000L; attempts = 31; #if DK3_SIZEOF_LONG > 4 bitmask = 0x4000000000000000L; attempts = 63; #endif #endif while(attempts--) { if(v & bitmask) { back++; } bitmask = bitmask >> 1; } return back; }