Skip to Content

Add watermark to images with Shiny and Magick library

This Shiny app allows to add a watermark to images and to do some basic photo retouch.

I created this shiny application with:

  • magick library;
  • I deployed it on shinyapps.io;
  • I embedded it in the blog with an iframe;
  • and the image is kindly provided by my cat (when he was a kitty).

The layout for this post is best seen via a computer.

The code

In the code below are missing the standard shiny commands such as:

  • ui <- ()
  • server <- function(input, output, session) {}
  • shinyApp(ui, server)

because I used shiny in a Rmarkdown file.

fluidPage(
fluidRow(column(4,fileInput("upload", "Upload new image", accept = c('image/png', 'image/jpeg'))),
         column(2,textInput("size", "Change size", value = "500x500!") ),
         column(2, sliderInput("rotation", "Rotate", 0, 180, 0)),
         column(2,  sliderInput("brightness", "Brightness", 0, 200, 100)),
        column(1, checkboxGroupInput("effects", "", choices = list( "Flop")))
         ),
hr(),

fluidRow(
   column(4, checkboxGroupInput("effects2", "Watermark adjustments:", choices = list("Add watermark")),
     textInput("W_text", "Watermark text", value = "Copyright"),
      sliderInput("W_size", "Watermark size", 25, 150, 40),
       sliderInput("W_degrees", "Watermark degrees", 0, 180, 0),
      selectInput("W_gravity", "Watermark position:",
             c("Center" = "center",
               "North" = "north",
               "West" = "west",
               "East" = "east",
               "South"="south",
               "North West" = "northwest",
               "North East" = "northeast",
               "South West" = "southwest",
               "South East" = "northeast")),
   downloadButton('downloadImage', 'Download modified image')),
   column(8,  imageOutput("img") )
)
)
  
library(magick)
  imageLoc <- reactiveVal("https://www.enricodata.com/images_added/mimo.png")

## convert the img location to an img value
  imageVal <- reactive({
    image_convert(image_read(imageLoc()), "jpeg")
  })
  
# When uploading new image
  observeEvent(input$upload, {
    if (length(input$upload$datapath)) {
      ## set the image location
      imageLoc(input$upload$datapath)
    }
    updateCheckboxGroupInput(session, "effects", selected = "")
  })

  ## if the image information ever updates, set the info values
  observe({
    info <- image_info(imageVal())
    updateTextInput(session, "size", value = paste0(info$width, "x", info$height, "!"))
  })

  updatedImageLoc <- reactive({
    ## retrieve the imageVal
    image <- imageVal()
  
# output$img <- renderImage({
    
    if("Add watermark" %in% input$effects2)
     image <- image_annotate(image, input$W_text, gravity = input$W_gravity, location = "+0+0",
               degrees = input$W_degrees, size = input$W_size,  color = "#FFFFFF66",
               strokecolor = NULL, boxcolor = NULL)
     
    if("Flop" %in% input$effects)
     image <- image_flop(image)
    
    tmpfile <- image %>%
    image_resize(input$size) %>%
    image_modulate(brightness = input$brightness , saturation = 100, hue = 100) %>%
    image_rotate(input$rotation) %>%
    image_write(tempfile(fileext='jpg'), format = 'jpg')
    
    ## return only the tmp file location
    tmpfile
  })
  
  # A plot of fixed size
  output$img <- renderImage(
    {
      # Return a list
      list(src = updatedImageLoc(), contentType = "image/jpeg")
    }, 
    ## DO NOT DELETE THE FILE!
    deleteFile = FALSE
  )

  output$downloadImage <- downloadHandler(
    filename = "Modified_image_from_EnricoData.jpeg",
    contentType = "image/jpeg",
    content = function(file) {
      ## copy the file from the updated image location to the final download location
      file.copy(updatedImageLoc(), file)
    }
  )