user18864224
user18864224

Reputation:

How to display a QR-code svg image in a shiny app

I've this piece of code which is generating me an QR code, from an input field, and than saving it as .svg.

observeEvent(input$safe_qr,{
  qr <- qr_code(input$qr_gen)
  generate_svg(qr, "QR_Code.svg",
               size = 100,
               foreground = "black",
               background = "white",
               show = interactive())
  renderPlot(qr)
}) 

Now I don't really need to save it, I want to see it next to my input field on the page. I have no idea how put an image inside the page.

One thing I was trying was Plot(qr) then a new window opened in edge and showed me the saved QR code. But yeah that's not what I want.

Upvotes: 0

Views: 393

Answers (1)

r2evans
r2evans

Reputation: 160447

Here's a working shiny app to allow arbitrary QR generate (of text), showing in both SVG and PNG.

library(shiny)
ui <- fluidPage(sidebarLayout(
  sidebarPanel(
    textInput("text", label = NULL, placeholder = "(some phrase)"),
    imageOutput("svgplot")
  ),
  mainPanel(
    plotOutput("plot")
  )
))

server <- function(input, output, session) {
  QR <- eventReactive(input$text, {
    qrcode::qr_code(input$text)
  })
  output$svgplot <- renderImage({
    txt <- isolate(input$text)
    tf <- tempfile(fileext = ".svg")
    qrcode::generate_svg(QR(), tf, size = 100, foreground = "black", background = "white", show = FALSE)
    list(
      src = normalizePath(tf),
      contentType = "image/svg+xml",
      width = 100, height = 100,
      alt = paste("My QR code:", sQuote(txt, FALSE))
    )
  }, deleteFile = TRUE)
  output$plot <- renderPlot({ plot(QR()) })
}

shinyApp(ui, server)

shiny app with QR svg and png

You don't need to show both, I thought I'd compare/contrast how to show them since they require different steps.

Key takeaways:

  • renderImage allows us to show an arbitrary image that the browser should support. The expression in this call must be a list with the attributes for the HTML img attribute, so here my list(...) is creating

    <img src="path/to/tempfile.svg" contentType="image/svg+xml" width=100 height=100 alt="...">
    
  • I'm doing a two-step here: create the QR object as reactive data, and then anything that will use that will depend on QR() (my QR object). This way there will be fewer reactive-chain calls. This may not be strictly necessary if all you're doing is showing a single QR code, over to you.

  • shiny::renderImage requires the deleteFile= argument; if all you want to is show it, this is fine; if the user wants to right-click on the displayed SVG file and download it locally, it's still fine. In fact, since the "link" text is data:image/svg+xml;base64,PD94bWwgdmVy... and is a fairly long string (39K chars in one example), even if the temp file is deleted, this link remains unchanged and working.

Upvotes: 1

Related Questions