Skip to content

feat: 修正 PdfParser 文本坐标映射#1

Merged
wszxdhr merged 2 commits intomainfrom
feat/pdf-text-position-fix
Dec 20, 2025
Merged

feat: 修正 PdfParser 文本坐标映射#1
wszxdhr merged 2 commits intomainfrom
feat/pdf-text-position-fix

Conversation

@wszxdhr
Copy link
Copy Markdown
Contributor

@wszxdhr wszxdhr commented Dec 20, 2025

Summary by CodeRabbit

  • Tests

    • Added a unit test validating text-content-to-intermediate mapping.
  • Refactor

    • Improved text layout and viewport-aware coordinate handling for more accurate text positioning.
    • Reworked outline destination resolution to better support URL- and page-based destinations and more reliable outline rendering.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Dec 20, 2025

Walkthrough

Adds a unit test verifying PdfParser.mapTextContentToIntermediate coordinate transforms, and refactors src/index.ts to introduce viewport-aware text layout, a metrics-based text pipeline, modular outline destination resolution, and several private helper methods.

Changes

Cohort / File(s) Summary
New test suite
src/__tests__/mapTextContentToIntermediate.test.ts
Adds a unit test that mocks pdfjs-dist and asserts that mapTextContentToIntermediate combines text and viewport transforms to produce correct IntermediateText coordinates (top-left origin).
Parser implementation & helpers
src/index.ts
Substantial refactor: text processing now uses a viewport-aware transformToViewport, asTextItem guard, and a collectMetrics pipeline to populate IntermediateText fields (fontSize, family, dimensions, ascent/descent, vertical, dir). Outline handling rewritten to use buildUrlDest, resolveDestArray, buildPageDest, appendOutlineChildren, and mapChildOutlineDest for URL/page dest resolution and child attachment. Added imports (Util, PageViewport, TextStyle) and moved legacy dest logic into modular private helpers; public API signatures unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review src/index.ts for correctness of transform math, metric collection, and direction/vertical text handling.
  • Verify outline destination resolution logic (URL vs page vs array) and error fallbacks.
  • Confirm new private helpers are covered by existing tests or add new tests where needed.
  • Validate the new test's mocking of pdfjs-dist matches real runtime behavior.

Poem

I nibbled bytes and chased a trace,
Matrices twined in a tiny space,
Viewports flipped and outlines grew,
A rabbit's hop — the parser knew. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: 修正 PdfParser 文本坐标映射' (Fix PdfParser text coordinate mapping) directly aligns with the main changes: viewport-aware text layout, coordinate transformation via transformToViewport, and coordinate derivation combining viewport and text transforms.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/pdf-text-position-fix

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dde32e5 and 8f0d22d.

📒 Files selected for processing (1)
  • src/index.ts (5 hunks)
🔇 Additional comments (12)
src/index.ts (12)

16-26: LGTM! Imports support viewport-aware text coordinate mapping.

The new imports (Util, PageViewport, TextContent, TextItem, TextStyle) enable the viewport transformation and metrics-based text processing that addresses the coordinate mapping issue.


114-115: LGTM! Viewport parameter enables correct coordinate transformation.

Passing the viewport to mapTextContentToIntermediate allows the text mapping logic to apply the necessary coordinate system transformation from PDF's bottom-left origin to top-left origin.


199-211: LGTM! Outline mapping is now more modular and maintainable.

The refactored flow clearly delegates to specialized helpers (buildUrlDest, resolveDestArray, buildPageDest) with proper fallbacks and consistent child outline attachment.


232-242: LGTM! URL destination builder is clear and type-safe.

The helper properly extracts URL-related fields from the outline node with appropriate type coercions.


244-257: LGTM! Destination array resolution handles both string and array formats.

The helper correctly resolves string-based destination names via pdf.getDestination and passes through array-based destinations, with safe error handling.


283-292: LGTM! Generic helper properly attaches child outlines.

The helper safely processes child outlines and attaches them only when present, maintaining type safety through the generic parameter.


294-336: LGTM! Text mapping now uses viewport-aware coordinate transformation.

