
    4 j(                        d Z ddlZddlZddlmZ ddlmZ ddlmZm	Z	m
Z
mZmZmZmZ ddlmZmZmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$ dd	l%m&Z' dd
l(m)Z)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZR  ej                  eT      ZU G d de)      ZV G d de)      ZW G d de)      ZX G d d      ZY G d d      ZZ G d de)      Z[ G d d      Z\ G d de)      Z] G d d      Z^ G d d      Z_ G d  d!      Z` G d" d#      Zay)$zParser for PDF files    N)BytesIO)Path)AnyDictIteratorListOptionalTupleUnion)BoundingBoxCoordOriginImageRefMode)ImageRef)BitmapResourceBoundingRectangle	ColorRGBACoord2DPdfHyperlinkPdfMetaDataPdfPageBoundaryTypePdfPageGeometryPdfShapePdfTableOfContentsPdfTextCell	PdfWidgetSegmentedPdfPageTextCellTextDirection)Image)	BaseModel
ConfigDict)'TIMING_KEY_CREATE_LINE_CELLSTIMING_KEY_CREATE_WORD_CELLSTIMING_KEY_DECODE_ANNOTSTIMING_KEY_DECODE_CONTENTSTIMING_KEY_DECODE_DIMENSIONSTIMING_KEY_DECODE_DOCUMENTTIMING_KEY_DECODE_FONTSTIMING_KEY_DECODE_FONTS_TOTALTIMING_KEY_DECODE_GRPHSTIMING_KEY_DECODE_GRPHS_TOTALTIMING_KEY_DECODE_PAGETIMING_KEY_DECODE_RESOURCESTIMING_KEY_DECODE_XOBJECTS TIMING_KEY_DECODE_XOBJECTS_TOTALTIMING_KEY_EXTRACT_ANNOTS_JSON"TIMING_KEY_EXTRACT_DOC_ANNOTATIONS(TIMING_KEY_PROCESS_DOCUMENT_FROM_BYTESIO%TIMING_KEY_PROCESS_DOCUMENT_FROM_FILETIMING_KEY_QPDF_PROCESSTIMING_KEY_ROTATE_CONTENTSTIMING_KEY_SANITISE_CONTENTSTIMING_KEY_SANITIZE_CELLSTIMING_KEY_SANITIZE_ORIENTATIONTIMING_KEY_TO_JSON_PAGETIMING_PREFIX_DECODE_FONTTIMING_PREFIX_DECODE_GRPHTIMING_PREFIX_DECODE_PAGETIMING_PREFIX_DECODE_XOBJECTTIMING_PREFIX_DECODING_PAGEDecodePageConfigPageDecodeResultPdfPageDecoderRenderConfigget_decode_page_timing_keysget_static_timing_keysis_static_timing_key
pdf_parserthreaded_pdf_parserthreaded_pdf_rendererc                   p    e Zd ZU dZ ed      Zeed<   dZe	dz  ed<   dZ
e	dz  ed<   dZed    dz  ed<   y)	PdfTocEntrya  PDF table of contents entry (recursive structure).

    Attributes:
        title: The text of the TOC entry
        level: Nesting level in the hierarchy (0 for top level)
        page: Page number this entry points to (optional)
        children: Nested TOC entries (optional)
    allow)extratitleNlevelpagechildren)__name__
__module____qualname____doc__r!   model_configstr__annotations__rN   intrO   rP   r        K/home/agent/.local/lib/python3.12/site-packages/docling_parse/pdf_parser.pyrJ   rJ   M   sH     G,LJE3:D#*+/Hd=!D(/rZ   rJ   c                       e Zd ZU dZ edd      ZdZeee	f   dz  e
d<   dZedz  e
d<   dZedz  e
d<   dZee   dz  e
d	<   y)
PdfAnnotationsa  PDF document annotations including form fields, language, metadata, and table of contents.

    Attributes:
        form: AcroForm data containing interactive form fields (raw dict structure). None if no forms present.
        language: Document language code (e.g., 'en-US', 'fr-FR'). None if not specified.
        meta_xml: XMP metadata as XML string. None if no metadata present.
        table_of_contents: Document outline/bookmark structure as list of entries. None if no TOC.
    TrK   )validate_assignmentrL   Nformlanguagemeta_xmltable_of_contents)rQ   rR   rS   rT   r!   rU   r_   r   rV   r   rW   r`   ra   rb   r   rJ   rY   rZ   r[   r]   r]   _   s]     $gFL"&D$sCx.4
