如何在Shiny应用中渲染TIFF文件(PNG转换方案失效)
解决Shiny中TIFF图片上传渲染的错误问题
你的错误根源确实是inFile$datapath <- readPNG("test.png")这行代码:readPNG()返回的是多维像素数组(对应图片的像素矩阵),而inFile$datapath原本是字符串类型的文件路径,强行将数组赋值给字符串字段,会触发数据结构不匹配的错误。
修正方案1:保留本地文件转换逻辑
直接使用生成的PNG文件路径生成dataURI,不需要修改inFile对象:
library(pacman) pacman::p_load(shiny,shinydashboard,base64enc,tiff,png,xfun,tidyverse) #Header header <- dashboardHeader(title = "Visualization Tool") #sidebar sidebar <- dashboardSidebar( sidebarMenu( menuItem("1",tabName = "iris", icon = icon("magnifying-glass")), menuItem("2",tabName = "cars", icon = icon("fill")), menuItem("3",tabName = "test", icon = icon("puzzle-piece")) ) ) #body body <- dashboardBody( tabItems( tabItem("cars", fluidPage( h1("Cars"), fileInput("upload","Upload image", accept=c("image/png","image/tif", "image/tiff")), uiOutput("image") ) ) ) ) ui <- dashboardPage(header, sidebar, body) server <- function(input,output){ tiff_image <- reactive({ inFile <- input[["upload"]] if(!is.null(inFile$datapath)){ file_ext <- xfun::file_ext(inFile$datapath) if(file_ext %in% c("tif", "tiff")){ # 读取TIFF并转为PNG tiff_img <- tiff::readTIFF(inFile$datapath, native=FALSE) # 使用临时文件避免覆盖 temp_png <- tempfile(fileext = ".png") png::writePNG(tiff_img, temp_png) # 直接用临时PNG文件生成dataURI base64enc::dataURI(file = temp_png, mime = "image/png") } else { # 非TIFF文件直接生成dataURI base64enc::dataURI(file = inFile$datapath, mime = paste0("image/", file_ext)) } } }) output[["image"]] <- renderUI({ req(tiff_image()) tags$div( tags$img(src= tiff_image(), width="100%"), style = "width: 400px;" ) }) } shinyApp(ui, server)
关键修改点:
- 用
tempfile()生成临时PNG文件,避免多次上传时覆盖同一个文件 - 直接使用临时PNG的路径生成dataURI,不再修改
inFile对象 - 扩展支持
.tiff后缀,同时根据文件后缀动态设置mime类型
优化方案2:内存中直接转换(无需本地文件)
可以跳过本地文件存储,直接在内存中完成TIFF到PNG的转换,更高效:
server <- function(input,output){ tiff_image <- reactive({ inFile <- input[["upload"]] req(inFile$datapath) file_ext <- xfun::file_ext(inFile$datapath) if(file_ext %in% c("tif", "tiff")){ tiff_img <- tiff::readTIFF(inFile$datapath, native=FALSE) # 创建内存连接 conn <- rawConnection(raw(0), "w") png::writePNG(tiff_img, conn) # 获取内存中的PNG数据并转base64 png_raw <- rawConnectionValue(conn) close(conn) base64enc::dataURI(data = png_raw, mime = "image/png") } else { base64enc::dataURI(file = inFile$datapath, mime = paste0("image/", file_ext)) } }) output[["image"]] <- renderUI({ req(tiff_image()) tags$div( tags$img(src= tiff_image(), width="100%"), style = "width: 400px;" ) }) }
这种方式不需要生成本地临时文件,适合频繁上传的场景,减少磁盘IO操作。
内容的提问来源于stack exchange,提问作者user214476
相关产品推荐
相关产品推荐

