def OnDropFiles(self, x, y, filenames): """validate image before passing it on to self.app.loadImage()""" path = filenames[0] ## create RGBEImage to check file type and data rgbeImg = RGBEImage(self, self.wxapp._log, ["-i", path]) rgbeImg.readImageData(path) if rgbeImg.error: msg = "Error loading image.\nFile: %s\nError: %s" % (path,rgbeImg.error) self.wxapp.showError(msg) else: ## now load for real self.wxapp.loadImage(path)
def test_doFalsecolor_fail(self, fci_mock): log.error = mock.MagicMock() fci_mock.return_value = False img = RGBEImage(wxparent, log) img.error = "some error" img.showError = mock.MagicMock() result = img.doFalsecolor() self.assertFalse(result) log.error.assert_called_with("FalsecolorImage.doFalsecolor() == False") img.showError.assert_called_with("falsecolor2 error:\nsome error")
def loadImage(self, path, args=[]): """create instance of falsecolor image from <path>""" self._log.info("loadImage(%s)" % path) self.reset() self.rgbeImg = RGBEImage(self, self._log, ["-i", path]) self.rgbeImg.readImageData(path) if self.rgbeImg.error: msg = "Error loading image:\n%s" % self.rgbeImg.error self.showError(msg) self.rgbeImg = None return False else: self.setPath(path) self.saveButton.Enable() self._loadImageData() self.imagepanel.update(self.rgbeImg) return True
def test_resize_fail(self): img = RGBEImage(wxparent, log) img.doPfilt = mock.MagicMock() img.doPfilt.return_value = False img._analyzeImage = mock.MagicMock() img.resize(600, 400) msg = "_analyzeImage() was called after failed resize()" self.assertFalse(img._analyzeImage.called, msg)
def test_resize(self): img = RGBEImage(wxparent, log) img.doPfilt = mock.MagicMock() img.doPfilt.return_value = True img._analyzeImage = mock.MagicMock() img.resize(600, 400) msg = "_analyzeImage() was not called after successful resize()" self.assertTrue(img._analyzeImage.called, msg)
class WxfcFrame(wx.Frame): """main wxfalsecolor frame""" def __init__(self, parent, wxapp, logger, config): wx.Frame.__init__(self, parent, title="wxFalsecolor - Radiance Picture Viewer") self._log = logger self.parser = WxfcOptionParser(logger=self._log) self._config = config self.wxapp = wxapp self.imagepanel = ImagePanel(self) self.rgbeImg = None self.img = None self.path = "" self.filename = "" self.loadingCanceled = False ## layout and show main window self._layout() #TODO: self._addMenu() self.Size = (800, 600) self.Show() def process_cmd_line_args(self): """check arguments, load and convert image""" ## check command line args if self.parser.parseOptions(sys.argv[1:]) != True: self.showError(self.parser.error) return ## load image if present if self.parser.has_option('picture'): self.loadImage(self.parser.get('picture')) self.Update() if self.parser.has_fc_option() == True: self.doFalsecolor() def _addFileButtons(self, panel): """create top buttons""" self.loadButton = wx.Button(panel, wx.ID_ANY, label='open HDR') self.loadButton.Bind(wx.EVT_LEFT_DOWN, self.onLoadImage) self.panelSizer.Add(self.loadButton, proportion=0, flag=wx.EXPAND | wx.ALL, border=5) self.saveButton = wx.Button(panel, wx.ID_ANY, label='save image') self.saveButton.Bind(wx.EVT_LEFT_DOWN, self.onSaveImage) self.saveButton.Disable() self.panelSizer.Add(self.saveButton, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) spacepanel = wx.Panel(panel, wx.ID_ANY, size=(-1, 5)) self.panelSizer.Add(spacepanel, proportion=0, flag=wx.EXPAND) def _addMenu(self): """add menu to frame (disabled)""" return self.menubar = wx.MenuBar() self.SetMenuBar(self.menubar) self.fileMenu = wx.Menu() self.menubar.Append(self.file, '&File') self.fileOpen = self.file.Append(wx.ID_ANY, '&Open file') self.Bind(wx.EVT_MENU, self.onLoadImage, self.fileOpen) def _doButtonLayout(self): """create buttons""" panel = wx.Panel(self, style=wx.RAISED_BORDER) self.panelSizer = wx.BoxSizer(wx.VERTICAL) ## 'load' and 'save' buttons self._addFileButtons(panel) ## foldable controls panel self._foldpanel = FoldableControlsPanel(panel, self, wx.ID_ANY) self.lablecontrols = self._foldpanel.lablecontrols self.fccontrols = self._foldpanel.fccontrols self.displaycontrols = self._foldpanel.displaycontrols self.panelSizer.Add(self._foldpanel, proportion=1, flag=wx.EXPAND | wx.ALL, border=5) ## 'quit' button quitbutton = wx.Button(panel, wx.ID_EXIT, label='quit') quitbutton.Bind(wx.EVT_LEFT_DOWN, self.onQuit) self.panelSizer.Add(quitbutton, proportion=0, flag=wx.EXPAND | wx.ALL | wx.ALIGN_BOTTOM, border=10) panel.SetSizer(self.panelSizer) return panel def check_for_update(self, event=None): self.wxapp.check_for_update(event) def doFalsecolor(self, args=[]): """convert Radiance RGBE image to wx.Bitmap""" self._log.debug("doFalsecolor(%s)" % str(args)) if not args: args = self.parser.get_options_as_args() if "-nofc" in args or self.imagepanel.doFalsecolor(args[:]) == True: self.fccontrols.setFromArgs(args[:]) self.displaycontrols.reset() return True else: return False def doPcond(self, args): """apply pcond args to image""" if self.imagepanel.doPcond(args) == True: self.fccontrols.reset() return True else: return False def exit(self, error=None): """close logger and exit""" if error: self._log.error(str(error)) self._config.save_changes() logging.shutdown() self.Close() def expandControlPanel(self, idx): """expand control panel with index idx""" self._foldpanel.expand(idx) def formatNumber(self, n): """use FalsecolorImage formating for consistency""" if self.rgbeImg: return self.rgbeImg.formatNumber(n) else: return str(n) def getLableText(self): """return text of lable text box""" return self.lablecontrols.getLableText() def getRGBVAt(self, pos): """return pixel value at position""" if self.rgbeImg: return self.rgbeImg.getRGBVAt(pos) else: return (-1, -1, -1, -1) def getRGBVAverage(self, start, end): """return average pixel value for rectangle""" if self.rgbeImg: return self.rgbeImg.getRGBVAverage(start, end) else: return (-1, -1, -1, -1) def _layout(self): """main layout of controls and image panel""" ## buttons panel = self._doButtonLayout() ## image - buttons layout self.sizer = wx.BoxSizer(wx.HORIZONTAL) self.sizer.Add(panel, proportion=0, flag=wx.EXPAND) self.sizer.Add(self.imagepanel, proportion=1, flag=wx.EXPAND) self.SetSizer(self.sizer) ## status bar self.statusbar = SplitStatusBar(self) self.SetStatusBar(self.statusbar) def loadImage(self, path, args=[]): """create instance of falsecolor image from <path>""" self._log.info("loadImage(%s)" % path) self.reset() self.rgbeImg = RGBEImage(self, self._log, ["-i", path]) self.rgbeImg.readImageData(path) if self.rgbeImg.error: msg = "Error loading image:\n%s" % self.rgbeImg.error self.showError(msg) self.rgbeImg = None return False else: self.setPath(path) self.saveButton.Enable() self._loadImageData() self.imagepanel.update(self.rgbeImg) return True def _loadImageData(self): """load image data of small images immediately""" ## TODO: evaluate image data (exclude fc images) max_size = self._config.getint("lables", "max_data_load", 1000000) if max_size == 0: self._log.info("automatic data loading disabled") self.lablecontrols.reset() return ## compare image resolution against max_size x, y = self.rgbeImg.getImageResolution() if x * y <= max_size: ## call OnShowValues with fake event self.lablecontrols.OnShowValues(-1) else: self.statusbar.SetStatusText("confirm 'load data' or resize image") nx, ny = beautyscale(x, y, max_size) info = { 'x': x, 'y': y, 'new_x': nx, 'new_y': ny, 'backup_name': self.rgbeImg.getBackupName(), 'do_resize': False } dlg = ResizeDialog(parent=self, ID=-1, title="foo") dlg.setImageInfo(info) result = dlg.ShowModal() if result == wx.ID_OK: if dlg.cb_resize.IsChecked(): self.resizeRGBEImage(dlg) else: self._log.info("loading original image data") self.lablecontrols.OnShowValues(-1) else: self._log.info("loading of image data cancelled by user") self.lablecontrols.reset() self.statusbar.SetStatusText("skipping 'load data'.") dlg.Destroy() #msg = "This is a large image.\nDo you want to load image data now?" #dlg = wx.MessageDialog(self, message=msg, caption="Load data?", style=wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) #if dlg.ShowModal() == wx.ID_YES: #else: def loadValues(self): """load luminance/illuminance data from image""" return self.rgbeImg.hasArrayData(self) def onImagePanelClick(self): """action on click on imagepanel""" if self.imagepanel.hasLables(): self.lablecontrols.loadClearButton.Enable() elif self.lablecontrols.loadClearButton.GetLabelText() == "load data": self.lablecontrols.loadClearButton.Enable() else: self.lablecontrols.loadClearButton.Disable() def onLoadImage(self, event): """load new Radiance RGBE image""" filedialog = wx.FileDialog( self, message='Choose an image to open', defaultDir='', defaultFile='', wildcard= 'Radiance Image Files (*.hdr,*.pic)|*.hdr;*.pic|all files |*.*', style=wx.OPEN) if filedialog.ShowModal() == wx.ID_OK: path = filedialog.GetPath() self.loadImage(path) def onQuit(self, event): """hasta la vista""" self.exit() def onSaveImage(self, event): """save bmp image to file""" dirname, filename = os.path.split(self.path) filebase = os.path.splitext(filename)[0] #formats = "|".join(["HDR file|*.hdr", WX_IMAGE_WILDCARD, "PIC (old)|*.pic"]) formats = "|".join( ["HDR file|*.hdr", WX_IMAGE_WILDCARD, "PPM file|*.ppm"]) filedialog = wx.FileDialog(self, message='save image', defaultDir=dirname, defaultFile=filebase + '.hdr', wildcard=formats, style=wx.SAVE) if filedialog.ShowModal() == wx.ID_OK: path = filedialog.GetPath() result = self.rgbeImg.saveToFile(path) if result != True: msg = "Error saving image:\n" + self.rgbeImg.error self.showError(msg) else: self.statusbar.SetStatusText("saved file '%s'" % path) def reset(self): """reset array to inital (empty) values""" self.displaycontrols.reset() self.imagepanel.clearLabels() self.fccontrols.reset() if self.rgbeImg: self.imagepanel.update(self.rgbeImg) if self.rgbeImg.isIrridiance(): self.fccontrols.reset("Lux") def resizeRGBEImage(self, dlg): """create backup copy, resize and save image""" w = int(dlg.img_width.GetValue()) h = int(dlg.img_height.GetValue()) backup = dlg.img_backup.GetValue() self._log.info("resizing image: w=%d, h=%d, backup='%s'" % (w, h, backup)) if backup != "": self.rgbeImg.saveToFile(backup) self.rgbeImg.resize(w, h) if self.rgbeImg.hasFilepath(): self.rgbeImg.saveToFile(self.rgbeImg.picture) self.rgbeImg.readImageData(self.rgbeImg.picture) def setPath(self, path): """update frame with new image path""" self.path = path self.filename = os.path.split(path)[1] self.SetTitle("wxFalsecolor - '%s'" % self.filename) def showAboutDialog(self, event=None): """show dialog with license etc""" info = wx.AboutDialogInfo() info.Name = "wxfalsecolor" info.Version = "%s" % VERSION info.Copyright = "(c) 2015 Thomas Bleicher" info.Description = "cross-platform GUI frontend for falsecolor" info.WebSite = ("http://tbleicher.github.io/wxfalsecolor/", "wxfalsecolor home page") info.Developers = ["Thomas Bleicher", "Axel Jacobs"] lines = [" ".join(line.split()) for line in LICENSE.split("\n\n")] info.License = wordwrap("\n\n".join(lines), 500, wx.ClientDC(self)) wx.AboutBox(info) def showError(self, msg): """show dialog with error message""" self._log.error(" ".join(msg.split())) self.statusbar.SetStatusText(msg) dlg = wx.MessageDialog(self, message=msg, caption="Error", style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() def showHeaders(self, event=None): """display image headers in popup dialog""" if not self.rgbeImg: return header = self.rgbeImg.getHeader() if header == False: self.showError("Image header not available!") return header2 = self.rgbeImg.getDataHeader() if header2 and header != header2: header += "\n\nmodified:\n" header += header2 ## create new dialog window dlg = HeaderDialog(self, header) dlg.Show() def showPixelValueAt(self, pos): """set pixel position of mouse cursor""" value = "" if self.rgbeImg: r, g, b, v = self.rgbeImg.getRGBVAt(pos) if r > 0: value = "rgb=(%.3f,%.3f,%.3f)" % (r, g, b) if v > 0 and self.rgbeImg.isIrridiance(): value = "%s value=%s lux" % (value, self.formatNumber(v)) self.statusbar.SetStatusText( "'%s': x,y=(%d,%d) %s" % (self.filename, pos[0], pos[1], value))
def test_doPcond(self): img = RGBEImage(wxparent, log) img._doPcommand = mock.MagicMock() args = ['a', 2] img.doPcond(args) img._doPcommand.assert_called_with("pcond", args)
def test_doFalsecolor(self, fci_mock): fci_mock.return_value = True img = RGBEImage(wxparent, log) result = img.doFalsecolor() self.assertTrue(result)