Class: Tabula::TextChunk
- Defined in:
- lib/tabula/text/text_chunk.rb
Overview
Represents a group of text elements (typically a word or phrase). Extends Rectangle to provide bounding box functionality.
Constant Summary
Constants inherited from Rectangle
Rectangle::VERTICAL_COMPARISON_THRESHOLD
Instance Attribute Summary collapse
-
#elements ⇒ Object
readonly
Returns the value of attribute elements.
Attributes inherited from Rectangle
Class Method Summary collapse
-
.all_same_char?(chunks, chars) ⇒ Boolean
Check if all chunks contain the same repeated character.
-
.group_by_lines(chunks) ⇒ Array<Line>
Group text chunks into lines.
Instance Method Summary collapse
-
#add(element) ⇒ Object
Add a text element to this chunk.
-
#add_all(elements) ⇒ Object
Add multiple elements.
- #empty? ⇒ Boolean
-
#font_name ⇒ Object
Get font name.
-
#font_size ⇒ Object
Get font size.
-
#initialize(element_or_rect = nil) ⇒ TextChunk
constructor
A new instance of TextChunk.
- #inspect ⇒ Object
-
#ltr_dominant? ⇒ Boolean
Check if LTR text is dominant in this chunk.
-
#merge_chunk(other) ⇒ TextChunk
Merge with another chunk.
-
#rtl_dominant? ⇒ Boolean
Check if this chunk is RTL dominant.
-
#same_char?(chars) ⇒ Boolean
Check if this chunk contains only a single repeated character.
- #size ⇒ Object
-
#split_at(index) ⇒ Array<TextChunk>
Split this chunk at an index.
-
#squeeze(char, min_run: 3) ⇒ TextChunk
Remove runs of identical characters.
-
#text(normalize: true) ⇒ String
Get the combined text content.
- #to_s ⇒ Object
-
#width_of_space ⇒ Object
Get width of space character for this chunk.
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(element_or_rect = nil) ⇒ TextChunk
Returns a new instance of TextChunk.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/tabula/text/text_chunk.rb', line 10 def initialize(element_or_rect = nil) if element_or_rect.is_a?(TextElement) super(element_or_rect.top, element_or_rect.left, element_or_rect.width, element_or_rect.height) @elements = [element_or_rect] elsif element_or_rect.is_a?(Rectangle) super(element_or_rect.top, element_or_rect.left, element_or_rect.width, element_or_rect.height) @elements = [] elsif element_or_rect.nil? super(0, 0, 0, 0) @elements = [] else raise ArgumentError, 'Expected TextElement, Rectangle, or nil' end end |
Instance Attribute Details
#elements ⇒ Object (readonly)
Returns the value of attribute elements.
7 8 9 |
# File 'lib/tabula/text/text_chunk.rb', line 7 def elements @elements end |
Class Method Details
.all_same_char?(chunks, chars) ⇒ Boolean
Check if all chunks contain the same repeated character
158 159 160 |
# File 'lib/tabula/text/text_chunk.rb', line 158 def all_same_char?(chunks, chars) chunks.all? { |c| c.same_char?(chars) } end |
.group_by_lines(chunks) ⇒ Array<Line>
Group text chunks into lines
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/tabula/text/text_chunk.rb', line 165 def group_by_lines(chunks) return [] if chunks.empty? sorted = chunks.sort_by { |c| [c.top, c.left] } lines = [] current_line = Line.new sorted.each do |chunk| unless current_line.empty? || current_line.vertically_overlaps?(chunk) lines << current_line current_line = Line.new end current_line.add_chunk(chunk) end lines << current_line unless current_line.empty? lines end |
Instance Method Details
#add(element) ⇒ Object
Add a text element to this chunk
27 28 29 30 31 |
# File 'lib/tabula/text/text_chunk.rb', line 27 def add(element) @elements << element merge!(element) self end |
#add_all(elements) ⇒ Object
Add multiple elements
35 36 37 38 |
# File 'lib/tabula/text/text_chunk.rb', line 35 def add_all(elements) elements.each { |e| add(e) } self end |
#empty? ⇒ Boolean
145 146 147 |
# File 'lib/tabula/text/text_chunk.rb', line 145 def empty? @elements.empty? end |
#font_name ⇒ Object
Get font name
65 66 67 |
# File 'lib/tabula/text/text_chunk.rb', line 65 def font_name @elements.first&.font_name end |
#font_size ⇒ Object
Get font size
70 71 72 |
# File 'lib/tabula/text/text_chunk.rb', line 70 def font_size @elements.first&.font_size end |
#inspect ⇒ Object
141 142 143 |
# File 'lib/tabula/text/text_chunk.rb', line 141 def inspect to_s end |
#ltr_dominant? ⇒ Boolean
Check if LTR text is dominant in this chunk
107 108 109 110 111 |
# File 'lib/tabula/text/text_chunk.rb', line 107 def ltr_dominant? ltr_count = @elements.count(&:ltr?) rtl_count = @elements.count(&:rtl?) ltr_count >= rtl_count end |
#merge_chunk(other) ⇒ TextChunk
Merge with another chunk
132 133 134 135 |
# File 'lib/tabula/text/text_chunk.rb', line 132 def merge_chunk(other) other.elements.each { |e| add(e) } self end |
#rtl_dominant? ⇒ Boolean
Check if this chunk is RTL dominant
55 56 57 |
# File 'lib/tabula/text/text_chunk.rb', line 55 def rtl_dominant? !ltr_dominant? end |
#same_char?(chars) ⇒ Boolean
Check if this chunk contains only a single repeated character
77 78 79 80 81 |
# File 'lib/tabula/text/text_chunk.rb', line 77 def same_char?(chars) return false if @elements.empty? @elements.all? { |e| chars.include?(e.text) } end |
#size ⇒ Object
149 150 151 |
# File 'lib/tabula/text/text_chunk.rb', line 149 def size @elements.size end |
#split_at(index) ⇒ Array<TextChunk>
Split this chunk at an index
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/tabula/text/text_chunk.rb', line 116 def split_at(index) return [dup, TextChunk.new] if index >= @elements.size return [TextChunk.new, dup] if index <= 0 left_chunk = TextChunk.new right_chunk = TextChunk.new @elements[0...index].each { |e| left_chunk.add(e) } @elements[index..].each { |e| right_chunk.add(e) } [left_chunk, right_chunk] end |
#squeeze(char, min_run: 3) ⇒ TextChunk
Remove runs of identical characters
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/tabula/text/text_chunk.rb', line 87 def squeeze(char, min_run: 3) return self if @elements.size < min_run new_chunk = TextChunk.new(Rectangle.new(top, left, width, height)) run_count = 0 @elements.each do |element| if element.text == char run_count += 1 new_chunk.add(element) if run_count <= 1 else run_count = 0 new_chunk.add(element) end end new_chunk end |
#text(normalize: true) ⇒ String
Get the combined text content
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/tabula/text/text_chunk.rb', line 43 def text(normalize: true) # Sort elements based on text direction sorted = if ltr_dominant? @elements.sort_by(&:left) else @elements.sort_by(&:left).reverse end raw = sorted.map(&:text).join normalize ? raw.gsub(/\s+/, ' ').strip : raw end |
#to_s ⇒ Object
137 138 139 |
# File 'lib/tabula/text/text_chunk.rb', line 137 def to_s "TextChunk[#{text.inspect}](#{left}, #{top}, #{width}, #{height})" end |
#width_of_space ⇒ Object
Get width of space character for this chunk
60 61 62 |
# File 'lib/tabula/text/text_chunk.rb', line 60 def width_of_space @elements.map(&:width_of_space).compact.first end |