&HcDjHcDj26tK(4/6rZ   r]   c                      e Zd ZU dZ ed      Zi Zeee	f   e
d<   i Zeeee	   f   e
d<   de	fdZdded	e	de	fd
Zdedee	   fdZdedefdZdede	fdZd Zd Zdeee	f   fdZdeee	f   fdZedefd       Zedee   fd       Zy)Timingsa  Timing information from PDF page parsing.

    Provides detailed timing breakdown of the parsing process, useful for
    performance analysis and optimization.

    Attributes:
        data: Dictionary mapping operation names to elapsed time in seconds (summed).
            Common keys include:
            - 'decode_page': Total page decoding time
            - 'decode_dimensions': Time to parse page dimensions
            - 'decode_resources': Time to decode page resources (fonts, etc.)
            - 'decode_contents': Time to decode page content streams
            - 'decode_annots': Time to decode annotations
            - 'create_word_cells': Time to create word cells (if requested)
            - 'create_line_cells': Time to create line cells (if requested)
        raw_data: Dictionary mapping operation names to list of elapsed times.
            This is useful when an operation is repeated multiple times
            (e.g., decoding multiple fonts) and you want to see individual timings.
    T)r^   dataraw_datareturnc                 H    t        | j                  j                               S )z%Get total time across all operations.)sumre   valuesselfs    r[   totalzTimings.total   s    499##%&&rZ   keydefaultc                 :    | j                   j                  ||      S )z9Get timing for a specific operation (summed if repeated).)re   get)rl   rn   ro   s      r[   rq   zTimings.get   s    yy}}S'**rZ   c                 :    | j                   j                  |g       S )z/Get all timing values for a specific operation.)rf   rq   rl   rn   s     r[   get_allzTimings.get_all   s    }}  b))rZ   c                 L    t        | j                  j                  |g             S )z/Get the number of times an operation was timed.)lenrf   rq   rs   s     r[   	get_countzTimings.get_count   s    4==$$S"-..rZ   c                      | j                   |   S N)re   rs   s     r[   __getitem__zTimings.__getitem__   s    yy~rZ   c                 6    | j                   j                         S )zGet all timing operation names.)re   keysrk   s    r[   r|   zTimings.keys   s    yy~~rZ   c                 6    | j                   j                         S )z.Get all timing items as (name, seconds) pairs.)re   itemsrk   s    r[   r~   zTimings.items   s    yy  rZ   c                     | j                   j                         D ci c]  \  }}t        |      s|| c}}S c c}}w )z'Get only static (constant) timing keys.re   r~   rE   rl   kvs      r[   get_static_timingszTimings.get_static_timings   s1    !%!2NA6J16M1NNN   ;;c                     | j                   j                         D ci c]  \  }}t        |      r|| c}}S c c}}w )zGet only dynamic timing keys.r   r   s      r[   get_dynamic_timingszTimings.get_dynamic_timings   s1    !%!2RA:Nq:Q1RRRr   c                      t               S )z Get all static timing key names.)rD   rY   rZ   r[   static_keyszTimings.static_keys   s     &''rZ   c                      t               S )zNGet timing keys used in decode_page method (in order, excluding global timer).)rC   rY   rZ   r[   decode_page_keyszTimings.decode_page_keys   s     +,,rZ   N)g        )rQ   rR   rS   rT   r!   rU   re   r   rV   floatrW   rf   r   rm   rq   rt   rX   rw   rz   r|   r~   r   r   staticmethodsetr   r   rY   rZ   r[   rd   rd   q   s   ( $7LD$sEz
')Hd3U#$)'u '+s +U +U +*3 *4; */S /S /s u  !ODe$4 OST#u*%5 S ( ( ( -d3i - -rZ   rd   c            	       "   e Zd Zej                  fdddedefdZdefdZde	fdZ
de	fd	Zd
eeef   fdZdefdZdedz  fdZdedz  fdZdddedz  deeeef      fdZdedee   fdZdee   dee   fdZdedz  fdZdddededz  defdZ dddededz  deee!f   fdZ"dededeee!f   fdZ#d%dedz  fdZ$de%fdZ&dee'e(e)f      fdZ*dee+   fdZ,dee-   fd Z.dee/   fd!Z0dee1   fd"Z2dedefd#Z3dededefd$Z4y)&PdfDocumentparserrF   rn   boundary_typec                 f    || _         || _        || _        i | _        d | _        d | _        d | _        y ry   )_parser_key_boundary_type_pages_toc_meta_annotations)rl   r   rn   r   s       r[   __init__zPdfDocument.__init__   s7     $*	+35/3	)-
37rZ   rg   c                 ^    t               }| j                  j                  |_        d|_        |S NF)r?   r   valuepage_boundarydo_sanitization)rl   configs     r[   _default_configzPdfDocument._default_config   s+    !##2288!&rZ   c                 N    | j                   j                  | j                        S )Nrn   )r   	is_loadedr   rk   s    r[   r   zPdfDocument.is_loaded   s    ||%%$))%44rZ   c                     | j                   j                          | j                         r%| j                  j	                  | j
                        S yr   )r   clearr   r   unload_documentr   rk   s    r[   unloadzPdfDocument.unload   s8    >><<//		::rZ   
page_rangec                     t        |d   |d         D ]d  }|dk  rt        j                  d       || j                  v s,|dz
  }| j                  j                  | j                  |       | j                  |= f y)z3unload page in range [page_range[0], page_range[1][r      zpage_no should always be >=1!)rn   rO   N)range_logerrorr   r   unload_document_pager   )rl   r   page_nopage_nums       r[   unload_pageszPdfDocument.unload_pages   sp    Z]JqM: 	)G{

:;$++%"Q;11diih1OKK(	)rZ   c                     | j                         r&| j                  j                  | j                        S t	        d      )Nr   This document is not loaded.)r   r   number_of_pagesr   RuntimeErrorrk   s    r[   r   zPdfDocument.number_of_pages   s4    >><<//DII/>>=>>rZ   Nc                 ^   | j                   | j                   S | j                         r{| j                  j                  | j                        }|| j                   S t        |t              r+t        |      | _         | j                   j                          | j                   S t        d      )Nr   )xmlr   )
r   r   r   get_meta_xmlr   
isinstancerV   r   
initialiser   )rl   r   s     r[   get_metazPdfDocument.get_meta   s    ::!::>>,,++		+:C{zz!#s#(S1


%%':: =>>rZ   c                 L   | j                         r| j                  j                  | j                        }|| j                  S | j                  | j                  S t        d      | _        | j                  |      | j                  _        | j                  S t        d      )Nr   z<root>texttocr   )	r   r   get_table_of_contentsr   r   r   _to_table_of_contentsrP   r   )rl   r   s     r[   r   z!PdfDocument.get_table_of_contents   s    >>,,444CC{yy yy$yy *9DI!%!;!;!;!DDII99=>>rZ   r   r   c             #      K   || j                         }t        | j                               D ]  }|dz   | j                  |dz   |      f ! y wNr   r   r   r   r   get_pagerl   r   r   s      r[   iterate_pageszPdfDocument.iterate_pages  sd     
 >))+FT1134 	G!aK!   	s   AAr   c                     g }|D ]@  }t        |d         }d|v r| j                  |d         |_        |j                  |       B |S )NrM   r   rP   r   )r   r   rP   append)rl   r   resultitemsubtocs        r[   r   z!PdfDocument._to_table_of_contents   sY     	"D'T'];FT!"&"<"<jAQ"<"RMM&!		" rZ   toc_listc                    g }|D ]y  }t        |j                  dd      |j                  d      |j                  d            }|j                  d      r| j                  |d         |_        |j	                  |       { |S )z1Convert raw TOC dict list to PdfTocEntry objects.rM    rN   rO   )rM   rN   rO   rP   )rJ   rq   _to_pdf_toc_entryrP   r   )rl   r   r   r   entrys        r[   r   zPdfDocument._to_pdf_toc_entry+  s~     	!Dhhw+hhw'XXf%E
 xx
#!%!7!7Z8H!IMM% 	! rZ   c                    | j                   | j                   S | j                         r| j                  j                  | j                        }|| j                   S d}|j                  d      r| j                  |d         }t        |j                  d      |j                  d      |j                  d      |      | _         | j                   S t        d      )	a  Get document annotations including form fields, language, metadata, and TOC.

        Returns:
            Optional[PdfAnnotations]: Annotations object with form, language, meta_xml,
                and table_of_contents fields. None if document is not loaded or no annotations.
        Nr   rb   r_   r`   ra   )r_   r`   ra   rb   r   )	r   r   r   get_annotationsr   rq   r   r]   r   )rl   annots_dicttoc_entriess      r[   r   zPdfDocument.get_annotations9  s     ($$$>>,,664996EK"((( K23"44[AT5UV . __V,$4$4"-	!D $$$=>>rZ   r   c                L    || j                         }| j                  ||      S )z.Get page using typed API (zero-copy from C++).r   )r   _get_page_typedrl   r   r   s      r[   r   zPdfDocument.get_pageY  s-     >))+F##GF#;;rZ   c          	          || j                         }d|cxk  r| j                         k  s/n t        d| d| j                   d| j                          d      | j	                  ||      S )a  Get page along with timing information.

        Similar to get_page() but also returns timing data from the parsing process.
        Useful for performance analysis and benchmarking.

        Note: This method does NOT use the page cache to ensure fresh timing data.

        Args:
            page_no: Page number (1-indexed).
            config: Page decoding configuration. If None, uses default config.

        Returns:
            Tuple of (SegmentedPdfPage, Timings) with the parsed page data and timing info.
        r   incorrect page_no: 	 for key= (min:1, max:)r   )r   r   
ValueErrorr   _get_page_with_timings_typedr   s      r[   get_page_with_timingsz!PdfDocument.get_page_with_timingsd  s    ( >))+FW6 4 4 66%gYi		{ C#3356a9 
 000HHrZ   c                $   | j                   j                  | j                  |dz
  |      }|t        d|       | j	                  ||      }|j                         }|j                         }t        t        |      t        |            }||fS )z&Get page with timings using typed API.r   rn   rO   r   Failed to decode page page_decoderr   )re   rf   )	r   get_page_decoderr   r   _to_segmented_page_from_decoderget_timingsget_timings_rawrd   dict)rl   r   r   r   segmented_pagetimings_dictraw_timings_dicttimingss           r[   r   z(PdfDocument._get_page_with_timings_typed  s     ||44		1 5 
 5gY?@@==% > 
 $//1'779tL1DAQ<RSw&&rZ   c                     || j                         }t        d| j                         dz         D ]  }| j                  ||        y r   r   r   s      r[   load_all_pageszPdfDocument.load_all_pages  sI    >))+FQ 4 4 6 :; 	2GMM'&M1	2rZ   c                 "   |j                         }|j                         }|j                         }|}t        |d   |d   |d   |d   |d   |d   |d   |d   t        j
                  	      }t        |d   |d   |d   |d   t        j
                        }t        |d   |d   |d   |d   t        j
                        }t        |d   |d   |d   |d   t        j
                        }	t        |t        | j                        ||||	|	|	      S )z2Convert typed PdfPageDimension to PdfPageGeometry.r   r         )	r_x0r_y0r_x1r_y1r_x2r_y2r_x3r_y3coord_origin)lbrtr   )angler   rectart_bbox
