Class: Tabula::Page

Inherits:
Rectangle show all
Defined in:
lib/tabula/pdf/page.rb

Overview

Represents a PDF page with extracted text elements and rulings. Provides methods for accessing page content and creating sub-areas.

Defined Under Namespace

Classes: Builder

Constant Summary

Constants inherited from Rectangle

Rectangle::VERTICAL_COMPARISON_THRESHOLD

Instance Attribute Summary collapse

Attributes inherited from Rectangle

#height, #left, #top, #width

Instance Method Summary collapse

Methods inherited from Rectangle

#<=>, #==, #area, #bottom, #bottom=, bounding_box_of, #bounds, #center, #contains?, #contains_point?, #dup, from_bounds, from_points, #hash, #horizontal_overlap, #horizontally_overlaps?, #intersection, #intersects?, #merge, #merge!, #overlap_ratio, #points, #right, #right=, #vertical_overlap, #vertically_overlaps?, #x, #x=, #y, #y=

Constructor Details

#initialize(top:, left:, width:, height:, page_number:, rotation: 0, text_elements: [], rulings: [], min_char_width: nil, min_char_height: nil) ⇒ Page

Returns a new instance of Page.

Parameters:

  • top (Float) —

    top coordinate

  • left (Float) —

    left coordinate

  • width (Float) —

    page width

  • height (Float) —

    page height

  • page_number (Integer) —

    page number (1-indexed)

  • rotation (Integer) (defaults to: 0) —

    page rotation in degrees

  • text_elements (Array<TextElement>) (defaults to: []) —

    extracted text elements

  • rulings (Array<Ruling>) (defaults to: []) —

    extracted ruling lines

  • min_char_width (Float) (defaults to: nil) —

    minimum character width

  • min_char_height (Float) (defaults to: nil) —

    minimum character height



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/tabula/pdf/page.rb', line 20

def initialize(top:, left:, width:, height:, page_number:, rotation: 0,
               text_elements: [], rulings: [], min_char_width: nil, min_char_height: nil)
  super(top, left, width, height)
  @page_number = page_number
  @rotation = rotation
  @text_elements = text_elements
  @rulings = rulings
  @min_char_width = min_char_width
  @min_char_height = min_char_height
  @spatial_index = build_spatial_index
  @processed_rulings = nil
end

Instance Attribute Details

#min_char_height ⇒ Object (readonly)

Returns the value of attribute min_char_height.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def min_char_height
  @min_char_height
end

#min_char_width ⇒ Object (readonly)

Returns the value of attribute min_char_width.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def min_char_width
  @min_char_width
end

#page_number ⇒ Object (readonly)

Returns the value of attribute page_number.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def page_number
  @page_number
end

#rotation ⇒ Object (readonly)

Returns the value of attribute rotation.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def rotation
  @rotation
end

#rulings ⇒ Object (readonly)

Returns the value of attribute rulings.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def rulings
  @rulings
end

#spatial_index ⇒ Object (readonly)

Returns the value of attribute spatial_index.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def spatial_index
  @spatial_index
end

#text_elements ⇒ Object (readonly)

Returns the value of attribute text_elements.



7
8
9
# File 'lib/tabula/pdf/page.rb', line 7

def text_elements
  @text_elements
end

Instance Method Details

#add_ruling(ruling) ⇒ Object

Add a ruling to the page

Parameters:

  • ruling (Ruling) —

    ruling to add



109
110
111
112
113
114
# File 'lib/tabula/pdf/page.rb', line 109

def add_ruling(ruling)
  return if ruling.oblique?

  @rulings << ruling
  @processed_rulings = nil # Invalidate cache
end

#get_area(top, left, bottom, right) ⇒ Page

Create a sub-page for a specific area

Parameters:

  • top (Float) —

    area top

  • left (Float) —

    area left

  • bottom (Float) —

    area bottom

  • right (Float) —

    area right

Returns:

  • (Page) —

    sub-page containing only elements in the area



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/tabula/pdf/page.rb', line 60

def get_area(top, left, bottom, right)
  area = Rectangle.from_bounds(top, left, bottom, right)

  # Filter text elements
  area_elements = get_text(area)

  # Filter and clip rulings
  area_rulings = Ruling.crop_to_area(rulings, area)

  Page.new(
    top: top,
    left: left,
    width: right - left,
    height: bottom - top,
    page_number: page_number,
    rotation: rotation,
    text_elements: area_elements,
    rulings: area_rulings,
    min_char_width: min_char_width,
    min_char_height: min_char_height
  )
end

#get_rulings ⇒ Array<Ruling>

Get processed ruling lines (collapsed and cleaned)

Returns:



85
86
87
# File 'lib/tabula/pdf/page.rb', line 85

def get_rulings
  @get_rulings ||= process_rulings
end

#get_text(area = nil) ⇒ Array<TextElement>

Get text elements within a rectangular area

Parameters:

  • area (Rectangle) (defaults to: nil) —

    area to query

Returns:



36
37
38
39
40
41
42
43
44
45
46
# File 'lib/tabula/pdf/page.rb', line 36

def get_text(area = nil)
  return @text_elements if area.nil?

  # Use intersects because text elements may extend beyond cell boundaries
  # (e.g., text with descenders or tall characters)
  # Filter to elements whose origin (top-left) is within the area
  @spatial_index.intersects(area).select do |te|
    te.top >= area.top && te.top < area.bottom &&
      te.left >= area.left && te.left < area.right
  end
end

#has_rulings? ⇒ Boolean

Check if page has ruling lines

Returns:

  • (Boolean)


118
119
120
# File 'lib/tabula/pdf/page.rb', line 118

def has_rulings?
  !@rulings.empty?
end

#horizontal_rulings ⇒ Array<Ruling>

Get horizontal ruling lines

Returns:



91
92
93
# File 'lib/tabula/pdf/page.rb', line 91

def horizontal_rulings
  get_rulings.select(&:horizontal?)
end

#inspect ⇒ Object



138
139
140
# File 'lib/tabula/pdf/page.rb', line 138

def inspect
  to_s
end

#text_bounds ⇒ Rectangle?

Get the bounding box of all text on the page

Returns:



50
51
52
# File 'lib/tabula/pdf/page.rb', line 50

def text_bounds
  Rectangle.bounding_box_of(@text_elements)
end

#text_chunks ⇒ Array<TextChunk>

Get text chunks (words) from the page

Returns:



124
125
126
# File 'lib/tabula/pdf/page.rb', line 124

def text_chunks
  TextElement.merge_words(@text_elements, vertical_rulings: vertical_rulings)
end

#text_lines ⇒ Array<Line>

Get lines of text

Returns:



130
131
132
# File 'lib/tabula/pdf/page.rb', line 130

def text_lines
  TextChunk.(text_chunks)
end

#to_s ⇒ Object



134
135
136
# File 'lib/tabula/pdf/page.rb', line 134

def to_s
  "Page[#{page_number}](#{left}, #{top}, #{width}, #{height})"
end

#unprocessed_rulings ⇒ Array<Ruling>

Get raw (unprocessed) rulings

Returns:



103
104
105
# File 'lib/tabula/pdf/page.rb', line 103

def unprocessed_rulings
  @rulings
end

#vertical_rulings ⇒ Array<Ruling>

Get vertical ruling lines

Returns:



97
98
99
# File 'lib/tabula/pdf/page.rb', line 97

def vertical_rulings
  get_rulings.select(&:vertical?)
end