From 539e93edfeb3a5e7dbb6a89faee6b404cd67e613 Mon Sep 17 00:00:00 2001 From: Matthew Clapp Date: Sat, 4 Aug 2018 23:19:09 -0700 Subject: [PATCH] Keep track of image history. Allows immediate undo/redo without converting between image_dc and image. Closes #103 --- marcam/image_scrolled_canvas.py | 68 ++++++++++++++++++++++++++++----- marcam/marcam.py | 25 +++++++++--- 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/marcam/image_scrolled_canvas.py b/marcam/image_scrolled_canvas.py index e400cbd..ff977b1 100644 --- a/marcam/image_scrolled_canvas.py +++ b/marcam/image_scrolled_canvas.py @@ -217,6 +217,8 @@ def __init__(self, parent, win_history, id_=wx.ID_ANY, *args, **kwargs): self.history = win_history self.img_at_wincenter = RealPoint(0, 0) self.img_coord_xlation = None + self.img = None + self.img_idx = None self.img_dc = None self.img_dc_div2 = None self.img_dc_div4 = None @@ -308,6 +310,8 @@ def set_no_image(self, refresh_update=True): self.history.reset() self.img_at_wincenter = RealPoint(0, 0) self.img_coord_xlation = None + self.img = None + self.img_idx = None self.img_dc = None self.img_dc_div2 = None self.img_dc_div4 = None @@ -1491,7 +1495,20 @@ def img2win_coord(self, img_x, img_y, scale_dc=1): return (win_x, win_y) @debug_fxn - def init_image(self, img, do_zoom_fit=True): + def get_current_img(self): + return self.img[self.img_idx] + + @debug_fxn + def new_img(self, img): + self.img = [img] + self.img_idx = 0 + + @debug_fxn + def set_img_idx(self, idx_set): + self.img_idx = idx_set + + @debug_fxn + def init_image(self, do_zoom_fit=True): """Load and initialize image Args: @@ -1500,6 +1517,10 @@ def init_image(self, img, do_zoom_fit=True): if LOGGER.isEnabledFor(logging.DEBUG): staticdc_start = time.time() + # before calling init_image, must call new_img, or set_img_idx + # so this is correct + img = self.img[self.img_idx] + self.img_size_y = img.GetHeight() self.img_size_x = img.GetWidth() @@ -1780,17 +1801,26 @@ def image_invert(self): if self.has_no_image(): return - wx_image_orig = image_proc.memorydc2image(self.img_dc) + # get current image + wx_image_orig = self.img[self.img_idx] + # create new image wx_image_new = image_proc.image_invert(wx_image_orig) + # delete all items after current one in list + self.img = self.img[:self.img_idx+1] + # add new img to end of list + self.img.append(wx_image_new) + # update img pointer + self.img_idx += 1 + # TODO: specifying orig,new for every image xform is redundant # (find a way to not duplicate image data in EditHistory) # Can possibly reference images in another holding area, # where only unique images saved. self.history.new( - ['IMAGE_XFORM', wx_image_orig, wx_image_new], + ['IMAGE_XFORM', self.img_idx - 1, self.img_idx], description="Invert Image" ) - self.init_image(wx_image_new, do_zoom_fit=False) + self.init_image(do_zoom_fit=False) @debug_fxn def image_remap_colormap(self, cmap='viridis'): @@ -1798,17 +1828,26 @@ def image_remap_colormap(self, cmap='viridis'): if self.has_no_image(): return - wx_image_orig = image_proc.memorydc2image(self.img_dc) + # get current image + wx_image_orig = self.img[self.img_idx] + # create new image wx_image_new = image_proc.image_remap_colormap(wx_image_orig, cmap=cmap) + # delete all items after current one in list + self.img = self.img[:self.img_idx+1] + # add new img to end of list + self.img.append(wx_image_new) + # update img pointer + self.img_idx += 1 + # TODO: specifying orig,new for every image xform is redundant # (find a way to not duplicate image data in EditHistory) # Can possibly reference images in another holding area, # where only unique images saved. self.history.new( - ['IMAGE_XFORM', wx_image_orig, wx_image_new], + ['IMAGE_XFORM', self.img_idx - 1, self.img_idx], description="Image False Color" ) - self.init_image(wx_image_new, do_zoom_fit=False) + self.init_image(do_zoom_fit=False) @debug_fxn def image_autocontrast(self, cutoff=0): @@ -1816,17 +1855,26 @@ def image_autocontrast(self, cutoff=0): if self.has_no_image(): return - wx_image_orig = image_proc.memorydc2image(self.img_dc) + # get current image + wx_image_orig = self.img[self.img_idx] + # create new image wx_image_new = image_proc.image_autocontrast(wx_image_orig, cutoff=cutoff) + # delete all items after current one in list + self.img = self.img[:self.img_idx+1] + # add new img to end of list + self.img.append(wx_image_new) + # update img pointer + self.img_idx += 1 + # TODO: specifying orig,new for every image xform is redundant # (find a way to not duplicate image data in EditHistory) # Can possibly reference images in another holding area, # where only unique images saved. self.history.new( - ['IMAGE_XFORM', wx_image_orig, wx_image_new], + ['IMAGE_XFORM', self.img_idx - 1, self.img_idx], description="Image Auto-Contrast" ) - self.init_image(wx_image_new, do_zoom_fit=False) + self.init_image(do_zoom_fit=False) @debug_fxn def get_image_info(self): diff --git a/marcam/marcam.py b/marcam/marcam.py index 7a4e747..919a8a6 100755 --- a/marcam/marcam.py +++ b/marcam/marcam.py @@ -1278,12 +1278,16 @@ def load_mcmfile_from_path(self, imdata_path): if img_ok: self.img_panel.mark_point_list(marks) - self.img_panel.init_image(img) + # reset img history in window to only new image, reset idx + self.img_panel.new_img(img) + # init image in window + self.img_panel.init_image() # set save_filepath to path of mcm file we loaded # self.img_path if from mcm is list: [, ] # TODO: do we even care about this list, or img_name? self.img_path = [imdata_path, img_name] self.save_filepath = imdata_path + # TODO: is this superfluous? self.statusbar.SetStatusText( "Image Data " + imdata_path + " loaded OK." ) @@ -1330,7 +1334,11 @@ def load_image_from_file(self, img_file): img_ok = img and img.IsOk() if img_ok: - self.img_panel.init_image(img) + # reset img history in window to only new image, reset idx + self.img_panel.new_img(img) + # init image in window + self.img_panel.init_image() + # TODO: is this superfluous? self.statusbar.SetStatusText("Image " + img_file + " loaded OK.") # reset filepath for mcm file to nothing if we load new image self.img_path = img_file @@ -1523,7 +1531,8 @@ def on_undo(self, _evt): if action[0] == 'MOVE_MARK': self.img_panel.move_mark(action[2], action[1], is_selected=False) if action[0] == 'IMAGE_XFORM': - self.img_panel.init_image(action[1], do_zoom_fit=False) + self.img_panel.set_img_idx(action[1]) + self.img_panel.init_image(do_zoom_fit=False) @debug_fxn def on_redo(self, _evt): @@ -1541,7 +1550,8 @@ def on_redo(self, _evt): if action[0] == 'MOVE_MARK': self.img_panel.move_mark(action[1], action[2], is_selected=False) if action[0] == 'IMAGE_XFORM': - self.img_panel.init_image(action[2], do_zoom_fit=False) + self.img_panel.set_img_idx(action[2]) + self.img_panel.init_image(do_zoom_fit=False) @debug_fxn def on_select_all(self, _evt): @@ -1691,8 +1701,11 @@ def save_img_data(self, imdata_path): Args: imdata_path (str): full path to filename to save to """ - current_img = image_proc.memorydc2image(self.img_panel.img_dc) - return mcmfile.save(imdata_path, current_img, self.img_panel.marks) + return mcmfile.save( + imdata_path, + self.img_panel.get_current_img(), + self.img_panel.marks + ) @debug_fxn def on_about(self, _evt):