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

如何在Javascript/Angular中实现PDF文本对比及可视化功能?

在Angular/JavaScript中实现PDF文本对比与可视化方案

一、核心思路拆解

要实现类似Git/Beyond Compare的PDF对比效果,核心分为三步:

  1. 从两个PDF中提取带行结构的纯文本
  2. 对提取的文本进行差异计算
  3. 在Angular中集成可视化差异展示组件

二、步骤1:PDF文本提取(含行号处理)

最成熟的工具是pdf.js(Mozilla官方维护),它能高效解析PDF并提取文本,我们可以基于它来按行拆分文本内容。

Angular中集成pdf.js

  1. 先安装依赖:
npm install pdfjs-dist @types/pdfjs-dist
  1. 创建一个PDF文本提取服务(pdf-text-extractor.service.ts):
import { Injectable } from '@angular/core';
import * as pdfjsLib from 'pdfjs-dist';
import { TextItem } from 'pdfjs-dist/types/src/display/api';

// 配置pdf.js的worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';

@Injectable({ providedIn: 'root' })
export class PdfTextExtractorService {
  async extractTextWithLines(pdfFile: File): Promise<string[]> {
    const arrayBuffer = await pdfFile.arrayBuffer();
    const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
    const allLines: string[] = [];

    for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
      const page = await pdf.getPage(pageNum);
      const textContent = await page.getTextContent();
      const pageLines: string[] = [];
      let currentLine = '';
      let lastY = -1;

      // 按Y坐标分组(PDF中文本行的Y坐标相近,以此判断换行)
      textContent.items.forEach((item: TextItem) => {
        // 当Y坐标变化超过阈值,视为新行
        if (lastY !== -1 && Math.abs(item.transform[5] - lastY) > 1) {
          pageLines.push(currentLine.trim());
          currentLine = '';
        }
        currentLine += item.str + ' ';
        lastY = item.transform[5];
      });

      // 加入当前页最后一行
      if (currentLine.trim()) pageLines.push(currentLine.trim());
      allLines.push(...pageLines);
    }

    return allLines;
  }
}

这个服务会把PDF文本按行拆分,返回字符串数组,每个元素对应一行文本,方便后续对比。

三、步骤2:文本差异计算

推荐使用diff-match-patch(Google开源的差异算法库),它能生成详细的差异数据,完美适配后续可视化需求。

安装与使用

  1. 安装依赖:
npm install diff-match-patch @types/diff-match-patch
  1. 在组件中使用它计算差异:
import { Component } from '@angular/core';
import { PdfTextExtractorService } from './pdf-text-extractor.service';
import DiffMatchPatch from 'diff-match-patch';

@Component({
  selector: 'app-pdf-compare',
  templateUrl: './pdf-compare.component.html',
  styleUrls: ['./pdf-compare.component.css']
})
export class PdfCompareComponent {
  private dmp = new DiffMatchPatch();
  leftPdfLines: string[] = [];
  rightPdfLines: string[] = [];

  constructor(private pdfExtractor: PdfTextExtractorService) {}

  async handleFileUpload(event: any, isLeft: boolean) {
    const file = event.target.files[0];
    if (!file) return;

    const lines = await this.pdfExtractor.extractTextWithLines(file);
    isLeft ? this.leftPdfLines = lines : this.rightPdfLines = lines;
  }

  calculateDiff() {
    // 只有两个文件都上传后才计算差异
    if (!this.leftPdfLines.length || !this.rightPdfLines.length) return;
    
    // 将行数组转为换行分隔的字符串,传入差异算法
    const leftText = this.leftPdfLines.join('\n');
    const rightText = this.rightPdfLines.join('\n');
    
    // 这里不需要手动处理差异结果,直接传给可视化组件即可
  }
}

四、步骤3:Angular可视化差异展示

如果不想自己写UI,推荐用ngx-text-diff这个Angular组件,它已经封装了类似Git的差异展示样式(新增行绿色高亮、删除行红色删除线),开箱即用。

集成ngx-text-diff

  1. 安装依赖:
npm install ngx-text-diff
  1. 在模块中导入:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NgxTextDiffModule } from 'ngx-text-diff';
import { PdfCompareComponent } from './pdf-compare.component';

@NgModule({
  imports: [BrowserModule, NgxTextDiffModule],
  declarations: [PdfCompareComponent],
  bootstrap: [PdfCompareComponent]
})
export class AppModule {}
  1. 在组件模板中使用:
<div class="pdf-compare-container">
  <div class="file-upload">
    <h3>原始PDF</h3>
    <input type="file" accept=".pdf" (change)="handleFileUpload($event, true)">
  </div>
  <div class="file-upload">
    <h3>对比PDF</h3>
    <input type="file" accept=".pdf" (change)="handleFileUpload($event, false)">
  </div>

  <button (click)="calculateDiff()" [disabled]="!leftPdfLines.length || !rightPdfLines.length">
    开始对比
  </button>

  <div *ngIf="leftPdfLines.length && rightPdfLines.length" class="diff-view">
    <h3>差异对比结果</h3>
    <ngx-text-diff 
      [left]="leftPdfLines.join('\n')" 
      [right]="rightPdfLines.join('\n')"
      [lineNumbers]="true">
    </ngx-text-diff>
  </div>
</div>
  1. 可选:自定义样式
    ngx-text-diff默认样式已经很实用,你可以通过CSS调整细节:
.pdf-compare-container {
  max-width: 1200px;
  margin: 20px auto;
  padding: 0 20px;
}

.file-upload {
  margin-bottom: 20px;
}

.diff-view {
  margin-top: 30px;
  border: 1px solid #eee;
  border-radius: 4px;
  padding: 10px;
}

.ngx-text-diff-deleted {
  background-color: #ffebee;
}

.ngx-text-diff-added {
  background-color: #e8f5e9;
}

五、注意事项

  • 行号准确性:PDF的文本布局可能复杂(比如多列、浮动元素),上述按Y坐标分组的方式可能不是100%精确,若需更精准的行号,可能需要结合PDF的页面布局信息做进一步处理。
  • 大文件性能:对于超大PDF,建议分页提取和对比,避免内存溢出。
  • 特殊字符:部分PDF可能包含特殊编码的文本,pdf.js基本能处理,但遇到异常情况可以尝试调整文本提取的参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:41:50