使用Shiny调整用户上传图片尺寸并存储低分辨率版本的问题咨询
解决方案
你遇到的报错是Shiny的正常设计:output对象为仅写入的渲染接口,不支持读取操作,因此无法直接从output$showphotos*中获取压缩后的图片数据。
核心解决思路为:先对用户上传的原始图片做压缩处理,生成高度200px的小图临时文件,再同时用这个临时文件做前端渲染和Google Drive上传。
前置依赖
首先安装所需的图片处理包:
install.packages("magick")
修改后的完整可运行代码
library(shiny) library(shinydashboard) library(googledrive) library(magick) ui <- dashboardPage( dashboardHeader(), dashboardSidebar(), dashboardBody( # 限制仅上传图片格式,避免非图片文件报错 fileInput("loadphotos", label="Carregar fotos", multiple=T, accept = "image/*"), actionButton("do", "Carregar"), imageOutput("showphotos1", height="200px"), imageOutput("showphotos2", height="200px"), imageOutput("showphotos3", height="200px") ) ) server <- function(input, output, session) { observeEvent(input$do, { # 判空:用户未上传文件时直接终止运行 req(input$loadphotos) # 最多处理3张图片,避免索引溢出报错 upload_num <- min(nrow(input$loadphotos), 3) # 存储压缩后的临时文件路径 compressed_imgs <- list() for(i in 1:upload_num) { # 读取原始图片 raw_img <- image_read(input$loadphotos$datapath[i]) # 压缩到高度200px,宽度自动按原比例缩放 compressed_img <- image_resize(raw_img, "x200") # 生成临时文件路径,后缀保留原始图片格式 tmp_path <- tempfile(fileext = tools::file_ext(input$loadphotos$name[i])) # 写入压缩后的图片到临时文件 image_write(compressed_img, tmp_path) compressed_imgs[[i]] <- tmp_path # 直接上传压缩后的小图到Google Drive drive_upload( media = tmp_path, path = as_id("https://drive.google.com/drive/u/1/folders/1qj0eeee..."), name = input$loadphotos$name[i] ) } # 批量渲染3个图片输出,无需重复编写3次renderImage逻辑 for(i in 1:3) { local({ idx <- i output[[paste0("showphotos", idx)]] <- renderImage({ # 对应索引无图片时返回空 if(idx > length(compressed_imgs)) return(list()) list(src = compressed_imgs[[idx]], height = "200") }, deleteFile = TRUE) # 渲染完成后自动删除临时文件,避免占用存储 }) } }) } shinyApp(ui, server)
优化说明
- 无需重复编写多份图片渲染、上传逻辑,后续如果要增加展示的图片数量,只需要新增对应
imageOutput组件、修改循环上限即可 - 增加了空值判断、上传数量限制,避免用户未上传文件、上传数量超过3张时的索引报错
- 自动保留原始图片的格式和文件名,压缩过程不改变图片宽高比
- 临时文件会在渲染完成后自动清理,不会占用服务器本地存储空间
内容的提问来源于stack exchange,提问作者Vitor Hugo Moreau
相关产品推荐
相关产品推荐

