Save base64 JPG to disk in R - Shiny - r

I have the following data frame which can be downloaded from here. The column image_path has jpg files in base64 format. I want to extract the image and store it in a local folder. I tried using the code given here and here.
While the second one perfectly opens the image in the browser, I couldn't figure out how to save the file locally. I tried the following code:
library(shiny)
for (i in 1:length(df)){
file <- paste(df$id[i])
png(paste0(~images/file, '.png'))
tags$img(src = df$image_path[i])
dev.off()
}
The following just runs but doesn't create any image files and no errors are shown. When I tried running tags$img(src = df$image_path[1]) to see if it generates the image, it doesn't. I understand tags$img is a function within shiny and works when I pass it inside ui (as suggested by #daatali), but not sure how do I save the files locally.
What I want is to run a for loop from inside a server environment of shiny and save the images locally as jpg using id numbers as filename, which can be rendered with various other details captured in the survey.
I have never worked with images and please bear with me if this is completely novice.

This creates your images from the base64 strings and saves the files to your current working directory, subfolder "/images/". This article describes pretty well how to save files locally in Shiny.
library(shiny)
library(base64enc)
filepath <- "images/"
dir.create(file.path(filepath), showWarnings = FALSE)
df <- read.csv("imagefiletest.csv", header=T, stringsAsFactors = F)
for (i in 1:nrow(df)){
if(df[i,"image_path"] == "NULL"){
next
}
testObj <- strsplit(df[i,"image_path"],",")[[1]][2]
inconn <- testObj
outconn <- file(paste0(filepath,"image_id",df[i,"id"],".png"),"wb")
base64decode(what=inconn, output=outconn)
close(outconn)
}

Related

Saving images from a for loop

I am new to R and trying to use the below code for cropping and saving multiple files in a R loop. It works fine, but the only problem is that as it saves the output images, the same output file gets overwritten resulting in only the last image being saved. I would like to have the cropped images saved as separate files as 'trial_1.png', 'trial_2.png', etc. I can't figure out how to fix this any any suggestions regarding this would be welcome. The code mainly uses the magick package functions. Thanks in advance.
Code:
library(pdftools)
library(magick)
library(png)
library(raster)
path = "~/Desktop/RME_task"
file.names<-dir(path, pattern = ".png")
for(i in 1:length(file.names)){
rme_stimuli_set1_1<-image_read(file.names[i])
rme_stimuli_set1_1_scaled<-image_scale(rme_stimuli_set1_1, "700x700")
rme_stimuli_set1_1_cropped<-image_crop(rme_stimuli_set1_1_scaled, "305x120+118+322")
image_write(rme_stimuli_set1_1_cropped, "CROPPED/trial_.png")
}
just change the file name in each interaction.
library(pdftools)
library(magick)
library(png)
library(raster)
path = "~/Desktop/RME_task"
file.names<-dir(path, pattern = ".png")
for(i in 1:length(file.names)){
rme_stimuli_set1_1<-image_read(file.names[i])
rme_stimuli_set1_1_scaled<-image_scale(rme_stimuli_set1_1, "700x700")
rme_stimuli_set1_1_cropped<-image_crop(rme_stimuli_set1_1_scaled, "305x120+118+322")
image_write(rme_stimuli_set1_1_cropped, paste0("CROPPED/trial_",i,".png"))
}
in this way each interaction of the loop will create trial_1.png, trial_2.png, etc.

Save cropped pdf image from R imagemagick to a new pdf

I'm using R with imagemagick to crop some borders from a pdf file. I'm executing the following commands:
library(magick)
pdf_total <- image_read_pdf(path = "file1.pdf")
pdf_cropped <- image_crop(pdf_total,"3000x1500")
After this process I have a perfect cropped file, but my problem occurs when I try to save the file to a new pdf file. What is the correct procedure to save this converted pdf?
My final solution is:
library(magick)
pdf_total <- image_read_pdf(path = "file1.pdf")
pdf_cropped <- image_crop(pdf_total,"3000x1500")
for(i in seq(1,length(pdf_cropped))){
plot(pdf_cropped[i])
}
dev.off()
In this case I made a for loop to save all the pages, if you pass plot(pdf_cropped) the result is a pdf with a single page (first picture).

Uploading picture to the knitr document via Shiny

I am using combination of Shiny and knitr to create PDF documents.
Currently I want to add feature that will allow user to upload picture that will be placed within the created document. However, I am really stuck because I am unable to get the path of the input picture. Could anyone help me with that?
Simple example:
Application:
library(knitr)
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("picture", label = 'Picture'),
downloadButton('report', label = 'Download PDF')
),
mainPanel()
)
)
server <- function(input,output){
picture <- reactive({
input$picture[,4]
})
output$report = downloadHandler(
filename = "test.pdf",
content = function(file){
picture = picture()
out = knit2pdf(input = 'test.Rnw', compiler = 'xelatex', clean = TRUE)
file.rename(out, file)
},
contentType = 'application/pdf'
)
}
shinyApp(ui = ui, server = server)
and the .Rnw document:
\documentclass{article}
\begin{document}
Put picture here:
<<echo = FALSE , message = F, results='asis'>>=
cat(paste('\\includegraphics[height=3in]{', picture,'}'))
#
\end{document}
Part '\includegraphics[height=3in]{', picture,'} is obviously causing the problem, because I do not know the picture path only temporary one.
You said you were working with Shiny Server, then you should be okay with the full path of the picture, even if it is in a temporary directory (because currently Shiny Server only works on Linux, and LaTeX should be okay with Linux file paths like /tmp/...../yourfile.png). The problem is perhaps the datapath (i.e. input$picture[, 4]) does not have the file extension, so LaTeX could not recognize it. You may try to retrieve the filename extension of the original file, and copy the uploaded picture to a temp file with the same extension, e.g.
picture <- reactive({
path1 <- input$picture$datapath
path2 <- tempfile(fileext = gsub('^(.*)([.].+)$', '\\2', input$picture$name))
file.copy(path1, path2, overwrite = TRUE)
path2
})
i see a solution in two ways:
1) copy the temporary file to a folder of your choice and use that image:
observe({
if (is.null(input$picture)) return()
picture<-"your/final/path/to/disk/uploadImage.jpg" # OR do a PASTE with the PATH and the upload file name
file.copy(input$picture$datapath, picture)
if(file.exists(picture)){
# PROCESS THE IMAGE IF NEEDED
}
picture<<-picture # sometimes needed to R to see the variable outside the observe scope
})
2) if you (in this case the R session) are not allowed to write to disk you can turn the image into a base64 variable and include that into your Knitr document (or save it to a database as a string). This takes the Knitr/HTML route if you are willing to take that detour. (R studio running from a server almost always has a lot of restrictions in reading/writing that you can only handle as an ADMIN. And the server runs the shiny session as RStudio and not you so Rstudio must have the read/write permissions needed if you run the Shiny app as an automatic Rstudio Shiny session and not run it directly form RStudio using RUN)
Make sure the base64 is readable by R ouside the 'observe' or 'if' scope again by using '<<-' together with '<-'. Scoping is quite something special with R so be sure to test it properly.
You should dive into this (base64) with sites like:
https://github.com/yihui/knitr/issues/944
https://github.com/yihui/knitr/blob/master/R/utils-base64.R

