§
    �’jo\  ã                   ó  — d Z ddlZddlmZmZ  G d„ d¦  «        Zddœd„Zd	dœd
„Zd	dœd„Zd„ Z	d„ Z
d„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd „ Zd!„ Zd"„ Zd#„ Z d$„ Z!dd%d&œd'„Z"dS )(aF  
Copyright (C) 2023 Artifex Software, Inc.

This file is part of PyMuPDF.

PyMuPDF is free software: you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

PyMuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.

You should have received a copy of the GNU Affero General Public License
along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>

Alternative licensing terms are available from the licensor.
For commercial licensing, see <https://www.artifex.com/> or contact
Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
CA 94129, USA, for further information.

---------------------------------------------------------------------

PyMuPDF table cell-span resolution (opt-in extension).

Provides SpanCell and resolve_spans (plus the _span_* helpers), which
reconstruct a detected table's merged-cell (colspan / rowspan) structure.
Re-exported by pymupdf.table; never runs on the default find_tables() path.
Reuses the word-selection helpers of pymupdf._table_refine.
é    N)Ú_refine_is_vertical_or_rotatedÚ_refine_page_wordsc                   ó   — e Zd ZdZdd„ZdS )ÚSpanCella¶  One reconstructed table cell after span resolution (PyMuPDF extension).

    ``bbox`` is the placement's ``(x0, y0, x1, y1)`` union rect, ``text`` the
    page text it claims (lines joined by ``\n``), and ``colspan``/``rowspan``
    how many grid columns/rows it covers. resolve_spans always sets a real bbox;
    a caller padding its own grid may construct SpanCells with ``bbox=None``.

    ``tag`` is the cell's HTML tag (``"td"``/``"th"``), defaulting to ``"td"``.
    resolve_spans leaves it at the default; find_tables(refine=True) overwrites
    it from the resolved header region so Table.to_html() can serialize the grid
    directly, and a caller building its own grid may set it too.Útdc                 óL   — || _         || _        || _        || _        || _        d S ©N)ÚbboxÚtextÚcolspanÚrowspanÚtag)Úselfr
   r   r   r   r   s         úBC:\Projects\DSCons\.venv\Lib\site-packages\pymupdf\_table_spans.pyÚ__init__zSpanCell.__init__7   s)   € ØˆŒ	ØˆŒ	ØˆŒØˆŒØˆŒˆˆó    N)r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   © r   r   r   r   *   s4   € € € € € ð
Dð 
Dðð ð ð ð ð r   r   g      @)Ú	tolerancec                ó–   — g }t          | ¦  «        D ]6}|r||d         z
  |k    rŒ|                     t          |¦  «        ¦  «         Œ7|S )zÛGreedy 1-D clustering of edge coordinates into slot boundaries.

    Keeps a sorted value only when it is more than ``tolerance`` from the last
    kept boundary, so the first value of each run is the retained boundary.éÿÿÿÿ)ÚsortedÚappendÚfloat)Úvaluesr   Ú
boundariesÚvalues       r   Ú_span_clustered_boundariesr!   @   s_   € ð
 €JÝ˜‘”ð (ð (ˆØð 	˜% *¨R¤.Ñ0°IÒ=Ð=ØØ×Ò�% ™,œ,Ñ'Ô'Ð'Ð'ØÐr   ç      ð?c                óÎ   — d}t          t          |¦  «        dz
  ¦  «        D ]4}||         ||dz            z   dz  }| |z
  |cxk    r	||z   k    rn Œ/|dz  }Œ5t          d|¦  «        S )zKHow many [boundaries[i], boundaries[i+1]] slots the span start..end covers.r   é   ç       @)ÚrangeÚlenÚmax)ÚstartÚendr   r   ÚcountÚindexÚmidpoints          r   Ú_span_covered_slot_countr.   M   s‰   € à€EÝ•s˜:‘”¨Ñ*Ñ+Ô+ð ð ˆØ˜uÔ%¨
