Try   HackMD

Resize images using R

Resize 1 photo

# Bring installed packages to memory
library(jpeg)
library(dplyr)
library(foreach)
library(doParallel)

# Input and output directories
dir.C.drive <-"C:"
dir.G.drive <- "G:/My Drive"

# That folder is the system level package library, you need to run Rstudio as "administrator" to be able to install there.
dir.R.packages <- file.path(dir.C.drive,"R","R-4.1.3","library")
dir.main <- file.path(dir.G.drive,"a_Property")

#--------------------------------------------------
# Resize single photo
#--------------------------------------------------
input.folder.path <- file.path(dir.main,"3 Innes Close, Parkinson, Qld 4115","on-site-inspection")
output.folder.path <- file.path(input.folder.path,"on-site-inspection-resized") # dir.exists(output.folder.path)
#dir.create(output.folder.path)

# File name pattern of the photos to resize
pattern.photos <- "\\d{8}_\\d{6}.jpg"

file.paths.jpg <- list.files(path=input.folder.path
                             ,pattern = pattern.photos
                             ,full.names = TRUE) # length(file.paths.jpg) 6
# Reduce 1 photo 
img <- jpeg::readJPEG(source=file.paths.jpg[1]
                      , native = TRUE) # class(img) [1] "nativeRaster"

# Export reduced object as a jpg file
output.file.path <-paste0(output.folder.path,"/resized_",basename(file.paths.jpg[2]))

jpeg::writeJPEG(image=img
                ,target = output.file.path
                , quality = 0.5) 

# Calculate % reduction
size.original <- file.info(file.paths.jpg[1])[,"size"]
size.new <- file.info(output.file.path)[,"size"]

(size.original-size.new)/size.original*100 # 67.67885% reduction

Reduce all photos in a folder

#--------------------------------------------------
# Reduce all photos in a folder
#--------------------------------------------------

cl <- parallel::makeCluster(parallel::detectCores()-1
                            ,outfile=file.path(dir.main
                                               ,paste0("image-file-size-reduction_error-log.txt")
                                               )
) 
# Use all detected cores minus 1 core (CPU) as a cluster, leaving 1 core for software or app running in the background in case desktop crashes (monitor turns black and nothing working)
doParallel::registerDoParallel(cl, cores = parallel::detectCores()-1)

# Verify that doParallel is available on the workers by executing:
clusterEvalQ(cl, library(doParallel))
# This error, if appear, the following code will show the same error
# Error in checkForRemoteErrors(lapply(cl, recvResult)) : 
#   3 nodes produced errors; first error: there is no package called 'doParallel'

# Photo file name in this pattern
pattern.photos <- "^\\d{8}_\\d{6}.jpg$"

# Get a list of directories containing "/on-site-inspection"
folder.path.on.site.inspection <- list.dirs(dir.main, full.names = TRUE) %>%
  # Keep directories containing "/on-site-inspection"
  grep(pattern = "on-site-inspection",value = TRUE) # length(folder.path.on.site.inspection) 77

dirname.filename.matches <- list.files(path = dir.main
                                       ,pattern = pattern.photos
                                       ,recursive = TRUE
                                       ,full.names = TRUE) %>%
  # Restrict file pattern search to sub-directory "/on-site-inspection"
  grep(pattern = "on-site-inspection",value = TRUE) # length(dirname.filename.matches) 164

# Resize all these image files
foreach::foreach(i=1:length(dirname.filename.matches)
                 ,.combine = 'c'
                 ,.packages=c("foreach","dplyr","jpeg")) %dopar% {
                   print(paste0("=========== Processing image ",i,"============"))
                   
                   # If data can be found, then subset. If data cannot be found, then copy the input image to the output
                   image.file.path <-dirname.filename.matches[i]
                   image.file.name <-basename(image.file.path)
                   
                   # Name output file
                   output.file.path <-paste0(dirname(image.file.path),"/resized_", image.file.name)
                   
                   # Read jpg file
                   img <- jpeg::readJPEG(source=image.file.path, native = TRUE) # class(img) [1] "nativeRaster"
                   
                   # Reduce jpg file size and output jpg file
                   jpeg::writeJPEG(image=img
                                   ,target = output.file.path
                                   , quality = 0.5) 
                   # Delete input file
                   unlink(image.file.path)
                 }