Print/save interactive report created using Rmarkdown and Shiny

I have an interactive Rmarkdown document which embeds a few shiny apps that generates graphs based on user inputs.
After I am happy with the graphs generated, I would like to save the report (so that it becomes static).
I have opened the report in my browser (Chrome), and tried printing to pdf. It sort of works, however some figures are cut into two by the page break.
Does anyone know what is the best way to print/save such reports?
I think it's a bit tricky but this is what i use on my app to save html plot on pdf or png format.
Instal wkhtmltopdf
wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command
line tools to render HTML into PDF and various image formats using the
Qt WebKit rendering engine. These run entirely "headless" and do not
require a display or display service.
Use it in R
This allow you to convert a htmlfile into pdfor img.
In my ShinyApp i use inside a downloadHandler() function somthing like this :
system("wkhtmltopdf --enable-javascript --javascript-delay 2000 plot.html plot.pdf")
I think for your example you could simply convert your html by using :
system("wkhtmltopdf yourFile.html yourFile.pdf")
You can give a download button on the ui.R as:
downloadButton('report', 'Download PDF')
And the corresponding server.R code:
library(knitr)
output$report = downloadHandler(
filename = function() {
paste("Report_", <date/identifier>, ".pdf", sep="")
},
content = function(file) {
rnw <- normalizePath('input.rnw') # assuming you wrote the code to display the graphs etc in this file
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(rnw, 'input.rnw')
out = knit2pdf(rnw, clean=TRUE)
file.rename(out, file)
}
)

rmarkdown shiny user input in chunk?

I have a shiny app that allows the user to download an HTML file (knitted from a .Rmd file) that includes the code used to run the analysis based on all the user inputs. I am trying to write the base .Rmd file that gets altered when user inputs vary. I am having trouble including user input variables (e.g. input$button1) into R code chunks. Say the user input for input$button1 = "text1".
```{r}
results <- someFun(input$button1)
```
And I'd like to have it knitted like this:
```{r}
results <- someFun('text1')
```
Every time I download the knitted HTML though, I get input$button1 getting written to file. I would also like to be able to produce an .Rmd file that is formatted with this substitution. It seems like knit_expand() might be the key, but I can't seem to relate available examples to my specific problem. Is the proper way to knit_expand() the whole .Rmd file and specify explicitly all the parameters you want subbed in, or is there a more elegant way within the .Rmd file itself? I would prefer a method similar to this, except that instead of using the asis engine, I could use the r one. Any help would be greatly appreciated. Thanks!
Got it. Solution below. Thanks to Yihui for the guidance. The trick was to knit_expand() the whole .Rmd file, then writeLines() to a new one, then render. With hindsight, the whole process makes sense. With hindsight.
For the example, p1 is a character param 'ice cream' and p2 is an integer param 10. There is a user-defined param in ui.R called input$mdType that is used to decide on the format provided for download.
Rmd file:
Some other text.
```{r}
results <- someFun("{{p1}}", {{p2}})
```
in the downloadHandler() within server.R:
content = function(file) {
src <- normalizePath('userReport.Rmd')
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'userReport.Rmd')
exp <- knit_expand('userReport.Rmd', p1=input$p1, p2=input$p2)
writeLines(exp, 'userReport2.Rmd')
out <- rmarkdown::render('userReport2.Rmd', switch(input$mdType,
PDF = pdf_document(), HTML = html_document(), Word = word_document()))
}
file.rename(out, file)
}
Resulting userReport2.Rmd before rendering:
```{r}
results <- someFun("ice cream", 10)
```

Resources