The refactored method correctly applies viewport transformation to compute coordinates and uses helper methods to safely extract text metrics, addressing the PR objective.


338-344: LGTM! Type guard safely filters text items.

The helper properly validates that an item is a text item by checking for the str property, filtering out marked content or other non-text items.


346-350: LGTM! Direction mapping handles all PDF text directions.

The helper correctly maps PDF.js text directions (ltr, rtl, ttb) to the TextDir enum with a safe default.


352-365: LGTM! Viewport transformation correctly maps PDF coordinates to top-left origin.

The helper applies the viewport transformation matrix to the text transformation matrix using Util.transform, converting from PDF's bottom-left coordinate system to the expected top-left system. The identity matrix fallback and finite number checks ensure robustness.


367-399: LGTM! Metrics collection safely extracts font dimensions with fallbacks.

The helper properly computes text metrics from PDF.js text items and styles, with appropriate fallback values and logic for fontSize and lineHeight calculations.


259-281: No changes needed. The implementation correctly handles PDF page destinations using the standard PDF.js API. The @ts-expect-error is appropriately justified by the any type returned from pdf.getDestination, which propagates to the ref parameter. The method properly validates the reference object, retrieves the page index, converts to 1-based page numbering, and attaches child outline items.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/index.ts (1)

370-402: Metric collection logic is solid.

The collectMetrics helper handles various fallback scenarios for fontSize and lineHeight calculation. The logic is reasonable for dealing with potentially missing or zero values from PDF text items.

Consider adding unit tests for edge cases in collectMetrics, such as:

  • Missing height and ascent/descent
  • Zero or negative values
  • Missing style properties

This would help ensure robustness of the fallback logic.

src/__tests__/mapTextContentToIntermediate.test.ts (1)

41-83: Test effectively validates coordinate transformation.

The test correctly verifies that the viewport transform is applied to text coordinates, confirming the Y-axis flip from bottom-left to top-left origin. The assertions are clear and appropriate.

Consider adding additional test cases to improve coverage:

  • Text items with identity transforms
  • Edge cases with zero or extreme coordinate values
  • Multiple text items with different transforms
  • Text items with missing or invalid transform arrays

These would help ensure robustness across various PDF content scenarios.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbd1524 and dde32e5.

📒 Files selected for processing (2)
  • src/__tests__/mapTextContentToIntermediate.test.ts (1 hunks)
  • src/index.ts (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/__tests__/mapTextContentToIntermediate.test.ts (1)
src/index.ts (1)
  • mapTextContentToIntermediate (297-339)
🔇 Additional comments (7)
src/index.ts (5)

19-29: LGTM! Imports support new coordinate transformation logic.

The additional imports (Util, PageViewport, TextContent, TextItem, TextStyle) are all utilized by the new coordinate transformation and text processing helpers.


32-32: LGTM! Good practice to make constants readonly.

Making ext readonly with explicit initialization prevents accidental modification and clearly signals its constant nature.


235-295: LGTM! Outline handling is well-refactored.

The extraction of helper methods (buildUrlDest, resolveDestArray, buildPageDest, appendOutlineChildren) improves code organization and readability. Error handling and type safety are properly maintained.


341-353: LGTM! Helper methods are clean and correct.

Both asTextItem and mapTextDir provide simple, focused functionality with appropriate type safety.


355-368: Coordinate transformation logic is correct.

The transformToViewport method properly combines viewport and text transforms using the transformation matrix that converts the coordinate system from PDF's bottom-left origin to canvas's top-left origin. The x and y coordinates are correctly extracted from transform[4] and transform[5]. The defensive programming with Number.isFinite checks prevents NaN/Infinity issues.

src/__tests__/mapTextContentToIntermediate.test.ts (2)

8-27: Mock implementation appears correct.

The mock Util.transform implements standard 2D affine transformation matrix multiplication, which is mathematically correct. The mock structure is appropriate for isolating the coordinate transformation logic.


29-39: Test setup is functional.

Accessing the private method via type assertion and binding is a standard pattern for unit testing. While somewhat brittle to refactoring, it's acceptable for targeted unit tests.

@wszxdhr wszxdhr merged commit 39e525c into main Dec 20, 2025
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant