
    j5j#                       U d Z ddlmZ ddlZddlZddlmZmZmZ ddl	m
Z
 ddlZddlmZ  ej                  e      ZdZ e
d	       G d
 d             ZddZddZddZd dZej,                  dfej,                  dfej,                  dfej,                  dfej.                  dfdZded<    eh d      ZdZd!dZ	 	 	 	 d"dZd#dZy)$u  Validate and repair malformed page-boundary boxes.

A page's boundary boxes (``/MediaBox``, ``/CropBox``, ``/TrimBox``, ``/ArtBox``,
``/BleedBox``) are sometimes malformed in ways that PDF readers tolerate but
that crash or corrupt downstream processing. This module normalizes them in
place following the PDF 2.0 specification (ISO 32000-2:2020):

- **Non-decimal coordinates** (§7.3.3): a coordinate written in exponential
  notation is invalid PDF number syntax and is stored by qpdf/pikepdf as a
  string. We coerce it back to a number (issue #1398).
- **Reversed corners** (§7.9.5): a rectangle is "a pair of diagonally opposite
  corners"; ``[llx lly urx ury]`` is only the typical order. We normalize to
  ``[min_x, min_y, max_x, max_y]`` (issue #1526).
- **Sub-box outside the MediaBox** (§14.11.2): "If the bounds of the crop,
  trim, bleed or art box extends outside of the bounds of the media box, a
  processor shall treat the box as its intersection with the media box." We
  clamp to that intersection, or discard the sub-box (so it inherits the
  MediaBox) when the intersection is empty (issue #1400).

A rectangle is treated as empty when its width or height is ``<= 0``; PDF 2.0
permits zero-dimension rectangles and defines no minimum page size, so no other
size floor is imposed.
    )annotationsN)IterableMappingSequence)	dataclass)Name)CropBoxTrimBoxArtBoxBleedBoxT)frozenc                  &    e Zd ZU dZded<   ded<   y)	BoxRepaira  A single change made to a page box.

    Attributes:
        box: The box name, e.g. ``"CropBox"``.
        kind: One of ``"reordered"`` (reversed corners normalized; lossless),
            ``"recoded"`` (non-numeric/exponential coordinate coerced),
            ``"clamped"`` (sub-box clamped to the MediaBox), ``"discarded"``
            (sub-box removed because its MediaBox intersection was empty), or
            ``"degenerate_mediabox"`` (MediaBox has zero width or height).
    strboxkindN)__name__
__module____qualname____doc____annotations__     I/var/www/html/qr/venv/lib/python3.12/site-packages/ocrmypdf/_pageboxes.pyr   r   ,   s    	 
H
Ir   r   c                   t        |       dk7  ryg }d}| D ]6  }	 t        |      }t        j                  |      s y|j                  |       8 |\  }}}}t        ||      t        ||      t        ||      t        ||      g}	|	|k7  }
|	||
fS # t        t        f$ r2 	 t        t	        |            }n# t        t        f$ r Y Y  yw xY wd}Y w xY w)aO  Coerce a box array to floats and normalize corner order.

    Returns ``(normalized_values, recoded, reordered)`` where ``recoded`` is
    True if any element needed string/exponential coercion and ``reordered`` is
    True if the corners were given in non-standard order. Returns None if the
    array is not four finite numbers.
       NFT)
lenfloat	TypeError
ValueErrorr   mathisfiniteappendminmax)valuesnumsrecodedvnx0y0x1y1
normalized	reordereds              r   	_read_boxr1   =   s     6{aDG 	aA }}QA NBBb"+s2r{CBKREJd"Iw	)) :& 	#a&Mz* G	s5   BCB32C3CCCCCc           	         t        |       } t        |       }||d   S g }| D ]  }	 |j                  t        |              |S # t        t
        f$ r& |j                  t        t        |                   Y Vw xY w)aS  Return box values coerced to floats with corner order normalized.

    Robust against exponential/string coordinates and reversed corners, so
    callers that only need to read a box (e.g. dimension calculations) do not
    crash on malformed input. Falls back to best-effort per-element coercion if
    the array is not four numbers.
    r   )listr1   r#   r   r   r    r   )r&   resultcoercedr)   s       r   
coerce_boxr6   [   s     &\FvFayG *	*NN58$*
 N :& 	*NN5Q=)	*s   A2A98A9c                >    | d   | d   z
  dk  xs | d   | d   z
  dk  S )z>A rectangle is empty when its width or height is non-positive.   r         r   r   s    r   	_is_emptyr<   p   s/    FSVO!;c!fs1vo!%;;r   c           	        g }d}	 t        t        | j                  j                                     }||\  }}}|r|j                  t        dd             |r|j                  t        dd             |s|r$t        j                  |      | j                  _        t        |      r|j                  t        dd             d}t        D ]m  }t        d|z         }|| j                  vr!	 t        t        | j                  |               }|F|\  }	}}|r|j                  t        |d             |r|j                  t        |d             |s|r"t        j                  |	      | j                  |<   |t#        |	d   |d         t#        |	d   |d         t%        |	d	   |d	         t%        |	d
   |d
         g}