°5¸1±9Ô(=Ñ=ÀÑDˆØ�9Ñ Ð;Ð;Ò;Ð;¨C°)©OÒ;Ð;Ð;Ð;Ð;Ø�Q‰JˆEøÝˆq�%‰=Œ=Ðr   c                ó,  — g }t          t          |¦  «        dz
  ¦  «        D ]N}||         ||dz            z   dz  }| j        |z
  |cxk    r| j        |z   k    rn Œ9|                     |¦  «         ŒO|sdS t          |¦  «        t          |¦  «        dz   fS )zIThe half-open column-slot range (first, last+1) a rect's x-extent covers.r$   r%   )r   r$   )r&   r'   Úx0Úx1r   Úminr(   )ÚrectÚx_boundariesr   Úhitsr,   r-   s         r   Ú_span_slot_ranger6   W   s³   € à€DÝ•s˜<Ñ(Ô(¨1Ñ,Ñ-Ô-ð ð ˆØ  Ô'¨,°u¸q±yÔ*AÑAÀSÑHˆØŒ7�YÑ (ÐAÐAÒAÐA¨d¬g¸	Ñ.AÒAÐAÐAÐAÐAØ�KŠK˜ÑÔÐøØð ØˆvÝ�‰IŒI•s˜4‘y”y 1‘}Ð%Ð%r   c                 óJ   — | d         |d         k     o|d         | d         k     S ©Nr   r$   r   ©ÚaÚbs     r   Ú_span_ranges_intersectr<   c   s%   € ØˆQŒ4�!�A”$Š;Ð&˜1˜Qœ4 ! A¤$š;Ð&r   c                 óÒ   — t          |j        ¦  «        | cxk    ot          |j        ¦  «        k    nc o3t          |j        ¦  «        |cxk    ot          |j        ¦  «        k    nc S r	   )r   r0   r1   Úy0Úy1)ÚxÚyr3   s      r   Ú_span_point_in_rectrB   g   sg   € Ý�”‰>Œ>˜QÐ0Ð0Ò0Ð0¥%¨¬¡.¤.Ò0Ð0Ð0Ð0ÐZµU¸4¼7±^´^ÀqÐ5ZÐ5ZÒ5ZÐ5ZÍEÐRVÔRYÉNÌNÒ5ZÐ5ZÐ5ZÐ5ZÐZr   c           	      óè   — t          j        t          d„ | D ¦   «         ¦  «        t          d„ | D ¦   «         ¦  «        t          d„ | D ¦   «         ¦  «        t          d„ | D ¦   «         ¦  «        ¦  «        S )Nc              3   ó$   K  — | ]}|j         V — Œd S r	   )r0   ©Ú.0r3   s     r   ú	<genexpr>z#_span_rect_union.<locals>.<genexpr>m   ó$   è è € Ð&Ð&˜ˆDŒGÐ&Ð&Ð&Ð&Ð&Ð&r   c              3   ó$   K  — | ]}|j         V — Œd S r	   ©r>   rE   s     r   rG   z#_span_rect_union.<locals>.<genexpr>n   rH   r   c              3   ó$   K  — | ]}|j         V — Œd S r	   )r1   rE   s     r   rG   z#_span_rect_union.<locals>.<genexpr>o   rH   r   c              3   ó$   K  — | ]}|j         V — Œd S r	   ©r?   rE   s     r   rG   z#_span_rect_union.<locals>.<genexpr>p   rH   r   )ÚpymupdfÚRectr2   r(   )Úrectss    r   Ú_span_rect_unionrQ   k   s~   € ÝŒ<ÝÐ&Ð& Ð&Ñ&Ô&Ñ&Ô&ÝÐ&Ð& Ð&Ñ&Ô&Ñ&Ô&ÝÐ&Ð& Ð&Ñ&Ô&Ñ&Ô&ÝÐ&Ð& Ð&Ñ&Ô&Ñ&Ô&ñ	ô ð r   c                 ól   — t          | j        |j        ¦  «        t          | j        |j        ¦  «        z
  S r	   )r2   r1   r(   r0   r9   s     r   Ú_span_x_overlaprS   t   s%   € ÝˆqŒt�Q”T‰?Œ?�S ¤ q¤t™_œ_Ñ,Ð,r   c                 ón   — t          | |¦  «        }|dk    rdS t          d|j        ¦  «        }||z  dk    S )a  True if a text span overlaps a cell by enough x to signal a merge.

    A few points of overlap is noise (a span drifting across a column line with
    trailing whitespace or a currency glyph); require >2pt and >=15% of the cell
    width before treating it as a merged-cell signal.r%   Fr"   g333333Ã?)rS   r(   Úwidth)Ú	span_rectÚ	cell_rectÚoverlapÚ
