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

使用wkhtmltopdf转换Doxygen HTML为PDF时遇空白及JS错误

解决Doxygen HTML转PDF(wkhtmltopdf)空白问题

问题场景

使用Doxygen 1.9.4生成HTML格式文档,通过wkhtmltopdf 0.12.6(带patched qt)转换为PDF时,执行以下命令:

wkhtmltopdf --debug-javascript --enable-local-file-access *.html output.pdf

PDF成功生成但内容完全空白,同时出现警告:

Loading pages (1/6)
Warning: file:///C:/Users/Downloads/Mik/html/jquery.js:2 jQuery.Deferred exception: 'null' is not an object
Warning: undefined:0 TypeError: 'null' is not an object
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

涉及的jQuery代码片段(Doxygen生成的标准文件):

S.extend({
    Deferred: function(e) {
      var o = [
          ["notify", "progress", S.Callbacks("memory"), S.Callbacks("memory"), 2],
          ["resolve", "done", S.Callbacks("once memory"), S.Callbacks("once memory"), 0, "resolved"],
          ["reject", "fail", S.Callbacks("once memory"), S.Callbacks("once memory"), 1, "rejected"]
        ],
        i = "pending",
        a = {
          state: function() {
            return i
          },
          always: function() {
            return s.done(arguments).fail(arguments), this
          },
          "catch": function(e) {
            return a.then(null, e)
          },
          pipe: function() {
            var i = arguments;
            return S.Deferred(function(r) {
              S.each(o, function(e, t) {
                var n = m(i[t[4]]) && i[t[4]];
                s[t[1]](function() {
                  var e = n && n.apply(this, arguments);
                  e && m(e.promise) ? e.promise().progress(r.notify).done(r.resolve).fail(r.reject) : r[t[0] + "With"](this, n ? [e] : arguments)
                })
              }), i = null
            }).promise()
          },
          then: function(t, n, r) {
            var u = 0;

            function l(i, o, a, s) {
              return function() {
                var n = this,
                  r = arguments,
                  e = function() {
                    var e, t;
                    if (!(i < u)) {
                      if ((e = a.apply(n, r)) === o.promise()) throw new TypeError("Thenable self-resolution");
                      t = e && ("object" == typeof e || "function" == typeof e) && e.then, m(t) ? s ? t.call(e, l(u, o, R, s), l(u, o, M, s)) : (u++, t.call(e, l(u, o, R, s), l(u, o, M, s), l(u, o, R, o.notifyWith))) : (a !== R && (n = void 0, r = [e]), (s || o.resolveWith)(n, r))
                    }
                  },
                  t = s ? e : function() {
                    try {
                      e()
                    } catch (e) {
                      S.Deferred.exceptionHook && S.Deferred.exceptionHook(e, t.stackTrace), u <= i + 1 && (a !== M && (n = void 0, r = [e]), o.rejectWith(n, r))
                    }
                  };
                i ? t() : (S.Deferred.getStackHook && (t.stackTrace = S.Deferred.getStackHook()), C.setTimeout(t))
              }
            }
            return S.Deferred(function(e) {
              o[0][3].add(l(0, e, m(r) ? r : R, e.notifyWith)), o[1][3].add(l(0, e, m(t) ? t : R)), o[2][3].add(l(0, e, m(n) ? n : M))
            }).promise()
          },
          promise: function(e) {
            return null != e ? S.extend(e, a) : a
          }
        },
        s = {};
      return S.each(o, function(e, t) {
        var n = t[2],
          r = t[5];
        a[t[1]] = n.add, r && n.add(function() {
          i = r
        }, o[3 - e][2].disable, o[3 - e][3].disable, o[0][2].lock, o[0][3].lock), n.add(t[3].fire), s[t[0]] = function() {
          return s[t[0] + "With"](this === s ? void 0 : this, arguments), this
        }, s[t[0] + "With"] = n.fireWith
      }), a.promise(s), e && e.call(s, s), s
    },
    when: function(e) {
      var n = arguments.length,
        t = n,
        r = Array(t),
        i = s.call(arguments),
        o = S.Deferred(),
        a = function(t) {
          return function(e) {
            r[t] = this, i[t] = 1 < arguments.length ? s.call(arguments) : e, --n || o.resolveWith(r, i)
          }
        };
      if (n <= 1 && (I(e, o.done(a(t)).resolve, o.reject, !n), "pending" === o.state() || m(i[t] && i[t].then))) return o.then();
      while (t--) I(i[t], a(t), o.reject);
      return o.promise()
    }
  });
  var W = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
  S.Deferred.exceptionHook = function(e, t) {
    C.console && C.console.warn && e && W.test(e.name) && C.console.warn("jQuery.Deferred exception: " + e.message, e.stack, t)
  }, S.readyException = function(e) {
    C.setTimeout(function() {
      throw e
    })
  };
  var F = S.Deferred();

解决方案

方案1:禁用JavaScript渲染

wkhtmltopdf对Doxygen自带的旧版jQuery的Deferred语法兼容存在问题,直接禁用JS即可绕开错误,修改命令为:

wkhtmltopdf --disable-javascript --enable-local-file-access *.html output.pdf

Doxygen生成的HTML核心内容无需JS即可正常展示,禁用后不会影响文档的可读性和布局。

方案2:修改Doxygen配置生成纯静态HTML

在Doxygen配置文件中添加以下设置,重新生成HTML文档:

GENERATE_JAVADOCS = NO
GENERATE_HTMLHELP = NO
SEARCHENGINE = NO
DISABLE_INDEX = YES

此配置会生成完全依赖CSS布局的静态HTML,无任何JS代码,转PDF时不会触发JS执行错误。

方案3:替换兼容版本的jQuery

找到Doxygen生成目录中的jquery.js文件,替换为wkhtmltopdf兼容的jQuery版本(如3.5.1)。替换后重新执行原转换命令,但需注意新版本jQuery可能与Doxygen的HTML结构存在样式兼容问题,此方法优先级低于前两种。


内容的提问来源于stack exchange,提问作者win.h

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 03:36:21