media_bbox	trim_bbox	crop_bbox
bleed_bbox)
get_crop_bboxget_media_bbox	get_angler   r   
BOTTOMLEFTr   r   r   r   )
rl   page_dimr
  r  r  bboxr  art_bbox_objmedia_bbox_objcrop_bbox_objs
             r[   _to_page_geometry_from_decoderz*PdfDocument._to_page_geometry_from_decoder  sC   **,	,,.
""$  aaaaaaaa$//

 #llll$//
 %mmmm$//
 $llll$//
 -d.A.AB!%##$	
 		
rZ   c                    g }t        |      D ]  \  }}t        |j                  |j                  |j                  |j
                  |j                  |j                  |j                  |j                        }|j                  t        ||j                  |j                  |j                  |j                  |j                  |j                   rt"        j$                  nt"        j&                  ||j(                  	              |S )z@Convert typed PdfCells container to list of PdfTextCell objects.r   r   r   r   r   r   r   r   )	r  r   origfont_key	font_namewidgettext_directionindexrendering_mode)	enumerater   r   r   r   r   r   r   r   r   r   r   r   r  r  r  left_to_rightr   LEFT_TO_RIGHTRIGHT_TO_LEFTr  )rl   cells_containerr   indcellr  s         r[   _to_cells_from_decoderz"PdfDocument._to_cells_from_decoder  s     68"?3 	IC$YYYYYYYYYYYYYYYY	D MM!]]"nn;;  -- &33*88#'#6#6	< rZ   c                 0   g }t        |      D ]  \  }}|j                         }|j                         }|j                         }	 t	        dt        |      d      D ]3  }||dz      }	||dz      }