cell_widths       r   Ú_span_substantial_x_overlaprZ   x   sB   € õ ˜i¨Ñ3Ô3€GØ�#‚~€~ØˆuÝ�S˜)œ/Ñ*Ô*€JØ�ZÑ 4Ò'Ð'r   c                 ó¼   — | sg S g }| d         x}}| dd…         D ])}||dz   k    r|}Œ|                      ||f¦  «         |x}}Œ*|                      ||f¦  «         |S )z>Collapse a sorted index list into (start, end) inclusive runs.r   r$   N)r   )ÚindicesÚrangesr)   r*   r,   s        r   Ú_span_contiguous_rangesr^   …   s�   € àð Øˆ	Ø€FØ˜!”*Ð€EˆCØ˜˜˜”ð ð ˆØ�C˜!‘GÒÐØˆCØØ�Š�u˜c�lÑ#Ô#Ð#ØÐˆ��Ø
‡M‚M�5˜#�,ÑÔÐØ€Mr   c                 óò   — g }t          | d„ ¬¦  «        D ]a\  }}}||k    rŒ|r||d         d         k    r|                     |||gf¦  «         Œ;|d         \  }}}|t          ||¦  «        ||gz   f|d<   Œb|S )zIMerge overlapping (start, end, text) intervals, accumulating their texts.c                 ó"   — | d         | d         fS r8   r   ©Úitems    r   ú<lambda>z'_span_merge_intervals.<locals>.<lambda>˜   s   € ÀÀQÄÈÈaÌÐ?Q€ r   ©Úkeyr   r$   )r   r   r(   )Ú	intervalsÚmergedr)   r*   r   Ú
prev_startÚprev_endÚtextss           r   Ú_span_merge_intervalsrk   •   s«   € à€FÝ" 9Ð2QÐ2QÐRÑRÔRð Fð FÑˆˆs�DØ�CŠ<ˆ<ØØð 	˜ ¨¤¨A¤Ò.Ð.Ø�MŠM˜5 #¨ vÐ.Ñ/Ô/Ð/ØØ&,¨R¤jÑ#ˆ
�H˜eØ ¥# h°Ñ"4Ô"4°e¸t¸f±nÐEˆˆr‰
ˆ
Ø€Mr   c                 ól   — d„ |                       dg ¦  «        D ¦   «         }d                     |¦  «        S )z=Space-joined non-empty span texts of a get_text('dict') line.c                 óæ   — g | ]n}t          |                     d ¦  «        pd¦  «                             ¦   «         ¯8t          |                     d ¦  «        pd¦  «                             ¦   «         ‘ŒoS )r   Ú )ÚstrÚgetÚstrip©rF   Úspans     r   ú
<listcomp>z#_span_line_text.<locals>.<listcomp>¦   sx   € ð ð ð àÝˆt�xŠx˜ÑÔÐ% 2Ñ&Ô&×,Ò,Ñ.Ô.ðÝˆD�HŠH�VÑÔÐ" Ñ#Ô#×)Ò)Ñ+Ô+ðð ð r   Úspansú )rp   Újoin)ÚlineÚpartss     r   Ú_span_line_textrz   ¤   s@   € ðð à—H’H˜W bÑ)Ô)ðñ ô €Eð
 �8Š8�E‰?Œ?Ðr   c                 óè   — |                       d¦  «        }|rt          j        |¦  «        }|j        s|S d„ |                       dg ¦  «        D ¦   «         }d„ |D ¦   «         }|sdS t	          |¦  «        S )zKBounding rect of a dict line (its bbox, else the union of its span bboxes).r
   c                 óŠ   — g | ]@}|                      d ¦  «        ¯t          j        |                      d ¦  «        pg ¦  «        ‘ŒAS )r
   )rp   rN   rO   rr   s     r   rt   z#_span_line_rect.<locals>.<listcomp>µ   sU   € ð ð ð àØ�8Š8�FÑÔðÝŒ�T—X’X˜fÑ%Ô%Ð+¨Ñ,Ô,ðð ð r   ru   c                 ó    — g | ]}|j         °	|‘ŒS r   )Úis_emptyrE   s     r   rt   z#_span_line_rect.<locals>.<listcomp>º   s   € Ð9Ð9Ð9�d¨4¬=Ð9ˆTÐ9Ð9Ð9r   N)rp   rN   rO   r~   rQ   )rx   r
   r3   rP   s       r   Ú_span_line_rectr   ®   s•   € à�8Š8�FÑÔ€DØð ÝŒ|˜DÑ!Ô!ˆØŒ}ð 	ØˆKðð à—H’H˜W bÑ)Ô)ðñ ô €Eð
 :Ð9˜eÐ9Ñ9Ô9€EØð ØˆtÝ˜EÑ"Ô"Ð"r   c                 óÊ  — t          | dd¦  «        }|�|S g }|                      d¦  «                             dg ¦  «        D ]~}|                     d¦  «        dvrŒ|                     dg ¦  «        D ]M}t          |¦  «        sŒt	          |¦  «        }|sŒ$t          |¦  «        }|€Œ6|                     ||f¦  «         ŒNŒ	 t          | d|¦  «         n# t          $ r Y nw xY w|S )zžVertical/rotated text lines as (rect, text), cached on the page.

    Selects non-horizontal lines whose reading order get_text('dict') already
    preserves.Ú_span_vertical_lines_cacheNÚdictÚblocksÚtype©Nr   Úlines)	ÚgetattrÚget_textrp   r   rz   r   r   ÚsetattrÚ	Exception)ÚpageÚcachedr†   Úblockrx   r   r3   s          r   Ú_span_vertical_text_linesrŽ   À   s&  € õ
 �TÐ7¸Ñ>Ô>€FØÐØˆØ€EØ—’˜vÑ&Ô&×*Ò*¨8°RÑ8Ô8ð 'ð 'ˆØ�9Š9�VÑÔ IÐ-Ð-ØØ—I’I˜g rÑ*Ô*ð 		'ð 		'ˆDÝ1°$Ñ7Ô7ð ØÝ" 4Ñ(Ô(ˆDØð ØÝ" 4Ñ(Ô(ˆDØˆ|ØØ�LŠL˜$ ˜Ñ&Ô&Ð&Ð&ð		'ðÝ�Ð2°EÑ:Ô:Ð:Ð:øÝð ð ð Øˆðøøøà€Ls   ÃC Ã
C ÃC c                 ó®  ‡‡— |sdS g }t          | ¦  «        D ]…\  }}t          |j        ¦  «        t          |j        ¦  «        z   dz  Št          |j        ¦  «        t          |j        ¦  «        z   dz  Št          ‰‰|¦  «        r|                     ||f¦  «         Œ†|sdS d}|D ]<\  }\  }}	}
}}||
z   dz  Š|	|z   dz  Št          ˆˆfd„|D ¦   «         ¦  «        r|dz  }Œ=|t          dt          |¦  «        ¦  «        z  dk     rdS t          d„ |D ¦   «         ¦  «        dk     rdS d	                     d
„ t          |d„ ¬¦  «        D ¦   «         ¦  «        S )a"  Text of vertical lines centered in rect, when they dominate the rect.

    Returns the stacked line text only if vertical lines are centered in the rect,
    cover >=60% of the rect's selected words, and carry >=2 tokens; else None so
    the caller falls back to horizontal line synthesis.Nç      à?r   c              3   ó@   •K  — | ]\  }}t          ‰‰|¦  «        V — Œd S r	   )rB   )rF   Ú	line_rectÚ_ÚcxÚcys      €€r   rG   z/_span_vertical_text_for_rect.<locals>.<genexpr>ñ   s4   øè è € ÐUÐU¹,¸)ÀQÕ" 2 r¨9Ñ5Ô5ÐUÐUÐUÐUÐUÐUr   r$   g333333ã?c              3   ó^   K  — | ](\  }}t          |                     ¦   «         ¦  «        V — Œ)d S r	   )r'   Úsplit©rF   r“   r   s      r   rG   z/_span_vertical_text_for_rect.<locals>.<genexpr>õ   s6   è è € Ð
7Ð
7¡  D�3ˆt�zŠz‰|Œ|ÑÔÐ
7Ð
7Ð
7Ð
7Ð
7Ð
7r   é   ú
c              3   ó    K  — | ]	\  }}|V — Œ
d S r	   r   r˜   s      r   rG   z/_span_vertical_text_for_rect.<locals>.<genexpr>÷   s:   è è € ð ð áˆAˆtð 	ðð ð ð ð ð r   c                 óŽ   — t          | d         j        ¦  «        t          | d         j        | d         j        z   dz  ¦  «         fS )Nr   r�   )r   r0   r>   r?   ra   s    r   rc   z._span_vertical_text_for_rect.<locals>.<lambda>û   s;   € �e D¨¤G¤JÑ/Ô/µ%¸¸a¼¼ÀdÈ1ÄgÄjÑ9PÐTWÑ8WÑ2XÔ2XÐ1XÐY€ r   rd   )rŽ   r   r0   r1   r>   r?   rB   r   Úanyr(   r'   Úsumrw   r   )r‹   r3   Úselected_wordsÚ
candidatesr’   r   Úvertical_hitsr“   Úwx0Úwy0Úwx1Úwy1r”   r•   s               @@r   Ú_span_vertical_text_for_rectr¦   Ý   s¿  øø€ ð ð ØˆtØ€JÝ4°TÑ:Ô:ð 1ð 1‰ˆ	�4Ý�I”LÑ!Ô!¥E¨)¬,Ñ$7Ô$7Ñ7¸3Ñ>ˆÝ�I”LÑ!Ô!¥E¨)¬,Ñ$7Ô$7Ñ7¸3Ñ>ˆÝ˜r 2 tÑ,Ô,ð 	1Ø×Ò˜y¨$Ð/Ñ0Ô0Ð0øØð ØˆtØ€MØ&4ð ð Ñ"ˆÑ"ˆC��c˜3 Ø�C‰i˜3ÑˆØ�C‰i˜3ÑˆÝÐUÐUÐUÐUÐUÈ*ÐUÑUÔUÑUÔUð 	Ø˜QÑˆMøØ•s˜1�c .Ñ1Ô1Ñ2Ô2Ñ2°SÒ8Ð8ØˆtÝ
Ð
7Ð
7¨JÐ
7Ñ
7Ô
7Ñ7Ô7¸!Ò;Ð;ØˆtØ�9Š9ð ð åØØYÐYð
ñ 
ô 
ðñ ô ñ ô ð r   c           
      ó  — | sdS d„ | D ¦   «         }t          |¦  «        t          |¦  «        dz           }t          d|dz  ¦  «        }g }t          | d„ ¬¦  «        D ]»\  }}}}||z   dz  }	d}
