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

技术问询:如何将PDF内容绘制到Canvas?Android用PdfDocument生成多页PDF

将PDF文件内容绘制到Canvas的实现方案

在Android平台上,要把PDF内容绘制到Canvas,最常用的是系统提供的PdfRenderer类,以下是具体实现步骤和代码示例:

  • 步骤1:获取PDF文件的文件描述符
    你可以从本地存储、Assets目录或者其他来源获取PDF文件,然后创建ParcelFileDescriptor:

    // 示例:从Assets读取PDF
    ParcelFileDescriptor fd = getAssets().openFd("sample.pdf").getParcelFileDescriptor();
    
  • 步骤2:初始化PdfRenderer并获取页面
    创建PdfRenderer实例,然后通过页码获取对应的PdfRenderer.Page:

    PdfRenderer renderer = new PdfRenderer(fd);
    int pageCount = renderer.getPageCount();
    // 获取第一页(页码从0开始)
    PdfRenderer.Page page = renderer.openPage(0);
    
  • 步骤3:创建Bitmap并渲染到Canvas
    创建和PDF页面尺寸匹配的Bitmap,将其关联到Canvas,然后把PDF页面渲染到Bitmap,最后绘制到目标Canvas:

    // 创建Bitmap,注意要使用ARGB_8888格式保证清晰度
    Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(), Bitmap.Config.ARGB_8888);
    // 渲染PDF页面到Bitmap
    page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
    
    // 绘制到目标Canvas(比如View的onDraw方法里的canvas)
    canvas.drawBitmap(bitmap, 0, 0, null);
    
  • 步骤4:释放资源
    使用完后务必关闭页面和渲染器,避免内存泄漏:

    page.close();
    renderer.close();
    fd.close();
    

基于Android PdfDocument生成多页PDF的代码优化与补充

你提供的代码已经有了基础框架,我帮你补充完整多页生成的逻辑,包括文本换行、分页判断的核心代码:

public byte[] buildPDF() {
    int pageWidth = Math.round(8.5f * 72f); // 8.5英寸,72dpi
    int pageHeight = Math.round(11.0f * 72f); // 11英寸
    int margin = Math.round(.5f * 72f);
    int fontSize = 12;
    int lineSpacing = Math.round(fontSize * 1.2f); // 行间距设为字体大小的1.2倍

    TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    textPaint.setColor(Color.BLACK);
    textPaint.setTextSize(fontSize);
    textPaint.setTypeface(Typeface.DEFAULT_BOLD);

    PdfDocument document = new PdfDocument();
    PdfDocument.Page page = null;
    Canvas canvas = null;
    int currentY = margin; // 当前绘制的Y坐标,初始为上边距

    // 模拟需要绘制的大段文本
    String longContent = "这里是你需要绘制的大段文本内容,可以是从数据库、接口获取的内容...".repeat(50);

    try {
        // 创建StaticLayout来处理文本自动换行
        StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain(longContent, 0, longContent.length(), textPaint, pageWidth - 2 * margin);
        layoutBuilder.setLineSpacing(lineSpacing, 1.0f); // 设置行间距
        StaticLayout staticLayout = layoutBuilder.build();

        int lineCount = staticLayout.getLineCount();
        int currentLine = 0;

        while (currentLine < lineCount) {
            // 如果当前页面剩余空间不足,新建页面
            if (page == null || currentY + lineSpacing > pageHeight - margin) {
                // 新建页面
                PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(pageWidth, pageHeight, document.getPages().size() + 1).create();
                page = document.startPage(pageInfo);
                canvas = page.getCanvas();
                currentY = margin; // 重置Y坐标到页边距
            }

            // 计算当前页面能容纳的行数
            int maxLinesPerPage = (pageHeight - 2 * margin) / lineSpacing;
            int endLine = Math.min(currentLine + maxLinesPerPage, lineCount);

            // 将指定范围的文本绘制到当前页面
            staticLayout.draw(canvas, margin, currentY);

            // 更新当前行和Y坐标
            currentLine = endLine;
            currentY += (endLine - currentLine) * lineSpacing;
            // 结束当前页面
            document.finishPage(page);
        }

        // 将PDF内容写入ByteArrayOutputStream
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        document.writeTo(outputStream);
        return outputStream.toByteArray();

    } catch (IOException e) {
        e.printStackTrace();
        return null;
    } finally {
        document.close();
    }
}

关键细节说明:

  • 使用StaticLayout来处理文本的自动换行,避免手动计算每行文本的麻烦;
  • 通过判断currentY(当前绘制位置)是否超出页面底部边距,来触发新建页面的逻辑;
  • 每次新建页面时重置currentY到页面顶部边距,保证页面布局规范;
  • 最后记得关闭PdfDocument,并将内容写入ByteArrayOutputStream转换为byte[]返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:35:12