g }t	        |	|
      D ]#  }|j                  t        ||   ||                % |j                         }|j                         }t        ||||j                         |j                         |j                         |j                         |j                         |j!                         t#        |j%                               |j'                         t)        |d   |d   |d         t)        |d   |d   |d               }|j                  |       6  |S )z>Convert typed PdfShapes container to list of PdfShape objects.r   r   r   )r  gr  )r  	parent_idpointshas_graphics_state
line_widthmiter_limitline_cap	line_join
dash_phase
dash_arrayflatnessrgb_strokingrgb_filling)r  get_xget_yget_ir   rv   r   r   get_rgb_stroking_opsget_rgb_filling_opsr   get_has_graphics_stateget_line_widthget_miter_limitget_line_capget_line_joinget_dash_phaselistget_dash_arrayget_flatnessr   )rl   shapes_containerr   r$  shapex_coordsy_coordsindicespair_idxi0i1r*  r   rgb_srgb_f	pdf_shapes                   r[   _to_shapes_from_decoderz#PdfDocument._to_shapes_from_decoder   s   !##$45 (	)JC{{}H{{}HkkmG "!S\15 )!(Q,/!(Q,/(*r2 EAMM'(1+x{"CDE 224113$&!','C'C'E$335 % 5 5 7"//1#113$335#E$8$8$:;"//1!*U1XqU1X!N )E!HaE!H M	 i(5)(	)T rZ   c                    g }t        |      D ]  \  }}t        |j                  |j                  |j                  |j                  |j                  |j
                  |j                  |j
                        }|j                  t        |||j                  xs d|j                  xs d|j                  xs d|j                  xs d              |S )z@Convert typed PdfWidgets container to list of PdfWidget objects.r  N)r  r  widget_textwidget_descriptionwidget_field_namewidget_field_type)r  r   x0y0x1y1r   r   r   description
field_name
field_type)rl   widgets_containerr   r$  r  r  s         r[   _to_widgets_from_decoderz$PdfDocument._to_widgets_from_decoder0  s    "$$%67 	KC$YYYYYYYYYYYYYYYY	D MM & 3t'-'9'9'AT&,&7&7&?4&,&7&7&?4		, rZ   c                 L   g }t        |      D ]  \  }}t        |j                  |j                  |j                  |j                  |j                  |j
                  |j                  |j
                        }|j                  t        |||j                  xs d              |S )zFConvert typed PdfHyperlinks container to list of PdfHyperlink objects.r  N)r  r  uri)	r  r   rT  rU  rV  rW  r   r   r^  )rl   hyperlinks_containerr   r$  	hyperlinkr  s         r[   _to_hyperlinks_from_decoderz'PdfDocument._to_hyperlinks_from_decoderL  s    %''(<= 	NC$\\\\\\\\\\\\\\\\	D MM!-	& rZ   c                 0   g }t        |      D ]  \  }}t        |j                  |j                  |j                  |j                  |j                  |j
                  |j                  |j
                        }d}t        j                  }	 |j                         }|r0t        |      dkD  r!|j                         }	d}
|	dv rt        j                  t        |            }
nO|	dv rK|j                         }|j                  }|j                   }|dkD  r|dkD  rt        j"                  |||f|      }
|
|
j$                  dk7  r|
j'                  d      }
t)        |j                  |j                  z
        }|dkD  r+|j                  dkD  rt+        |j                  dz  |z        }nd}t-        j.                  |
|	      }t        j0                  }t9        ||d||      }|j;                  |        |S # t2        $ r t4        j7                  d
       Y Fw xY w)zDConvert typed PdfImages container to list of BitmapResource objects.r  Nr   )jpegjp2)rawjbig2RGBAg      R@H   )dpizDFailed to extract image data for bitmap, falling back to placeholder)r  r  r^  imagemode)r  r   rT  rU  rV  rW  r   PLACEHOLDERget_image_as_bytesrv   get_image_formatPILImageopenr   get_pil_modeimage_widthimage_height	frombytesrk  convertabsroundr   from_pilEMBEDDED	Exceptionr   debugr   r   )rl   images_containerr   r$  rj  r  	image_refrk  image_bytesfmt	pil_imagepil_modewh