t        |
      r*| j                  |= |j                  t        |d             *|
|	k7  s1t        j                  |
      | j                  |<   |j                  t        |d             p |S # t        t
        t        f$ r d}Y $w xY w# t         t        f$ r Y w xY w)a  Validate and repair the boundary boxes of a single page, in place.

    Returns the list of changes made (empty if the page was already valid).
    Only boxes that actually change are written back, so valid pages are left
    untouched. Performs no logging or I/O.
    NMediaBoxr0   r(   degenerate_mediabox/r   r:   r8   r9   	discardedclamped)r1   r3   mediaboxas_listAttributeErrorKeyErrorRuntimeErrorr#   r   pikepdfArrayobjr>   r<   	_SUBBOXESr   r   r%   r$   )pagerepairsrC   	mb_resultr(   r0   r   name
sub_resultr&   intersections              r   repair_page_boxesrR   u   s@     "G $(Hd4==#8#8#:;<	 '0$'9NN9Z=>NN9Z;<i 'h 7DHHXNN9Z1FGHH 6C#Itxx	"4#78J %/"NN9S+67NN9S)45i$]]62DHHTNq	8A;'q	8A;'q	8A;'q	8A;'	
 \"NN9S+67V#$]]<8DHHTNNN9S)45?6B N_ Hl3 	( <( 		s#   ,H= ,!I=III-,I-zN{box} lies outside the MediaBox and was discarded; the full page will be shownz8{box} extended beyond the MediaBox and was clamped to itzK{box} used invalid (e.g. exponential) coordinates, which were reinterpretedzRMediaBox has zero width or height and could not be repaired; output may be invalidz4{box} corners were reversed and have been normalized)rA   rB   r(   r?   r0   zdict[str, tuple[int, str]]_KIND_MESSAGES>   rB   r(   rA   z( Please visually inspect the output PDF.c                    t        d | D              }g }|d   x}}|dd D ]$  }||dz   k(  r|}|j                  ||f       |x}}& |j                  ||f       dj                  d |D              S )z>Format 0-based page numbers as a compact 1-based range string.c              3  &   K   | ]	  }|d z     yw)r:   Nr   ).0ps     r   	<genexpr>z _format_pages.<locals>.<genexpr>   s     )A!a%)s   r   r:   Nz, c              3  @   K   | ]  \  }}||k(  r| n| d |   yw)-Nr   )rV   abs      r   rX   z _format_pages.<locals>.<genexpr>   s+     I$!QqAvsaS!:5Is   )sortedr#   join)pagenosr'   rangesstartprevr*   s         r   _format_pagesrc      s    )))D$&F7ED!"X q=Dudm$ MM5$- 99I&IIIr   c                   i }| j                         D ]K  \  }}|D ]A  }|j                  |j                  |j                  ft	                     j                  |       C M g }t        |j                               D ]Z  \  \  }}}t        |   \  }	}
dt        |       d|
j                  |       d}|t        v r	|t        z  }|j                  |	|f       \ |S )zAggregate per-page repairs into ``(log_level, message)`` pairs.

    Repairs are grouped by ``(kind, box)`` so a defect shared across many pages
    yields a single message listing the affected pages, rather than one message
    per page.
    zPage(s) z: r;   .)items
setdefaultr   r   setaddr]   rS   rc   format_INSPECT_KINDS_INSPECTr#   )repairs_by_pagegroupspagenorM   repairmessagesr   r   pagesleveltemplatetexts               r   summarize_box_repairsrv      s     /1F*002 L 	LFv{{FJJ7?CCFK	LL ')H$V\\^4 'sU(.x-./r(//c/2J1K1M>!HD&' Or   c                V    t        |       D ]  \  }}t        j                  ||        y)zCEmit aggregated log messages for the repairs made across all pages.N)rv   log)rm   rs   messages      r   log_box_repairsrz      s(    /@  ww r   )r&   r   returnz%tuple[list[float], bool, bool] | None)r&   r   r{   zlist[float])r   zSequence[float]r{   bool)rL   zpikepdf.Pager{   zlist[BoxRepair])r_   zIterable[int]r{   r   )rm   !Mapping[int, Sequence[BoxRepair]]r{   zlist[tuple[int, str]])rm   r}   r{   None) r   
__future__r   loggingr!   collections.abcr   r   r   dataclassesr   rH   r   	getLoggerr   rx   rK   r   r1   r6   r<   rR   WARNINGDEBUGrS   r   	frozensetrk   rl   rc   rv   rz   r   r   r   <module>r      s  
0 #   7 7 !  g!8	 $   *<*<
<D 		& 	B
 	U
 		  	>'.* 4 >?5J60 r   