├── DESCRIPTION ├── LICENCE ├── NAMESPACE ├── R ├── Insert_Image.Rmd ├── Insert_Image.docx ├── Insert_Image.html ├── config.R ├── insertImageCode.R └── stackoverflow.png ├── README.md ├── clipboardImage_1.png ├── clipboardImage_2.png ├── clipboardImage_5.png ├── imageclipr.Rproj ├── inst └── rstudio │ └── addins.dcf ├── man ├── create_valid_file_name.Rd ├── insert_image_code.Rd └── save_clipboard_image.Rd └── usage.gif /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: imageclipr 2 | Type: Package 3 | Title: Copy image from clipboard to RMarkdown .Rmd files 4 | Version: 0.3.0 5 | Author: Tonio Liebrand 6 | Maintainer: Tonio Liebrand 7 | Description: Copy image from clipboard to RMarkdown .Rmd files. rmd code is generated and the image automatically inserted 8 | License: MIT + file LICENSE 9 | Encoding: UTF-8 10 | LazyData: true 11 | Imports: rstudioapi, shiny, miniUI, shinyjs 12 | RoxygenNote: 7.1.0 13 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | YEAR: 2020 2 | COPYRIGHT HOLDER: Andreas Tonio Liebrand 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | exportPattern("^[[:alpha:]]+") 2 | import(rstudioapi) 3 | import(shiny) 4 | import(miniUI) 5 | import(shinyjs) 6 | -------------------------------------------------------------------------------- /R/Insert_Image.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "UI Report" 3 | output: 4 | word_document: 5 | fig_caption: yes 6 | highlight: tango 7 | pdf_document: default 8 | html_document: 9 | df_print: paged 10 | date: '2019' 11 | subtitle: Template 12 | --- 13 | 14 | ```{r setup, include=FALSE} 15 | library(knitr) 16 | ``` 17 | 18 | ```{r chunk-label, echo = FALSE, fig.cap = "Caption"} 19 | knitr::include_graphics("") 20 | ``` 21 | 22 | 23 | -------------------------------------------------------------------------------- /R/Insert_Image.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/R/Insert_Image.docx -------------------------------------------------------------------------------- /R/config.R: -------------------------------------------------------------------------------- 1 | rmd_img_code <- 'function(img_file_name) paste0("\\begin{figure} 2 | \\begin{center} 3 | \\fbox{\\include_graphics[width = 0.75 \\linewidth]{", img_file_name, "}} 4 | \\caption{Caption} 5 | \\end{center} 6 | \\end{figure}")' 7 | 8 | nwcd <- data.frame( 9 | simple = 'function(img_file_name) paste0("![Plot title. ](", img_file_name,")")', 10 | include_graphics = rmd_img_code, 11 | stringsAsFactors = FALSE # for R < 4.0.0 12 | ) 13 | 14 | config <- function() { 15 | 16 | ui <- miniUI::miniPage( 17 | shinyjs::useShinyjs(), 18 | 19 | miniUI::gadgetTitleBar("Choose code to insert for graphic:"), 20 | 21 | miniUI::miniContentPanel( 22 | 23 | radioButtons("code", "Code choices - customize in text field:", 24 | c("simple" = "simple", 25 | "include_graphics" = "include_graphics")), 26 | 27 | textInput("file_name", "file name", "clipboardImage_1.png"), 28 | checkboxInput("show_field", "Code bearbeiten:", FALSE), 29 | uiOutput("edit_code"), 30 | verbatimTextOutput("code"), 31 | h6("Click 'done' to close and then select addin (or corresponding Keyboard shortcut) to insert image from clipboard to .Rmd.") 32 | ) 33 | ) 34 | 35 | server <- function(input, output, session) { 36 | 37 | global <- reactiveValues(rmd_img_code = nwcd) 38 | 39 | observeEvent(input$insert_code, { 40 | global$rmd_img_code[[input$code]] <- input$insert_code 41 | }) 42 | 43 | observeEvent(input$show_field, { 44 | if(!input$show_field){ 45 | shinyjs::hide(id = "edit_code") 46 | }else{ 47 | shinyjs::show(id = "edit_code") 48 | } 49 | }) 50 | 51 | rmd_img_code <- reactive({ 52 | user_code <- gsub("\\", "\\\\", global$rmd_img_code[[input$code]], fixed = TRUE) 53 | eval(parse(text = paste0("func = ", user_code))) 54 | }) 55 | 56 | output$code <- renderText({ 57 | user_code <- gsub("\\", "\\\\", global$rmd_img_code[[input$code]], fixed = TRUE) 58 | eval(parse(text = paste0("func = ", user_code, ";func('", input$file_name,"')"))) 59 | }) 60 | 61 | output$edit_code <- renderUI({ 62 | #refactor;3;3;new variable names 63 | textAreaInput("insert_code", "This code will be inserted:", global$rmd_img_code[[input$code]], 64 | width = "500px", rows = 10) 65 | }) 66 | 67 | observeEvent(input$done, { 68 | imageclipr_env$rmd_img_code <- rmd_img_code() 69 | stopApp() 70 | }) 71 | 72 | } 73 | 74 | runGadget(ui, server, viewer = paneViewer(300)) 75 | } 76 | -------------------------------------------------------------------------------- /R/insertImageCode.R: -------------------------------------------------------------------------------- 1 | imageclipr_env <- new.env(parent = emptyenv()) 2 | imageclipr_env$newCode <- function(img_file_name) paste0("![Plot title. ](", img_file_name, ")") 3 | 4 | #' Saving the clipboard image to disk 5 | #' 6 | #'The image from the clipboard has to be saved to disk. Mac, Linux and Windows are supported. For Windows Powershell is used. For Linux xclip is required. 7 | #' 8 | #' @param file_name The image from the clipboard has to be saved to disk. file_name is the name of the image when saving it to disk. 9 | #' @param dir The image from the clipboard has to be saved to disk. dir is the directory to save the image in. By default it is the current working directory. 10 | #' 11 | save_clipboard_image <- function(file_name, dir = getwd()) { 12 | 13 | file_path <- file.path(dir, file_name) 14 | if (file.exists(file_path)){ 15 | stop(paste0("File already exists at: ", file_path, ". Did not save the file.")) 16 | } 17 | 18 | platform <- Sys.info()[1] 19 | 20 | if (platform == "Darwin") { # MAC OS 21 | 22 | script <- paste0( 23 | "osascript -e \' 24 | set theFile to (open for access POSIX file \"", file_path, "\" with write permission) 25 | try 26 | write (the clipboard as \u00abclass PNGf\u00bb) to theFile 27 | end try 28 | close access theFile'" 29 | ) 30 | system(script) 31 | 32 | } else if (platform == "Windows") { 33 | 34 | script <- paste0( 35 | "powershell -sta \"\n", 36 | " Add-Type -AssemblyName System.Windows.Forms;\n", 37 | " if ($([System.Windows.Forms.Clipboard]::ContainsImage())) {\n", 38 | " [System.Drawing.Bitmap][System.Windows.Forms.Clipboard]::GetDataObject().getimage().Save('", 39 | paste0(file_path, "', [System.Drawing.Imaging.ImageFormat]::Png) \n"), 40 | " }\"" 41 | ) 42 | system(script) 43 | 44 | } else if (platform == "Linux") { 45 | 46 | # Validate xclip is installed and get targets from clipboard 47 | tryCatch(targets <- tolower(system("xclip -selection clipboard -t TARGETS -o", intern = T)), error = function(e) { 48 | stop( 49 | "Getting image from clipboard with xclip failed. The used command is: 'xclip -selection clipboard -t TARGETS -o'. 50 | Please ensure that the required system dependency xclip is installed and can be used. Otherwise file an issue at Github." 51 | ) 52 | }) 53 | 54 | if (any(grepl(".*png$", targets))) { 55 | system(paste0("xclip -selection clipboard -t image/png -o > ", file_path)) 56 | } 57 | 58 | } 59 | 60 | # check if a valid picture was saved. 61 | # In mac os, if no image is in the clipboard, exec script will create a empty image 62 | # In windows, no image will be created 63 | if (!file.exists(file_path) | file.size(file_path) == 0) { 64 | stop("Clipboard data is not an image.") 65 | } 66 | 67 | 68 | } 69 | 70 | 71 | #' Create a valid, unique file name. 72 | #' 73 | #' In case the current file name, for the image, is already taken an index will be added to the file name. 74 | #' 75 | #' @param file_path Directory path including name of the file 76 | #' @param file_type Extension of the image, e.g. .png 77 | #' 78 | #' @return An unique name for the image for the given path 79 | create_valid_file_name <- function(file_path, file_type = ".png") { 80 | 81 | dir_path <- dirname(file_path) 82 | file_name_id <- paste0(gsub(paste0("\\.", tools::file_ext(file_path)), "", basename(file_path)), "_insertimage_") 83 | 84 | file_names <- list.files(dir_path) 85 | 86 | idx <- grep(file_name_id, file_names) 87 | candidates <- strsplit(file_names[idx], file_name_id) 88 | 89 | if (!length(candidates)) { 90 | img_nr <- 1 91 | } else { 92 | nrs <- sapply(candidates, function(cand) { 93 | # refactor;2;4;what if other types of names -kopie... 94 | as.numeric(strsplit(cand[2], "[.]")[[1]][1]) 95 | }) 96 | img_nr <- max(nrs) + 1 97 | } 98 | return(paste0(file_name_id, img_nr, file_type)) 99 | } 100 | 101 | 102 | # open issue;2;3;configure parameter for addins 103 | # todo;2;3;create an image folder and edit the path accordingly 104 | 105 | #' Insert the markdown code for the image in the .Rmd file. 106 | #' 107 | #' Given the image in the clipboard, the corresponding markdown code will be inserted in the .Rmd file. The code 108 | #' will be generated given the code template from the configuration and the generated file path. It will be inserted with 109 | #' the rstudioapi package. 110 | #' Unsaved documents as Untitled1.Rmd can not properly be accessed by rstudioapi. The document has to be saved to disk. 111 | #' If multiple images are copied only one will be copied. 112 | #' The image can only be inserted in the source editor not in the console nor the terminal. 113 | #' 114 | insert_image_code <- function() { 115 | 116 | doc_id <- rstudioapi::getActiveDocumentContext()$id 117 | if (doc_id %in% c("#console", "#terminal")){ 118 | stop("You can`t insert an image in the console nor in the terminal. Please select a line in the source editor.") 119 | } 120 | 121 | file_path <- rstudioapi::getActiveDocumentContext()$path 122 | if (!nchar(file_path)){ 123 | stop("Please save the file before pasting an image.") 124 | } 125 | 126 | # if the first is tilde, then the python code breaks. Let's replace this using Sys.getenv 127 | file_path <- gsub("^~", Sys.getenv("HOME"), file_path) 128 | img_file_name <- create_valid_file_name(file_path, file_type = ".png") 129 | 130 | # refactor;3;3;get file ending 131 | save_clipboard_image(img_file_name, dir = dirname(file_path)) 132 | position <- rstudioapi::getActiveDocumentContext()$selection[[1]]$range$start 133 | code_to_insert <- imageclipr_env$newCode 134 | rstudioapi::insertText(position, code_to_insert(img_file_name), id = doc_id) 135 | } 136 | -------------------------------------------------------------------------------- /R/stackoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/R/stackoverflow.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## imageclipr 2 | [![CRAN version](http://www.r-pkg.org/badges/version/imageclipr)](https://cran.r-project.org/package=imageclipr) 3 | 4 | RStudio Addin: Copy images from clipboard into RMarkdown .Rmd files. 5 | 6 | ![Usage of imageclipr](usage.gif) 7 | 8 | ## Installation 9 | `devtools::install_github('Timag/imageclipr')` 10 | 11 | ## Dependencies 12 | R packages `library(rstudioapi)`, (`library(rmarkdown)` for markdown files) 13 | 14 | For linux [xclip](https://github.com/astrand/xclip) is required. 15 | For debian, ubuntu,... install it with: 16 | ``` 17 | sudo apt-get install xclip 18 | ``` 19 | 20 | ## Open issues 21 | - can not: 22 | 23 | -- copy and paste image and text together 24 | 25 | -- copy and paste an image by copying the file in the explorer 26 | 27 | ## Technical walkthrough 28 | (highlevel): https://stackoverflow.com/questions/55541345/copy-and-paste-an-image-from-clipboard-to-rmarkdown-rmd-code 29 | 30 | 31 | 32 | ## Usage 33 | 34 | ### Select the addin 35 | 36 | Note: You will see "Paste Img to Rmd file" instead of "Insert Image". 37 | 38 | ![Addin selection](clipboardImage_5.png) 39 | 40 | ### Adding a keyboard shortcut (Recommended) 41 | In RStudio go to Tools - Modify Keyboard Shortcuts... 42 | 43 | Note: You will see "Paste Img to Rmd file" instead of "Insert Image". 44 | 45 | 46 | ![Find Shortcuts](clipboardImage_1.png) 47 | 48 | ![Modify Shortcuts](clipboardImage_2.png) 49 | 50 | 51 | (This project is part of my life long application to RStudio :)) 52 | -------------------------------------------------------------------------------- /clipboardImage_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/clipboardImage_1.png -------------------------------------------------------------------------------- /clipboardImage_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/clipboardImage_2.png -------------------------------------------------------------------------------- /clipboardImage_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/clipboardImage_5.png -------------------------------------------------------------------------------- /imageclipr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /inst/rstudio/addins.dcf: -------------------------------------------------------------------------------- 1 | Name: Paste Image to Rmd file 2 | Description: Insert Image from Clipboard 3 | Binding: insert_image_code 4 | Interactive: false 5 | 6 | Name: Configuration 7 | Description: Configure which code to insert 8 | Binding: config 9 | Interactive: true 10 | -------------------------------------------------------------------------------- /man/create_valid_file_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/insertImageCode.R 3 | \name{create_valid_file_name} 4 | \alias{create_valid_file_name} 5 | \title{Create a valid, unique file name.} 6 | \usage{ 7 | create_valid_file_name(file_path, file_type = ".png") 8 | } 9 | \arguments{ 10 | \item{file_path}{Directory path including name of the file} 11 | 12 | \item{file_type}{Extension of the image, e.g. .png} 13 | } 14 | \value{ 15 | An unique name for the image for the given path 16 | } 17 | \description{ 18 | In case the current file name, for the image, is already taken an index will be added to the file name. 19 | } 20 | -------------------------------------------------------------------------------- /man/insert_image_code.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/insertImageCode.R 3 | \name{insert_image_code} 4 | \alias{insert_image_code} 5 | \title{Insert the markdown code for the image in the .Rmd file.} 6 | \usage{ 7 | insert_image_code() 8 | } 9 | \description{ 10 | Given the image in the clipboard, the corresponding markdown code will be inserted in the .Rmd file. The code 11 | will be generated given the code template from the configuration and the generated file path. It will be inserted with 12 | the rstudioapi package. 13 | Unsaved documents as Untitled1.Rmd can not properly be accessed by rstudioapi. The document has to be saved to disk. 14 | If multiple images are copied only one will be copied. 15 | The image can only be inserted in the source editor not in the console nor the terminal. 16 | } 17 | -------------------------------------------------------------------------------- /man/save_clipboard_image.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/insertImageCode.R 3 | \name{save_clipboard_image} 4 | \alias{save_clipboard_image} 5 | \title{Saving the clipboard image to disk} 6 | \usage{ 7 | save_clipboard_image(file_name, dir = getwd()) 8 | } 9 | \arguments{ 10 | \item{file_name}{The image from the clipboard has to be saved to disk. file_name is the name of the image when saving it to disk.} 11 | 12 | \item{dir}{The image from the clipboard has to be saved to disk. dir is the directory to save the image in. By default it is the current working directory.} 13 | } 14 | \description{ 15 | The image from the clipboard has to be saved to disk. Mac, Linux and Windows are supported. For Windows Powershell is used. For Linux xclip is required. 16 | } 17 | -------------------------------------------------------------------------------- /usage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Toniiiio/imageclipr/4b49aef08aa50b2a9c14eaff9298cfa10bbd6f5c/usage.gif --------------------------------------------------------------------------------