|}|D ]1}t          |	t	          |d	         ¦  «        z
  ¦  «        }||k    r|}
|}Œ2|
€|                     |	||fgd
œ¦  «         Œe|
d                              ||f¦  «         t          |
d         ¦  «        }t	          |
d	         ¦  «        |dz
  z  |	z   |z  |
d	<   Œ¼g }t          |d„ ¬¦  «        D ]J}|                     d                     d„ t          |d         d„ ¬¦  «        D ¦   «         ¦  «        ¦  «         ŒKd                     |¦  «        S )a  Join center-point-selected cell words into text, re-synthesizing lines.

    ``words`` are (y0, x0, y1, text) tuples; they are grouped into lines by an
    adaptive median-height nearest-line rule, each line's words ordered by x, and
    the lines joined by newlines.rn   c                 ó>   — g | ]\  }}}}t          d ||z
  ¦  «        ‘ŒS )gš™™™™™¹?©r(   )rF   r>   r“   r?   s       r   rt   z,_span_words_to_line_text.<locals>.<listcomp>  s.   € Ð;Ð;Ð;¡\ R¨¨B°�s�3˜˜R™Ñ Ô Ð;Ð;Ð;r   r™   r%   gš™™™™™á?c                 ó"   — | d         | d         fS r8   r   ra   s    r   rc   z*_span_words_to_line_text.<locals>.<lambda>  s   € ¸DÀ¼GÀTÈ!ÄWÐ;M€ r   rd   NÚcenter_y)r«   Úwordsr¬   r$   c                 ó,   — t          | d         ¦  «        S )Nr«   )r   ra   s    r   rc   z*_span_words_to_line_text.<locals>.<lambda>  s   € ­u°T¸*Ô5EÑ/FÔ/F€ r   rv   c              3   ó    K  — | ]	\  }}|V — Œ
d S r	   r   r˜   s      r   rG   z+_span_words_to_line_text.<locals>.<genexpr>  s&   è è € Ð"gÐ"g©G¨A¨t 4Ð"gÐ"gÐ"gÐ"gÐ"gÐ"gr   c                 ó   — | d         S r…   r   ra   s    r   rc   z*_span_words_to_line_text.<locals>.<lambda>  s   € Ð^bÐcdÔ^e€ r   rš   )r   r'   r(   Úabsr   r   rw   )r¬   ÚheightsÚmedian_heightÚline_thresholdr†   r>   r0   r?   r   r•   Ú	best_lineÚbest_distancerx   Údistancer+   Ú
text_liness                   r   Ú_span_words_to_line_textr¸      sä  € ð ð ØˆrØ;Ð;°UÐ;Ñ;Ô;€GÝ˜7‘O”O¥C¨¡L¤L°AÑ$5Ô6€MÝ˜˜m¨dÑ2Ñ3Ô3€NØ€EÝ" 5Ð.MÐ.MÐNÑNÔNð Zð ZÑˆˆB��DØ�2‰g˜‰_ˆØˆ	Ø&ˆØð 	)ð 	)ˆDÝ˜2¥ d¨:Ô&6Ñ 7Ô 7Ñ7Ñ8Ô8ˆHØ˜=Ò(Ð(Ø �	Ø (�øØÐØ�LŠL b°R¸°J°<Ð@Ð@ÑAÔAÐAØØ�'Ô×!Ò! 2 t *Ñ-Ô-Ð-Ý�I˜gÔ&Ñ'Ô'ˆÝ!& y°Ô'<Ñ!=Ô!=ÀÈÁÑ!KÈbÑ!PÐTYÑ Yˆ	�*ÑÐØ€JÝ�uÐ"FÐ"FÐGÑGÔGð ið iˆØ×Ò˜#Ÿ(š(Ð"gÐ"gµv¸dÀ7¼mÐQeÐQeÐ7fÑ7fÔ7fÐ"gÑ"gÔ"gÑgÔgÑhÔhÐhÐhØ�9Š9�ZÑ Ô Ð r   c                 ó†   — | \  }}}}}t          |¦  «        t          |¦  «        t          |¦  «        t          |¦  «        fS )zKReorder a (x0, y0, x1, y1, text) word to the (y0, x0, y1, text) line tuple.)r   ro   )Úwordr0   r>   Ú_x1r?   r   s         r   Ú_span_word_line_tupler¼   !  s9   € à Ñ€BˆˆC��TÝ�"‰IŒI•u˜R‘y”y¥%¨¡)¤)­S°©Y¬YÐ7Ð7r   c                 óø   — g }t          | ¦  «        D ]g\  }}|\  }}}}}	t          |	¦  «                             ¦   «         sŒ/||z   dz  }
||z   dz  }t          |
||¦  «        r|                     ||f¦  «         Œh|S )zá(index, word) pairs whose center lies in rect, index into ``page_words``.

    The index is what lets resolve_spans claim each page word for exactly one
    placement (an earlier cell's word is not re-claimed by a later one).r�   )Ú	enumeratero   rq   rB   r   )Ú
page_wordsr3   Úselectedr,   rº   r¢   r£   r¤   r¥   r   r”   r•   s               r   Ú_span_select_words_in_rectrÁ   '  s›   € ð
 €HÝ  Ñ,Ô,ð +ð +‰ˆˆtØ#'Ñ ˆˆS�#�s˜DÝ�4‰yŒy�ŠÑ Ô ð 	ØØ�C‰i˜3ÑˆØ�C‰i˜3ÑˆÝ˜r 2 tÑ,Ô,ð 	+Ø�OŠO˜U D˜MÑ*Ô*Ð*øØ€Or   c                 ó^   — t          | ||¦  «        }|�|S t          d„ |D ¦   «         ¦  «        S )zIText for a rect: vertical-line text if it dominates, else line synthesis.Nc                 ó2   — g | ]\  }}t          |¦  «        ‘ŒS r   )r¼   )rF   r“   rº   s      r   rt   z-_span_words_text_for_rect.<locals>.<listcomp>=  s%   € Ð$_Ð$_Ð$_ÁWÀQÈÕ%:¸4Ñ%@Ô%@Ð$_Ð$_Ð$_r   )r¦   r¸   )r‹   r3   rŸ   Úvertical_texts       r   Ú_span_words_text_for_rectrÅ   8  s=   € å0°°t¸^ÑLÔL€MØÐ ØÐÝ#Ð$_Ð$_ÐP^Ð$_Ñ$_Ô$_Ñ`Ô`Ð`r   c                 ó˜   ‡— ˆfd„t          ||¦  «        D ¦   «         }|D ]\  }}‰                     |¦  «         Œt          | ||¦  «        S )zKText of rect's words, skipping words already claimed and claiming the rest.c                 ó&   •— g | ]\  }}|‰v¯	||f‘ŒS r   r   )rF   r,   rº   Úclaimed_wordss      €r   rt   z,_span_claim_text_in_rect.<locals>.<listcomp>B  s6   ø€ ð ð ð áˆE�4Ø˜Ð%Ð%ð 
�ˆà%Ð%Ð%r   )rÁ   ÚaddrÅ   )r‹   r3   r¿   rÈ   rÀ   r,   r“   s      `   r   Ú_span_claim_text_in_rectrÊ   @  ss   ø€ ðð ð ð å5°jÀ$ÑGÔGðñ ô €Hð
 ð !ð !‰ˆˆqØ×Ò˜%Ñ Ô Ð Ð Ý$ T¨4°Ñ:Ô:Ð:r   c                 ó`  — t          | dd¦  «        }|�|S g }|                      d¦  «                             dg ¦  «        D ]É}|                     dg ¦  «        D ]°}|                     dg ¦  «        D ]—}t          |                     d¦  «        pd¦  «                             ¦   «         }t          |¦  «        d	k     rŒL|                     d