bbox_widthri  bitmaps                    r[   !_to_bitmap_resources_from_decoderz-PdfDocument._to_bitmap_resources_from_decodere  s    (*#$45 8	"JC$XXXXXXXXXXXXXXXX	D I++D$#6683{#3a#7002C7;Io-$,MM'+2F$G	 00#(#5#5#7!--!..q5QU(0(:(: (1a&+)I !,$>>V3(1(9(9&(AI &)EHH)<%=
%>e.?.?!.C"'(9(9D(@:(M"NC"$C$,$5$5iS$I	+44 $$idF MM&!q8	"t   

Zs   EG44HHc                   | j                  |j                               }| j                  |j                               }| j	                  |j                               }| j                  |j                               }| j                  |j                               }t        | j                  |j                               |g g t        |      dkD  ||||	      }|j                         rA| j                  |j                               |_        t        |j                         dkD  |_        |j%                         rA| j                  |j'                               |_        t        |j(                        dkD  |_        |S )zBConvert typed PdfPageDecoder to SegmentedPdfPage (zero-copy path).r   )		dimension
char_cells
word_cellstextline_cells	has_charsbitmap_resourcesshapeswidgets
hyperlinks)r&  get_char_cellsrN  get_page_shapesr\  get_page_widgetsra  get_page_hyperlinksr  get_page_imagesr   r  get_page_dimensionrv   has_word_cellsget_word_cellsr  	has_wordshas_line_cellsget_line_cellsr  	has_lines)	rl   r   r   r  r  r  r  r  r   s	            r[   r   z+PdfDocument._to_segmented_page_from_decoder  se    001L1L1NO
--l.J.J.LM//0M0M0OP55,,.

  AA((*
 *99//1 "*o)-!
 &&((,(C(C++-)N% (+>+D+D'E'IN$&&(,0,G,G++--N) (+>+H+H'IA'MN$rZ   c          	         || j                   j                         v r| j                   |   S d|cxk  r| j                         k  rmn nj| j                  j	                  | j
                  |dz
  |      }|t        d|       | j                  ||      | j                   |<   | j                   |   S t        d| d| j
                   d| j                          d      )	a  Get page using typed API (zero-copy from C++, faster than get_page).

        This method uses direct typed bindings to C++ objects, avoiding JSON
        serialization/deserialization overhead. Use this for better performance.

        Args:
            page_no: Page number (1-indexed).
            config: Page decoding configuration.

        Returns:
            SegmentedPdfPage with the parsed page data.
        r   r   r   r   r   r   r   r   )r   r|   r   r   r   r   r   r   )rl   r   r   r   s       r[   r   zPdfDocument._get_page_typed  s    $ dkk&&((;;w''14//11<<88IIq[ 9 L # #9'!CDD#'#G#G) $H $DKK  ;;w''!')DII;mDL`L`LbKccde
 	
rZ   ry   )5rQ   rR   rS   r   CROP_BOXrV   r   r?   r   boolr   r   tuplerX   r   r   r   r   r   r   r   r
   r   r   r   r   r   r   rJ   r   r]   r   r   rd   r   r   r   r   r  r   r   r   r&  r   rN  r   r\  r   ra  r   r  r   r   rY   rZ   r[   r   r      s`   
 .A-I-I	88 8 +	8!1 54 5 
)uS#X 
)? ??+, ?(?'9D'@ ?( +/ !4' 
%--.	/	 	 	$7I2J 	$t* k9J ?$!6 ?H +/		<	< !4'		<
 
	< +/	II !4'	I
 
(	)I>'' !	'
 
(	)'82%5%< 23
/ 3
j$	eK)*	+$L.4> .`T)_ 84CU 2@	n	@D, !	,
 
,\'
'
 !	'

 
'
rZ   r   c                       e Zd ZddefdZdefdZdee   fdZdej                  dfde
eeef   d	ed
ededz  def
dZ	 ddedededz  defdZdededefdZy)DoclingPdfParserloglevelc                 &    t        |      | _        y)z
        Set the log level using a string label.

        Parameters:
            level (str): Logging level as a string.
                     One of ['fatal', 'error', 'warning', 'info']
        rN   N)rF   r   rl   r  s     r[   r   zDoclingPdfParser.__init__   s     !x0rZ   c                 <    | j                   j                  |       y)zSet the log level using a string label.

        Parameters:
        level (str): Logging level as a string.
                     One of ['fatal', 'error', 'warning', 'info']
           )")
        r  N)r   set_loglevel_with_labelr  s     r[   set_loglevelzDoclingPdfParser.set_loglevel
  s     	++(+;rZ   rg   c                 6    | j                   j                         S )zList the keys of the loaded documents.

        Returns:
            List[str]: A list of keys for the currently loaded documents.
        )r   list_loaded_keysrk   s    r[   r  z!DoclingPdfParser.list_loaded_keys  s     {{++--rZ   TNpath_or_streamlazyr   passwordc                 D   t        |t              rt        |      }t        |t              r#d|}| j                  |t        |      |      }nt        |t              rt        j                  d      }|j                  d      x}r%|j                  |       |j                  d      x}r%|j                  d       |j                         }	d|	 }| j                  ||      }r,t        | j                  |      }
|s|
j                          |
S t        d	       )
Nkey=rn   filenamer  Fusedforsecurity    r   )rn   re   )r   rn   r   !Failed to load document with key )r   rV   r   _load_documentr   hashlibsha256readupdateseek	hexdigest_load_document_from_bytesior   r   r   r   )rl   r  r  r   r  rn   successhasherchunkhash
result_docs              r[   loadzDoclingPdfParser.load  s"    nc*!.1Nnd+*+C))#n"5 * G 0^^E:F)..t44%4e$ *..t44%4"##%D-C663^6TG${{=J ))+!B3%HIIrZ   rn   r  c                 \    | j                   j                  ||j                  d      |      S )a  Load a document by key and filename.

        Parameters:
            key (str): The unique key to identify the document.
            filename (str): The path to the document file to load.
            password (str, optional): Optional password for password-protected files

        Returns:
            bool: True if the document was successfully loaded, False otherwise.)")
        utf8r  )r   load_documentencode)rl   rn   r  r  s       r[   r  zDoclingPdfParser._load_documentC  s0     {{((hoof5 ) 
 	
rZ   re   c                 <    | j                   j                  ||      S )aH  Load a document by key from a BytesIO-like object.

        Parameters:
            key (str): The unique key to identify the document.
             bytes_io (Any): A BytesIO-like object containing the document data.

        Returns:
             bool: True if the document was successfully loaded, False otherwise.)")
        )rn   bytes_io)r   load_document_from_bytesio)rl   rn   re   s      r[   r  z,DoclingPdfParser._load_document_from_bytesioT  s     {{55#5MMrZ   )fatalry   )rQ   rR   rS   rV   r   r  r   r  r   r  r   r   r   r  r   r  r  r  rY   rZ   r[   r  r    s    1 1<S <.$s) . -@-I-I#%Jc401%J %J +	%J
 *%J 
%JP ?C

"%
14t
	
"
Ns 
N' 
Nd 
NrZ   r  c                   N    e Zd ZU dZ ed      ZdZeed<   dZ	e
ed<   dZe
ed	<   y
)ThreadedPdfParserConfiga  Configuration for the threaded PDF parser.

    Attributes:
        loglevel: Logging level ('fatal', 'error', 'warning', 'info').
        threads: Number of worker threads for parallel page decoding.
        max_concurrent_results: Maximum results buffered before workers pause.
    Tarbitrary_types_allowedr  r     threads    max_concurrent_resultsNrQ   rR   rS   rT   r!   rU   r  rV   rW   r  rX   r  rY   rZ   r[   r  r  a  2     d;LHcGS"$C$rZ   r  c                   p    e Zd ZdZ	 	 ddedz  dedz  fdZ	 ddeee	e
f   dedz  defd	Zdefd
ZddZy)DoclingThreadedPdfParseraj  Threaded PDF parser that decodes pages from multiple documents in parallel.

    Usage::

        parser_config = ThreadedPdfParserConfig(loglevel="fatal", threads=4, max_concurrent_results=32)
        decode_config = DecodePageConfig()

        parser = DoclingThreadedPdfParser(parser_config=parser_config, decode_config=decode_config)

        for source in sources:
            parser.load(source)

        while parser.has_tasks():
            task = parser.get_task()

            if task.success:
                page_decoder, timings = task.get()
            else:
                error_msg = task.error()
    Nparser_configdecode_configc                     |
t               }|
t               }t        |j                  |j                  |j
                  |      | _        y )N)r  num_threadsr  r   )r  r?   rG   r  r  r  r   )rl   r  r  s      r[   r   z!DoclingThreadedPdfParser.__init__  sJ    
  35M ,.M*"++%--#0#G#G 	
rZ   r  r  rg   c                 h   t        |t              rt        |      }t        |t              r<d|}| j                  j	                  |t        |      j                  d      |      }nt        |t              rt        j                  d      }|j                  d      x}r%|j                  |       |j                  d      x}r%|j                  d       |j                         }d| }| j                  j                  |||      }nt        d	t        |             |st!        d
|       |S )zLoad a document for parallel processing.

        Parameters:
            path_or_stream: File path or BytesIO object.
            password: Optional password for protected files.

        Returns:
            str: The document key.
        r  r  r  Fr  r  r   rn   r  r  $Expected str, Path, or BytesIO, got r  )r   rV   r   r   r  r  r   r  r  r  r  r  r  r  	TypeErrortyper   rl   r  r  rn   r  r  r  hash_vals           r[   r  zDoclingThreadedPdfParser.load  s7    nc*!.1Nnd+*+Cll00#n"5"<"<V"Dx 1 G 0^^E:F)..t44%4e$ *..t44%4"'')H
#Cll==.8 > G 6tN7K6LM  !B3%HII
rZ   c                 6    | j                   j                         S zCheck if there are remaining tasks to consume.

        On first call, builds the task queue and starts worker threads.

        Returns:
            bool: True if there are remaining results to consume.
        )r   	has_tasksrk   s    r[   r  z"DoclingThreadedPdfParser.has_tasks  s     ||%%''rZ   c                 6    | j                   j                         S )a'  Get the next completed page decode result.

        Blocks until a result is available.

        Returns:
            PageDecodeResult: The result with doc_key, page_number, success flag.
                Use task.get() to get (PdfPageDecoder, timings) or task.error() for error message.
        )r   get_taskrk   s    r[   r  z!DoclingThreadedPdfParser.get_task  s     ||$$&&rZ   )NNry   )rg   r@   )rQ   rR   rS   rT   r  r?   r   r   rV   r   r   r  r  r  r  rY   rZ   r[   r  r  q  sx    . 9=15
.5
 ($.
(  $)c401) *) 
	)V(4 (	'rZ   r  c                   N    e Zd ZU dZ ed      ZdZeed<   dZ	e
ed<   dZe
ed	<   y
)ThreadedPdfRendererConfiga  Configuration for the threaded PDF renderer.

    Attributes:
        loglevel: Logging level ('fatal', 'error', 'warning', 'info').
        threads: Number of worker threads for parallel page rendering.
        max_concurrent_results: Maximum results buffered before workers pause.
    Tr  r  r  r  r  r  r  Nr  rY   rZ   r[   r  r    r  rZ   r  c                   h    e Zd ZdZd ZdefdZdeee	ee
f   f   fdZdej                  dz  fdZy)PdfPageRenderResultzWrapper around a raw C++ PageRenderResult providing PIL image conversion.

    Attributes:
        doc_key: Document key the page belongs to.
        page_number: 0-indexed page number.
        success: Whether rendering succeeded.
    c                 x    || _         |j                  | _        |j                  | _        |j                  | _        y ry   )_rawdoc_keypage_numberr  )rl   re  s     r[   r   zPdfPageRenderResult.__init__  s+    	KK # [[rZ   rg   c                 J    | j                   s| j                  j                  S dS )zEReturn the error message if rendering failed, empty string otherwise.r   )r  r  error_messagerk   s    r[   r   zPdfPageRenderResult.error  s    .2lltyy&&BBrZ   c                 6    | j                   j                         S )aA  Return (page_decoder, timings) for the rendered page.

        Delegates to the underlying PageDecodeResult.get() so that render
        results can be used interchangeably with parse results when accessing
        the decoded page data.

        Raises:
            RuntimeError: If the task was not successful.
        )r  rq   rk   s    r[   rq   zPdfPageRenderResult.get  s     yy}}rZ   Nc           	          | j                   sy| j                  j                         }|sy| j                  j                  \  }}}t	        j
                  d||f|dddd      S )zConvert rendered pixel data to a PIL RGBA Image.

        Returns:
            PIL.Image.Image in RGBA mode, or None if rendering failed.
        Nrg  re  r   r   )r  r  	get_imageimage_shapero  
