Skip to content

Instantly share code, notes, and snippets.

@stla
Last active December 26, 2015 17:19
Show Gist options
  • Select an option

  • Save stla/7186022 to your computer and use it in GitHub Desktop.

Select an option

Save stla/7186022 to your computer and use it in GitHub Desktop.
Shiny ImageMagick - single file
library(shiny)
library(shinyIncubator)
library(shinyAce)
options(shiny.maxRequestSize = -1)
platform <- sessionInfo()$R.version$platform
linux <- stringr::str_detect(platform, "linux")
logo <- function(img,link, height="200px") tags$a(href=link, tags$img(src=img, height=height))
sourcecode <- function(link){
tags$a(href=link,
style="float:right; padding-right:10px;padding-top:10px; color:yellow; background-color:red; font-family:arial; font-size:20px",
">>source code<<")
}
ProgressBar <- function(session, max, message="in progress...", detail=""){
withProgress(session, min=1, max=max, expr={
for(i in 1:max) {
setProgress(message = message,
detail = detail,
value=i)
print(i)
Sys.sleep(0.1)
}
})
}
shinyServer(function(input, output, session) {
DONE <- reactiveValues()
## uploading ##
output$upload <- renderUI({
if(!is.null(input$files)){
if(is.null(DONE[["image0"]])) return(NULL)
actionButton("info",">>image info (see/hide)<<")
}else fileInput("files", "Upload a JPEG file:", multiple = FALSE)
})
Upload <- reactive({
if(is.null(input$files)) return(NULL)
input$files
})
output$filesInfo <- renderTable({
Upload()
})
## image info ##
output$imageinfo <- renderUI({
if(is.null(input$files) | is.null(input$info)) return(NULL)
if(input$info%%2==0) return(NULL)
ProgressBar(session,max=30)
files <- filesNames()
comm <- paste("identify -verbose", files$infile)
info <- if(linux) system(comm, intern=TRUE) else shell(comm, intern=TRUE)
aceEditor("aceinfo",
value=paste(info, collapse="\n"),
mode="plain_text", theme="monokai", height="200px", fontSize=14, readOnly=TRUE)
})
## zoom ##
output$scaleUI <- renderUI({
if(is.null(Upload())) return(NULL)
sliderInput("scale", "Zoom", min=10, max=200, value=100, step=2)
})
## get file names ##
filesNames <- reactive({
if(is.null(input$files)) return(NULL)
files <- Upload()
infile <- files$datapath
infile.path <- dirname(infile)
infile.name <- files$name
outfile.name <- paste0("compressed_",infile.name)
outfile <- paste0(infile.path,"/",outfile.name)
list(path=infile.path, infile=infile, outfile=outfile, infile.name=infile.name, outfile.name=outfile.name)
})
## rendering original image ##
output$image0 <- renderImage({
if(is.null(input$files)) return(NULL)
files <- filesNames()
# calculate progress bar time proportional to file size
maxprogress <- floor(file.info(files$infile)$size / 30000) + 1
ProgressBar(session, max=maxprogress,
message = 'Rendering in progress',
detail = 'This may take a while...')
DONE[["image0"]] <- "ok"
outfile <- files$infile
list(src = outfile,
alt = "This is alternate text",
contentType="image/jpeg")
}, deleteFile = FALSE)
output$image <- renderUI({
if(is.null(input$scale)) return(NULL)
scale <- as.numeric(input$scale)
imageOutput("image0", width=paste0(input$scale,"%"))
})
## compression settings ##
getCommand <- reactive({
paste0("convert -strip -interlace Plane -gaussian-blur ", input$blur, " -quality ", input$quality, "%")
})
observe({ # image magick command
updateAceEditor(session, "magick",
value=getCommand(),
mode="r", theme="cobalt")
})
observe({ # stop the app if user acts after download
input$go
input$blur
input$compression
input$tab
deleted <- isolate(DONE[["deleted"]])
if(is.null(deleted)) return(NULL)
stopApp()
})
Compress <- reactive({ # run compression
input$go # makes reactivity to the go button
files <- filesNames()
comm0 <- isolate(getCommand())
comm <- paste(comm0, files$infile, files$outfile)
if(stringr::str_detect(platform, "linux")) system(comm) else shell(comm)
})
## compress and render image ##
output$cimage <- renderImage({
files <- filesNames()
# calculate progress bar time proportional to file size
maxprogress <- floor(file.info(files$outfile)$size / 40000) + 1
ProgressBar(session, max=maxprogress)
DONE[["cimage"]] <- "ok"
files <- filesNames()
list(src = files$outfile,
alt = "This is alternate text")
}, delete=FALSE)
output$cimageUI0 <- renderUI({
scale <- as.numeric(input$scale)
imageOutput("cimage", width=paste0(scale,"%"))
})
output$cimageUI <- renderUI({
maxprogress <- 30
if(is.null(input$files)) return(NULL)
deleted <- !is.null(isolate(DONE[["deleted"]]))
if(input$go==0 | deleted) return(h2("Preview will appear here"))
ProgressBar(session,max=maxprogress)
Compress()
DONE[["magick"]] <- TRUE
uiOutput("cimageUI0") # reactivity to input$scale only
})
## compressed image info ##
output$cimageTableInfo <- renderTable({
if(is.null(DONE[["magick"]])) return(NULL)
input$go
files <- filesNames()
if(!is.null(DONE[["deleted"]])){
tabl <- data.frame("size (Mo)"=rep("0 (deleted)",2), check.names=TRUE)
rownames(tabl) <- c(files$infile.name, files$outfile.name)
return(tabl)
}
if(!(files$outfile.name %in% list.files(files$path))) return(NULL)
tabl <- subset(file.info(files$infile, files$outfile), select=size)
tabl$size <- round(tabl$size/1000000,1)
colnames(tabl) <- "size (Mo)"
rownames(tabl) <- c(files$infile.name, files$outfile.name)
tabl
})
output$cimageinfobutton <- renderUI({
if(is.null(DONE[["cimage"]])) return(NULL)
actionButton("cimageinfo", ">>>Image info (see/hide)<<<")
})
output$cimageinfo <- renderUI({
if(is.null(input$files) | is.null(input$cimageinfo)) return(NULL)
if(input$cimageinfo%%2==0) return(NULL)
ProgressBar(session,max=10)
files <- filesNames()
comm <- paste("identify -verbose", files$outfile)
info <- if(linux) system(comm, intern=TRUE) else shell(comm, intern=TRUE)
aceEditor("aceinfocimage",
value=paste(info, collapse="\n"),
mode="plain_text", theme="monokai", height="200px", fontSize=14, readOnly=TRUE)
})
## tab: Compressed Image ##
output$tab2 <- renderUI({
if(is.null(input$files)) return(h2("Preview will appear here"))
input$go
uiOutput("cimageUI")
})
## download compressed image ##
output$download <- downloadHandler(
filename = filesNames()$outfile.name,
content = function(file){
file.copy(filesNames()$outfile, file)
# delete all files after download
file.remove(unlist(filesNames()[c("infile","outfile")]))
DONE[["deleted"]] <- TRUE
}
)
output$downloadUI <- renderUI({
if(is.null(DONE[["cimage"]])) return(NULL)
downloadButton("download", label="Download")
})
})
shinyUI(pageWithSidebar(
headerPanel("ImageMagick compression - single JPEG file",
tags$head(
logo(img="http://www.imagemagick.org/image/logo.jpg", link="http://www.imagemagick.org/script/index.php"),
sourcecode(link="https://gist.github.com/stla/7186022")
)
),
sidebarPanel(
conditionalPanel(
condition='input.tab=="Original image"',
uiOutput("upload"),
br()
),
conditionalPanel(
condition='input.tab=="Compressed image"',
numericInput("quality", "compression (%)", value=80, step=2),
numericInput("blur", "gaussian blur", value=0.05, step=0.01)
),
uiOutput("scaleUI"),
conditionalPanel(
condition='input.tab=="Compressed image"',
uiOutput("cimageinfobutton"),
tableOutput("cimageTableInfo")
)
),
mainPanel(
progressInit(),
tabsetPanel(
tabPanel("Original image",
tableOutput("filesInfo"),
uiOutput("imageinfo"),
uiOutput("image")
),
tabPanel("Compressed image",
h4("This ImageMagick command is ready to be executed:"),
aceEditor("magick",
value="",
mode="r", theme="cobalt", height="10px", fontSize=14, readOnly=TRUE),
div(class='row-fluid',
div(class='span6',
actionButton("go", "Run this ImageMagick command")
),
div(class='span6',
uiOutput("downloadUI")
)
),
helpText(HTML("<p> >>><a href = \"http://stackoverflow.com/questions/7261855/recommendation-for-compress-jpg-files-with-image-magick\">recommendations for JPEG recompressing</a><<<")),
uiOutput("cimageinfo"),
uiOutput("tab2")
),
id="tab"
)
)
))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment