
    Ipj;                         S r SSKrSSKJrJrJrJrJr  SrSr	Sr
SrSrS	rS
 rS rS rS rS rS rS rS rS rS rS rS rg)a  
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 union stage, behind find_tables(union=True): fuse the layout
analyzer's table grids with the line-based finder's candidates. Table,
TableFinder and _iou come from pymupdf.table; find_tables is imported lazily.
    N)CHARSEDGESTableTableFinder_ioulines_strictg?Tg      @g333333?g      ?c                    / nU R                   =(       d    /  GHc  n[        U[        5      (       d  M  UR                  S5      S:w  a  M2  UR                  S5      nUR                  S5      nU(       a  Uc  M`  US   US   US   US	   4u  pVpxU/UR                   V	s/ s H  oU-   PM	     sn	-   U/-   n
U/UR
                   Vs/ s H  oU-   PM	     sn-   U/-   n/ n[        [        U
5      S-
  5       HY  n/ n[        [        U5      S-
  5       H(  nUR                  UU   X   UUS-      XS-      45        M*     UR                  U5        M[     UR                  [        R                  " USS
 5      U45        GMf     U$ s  sn	f s  snf )a`  Primary table grids from the raw layout analyzer result.

Reads page.layout_information in its raw (return_raw=True) form and yields a
``(bbox, grid)`` pair per "table" group -- ``grid`` is the full row-major cell
grid built from the group box plus its interior GridPrediction lines, in
layout (reading) order. Boxes without a usable grid are skipped.

class_nametable
group_bbox
table_gridNr               )layout_information
isinstancedictgeth_linesv_linesrangelenappendpymupdfRect)pagegridsgroupr   	grid_predx0y0x1y1hr   vr   gridirowjs                    P/var/www/html/pdf-tiff/venv/lib/python3.13/site-packages/pymupdf/_table_union.py_layout_table_gridsr,   :   s    E))/R/%&& 99\"g-YY|,
IIl+	Y.#A
1z!}jQRmS$)*;*;<*;Qb&*;<<tC$)*;*;<*;Qb&*;<<tCs7|a'(AC3w<!+,

GAJ
GAENGPQENST -KK	 )
 	gll:bq>2D9:) 0* L =<s   FFc           	      4   SSK Jn  U" U [        SS9n/ n[        5       n[	        USS5      =(       d    /  H  n [
        R                  " UR                  5      nUR                  (       a  M7  UR                  =(       d    /  VVs/ s H  owR                   Vs/ s H  oPM     snPM      n	nnU	(       d  M  [        S U 5       5      n
