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

如何为PdfDocument生成的位图PDF添加可选文本?

问题解答:让Bitmap生成的PDF支持文本选中

可以实现。你当前生成的PDF无法选中文本,是因为PdfDocument绘制Bitmap后,页面仅包含位图数据,没有可被编辑器识别的文本对象。解决思路是:通过OCR识别Bitmap中的文本内容和位置,在PDF页面的Bitmap上方叠加一层透明的可选中文本层——这层文本不会影响视觉效果,但会被PDF编辑器识别为可选中的文本元素。

现有代码分析与优化

1. OCR文本识别(mlkitforembededtext)

你已经用MLKit完成了文本内容、边界框的提取,但文本大小计算逻辑存在问题,需调整为更合理的行高匹配逻辑:

// 原错误逻辑:用边界框宽度除以单个symbol数量,不符合字体大小对应关系
// float textSize = ( (float) boundingBoxforsave.width() /FORCOUNT.size());

// 修改为:取行边界框高度作为初始文本大小(字体高度与行高匹配更准确)
float textSize = boundingBoxforsave != null ? boundingBoxforsave.height() : 0;
pageTextSizes.add(textSize);

同时简化代码层级,无需遍历到Symbol级别:

for (Text.TextBlock block : visionText.getTextBlocks()) {
    for (Text.Line line : block.getLines()) {
        Rect boundingBox = line.getBoundingBox();
        String textValue = line.getText();
        if (boundingBox != null && textValue != null) {
            pageBoundingBoxes.add(boundingBox);
            pageTextValues.add(textValue);
            pageTextSizes.add(boundingBox.height());
            Log.i("MLKIT", "Text and bounding box added: " + textValue + " " + boundingBox.toString());
        } else {
            Log.e("MLKitError", "BoundingBox or Text is null");
        }
    }
}

2. PDF生成(createpdf)

当前代码绘制了可见文本,会干扰原Bitmap视觉,需改为透明文本层,同时优化对齐逻辑:

public void createpdf() throws IOException {
    PdfDocument document = new PdfDocument();

    for (int i = 0; i < pdfBitmaps.size(); i++) {
        Bitmap bitmap = pdfBitmaps.get(i);
        PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(bitmap.getWidth(), bitmap.getHeight(), i + 1).create();
        PdfDocument.Page page = document.startPage(pageInfo);
        Canvas canvas2 = page.getCanvas();

        // 1. 直接绘制原Bitmap(去掉多余的压缩解码步骤)
        canvas2.drawBitmap(bitmap, 0f, 0f, null);

        // 2. 准备绘制透明文本层
        List<String> textValues = allPageTextValues.get(i);
        List<Rect> boundingBoxes = allPageBoundingBoxes.get(i);
        List<Float> textSizes = allPageTextSizes.get(i);

        Paint textPaint = new Paint();
        textPaint.setStyle(Paint.Style.FILL);
        // 设置文本为透明,不干扰原Bitmap显示
        textPaint.setColor(Color.TRANSPARENT);
        textPaint.setTypeface(Typeface.DEFAULT); // 可替换为匹配原文本的字体
        textPaint.setAntiAlias(true);
        textPaint.setTextAlign(Paint.Align.LEFT);

        for (int p = 0; p < boundingBoxes.size(); p++) {
            String text = textValues.get(p);
            Rect box = boundingBoxes.get(p);
            float textSize = textSizes.get(p);

            textPaint.setTextSize(textSize);
            // 计算缩放因子,让文本适配边界框宽度
            float textWidth = textPaint.measureText(text);
            float scaleFactor = box.width() / textWidth;
            // 限制缩放范围,避免文本变形
            scaleFactor = Math.min(Math.max(scaleFactor, 0.8f), 1.2f);
            textPaint.setTextSize(textSize * scaleFactor);

            // 计算文本绘制位置:对齐边界框左上角,适配字体基线确保垂直居中
            float x = box.left;
            float y = box.bottom - textPaint.descent();
            // 绘制透明文本,提供可选中的文本数据
            canvas2.drawText(text, x, y, textPaint);
        }

        document.finishPage(page);
    }

    // 补充PDF保存逻辑
    File outputFile = new File(getExternalFilesDir(null), "output.pdf");
    document.writeTo(new FileOutputStream(outputFile));
    document.close();
}

关键优化点

  • 透明文本层:将文本颜色设为Color.TRANSPARENT,既不影响原Bitmap显示,又能让PDF编辑器识别文本。
  • 字体适配:基于边界框宽度调整缩放因子,确保文本与原Bitmap中的文本位置完全对齐。
  • 性能优化:去掉多余的Bitmap压缩解码步骤,直接绘制原Bitmap提升效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:52:35