¦  «        }|sŒdt          j        |¦  «        }|j        rŒ€| 	                    ||f¦  «         Œ˜Œ±ŒÊ	 t          | d|¦  «         n# t          $ r Y nw xY w|S )zÕPage text spans as (rect, text), length>=2, cached on the page.

    These drive merged-cell detection: a single span whose x-extent crosses a
    grid column line signals cells the line grid split but text joins.Ú_span_text_spans_cacheNr‚   rƒ   r†   ru   r   rn   r™   r
   )r‡   rˆ   rp   ro   rq   r'   rN   rO   r~   r   r‰   rŠ   )	r‹   rŒ   ru   r�   rx   rs   r   r
   r3   s	            r   Ú_span_text_spansrÍ   L  sb  € õ
 �TÐ3°TÑ:Ô:€FØÐØˆØ€EØ—’˜vÑ&Ô&×*Ò*¨8°RÑ8Ô8ð +ð +ˆØ—I’I˜g rÑ*Ô*ð 	+ð 	+ˆDØŸš ¨"Ñ-Ô-ð 
+ð 
+�Ý˜4Ÿ8š8 FÑ+Ô+Ð1¨rÑ2Ô2×8Ò8Ñ:Ô:�Ý�t‘9”9˜q’=�=ØØ—x’x Ñ'Ô'�Øð ØÝ”| DÑ)Ô)�Ø”=ð ØØ—’˜d D˜\Ñ*Ô*Ð*Ð*ð
+ð	+ðÝ�Ð.°Ñ6Ô6Ð6Ð6øÝð ð ð Øˆðøøøà€Ls   ÄD Ä
D+Ä*D+c                 óÒ  ‡
— t          | ¦  «        dk     rg S t          d„ | D ¦   «         ¦  «        }t          d„ | D ¦   «         ¦  «        }g }|D ]Œ\  Š
}‰
j        ‰
j        z   dz  }||dz
  k     s	||dz   k    rŒ*ˆ
fd„t          | ¦  «        D ¦   «         }t          |¦  «        dk     rŒYt          |¦  «        D ]#\  }}	|	|k    r|                     ||	|f¦  «         Œ$Œ�t          |¦  «        S )aN  Column ranges within one grid row that a single text span crosses.

    ``entries`` are the row's cell rects (in column order). A text span centered
    in the row band and substantially overlapping >=2 adjacent cells marks those
    cells for merging; overlapping intervals are merged. Returns
    (start, end, texts) with end>start.r™   c              3   ó$   K  — | ]}|j         V — Œd S r	   rJ   ©rF   Úentrys     r   rG   z+_span_crossing_intervals.<locals>.<genexpr>r  ó$   è è € Ð/Ð/˜e�”Ð/Ð/Ð/Ð/Ð/Ð/r   c              3   ó$   K  — | ]}|j         V — Œd S r	   rM   rÐ   s     r   rG   z+_span_crossing_intervals.<locals>.<genexpr>s  rÒ   r   r%   r"   c                 ó:   •— g | ]\  }}t          ‰|¦  «        ¯|‘ŒS r   )rZ   )rF   ÚpositionrÑ   rV   s      €r   rt   z,_span_crossing_intervals.<locals>.<listcomp>y  s=   ø€ ð 