frombuffer)rl   	raw_bytesr  r  _s        r[   r  zPdfPageRenderResult.get_image  s]     ||II'')	))''1a""6Aq69eVQPQRRrZ   )rQ   rR   rS   rT   r   rV   r   r
   rA   r   r   rq   ro  r   r  rY   rZ   r[   r  r    sP    )Cs C
U>4U
+;;< 
S8>>D0 SrZ   r  c                       e Zd ZdZ	 	 	 ddedz  dedz  dedz  fdZ	 ddee	e
ef   de	dz  d	e	fd
Zd	efdZd	efdZy)DoclingThreadedPdfRendereran  Threaded PDF renderer that decodes and renders pages from multiple documents in parallel.

    Each result contains both the decoded page data (accessible via the page_decoder)
    and the rendered RGBA image, produced in a single pass.

    Usage::

        render_config = RenderConfig()
        decode_config = DecodePageConfig()
        renderer_config = ThreadedPdfRendererConfig(threads=4)

        renderer = DoclingThreadedPdfRenderer(
            renderer_config=renderer_config,
            decode_config=decode_config,
            render_config=render_config,
        )

        for source in sources:
            renderer.load(source)

        while renderer.has_tasks():
            result = renderer.get_task()
            if result.success:
                image = result.get_image()   # PIL RGBA Image
            else:
                print(result.error())
    Nrenderer_configr  render_configc                     |
