def GetSaveFiles(folder: Path) -> List[Tuple[str, Path]]: """ Finds all save files recursively, grouped by the subfolder relative to the `folder` input. Returns a list of tuples joining each save file with the subfolder it belongs to. [ (subfolder1name, path/to/save/file/1/in/sub/1) (subfolder1name, path/to/save/file/2/in/sub/1) (subfolder2name, path/to/save/file/1/in/sub/2) (subfolder2name, path/to/save/file/2/in/sub/2) ] """ markedFolderMatchString = config.markedImageFolderName subfolders = [f for f in os.scandir(folder) if f.is_dir()] saveFiles = [] for dirname in list(subfolders): allfolders = fast_scandir(dirname) markedFolders = [ d for d in allfolders if d.name == markedFolderMatchString ] for markedFolder in markedFolders: saveFile = config.markedDataFile( transectFolder=Path(markedFolder).parent) if saveFile.exists(): saveFiles.append((dirname.name, saveFile)) return saveFiles
def transectData(self): """ Computes the transect save data and returns it. **Unused** """ if len(self._changedIndexes) == 0: return # If the save file doesn't exist, initialize empty. transectPath = config.markedDataFile(transectFolder=self._folder()) if transectPath.exists(): saveData = TransectData.load(transectPath) else: saveData = TransectData({}, fp=transectPath) # Only save files that have changed for index in self._changedIndexes: # If this index is None, i.e., was already taken care of # by a previous index (part of same overall image), continue # to next index. if index is None: continue # Retreive the path of the original image, and find # the indexes of the images that also correspond # to that path. originalPath: Path = self.data(index, role=UserRoles.ImagePath) indexes = self.matchPath(originalPath) # Now that we have all the indexes associated with this # path, we no longer need them in "changedIndexes" for idx in indexes: try: num = self._changedIndexes.index(idx) except ValueError: pass else: self._changedIndexes[num] = None # Merge the indexes togther, create a preview image mergedIndexes = MergedIndexes(indexes) _ = mergedIndexes.resultantImage() # Merge drawn items and draw them onto the image drawings = mergedIndexes.drawnItems() if drawings is not None: # We should only save these drawings if they aren't already saved. if not saveData.imageHasDrawings(originalPath.name, drawings): saveData.addDrawings(originalPath.name, drawings) else: saveData.removeDrawings(originalPath.name) # Return the transect data return saveData
def readDirectory(self, fp): """ Populates model from directory. `fp`: any Path()-able type""" self._parentDir = str(fp) fp = Path(fp) # Error checks if not fp.exists(): raise ValueError( f"Cannot read data from path that does not exist: {fp}") if not fp.is_dir(): raise ValueError(f"Can only read from dir, not file: {fp}") # If the .marked/ folder exists, this is a single transect if config.markedFolder(transectFolder=fp).exists(): self.inTransect = True # If the save file exists, read it saveFile = config.markedDataFile(transectFolder=fp) if saveFile.exists(): saveDatas = TransectDataGroupList([]) saveDatas.load(saveFile) self._resetData(saveDatas) else: self._resetData(TransectDataGroupList()) # Otherwise, try to find all .marked/ folders within this dir else: self.inTransect = False filesToLoad: List[Tuple[str, Path]] = GetSaveFiles(fp) if filesToLoad: newTransectDataGroupList = self._loadFiles(filesToLoad) else: newTransectDataGroupList = TransectDataGroupList([]) self._resetData(newTransectDataGroupList)
def _readSaveData(self): """ Reads in save data, if it can be found. Save file specified in Config(). """ # Nothing to read if there are no images if len(self._images) == 0: return # Generate the save path originalFolder = self._folder() savePath = config.markedDataFile(transectFolder=originalFolder) # If the path doesn't exist, don't try to load anything if not savePath.is_file(): return # Load save data saveData = TransectData.load(savePath) for imageName, drawings in saveData.drawings(): # Merge indexes that compose this file, and # set the drawings to the merged set. indexes = self.matchPath(originalFolder / imageName) if not indexes: print(f"Warning: bad save file -- {imageName} not found.") else: mergedIndexes = MergedIndexes(indexes) mergedIndexes.setModelDrawings(self, drawings) # Since we just read in new data and will have changed # the indexes as a part of that, we should note that # these indexes actually don't have to be saved again. self._changedIndexes = []
def save(self): """ Save changes made to the images. This involves: * Writing drawing data to a file * Saving the marked up image to a file """ if len(self._changedIndexes) == 0: return # Setup save directory files and folders markedFolder = config.markedFolder(transectFolder=self._folder()) markedFolder.mkdir(exist_ok=True) transectPath = config.markedDataFile(transectFolder=self._folder()) transectPath.parent.mkdir(exist_ok=True) if transectPath.exists(): # Initialize save data from old data path saveData = TransectData.load(transectPath) else: transectPath.touch() saveData = TransectData({}, fp=transectPath) # List of images to be saved and the `save` arguments # [(image, ['C:/Photos/myFavoriteImage.jpg']), ] markedImages = [] # Only save files that have changed for index in self._changedIndexes: # If this index is None, i.e., was already taken care of # by a previous index (part of same overall image), continue # to next index. if index is None: continue # Retreive the path of the original image, and find # the indexes of the images that also correspond # to that path. originalPath: Path = self.data(index, role=UserRoles.ImagePath) indexes = self.matchPath(originalPath) # Now that we have all the indexes associated with this # path, we no longer need them in "changedIndexes". # Setting them to None will cause them to be skipped higher # in the loop for idx in indexes: try: num = self._changedIndexes.index(idx) except ValueError: pass else: self._changedIndexes[num] = None # Merge the indexes togther, create a preview image mergedIndexes = MergedIndexes(indexes) preview = mergedIndexes.resultantImage() # Form the new path (./.marked/Alpha_001.JPG) markedPath = markedFolder / originalPath.name # Merge drawn items and draw them onto the image drawings: DrawingDataList = mergedIndexes.drawnItems() if not drawings.isEmpty(): # We should only save these drawings if they aren't # already saved. if not saveData.imageHasDrawings(originalPath.name, drawings): # Add this image to the list of images # to save and add the drawn item string to the save data drawings.paintToDevice(preview) markedImages.append((preview, [str(markedPath)])) saveData.addDrawings(originalPath.name, drawings) # If there are no drawings, we should delete the image # from the marked folder. (If applicable.) else: try: markedPath.unlink() except FileNotFoundError: pass finally: # Ensure that there are no drawings saved alongside # this image (in particular, if the drawings already # existed, we need to delete them) saveData.removeDrawings(originalPath.name) # Save & emit the transect data saveData.dump(transectPath) self.transectDataChanged.emit(saveData) # Clear the changed index list self._changedIndexes = [] # On another thread, do the heavily-lifing of # saving the images. if len(markedImages) != 1: msg = f"Saving {len(markedImages)} images..." else: msg = f"Saving {Path(*markedImages[0][1]).name}..." self.message.emit((msg,)) self._saveWorker = QWorker(saveManyImages, [markedImages]) self._saveWorker.signals.finished.connect(self._resetSaveWorker) self._saveWorker.signals.finished.connect(self._saveWorkerFinished) self._threadpool.start(self._saveWorker)