ð 
ð 
á�˜%Ý*¨9°eÑ<Ô<ð
Øð
ð 
ð 
r   )	r'   r2   r(   r>   r?   r¾   r^   r   rk   )ÚentriesÚ
text_spansÚrow_y0Úrow_y1rf   Ú	span_textr«   Úhit_positionsr)   r*   rV   s             @r   Ú_span_crossing_intervalsrÜ   i  s<  ø€ õ ˆ7�|„|�aÒÐØˆ	ÝÐ/Ð/ wÐ/Ñ/Ô/Ñ/Ô/€FÝÐ/Ð/ wÐ/Ñ/Ô/Ñ/Ô/€FØ€IØ *ð :ð :Ñˆ	�9Ø”L 9¤<Ñ/°3Ñ6ˆØ�f˜s‘lÒ"Ð" h°¸#±Ò&=Ð&=Øð
ð 
ð 
ð 
å#,¨WÑ#5Ô#5ð
ñ 
ô 
ˆõ
 ˆ}ÑÔ Ò!Ð!ØÝ1°-Ñ@Ô@ð 	:ð 	:‰JˆE�3Ø�UŠ{ˆ{Ø× Ò  %¨¨iÐ!8Ñ9Ô9Ð9øð	:õ ! Ñ+Ô+Ð+r   c                 óš   — | |k    rdS |D ]?}|d         dvrŒ|d         | k    s|d         |k    rŒ&t          ||d         ¦  «        r dS Œ@dS )NFÚrole>   ÚheaderÚheader_leafÚheader_groupÚrowÚcolsT©r<   )Úrow_idxrã   ÚbaseÚ
body_startÚothers        r   Ú_span_is_leaf_header_rangeré   Š  s{   € Ø�*ÒÐØˆuØð ð ˆØ�Œ=Ð IÐIÐIØØ�Œ<˜7Ò"Ð" e¨E¤l°jÒ&@Ð&@ØÝ! $¨¨f¬Ñ6Ô6ð 	Ø�5�5ð	àˆ4r   c                 óŽ  — g }t          | ¦  «        D ]{\  }}t          d„ |D ¦   «         ¦  «        D ]\\  }}t          j        |¦  «        }t          ||¦  «        }	|                     ||||	|	d         |	d         z
  ||k    rdnddœ¦  «         Œ]Œ||D ]4}
|
d         dk    rŒt          |
d         |
d	         ||¦  «        rd
nd|
d<   Œ5|S )a
  Describe every grid cell by row/slot-range/role for the strict-colspan gate.

    Header cells split into ``header_leaf`` (no header cell below within body) vs
    ``header_group`` (spans over a lower leaf), which the reject rules compare
    against the body split.c                 ó   — g | ]}|®|‘ŒS r	   r   ©rF   Úcells     r   rt   z*_span_build_base_cells.<locals>.<listcomp>Ÿ  s   € Ð(RÐ(RÐ(R°$ÀÐAQ¨ÐAQÐAQÐAQr   r$   r   Úbodyrß   )râ   rÕ   r3   rã   r   rÞ   rÞ   râ   rã   rà   rá   )r¾   rN   rO   r6   r   ré   )Úcellsr4   rç   ræ   rå   râ   rÕ   rí   r3   rã   rb   s              r   Ú_span_build_base_cellsrð   —  s  € ð €DÝ! %Ñ(Ô(ð ð ‰ˆ�Ý'Ð(RÐ(R¸#Ð(RÑ(RÔ(RÑSÔSð 	ð 	‰NˆH�dÝ”< Ñ%Ô%ˆDÝ# D¨,Ñ7Ô7ˆDØ�KŠKà"Ø (Ø Ø Ø# Aœw¨¨a¬Ñ0Ø&-°Ò&;Ð&;˜F˜FÀðð ñ	ô 	ð 	ð 	ð	ð ð 
ð 
ˆØ�Œ<˜8Ò#Ð#Øõ *¨$¨u¬+°t¸F´|ÀTÈ:ÑVÔVð ˆMˆMàð 	ˆV‰ˆð
 €Kr   c                 ó^  ‡ ‡‡— t          ˆfd„|D ¦   «         ¦  «        }|D ]‹Šˆ ˆfd„|D ¦   «         }|sŒt          |¦  «        dk    r|d         d         ‰ k    rŒ:t          ˆ fd„|D ¦   «         ¦  «        }t          ˆ fd„|D ¦   «         ¦  «        }|‰ d         k    r|‰ d         k    r dS ŒŒd	S )