t               }|
t               }|
t               }t        |j                  |j
                  |j                  ||      | _        y )N)r  r  r  r  r  )r  r?   rB   rH   r  r  r  	_renderer)rl   r  r  r  s       r[   r   z#DoclingThreadedPdfRenderer.__init__;  sZ     "79O ,.M (NM.$--'//#2#I#I''
rZ   r  r  rg   c                 h   t        |t              rt        |      }t        |t              r<d|}| j                  j	                  |t        |      j                  d      |      }nt        |t              rt        j                  d      }|j                  d      x}r%|j                  |       |j                  d      x}r%|j                  d       |j                         }d| }| j                  j                  |||      }nt        d	t        |             |st!        d
|       |S )zLoad a document for parallel rendering.

        Parameters:
            path_or_stream: File path or BytesIO object.
            password: Optional password for protected files.

        Returns:
            str: The document key.
        r  r  r  Fr  r  r   r  r  r  )r   rV   r   r  r  r  r   r  r  r  r  r  r  r  r  r  r   r  s           r[   r  zDoclingThreadedPdfRenderer.loadP  s8    nc*!.1Nnd+*+Cnn22#n"5"<"<V"Dx 3 G 0^^E:F)..t44%4e$ *..t44%4"'')H
#Cnn??.8 @ G 6tN7K6LM  !B3%HII
rZ   c                 6    | j                   j                         S r  )r  r  rk   s    r[   r  z$DoclingThreadedPdfRenderer.has_tasks{  s     ~~''))rZ   c                 H    t        | j                  j                               S )zGet the next completed page render result.

        Blocks until a result is available.

        Returns:
            PdfPageRenderResult: wraps doc_key, page_number, success, and get_image().
        )r  r  r  rk   s    r[   r  z#DoclingThreadedPdfRenderer.get_task  s     #4>>#:#:#<==rZ   )NNNry   )rQ   rR   rS   rT   r  r?   rB   r   r   rV   r   r   r  r  r  r  r  rY   rZ   r[   r  r    s    < =A15-1	
2T9
 ($.
 $d*	
0  $)c401) *) 
	)V*4 *>- >rZ   r  c                       e Zd Zdddeeef   dededede	de