X;   a  M  UR                  U
5        UR                  Xi45        M     X24$ ! [        [        4 a     M  f = fs  snf s  snnf )aa  Line-based table candidates for the union stage as ``(bbox, grid)`` pairs.

Runs a nested find_tables (strategy=_UNION_STRATEGY, use_layout=False) and
keeps each detected table's bbox and row-major cell grid (Table.rows, None
for a gap), deduped by rounded bbox. Returns ``(candidates, finder)``; the
finder is reused as the returned TableFinder shell.
r   )find_tablesF)strategy
use_layouttablesNc              3   8   #    U  H  n[        U5      v   M     g 7f)N)round).0values     r+   	<genexpr>)_union_line_candidates.<locals>.<genexpr>s   s     3dUE%LLds   )pymupdf.tabler.   _UNION_STRATEGYsetgetattrr   r   bbox
ValueError	TypeErroris_emptyrowscellstupleaddr   )r   r.   finder
candidatesseentabr<   r)   cellr'   keys              r+   _union_line_candidatesrJ   [   s     *EJFJ5D$/525	<<)D ==9<RI)),)$),I3d33;4,' 6  I& 		 -Is)    C8DD"D8DDDc                     [        S[        U R                  U R                  -
  5      5      [        S[        U R                  U R
                  -
  5      5      -  $ N        )maxfloatr#   r!   r$   r"   )rects    r+   _union_rect_arearQ   {   s?    sE$''DGG+,-Ctww?P9Q0RRR    c                    [        [        U R                  5      [        UR                  5      5      n[        [        U R                  5      [        UR                  5      5      n[	        [        U R
                  5      [        UR
                  5      5      n[	        [        U R                  5      [        UR                  5      5      nXB::  d  XS::  a  gXB-
  XS-
  -  $ rL   )rN   rO   r!   r"   minr#   r$   )leftrightr!   r"   r#   r$   s         r+   _union_intersection_arearW      s    	U477^U588_	-B	U477^U588_	-B	U477^U588_	-B	U477^U588_	-B	x28G  rR   c           
          [        S[        [        U R                  5      [        UR                  5      5      [        [        U R                  5      [        UR                  5      5      -
  5      $ rL   )rN   rT   rO   r#   r!   )rU   rV   s     r+   _union_x_overlaprY      sE    sCdggehh83uTWW~uUZU]U];__``rR   c                    [        U 5      nUS::  a  gSnSnSn[        U5       H^  u  pg[        U5      n[        X5      n	U	S::  d  US::  a  M)  X-  n
X-  nU
[        :  a  X:  a  UnU
nMF  U
[        :  d  U[        :  d  M\  SnM`     X54$ )a&  The primary a split candidate belongs inside, plus an ambiguity flag.

Returns ``(owner_index, ambiguous)``: owner is the best-contained primary
(candidate>=_UNION_OWNER_CONTAINMENT inside it), else None; ambiguous is True
when the candidate overlaps some primary enough to be unsafe to append.r   )NTNrM   FT)rQ   	enumeraterW   _UNION_OWNER_CONTAINMENT_UNION_OWNER_AMBIGUOUS_OVERLAP)candidate_bboxexisting_bboxescandidate_area
best_ownerbest_containment	ambiguousindexexisting_bboxexisting_area
inter_areacandidate_containmentexisting_coverages               r+   _union_find_ownerrj      s     &n5NJI )/ :(7-nL
?mq0 * ;&6 $<<AVAiJ4"&DDHY]{H{I !;   rR   c                 n   [        U SS5      nUb  U$ / nU R                  S5      R                  S/ 5      =(       d    /  H  nUR                  S/ 5      =(       d    /  H  nUR                  S/ 5      =(       d    /  H  n[        UR                  S5      =(       d    S5      R	                  5       (       d  M;  UR                  S	5      nU(       d  MU  [
        R                  " U5      nUR                  (       a  M~  UR                  U5        M     M     M      [        U SU5        U$ ! [         a     U$ f = f)
zNon-empty page text-span rects, cached on the page.

Drives the grid-ref span-multiplicity gate: every non-blank span as a bare
rect._union_text_spans_cacheNr   blockslinesspanstext r<   )r;   get_textr   strstripr   r   r?   r   setattr	Exception)r   cachedro   blocklinespanr<   rP   s           r+   _union_text_span_rectsr{      s   
 T4d;FEv&**8R8>B>IIgr*0b0D"-33488F+1r288::xx'||D)}}}LL& 4 1 ?/7 L  Ls   D& &
D43D4c                 B   / nU GHF  n[        UR                  5      [        UR                  5      -   S-  nU[        U R                  5      S-
  :  d  U[        U R                  5      S-   :  a  Ml  [        X05      S::  a  M}  [	        [        U R
                  5      [        UR
                  5      5      n[        [        U R                  5      [        UR                  5      5      nXe::  a  M  [        U5       H:  u  nu  p[        XH-
  5      S::  d  M  U	R                  XV45        X-   S-  U	4X''     GM/     UR                  XEU4/45        GMI     Sn
U HG  u  pSnSn[        U	5       H$  u  pVUb  X]-
  S:  a	  US-  nUnM  [	        X5      nM&     [	        X5      n
MI     U
$ )zNMax horizontally-separated text-span groups on any single text line in a cell.g       @g      ?g      @r   Nr   )rO   r"   r$   rY   rN   r!   rT   r#   r[   absr   sorted)rH   
text_spans
line_bandsrz   center_yr!   r#   rd   band_y	intervalsbest_groupslast_x1s                 r+   _union_cell_span_group_countr      s|   J$''NU477^3s:eDGGns**htww#9M.MD'3.twwtww0twwtww08*3J*?&E&F8$%,  "*&,&73%>	$J
!	 +@ xr(45! " D"Y'FB","4!g* ( 4  # KrR   c                 
   U c  g[        U 5      nSnU H]  nU HT  nUc  M  [        R                  " U5      nUR                  (       a  M1  [	        Xb5      nUS:  d  MD  Uc  UO
[        X75      nMV     M_     Ub  [        U5      $ S$ )zEMax cell span-group count over a grid (high => under-segmented grid).Nr   )r{   r   r   r?   r   rN   rO   )r   r'   r   r   r)   rH   rP   counts           r+   _union_span_multiplicityr      s    |'-JDD|<<%D}}0BEqy $u#d2B   *5;44rR   c                v   0 n0 n[        U 5       H  u  nu  p[        U5       Hr  u  nu  p[        X5      nX:  d  M  UR                  U/ 5      R                  U[	        U5      45        UR                  U/ 5      R                  U[	        U5      45        Mt     M     0 n[        5       nUR                  5        Hz  u  nn[        U5      S:w  a  M  US   u  nn[        UR                  U/ 5      5      S:w  a  M@  U(       a  [        X1U   S   5      nUb  UU:  a  Mc  X   X'   UR                  U5        M|     UU4$ )aM  Primaries a candidate can grid-ref (replace grid with), 1:1 by IoU.

``existing``/``candidates`` are ``(bbox, grid)`` lists. Returns ``(refs,
consumed)``: ``refs`` maps a primary index to the candidate supplying its
grid (mutual 1:1 IoU>=threshold matches passing the span-multiplicity gate),
``consumed`` the candidate indexes used.r   r   )r[   r   
setdefaultr   rO   r:   itemsr   r   r   rC   )existingrE   iou_thresholdr   span_mult_gatespan_mult_thresholdexisting_matchescandidate_matchesexisting_indexre   _gridcandidate_indexr^   _cgridiourefsconsumedmatchesr   	span_mults                       r+   _union_one_to_one_grid_refsr      sK    2;H2E..9B:9N5O5n}5C# ++NB?FFY^_bYcGde!,,_bAHH.Z_`cZdIef	 :O 3F DuH#3#9#9#;w<1$QZ $$_b9:a?0/7RST7UVI$6I)I):_% $< >rR   c          
         U  Vs/ s H  owS   PM	     nnU(       a  [        U UUUUUS9u  pO0 [        5       p0 n/ n[        U5       H^  u  pX;   a  M  [        US   U5      u  nnUb#  UR	                  U/ 5      R                  U5        MD  U(       a  MM  UR                  U5        M`     UR                  5        VVs0 s H#  u  nn[        U5      S:  d  M  U[        US S9_M%     nnn/ n[        U 5       HW  u  nnUU;   a  UR                  UU   5        M"  UU	;   a  UR                  US   U	U   S   45        MF  UR                  U5        MY     UR                  U5        U$ s  snf s  snnf )a  Fuse primary and candidate ``(bbox, grid)`` entries.

Applies grid-ref replacement, split replacement (>=2 candidates owned by one
primary replace it, ordered by y0/x0) and append of unowned candidates,
returning the fused entry list in the contractual order.r   )r   r   r   r   r   c                 b    [        U S   R                  5      [        U S   R                  5      4$ )Nr   )rO   r"   r!   )entrys    r+   <lambda>'_union_replace_append.<locals>.<lambda>7  s$    eAhkk0BE%PQ(++DV/WrR   )rI   r   )
r   r:   r[   rj   r   r   r   r   r~   extend)r   rE   r   grid_refgrid_ref_iour   r   r   r_   	grid_refsr   replacementsappend_candidatesr   	candidateowner_indexrc   rd   r   final_replacementsentriess                        r+   _union_replace_appendr     s    .66XEQxXO69&) 3
	8 !#%8L&/
&;"&!29Q<!QY"##K4;;IF$$Y/ '< )..00LE5u:? 	Yve!WXX0  
 G!(+u&&NN-e45iNNE!Hi&6q&9:;NN5! , NN$%NO 70s   E$<E)E)c           
         U R                   c  U R                  SS9  [        U 5      n[        U 5      u  p#[	        UUU S[
        [        [        S9nUc5  [        R                  " 5         [        R                  " 5         [        U 5      n/ nU HH  u  pgU VV	s/ s H  o  H	  oc  M  U	PM     M     n
nn	U
(       d  M/  UR                  [        X
US95        MJ     XSl        U$ s  sn	nf )a  Detect a page's tables by fusing layout grids with line-based candidates.

Ensures the raw layout (computed only when page.layout_information is None,
like the official use_layout path), reads primary grids, detects candidates,
applies grid-ref / split / append, and returns a TableFinder whose .tables
carry the fused grids in contractual order (grid-ref tables keep their
explicit layout bbox).T)
return_raw)r   r   r   r   r   )r<   )r   
get_layoutr,   rJ   r   _UNION_GRID_REF_IOU_UNION_GRID_REF_SPAN_MULT_GATE#_UNION_GRID_REF_SPAN_MULT_THRESHOLDr   clearr   r   r   r   r1   )r   	primariesrE   rD   r   r1   r<   r'   r)   rH   flats              r+   _find_tables_unionr   H  s     &4(#D)I/5J#(5?G ~
 	T"F
 $IIeDT23	 
 MM Js   C %
C )__doc__r   r8   r   r   r   r   r   r9   r   r   r   r\   r]   r,   rJ   rQ   rW   rY   rj   r{   r   r   r   r   r    rR   r+   <module>r      s}   <  @ @" ! !% &) # !% B@S!a!66D5&@-`$rR   