zDTrue if some body row splits the column range ``cols`` into >1 cell.c                 óP   •— h | ]"}|d          dk    ¯|d         ‰k    ¯|d         ’Œ#S )rÞ   rî   râ   r   )rF   rb   rç   s     €r   ú	<setcomp>z._span_body_rows_split_under.<locals>.<setcomp>¹  s=   ø€ ÐmÐmÐm¨¸¸V¼ÈÒ8NÐ8NÐSWÐX]ÔS^ÐblÒSlÐSl˜˜UœÐSlÐSlÐSlr   c                 óp   •— g | ]2}|d          dk    ¯|d         ‰k    ¯t          ‰|d         ¦  «        ¯0|‘Œ3S )rÞ   rî   râ   rã   rä   )rF   rb   rã   rå   s     €€r   rt   z/_span_body_rows_split_under.<locals>.<listcomp>»  sX   ø€ ð 
ð 
ð 
àØ�FŒ|˜vÒ%Ð%¨$¨u¬+¸Ò*@Ð*@ÕE[Ð\`ÐbfÐgmÔbnÑEoÔEoÐ*@ð à*@Ð*@Ð*@r   r$   r   rã   c              3   ó\   •K  — | ]&}t          ‰d          |d         d          ¦  «        V — Œ'dS ©r   rã   Nr©   ©rF   rb   rã   s     €r   rG   z._span_body_rows_split_under.<locals>.<genexpr>Ä  s9   øè è € ÐKÐK¸d�C  Q¤¨¨f¬°a¬Ñ9Ô9ÐKÐKÐKÐKÐKÐKr   c              3   ó\   •K  — | ]&}t          ‰d          |d         d          ¦  «        V — Œ'dS ©r$   rã   N©r2   r÷   s     €r   rG   z._span_body_rows_split_under.<locals>.<genexpr>Å  s9   øè è € ÐIÐI¸D�#˜d 1œg t¨F¤|°A¤Ñ7Ô7ÐIÐIÐIÐIÐIÐIr   TF)r   r'   r2   r(   )rã   ræ   rç   Ú	body_rowsr5   Úcovered_startÚcovered_endrå   s   ` `    @r   Ú_span_body_rows_split_underrþ   ·  s  øøø€ åÐmÐmÐmÐm°ÐmÑmÔmÑnÔn€IØð ð ˆð
ð 
ð 
ð 
ð 
àð
ñ 
ô 
ˆð
 ð 	ØÝˆt‰9Œ9˜Š>ˆ>˜d 1œg fœo°Ò5Ð5ØÝÐKÐKÐKÐKÀdÐKÑKÔKÑKÔKˆÝÐIÐIÐIÐIÀDÐIÑIÔIÑIÔIˆØ˜D œGÒ#Ð#¨°t¸A´wÒ(>Ð(>Ø�4�4øØˆ5r   c                 ó  ‡ — ˆ fd„|D ¦   «         }|sdS t          |¦  «        dk    r|d         d         ‰ k    rdS t          ˆ fd„|D ¦   «         ¦  «        }t          ˆ fd„|D ¦   «         ¦  «        }|‰ d         k    o|‰ d         k    S )zGTrue if leaf-header cells split the column range ``cols`` into >1 cell.c                 óX   •— g | ]&}|d          dk    ¯t          ‰|d         ¦  «        ¯$|‘Œ'S )rÞ   rà   rã   rä   r÷   s     €r   rt   z1_span_header_leafs_split_over.<locals>.<listcomp>Í  s?   ø€ ÐrÐrÐr�T T¨&¤\°]Ò%BÐ%BÕG]Ð^bÐdhÐioÔdpÑGqÔGqÐ%BˆDÐ%BÐ%BÐ%Br   Fr$   r   rã   c              3   ó\   •K  — | ]&}t          ‰d          |d         d          ¦  «        V — Œ'dS rö   r©   r÷   s     €r   rG   z0_span_header_leafs_split_over.<locals>.<genexpr>Ò  s9   øè è € ÐGÐG¸$�˜D œG T¨&¤\°!¤_Ñ5Ô5ÐGÐGÐGÐGÐGÐGr   c              3   ó\   •K  — | ]&}t          ‰d          |d         d          ¦  «        V — Œ'dS rù   rú   r÷   s     €r   rG   z0_span_header_leafs_split_over.<locals>.<genexpr>Ó  s9   øè è € ÐEÐE¸•c˜$˜qœ' 4¨¤<°¤?Ñ3Ô3ÐEÐEÐEÐEÐEÐEr   )r'   r2   r(   )rã   ræ   r5   rü   rý   s   `    r   Ú_span_header_leafs_split_overr  Ë  s°   ø€ àrÐrÐrÐr˜TÐrÑrÔr€DØð ØˆuÝ
ˆ4�y„y�A‚~€~˜$˜qœ' &œ/¨TÒ1Ð1ØˆuÝÐGÐGÐGÐGÀ$ÐGÑGÔGÑGÔG€MÝÐEÐEÐEÐEÀÐEÑEÔEÑEÔE€KØ˜D œGÒ#Ð>¨°t¸A´wÒ(>Ð>r   c                 ó¶   — |d         |d         z
  dk    rdS | |k     r)t          | |||¦  «        sdS t          |||¦  «        rdS dS t          ||¦  «        rdS dS )zJWhether to reject a candidate merge over ``cols`` as a (reason,) mismatch.r$   r   )Frn   )TÚ.header_leaf_colspan_changed_against_body_split)TÚ.body_colspan_changed_against_header_leaf_split)ré   rþ   r  ©rå   rã   ræ   rç   s       r   Ú#_span_reject_colspan_mismatch_merger  ×  sƒ   € àˆA„w��a”Ñ˜AÒÐØˆyØ�ÒÐÝ)¨'°4¸¸zÑJÔJð 	Ø�9Ý& t¨T°:Ñ>Ô>ð 	JØIÐIØˆyÝ$ T¨4Ñ0Ô0ð FØEÐEØˆ9r   c                 ó’   — g }|||dz   …         D ]6}t          ||¦  «        }|                     t          | ||¦  «        ¦  «         Œ7|S )Nr$   )rÁ   r   rÅ   )r‹   rÖ   r)   r*   r¿   rj   rÑ   r¬   s           r   Ú_span_cell_texts_for_entriesr
  æ  s[   € Ø€EØ˜  q¡˜Ô)ð Dð DˆÝ*¨:°uÑ=Ô=ˆØ�ŠÕ.¨t°U¸EÑBÔBÑCÔCÐCÐCØ€Lr   c                 ól   — | dk    rdS d„ t          |||||¦  «        D ¦   «         }t          |¦  «         S )zçAllow an otherwise-rejected header merge when a covered part is empty.

    A header leaf that would be rejected against a body split is still merged if
    one of the merged parts has no text (an empty header slot the body fills).r  Fc                 ó6   — g | ]}|                      ¦   «         ‘ŒS r   )rq   )rF   r   s     r   rt   zD_span_allow_header_colspan_merge_with_empty_part.<locals>.<listcomp>õ  s    € ÐoÐoÐo 4�$—*’*‘,”,ÐoÐoÐor   )r
  Úall)Úreasonr‹   rÖ   r)   r*   r¿   Ú