dz  fd	ZddZddd
e
fdZddZd
efdZded
efdZd
eeeef      fdZd
efdZy)PdfRenderDocumentNr  r  
parser_docr  r  r  r  c                f    || _         || _        || _        || _        || _        || _        i | _        y ry   )_path_or_stream_parser_doc_renderer_config_decode_config_render_config	_passwordr   )rl   r  r  r  r  r  r  s          r[   r   zPdfRenderDocument.__init__  s:      .% /++!68rZ   rg   r  c                 Z    t        | j                  | j                  | j                        S )N)r  r  r  )r  r
  r  r  rk   s    r[   _make_rendererz PdfRenderDocument._make_renderer  s*    ) 11----
 	
rZ   rendererc                     t        | j                  t              r'|j                  | j                  | j                        S |j                  t        | j                        | j                        S )Nr  )r   r  r   r  r  r   )rl   r  s     r[   _load_sourcezPdfRenderDocument._load_source  sQ    d**D1==!5!5=OO}}WT%9%9:T^^}TTrZ   c                    t        | j                        | j                         k(  ry | j                         }| j	                  |      }|j                         r|j                         }|j                  |k7  r0|j                  s,t        d|j                  dz    d|j                                || j                  |j                  dz   <   |j                         ry y )NzFailed to render page r   z: )rv   r   r   r  r  r  r  r  r  r   r  r   )rl   r  rn   r   s       r[   _render_all_pagesz#PdfRenderDocument._render_all_pages  s    t{{t3355&&()  "&&(F~~$>>",V-?-?!-C,DBv||~FVW  39DKK**Q./   "rZ   c                 6    | j                   j                         S ry   )r	  r   rk   s    r[   r   z!PdfRenderDocument.number_of_pages  s    //11rZ   r   c                     d|cxk  r| j                         k  s"n t        d| d| j                          d      || j                  vr| j                          | j                  |   S )Nr   r   r   r   )r   r   r   r  rl   r   s     r[   r   zPdfRenderDocument.get_page  sk    W6 4 4 66%gYmD<P<P<R;SSTU  $++%""${{7##rZ   c              #      K   | j                          t        d| j                         dz         D ]  }|| j                  |   f  y w)Nr   )r  r   r   r   r  s     r[   r   zPdfRenderDocument.iterate_pages  sJ      Q 4 4 6 :; 	0G4;;w///	0s   AA	c                 j    | j                   j                          | j                  j                         S ry   )r   r   r	  r   rk   s    r[   r   zPdfRenderDocument.unload  s'    &&((rZ   )rg   r  )rg   N)rQ   rR   rS   r   r   bytesr   r  r?   rB   rV   r   r  r  r  rX   r   r  r   r   r
   r   r  r   rY   rZ   r[   r  r    s      $9 dEk*9  	9
 39 (9 $9 *9$
U%A Uc U9"2 2	$ 	$(; 	$0xc3F.F(GH 0
) )rZ   r  c                   ~    e Zd Z	 	 	 ddededz  dedz  fdZdej                  dfde	ee
ef   ded	ed
edz  def
dZy)DoclingPdfRendererNr  r  r  c                     || _         t        |      | _        t        |dd      | _        |xs
 t               | _        |xs
 t               | _        y )N)r  r   )r  r  r  )		_loglevelr  r   r  r
  r?   r  rB   r  )rl   r  r  r  s       r[   r   zDoclingPdfRenderer.__init__  sO     "': 9#$!

 ,A/?/A+=|~rZ   Tr  r  r   r  rg   c                 l   | j                   j                  ||||      }t        |t              rt	        |      }nKt        |t              r|}n8t        |t
              r|j                         }nt        dt        |             t        ||| j                  | j                  | j                  |      S )N)r  r  r   r  r  )r  r  r  r  r  r  )r   r  r   rV   r   r   getvaluer  r  r  r
  r  r  )rl   r  r  r   r  r  sources          r[   r  zDoclingPdfRenderer.load  s     \\&&)'	 ' 

 nc*)-n)=F-#F0#,,.F6tN7K6LM  !!! 11----
 	
rZ   )r  NN)rQ   rR   rS   rV   r?   rB   r   r   r  r   r   r   r  r  r  rY   rZ   r[   r  r    s      15-1	>> ($.> $d*	>& -@-I-I# 
c401 
  
 +	 

 * 
 
 
rZ   r  )brT   r  loggingior   pathlibr   typingr   r   r   r   r	   r
   r   docling_core.types.doc.baser   r   r   docling_core.types.doc.documentr   docling_core.types.doc.pager   r   r   r   r   r   r   r   r   r   r   r   r   r   r   PILr   ro  pydanticr    r!   docling_parse.pdf_parsersr"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   	getLoggerrQ   r   rJ   r]   rd   r   r  r  r  r  r  r  r  r  rY   rZ   r[   <module>r-     s,        D D D N N 4    " " *( ( ( ( ( ( ( ( ( ( (V w"0) 0$7Y 7$E-i E-PC	
 C	
L_N _ND%i % e' e'Z%	 % -S -S`o> o>dF) F)R1
 1
rZ   