diff --git a/DESCRIPTION b/DESCRIPTION index 714fddb..c3e0bc9 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,14 +1,15 @@ Package: zerenebatchR Type: Package Title: Utility for Batch Processing in Zerene Stacker -Version: 0.2.1 +Version: 0.2.2 Imports: fs, magrittr, - xml2 + xml2, + stringr Author: Ethan Bass Maintainer: Ethan Bass Description: Writes Zerene Stacker batch files and executes them from the commandline. License: MIT + file LICENSE Encoding: UTF-8 LazyData: true -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.0 diff --git a/NAMESPACE b/NAMESPACE index 53eed6c..deb23d2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,3 +11,4 @@ importFrom(fs,file_copy) importFrom(fs,file_move) importFrom(fs,path) importFrom(fs,path_home) +importFrom(stringr,str_pad) diff --git a/NEWS.md b/NEWS.md index 77d2956..90d4cf2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,9 @@ +# zerenebatchR 0.2.2 + +* Allow multiple columns as inputs to `c_id` in `run_zs_batch`. +* Automatically expand `path_out`, so abbreviated paths don't cause Zerene Stacker to error out. +* Added `digits` argument to add leading zeros to file numbers in `expand_zs_dataframe`. + # zerenebatchR 0.2.1 * Added check for duplicated ids in `expand_zs_dataframe`. diff --git a/R/expand_zs_dataframe.R b/R/expand_zs_dataframe.R index 33d752f..4573d2d 100644 --- a/R/expand_zs_dataframe.R +++ b/R/expand_zs_dataframe.R @@ -2,6 +2,8 @@ #' #' This function facilitates stacking photos that are numbered sequentially. It #' must be supplied with a \code{data.frame} with columns containing the +#' information about the images to be stacked. +#' @importFrom stringr str_pad #' @param df A data.frame containing the first and last photo, file path, and #' grouping variable. #' @param c_path String or numerical index specifying the column where the file @@ -15,42 +17,56 @@ #' @param extension String specifying the file extension of the images. The #' extension must be in the correct case so it matches exactly to the extension #' of the files to be stacked. +#' @param digits How many digits should be in the number. #' @return Expanded data.frame #' @export expand_zs_dataframe <- function(df, c_path, c_id, c_start, c_end, - extension = "JPG"){ + extension = "JPG", digits = 4){ # check missing lines - rm <- which(is.na(df[,c_start]) | is.na(df[,c_end])) + df <- as.data.frame(df) + df[,c_start] <- as.numeric(df[,c_start]) + df[,c_end] <- as.numeric(df[,c_end]) + rm <- which(is.na(df[, c_start]) | is.na(df[, c_end])) if (length(rm) > 0){ df <- df[-rm,] } + if (length(c_id) > 1){ + df$id <- apply(df[, c_id], MARGIN = 1, function(x) paste(x, collapse = "-")) + } else{ + df$id <- df[, c_id] + } # check for duplicated IDs - duplicated_ids <- duplicated(df[,c_id]) + duplicated_ids <- duplicated(df$id) if (any(duplicated_ids)){ stop(paste0("Some identifiers appear to be duplicated. Please double check IDs and try again. - Duplicated IDs: ", sQuote(paste0(df[which(duplicated_ids), c_id])), ".")) + Duplicated IDs: ", paste(sQuote(df[which(duplicated_ids), "id"]), collapse = ", "), ".")) } # check for photos out of order - wrong_order <- which(!(df[,c_start] < df[,c_end])) + wrong_order <- which(!(df[, c_start] < df[, c_end])) if (length(wrong_order) > 0){ - stop(paste0("Images appear to be out of order. Double check line ", - sQuote(paste0(wrong_order,collapse=", ")), ".")) + stop(paste0("Images appear to be out of order. Double check IDs: ", + paste(sQuote(df[wrong_order,"id"]), collapse = ", "), ".")) } extension <- gsub("^\\." ,"", extension) pp <- lapply(1:nrow(df), function(i){ - data.frame(id = paste(df[i, c_id], collapse="_"), - path = paste0(df[i,c_path], - seq(df[i, c_start], df[i, c_end], by = 1), + data.frame(id = paste(df[i, "id"], collapse = "_"), + path = paste0(df[i, c_path], + stringr::str_pad(seq(df[i, c_start], df[i, c_end], by = 1), + width = digits, side = "left", pad = "0"), ".", extension)) }) pp <- do.call(rbind, pp) # check for missing files - missing_files <- which(!file.exists(pp$path)) - if (length(missing_files > 0)){ - warning(paste0("Some image files could not be found: ", - (paste0(sQuote(missing_files), collapse=", ")), ".")) - pp <- pp[-missing_files,] + missing_files <- pp[which(!file.exists(pp$path)), "path"] + if (length(missing_files) > 0){ + if (length(missing_files) == nrow(df)){ + stop("Files could not be found. Please check path(s) and try again.") + } else{ + warning(paste0("Some image files could not be found: ", + (paste0(sQuote(missing_files), collapse=", ")), ".")) + pp <- pp[-missing_files,] + } } pp } diff --git a/R/run_zs_batch.R b/R/run_zs_batch.R index ff7303c..075bda4 100644 --- a/R/run_zs_batch.R +++ b/R/run_zs_batch.R @@ -30,7 +30,7 @@ globalVariables(c(".")) #' @author Ethan Bass #' @export -run_zs_batch <- function(files, c_path = 1, c_split = 2, +run_zs_batch <- function(files, c_split = 1, c_path = 2, path_out, stacker = c("pmax", "dmap"), temp, path_template = NULL, path_xml = NULL, stack = TRUE){ @@ -51,7 +51,7 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, if (stack){ stop("If `stack == TRUE`, a `data.frame` should be provided to the files argument.") } - exists <- dir_exists(files) + exists <- fs::dir_exists(files) if (!any(exists)){ stop("The provided directories do not exist. Please check paths and try again.") } @@ -85,8 +85,8 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, system <- .Platform$OS.type launch_cmd_path <- switch(system, - "unix" = path_home("Library/Preferences/ZereneStacker/zerenstk.launchcmd"), - "windows" = path_home("AppData\\ZereneStacker\\zerenstk.launchcmd"), + "unix" = fs::path_home("Library/Preferences/ZereneStacker/zerenstk.launchcmd"), + "windows" = fs::path_home("AppData\\ZereneStacker\\zerenstk.launchcmd"), "linux" = "~/.ZereneStacker/zerenstk.launchcmd" ) @@ -118,13 +118,11 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, l <- x %>% xml_children() %>% .[[2]] %>% xml_find_all("//Sources") %>% xml_children %>% length sources <- x %>% xml_children() %>% .[[2]] %>% xml_find_all("//Sources") xml_attr(sources, "length") <- as.character(l) - # x %>% xml_children() %>% .[[2]] %>% xml_find_all("//Sources") # set path out x %>% xml_children() %>% .[[2]] %>% xml_find_all("//OutputImagesDesignatedFolder") %>% - xml_replace(paste0('OutputImagesDesignatedFolder value="', path_out, '"')) - # x %>% xml_children %>% .[[4]] %>% xml_add_child(.value=gsub("path_out", path_out, parser)) + xml_replace(paste0('OutputImagesDesignatedFolder value="', fs::path_expand(path_out), '"')) # set stacking algorithm @@ -138,7 +136,8 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, # write batch file if (is.null(path_xml)){ - path_xml <- paste0(path_out, "batchfile_", strftime(Sys.time(),format = "%Y-%m-%d_%H-%M-%S"), ".xml") + path_xml <- paste0(path_out, "batchfile_", strftime(Sys.time(), + format = "%Y-%m-%d_%H-%M-%S"), ".xml") } write_xml(x, file = path_xml) @@ -148,12 +147,11 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, system(paste0(launch_cmd, " -noSplashScreen -runMinimized -exitOnBatchScriptCompletion -batchScript ", path_xml)) - # , " -sourcePath=", path # delete temp folders if (temp){ - dir_delete(stacks) + fs::dir_delete(stacks) } } @@ -174,22 +172,22 @@ run_zs_batch <- function(files, c_path = 1, c_split = 2, stack_files <- function(df, c_path, c_split, temp = TRUE){ if (length(c_split) > 1){ - df$id <-apply(df[,c_split], MARGIN = 1, function(x) paste(x, collapse="-")) + df$id <-apply(df[, c_split], MARGIN = 1, function(x) paste(x, collapse = "-")) } else{ - df$id <- df[,c_split] + df$id <- df[, c_split] } df <- split(as.data.frame(df), df[, "id"]) file_action <- switch(as.character(temp), - "TRUE" = file_copy, - "FALSE" = file_move) + "TRUE" = fs::file_copy, + "FALSE" = fs::file_move) paths <- sapply(df, function(x){ if (any(fs::file_exists(x[, c_path]))){ path <- x[1, c_path] dirn <- dirname(path) - dirn <- ifelse(temp, fs::path(dirn,"temp"), dirn) + dirn <- ifelse(temp, fs::path(dirn, "temp"), dirn) dir_path <- fs::path(dirn, x[, "id"][1]) - dir_create(dir_path) + fs::dir_create(dir_path) sapply(x[,c_path], function(file){ try(file_action(file, dir_path)) }) diff --git a/man/expand_zs_dataframe.Rd b/man/expand_zs_dataframe.Rd index 3de720c..a1cf6d2 100644 --- a/man/expand_zs_dataframe.Rd +++ b/man/expand_zs_dataframe.Rd @@ -4,7 +4,15 @@ \alias{expand_zs_dataframe} \title{Expand data.frame} \usage{ -expand_zs_dataframe(df, c_path, c_id, c_start, c_end, extension = "JPG") +expand_zs_dataframe( + df, + c_path, + c_id, + c_start, + c_end, + extension = "JPG", + digits = 4 +) } \arguments{ \item{df}{A data.frame containing the first and last photo, file path, and @@ -25,6 +33,8 @@ the last photo of each stack.} \item{extension}{String specifying the file extension of the images. The extension must be in the correct case so it matches exactly to the extension of the files to be stacked.} + +\item{digits}{How many digits should be in the number.} } \value{ Expanded data.frame @@ -32,4 +42,5 @@ Expanded data.frame \description{ This function facilitates stacking photos that are numbered sequentially. It must be supplied with a \code{data.frame} with columns containing the +information about the images to be stacked. } diff --git a/man/run_zs_batch.Rd b/man/run_zs_batch.Rd index 52f5602..076eeba 100644 --- a/man/run_zs_batch.Rd +++ b/man/run_zs_batch.Rd @@ -6,8 +6,8 @@ \usage{ run_zs_batch( files, - c_path = 1, - c_split = 2, + c_split = 1, + c_path = 2, path_out, stacker = c("pmax", "dmap"), temp, @@ -23,11 +23,11 @@ the files to parse (\code{c_path}) and a grouping factor (\code{c_split}). If \code{stack == FALSE}, a character vector should be provided containing paths to the stacked files.} -\item{c_path}{String or numerical index specifying column where paths can be found.} - \item{c_split}{String or numerical index specifying column where factor can be found for grouping images.} +\item{c_path}{String or numerical index specifying column where paths can be found.} + \item{path_out}{directory to export converted files.} \item{stacker}{Which stacking algorithm to use. Either \code{pmax} or \code{dmap}.}