part_textss          r   Ú0_span_allow_header_colspan_merge_with_empty_partr  î  sK   € ð
 ÐAÒAÐAØˆuØoÐoÕ+GÈÈgÐW\Ð^aÐcmÑ+nÔ+nÐoÑoÔo€JÝ�:‰ŒÐÐr   F)Úheader_row_countÚstrict_colspanc                óX  — t          |¦  «        }g }g }|D ]`}|D ][}|€Œt          j        |¦  «        }	|                     |	j        |	j        g¦  «         |                     |	j        |	j        g¦  «         Œ\Œat          |¦  «        }
t          |¦  «        }|r-t          dt          t          |pd¦  «        |¦  «        ¦  «        nd}|rt          ||
|¦  «        ng }t          | ¦  «        }t          | ¦  «        }t          ¦   «         }g }t!          |¦  «        D �]�\  }}g }d„ |D ¦   «         }t#          ||¦  «        }d„ |D ¦   «         }d}|t          |¦  «        k     �r5|                     |¦  «        }|�||\  }}t'          |||dz   …         ¦  «        }	|rUt)          |	|
¦  «        }t+          ||||¬¦  «        \  }}|rt-          || ||||¬¦  «        rd}|r||         }	|dz  }n|dz   }n|dz   }n||         }	|dz  }|	j        rŒ¼t1          |	j        |	j        |
¦  «        }t1          |	j        |	j        |¦  «        }|                     t5          t7          |	¦  «        t9          | |	||¦  «        ||¬	¦  «        ¦  «         |t          |¦  «        k     �°5|                     |¦  «         �Œ’|S )
a¡  Resolve a detected table's merged-cell (colspan/rowspan) structure.

    ``cells`` is a row-major grid: a list of rows, each a list of ``[x0, y0, x1,
    y1]`` cell rectangles (``None`` for a gap) -- the same grid shape
    :func:`refine_grid` accepts. Returns a row-major grid of :class:`SpanCell`
    placements, ragged where cells span: each placement carries its union
    ``bbox``, the page ``text`` it claims, and its ``colspan``/``rowspan`` (how
    many clustered column/row slots it covers). Every page word is claimed by at
    most one placement.

    ``header_row_count`` is the number of leading header rows (default a
    conservative 1); it only matters together with ``strict_colspan``.
    ``strict_colspan`` (default False), when set, refuses a merge whose colspan
    would contradict the header/body column split. This is a PyMuPDF extension;
    it reads page text/graphics but does not mutate the page.
    Nr$   r   c                 ó:   — g | ]}|®t          j        |¦  «        ‘ŒS r	   )rN   rO   rì   s     r   rt   z!resolve_spans.<locals>.<listcomp>!  s'   € ÐJÐJÐJ¨$¸Ð9I•7”< Ñ%Ô%Ð9IÐ9IÐ9Ir   c                 ó    — i | ]\  }}}|||f“ŒS r   r   )rF   r)   r*   rj   s       r   ú
<dictcomp>z!resolve_spans.<locals>.<dictcomp>#  s%   € ÐUÐUÐUÑ6G°e¸SÀ%˜e c¨5 \ÐUÐUÐUr   r  )r  r‹   rÖ   r)   r*   r¿   F)r
   r   r   r   )r'   rN   rO   Úextendr0   r1   r>   r?   r!   r(   r2   Úintrð   rÍ   r   Úsetr¾   rÜ   rp   rQ   r6   r  r  r~   r.   r   r   ÚtuplerÊ   ) r‹   rï   r  r  ÚrowsÚx_edgesÚy_edgesrâ   rí   r3   r4   Úy_boundariesrç   Ú
base_cellsr×   r¿   rÈ   Ú
placementsrå   Úplacement_rowrÖ   rf   Úintervals_by_startrÕ   ÚintervalÚend_positionÚ_crossing_textsÚcandidate_colsÚrejectr  r   r   s                                    r   Úresolve_spansr(  ù  s;  € õ" ˆu‰:Œ:€Dà€GØ€GØð /ð /ˆØð 	/ð 	/ˆDØˆ|ØÝ”< Ñ%Ô%ˆDØ�NŠN˜DœG T¤WÐ-Ñ.Ô.Ð.Ø�NŠN˜DœG T¤WÐ-Ñ.Ô.Ð.Ð.ð	/õ .¨gÑ6Ô6€LÝ-¨gÑ6Ô6€LØBFÐM•�Q��CÐ 0Ð 5°AÑ6Ô6¸Ñ=Ô=Ñ>Ô>Ð>ÈA€JØLZÐbÕ'¨¨|¸ZÑHÔHÐHÐ`b€Jå! $Ñ'Ô'€JÝ# DÑ)Ô)€JÝ‘E”E€MØ€JÝ! %Ñ(Ô(ð 3)ñ 3)‰ˆ�ØˆØJÐJ°#ÐJÑJÔJˆÝ,¨W°jÑAÔAˆ	ØUÐUÈ9ÐUÑUÔUÐØˆØ�˜W™œÒ%Ñ%Ø)×-Ò-¨hÑ7Ô7ˆHØÐ#Ø08Ñ-�˜oÝ'¨°¸<È!Ñ;KÐ0KÔ(LÑMÔM�Ø!ð 0Ý%5°d¸LÑ%IÔ%I�NÝ%HØ 'Ø+Ø'Ø#-ð	&ñ &ô &‘N�F˜Fð ð 'Õ"RØ%Ø!Ø 'Ø&Ø(Ø#-ð#ñ #ô #ð 'ð "'˜Øð 4Ø& xÔ0˜Ø  A™˜˜à#/°!Ñ#3˜˜à+¨aÑ/�H�Hà˜xÔ(�Ø˜A‘�àŒ}ð ØÝ.¨t¬w¸¼ÀÑNÔNˆGÝ.¨t¬w¸¼ÀÑNÔNˆGØ× Ò ÝÝ˜t™œÝ1°$¸¸jÈ-ÑXÔXØ#Ø#ð	ñ ô ñô ð ðK �˜W™œÒ%Ñ%ðZ 	×Ò˜-Ñ(Ô(Ð(Ñ(àÐr   )#r   rN   Úpymupdf._table_refiner   r   r   r!   r.   r6   r<   rB   rQ   rS   rZ   r^   rk   rz   r   rŽ   r¦   r¸   r¼   rÁ   rÅ   rÊ   rÍ   rÜ   ré   rð   rþ   r  r  r
  r  r(  r   r   r   ú<module>r*     sy  ððð ðB €€€ðð ð ð ð ð ð ð ðð ð ð ð ñ ô ð ð, 58ð 
ð 
ð 
ð 
ð 
ð CFð ð ð ð ð ð 7:ð 	&ð 	&ð 	&ð 	&ð 	&ð'ð 'ð 'ð[ð [ð [ðð ð ð-ð -ð -ð
(ð 
(ð 
(ðð ð ð ð ð ðð ð ð#ð #ð #ð$ð ð ð: ð  ð  ðF!ð !ð !ðB8ð 8ð 8ðð ð ð"að að að	;ð 	;ð 	;ðð ð ð:,ð ,ð ,ðB
ð 
ð 
ðð ð ð@ð ð ð(	?ð 	?ð 	?ðð ð ðð ð ðð ð ð 48Èð [ð [ð [ð [ð [ð [ð [r   