You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Plumber API生成含图片Word文档时遇png()设备启动错误

问题描述

我正在创建一个Plumber API用于生成包含图片的MS Word文档,但在Swagger中出现以下错误:

"message": "Error in png():
! unable to start png() device
"

关联代码

plumber.R 文件

#* @serializer contentType list(type="application/vnd.openxmlformats-officedocument.wordprocessingml.document")
#* @get /word
function(team){
  tmp <- getwd()
  
  render("test_report.Rmd", tmp, output_format = "word_document",
         params = list(team = team))

  readBin(paste0(tmp, ".docx"), "raw", n=file.info(paste0(tmp, ".docx"))$size)
}

test_report.Rmd 文件

---
title: test
output: html_document
params:
  team: NA
---

`r params$team`

```{r cars}
summary(cars)
plot(pressure)
#### API启动代码
```r
library(plumber)
library(rmarkdown)
pr("plumber.R") %>%
       pr_run(port=8000)

已知已使用正确的序列化器,且移除plot()代码后API可正常运行,请问问题出在哪里?


问题原因与解决办法

核心原因

Plumber运行在无图形界面的环境(如后台进程、服务器)时,R默认的png()图形设备需要依赖系统显示设备(X11/Windows图形界面),而这类环境没有可用的显示驱动,导致无法启动图片设备,进而生成文档失败。

具体修复步骤

  1. 统一Rmd输出格式
    你的Rmd头部指定output: html_document,但调用render时强制使用word_document,虽不是直接报错原因,但易引发混淆。建议将Rmd头部修改为:

    ---
    title: test
    output: word_document
    params:
      team: NA
    ---
    
  2. 指定无界面图形设备
    有三种方案可选,任选其一即可:

    • 方案一:在Rmd代码块中显式设置
      在绘图代码块中指定png设备的无界面类型:
      ```{r, echo=FALSE}
      png(type = "cairo")
      plot(pressure)
      dev.off()
      
    • 方案二:全局设置默认设备
      在API启动代码中添加全局配置,让所有绘图都使用无界面设备:
      library(plumber)
      library(rmarkdown)
      # 全局配置无界面png设备
      options(device = function(...) png(type = "cairo", ...))
      pr("plumber.R") %>%
             pr_run(port=8000)
      
    • 方案三:使用ragg包(推荐)
      ragg是专为无界面环境设计的高性能图形设备,稳定性更强。先安装包:install.packages("ragg"),然后:
      要么在Rmd代码块中使用:
      ```{r, echo=FALSE}
      library(ragg)
      agg_png(tempfile())
      plot(pressure)
      dev.off()
      
      要么全局设置:
      ```r
      options(device = ragg::agg_png)
      
  3. 修复临时文件处理逻辑
    原代码中render的参数使用错误,且用getwd()作为输出路径易引发文件冲突或权限问题。修改plumber函数如下:

    #* @serializer contentType list(type="application/vnd.openxmlformats-officedocument.wordprocessingml.document")
    #* @get /word
    function(team){
      # 生成唯一临时docx文件路径
      tmp_doc <- tempfile(fileext = ".docx")
      # 正确指定output_file参数
      render(
        input = "test_report.Rmd",
        output_file = tmp_doc,
        output_format = "word_document",
        params = list(team = team)
      )
      # 读取文件并返回
      readBin(tmp_doc, "raw", n = file.info(tmp_doc)$size)
    }
    

内容的提问来源于stack exchange,提问作者Cristian Santa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:55:19