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

证书生成器项目:PDF无内容问题及基于pdf-lib的实现需求问询

证书生成器PDF无内容问题解决指南

问题根源

  1. 核心逻辑文件index.js被注释,未执行任何PDF生成代码
  2. 使用PNG作为模板,但pdf-lib基于PDF文档操作,需将PNG转为PDF页面背景
  3. 缺少字体加载、文本绘制的关键实现逻辑

1. 修复HTML结构

取消index.js的注释,确保核心逻辑文件被加载,同时替换FileSaver为CDN链接避免模块加载问题:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Certificate Generator</title>
    <link href="styles.css" rel="stylesheet" />

    <script src="https://unpkg.com/pdf-lib/dist/pdf-lib.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js"></script>
  </head>
  <body>
    <section>
      <div class="container">
        <img
          src="https://codedamn.com/assets/images/red-logo.png"
          width="75"
          alt="codedamn logo"
        />
        <p>Get your certificate of</p>
        <h1>Project Certificate Generator</h1>
        <p class="name-text">Enter Your Name</p>

        <input type="text" id="participant-name" placeholder="Steve" />
        <button id="proceed">Generate Certificate</button>
      </div>
    </section>
  </body>
  <script src="index.js"></script>
</html>

2. 编写核心生成逻辑(index.js)

严格按照需求的7步实现:

const { PDFDocument, rgb, StandardFonts } = PDFLib;

document.getElementById('proceed').addEventListener('click', async () => {
  const participantName = document.getElementById('participant-name').value.trim();
  if (!participantName) {
    alert('请输入姓名');
    return;
  }

  try {
    // 1. 从文件系统获取证书模板(确保模板在项目根目录)
    const templateResponse = await fetch('./证书模板.png');
    const templatePngBytes = await templateResponse.arrayBuffer();

    // 2. 创建并初始化PDFDocument对象
    const pdfDoc = await PDFDocument.create();

    // 将PNG模板转为PDF页面
    const pngImage = await pdfDoc.embedPng(templatePngBytes);
    const pageWidth = pngImage.width;
    const pageHeight = pngImage.height;
    const page = pdfDoc.addPage([pageWidth, pageHeight]);

    // 绘制PNG作为页面背景
    page.drawImage(pngImage, {
      x: 0,
      y: 0,
      width: pageWidth,
      height: pageHeight,
    });

    // 3. 加载字体(使用内置粗体Helvetica,也可替换为自定义字体)
    const font = await pdfDoc.embedFont(StandardFonts.HelveticaBold);

    // 4. 字体已通过embedFont完成嵌入

    // 5. 在证书空白区域插入文本(需根据实际模板调整坐标和字号)
    const fontSize = 36;
    // 居中计算X坐标,Y坐标需根据模板空白位置微调
    const textX = pageWidth / 2 - font.widthOfTextAtSize(participantName, fontSize) / 2;
    const textY = pageHeight / 2 + 20;

    page.drawText(participantName, {
      x: textX,
      y: textY,
      size: fontSize,
      font: font,
      color: rgb(0, 0, 0),
    });

    // 6. 保存PDF为字节数组
    const pdfBytes = await pdfDoc.save();

    // 7. 创建文件并触发下载
    const pdfFile = new Blob([pdfBytes], { type: 'application/pdf' });
    saveAs(pdfFile, `${participantName}_证书.pdf`);
  } catch (error) {
    console.error('生成PDF失败:', error);
    alert('生成证书失败,请检查控制台日志');
  }
});

关键注意事项

  • 模板路径:确保证书模板.png放在项目根目录,否则需调整fetch的路径
  • 坐标微调:textX和textY需要根据你的证书模板空白区域实际位置调整,可通过打印pageWidth/pageHeight测试定位
  • 自定义字体:如果需要使用特定字体,替换内置字体为本地字体加载逻辑:
    const fontResponse = await fetch('./你的字体文件.ttf');
    const fontBytes = await fontResponse.arrayBuffer();
    const font = await pdfDoc.embedFont(fontBytes);
    
  • 本地运行:直接打开HTML文件可能存在CORS问题,建议用本地服务器(如VS Code的Live Server)运行项目

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 17:43:04