
    j5jc                    l   U d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	 ddl
mZ ddl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mZ dd
lmZmZ ddlmZ ddlmZ  ej@                  e!      Z"i a#de$d<   eez  ez  e%z  e&z  Z' G d de      Z( G d de      Z)ddZ*ddZ+dddZ, G d de      Z-y)z$Internal options model for OCRmyPDF.    )annotationsN)Sequence)StrEnum)IOBase)Path)AnyBinaryIO)	BaseModel
ConfigDictFieldfield_validatormodel_validator)DEFAULT_LANGUAGEDEFAULT_ROTATE_PAGES_THRESHOLD)BadArgsError)	monotonicdict[str, type]_plugin_option_modelsc                  $    e Zd ZdZdZdZdZdZdZy)ProcessingModea  OCR processing mode for handling pages with existing text.

    This enum controls how OCRmyPDF handles pages that already contain text:

    - ``default``: Error if text is found (standard OCR behavior)
    - ``force``: Rasterize all content and run OCR regardless of existing text
    - ``skip``: Skip OCR on pages that already have text
    - ``redo``: Re-OCR pages, stripping old invisible text layer
    - ``strip``: Remove the invisible OCR text layer in place; do not OCR
    defaultforceskipredostripN)	__name__
__module____qualname____doc__r   r   r   r   
strip_text     G/var/www/html/qr/venv/lib/python3.12/site-packages/ocrmypdf/_options.pyr   r   %   s$    	 GEDD Jr"   r   c                      e Zd ZdZdZdZy)TaggedPdfModeaV  Control behavior when encountering a Tagged PDF.

    Tagged PDFs often indicate documents generated from office applications
    that may not need OCR. This enum controls how OCRmyPDF handles them:

    - ``default``: Error if ProcessingMode is default, otherwise warn
    - ``ignore``: Always warn but continue processing (never error)
    r   ignoreN)r   r   r   r   r   r&   r!   r"   r#   r%   r%   :   s     GFr"   r%   c                &    d| j                         v S )z<Return True if the page range string uses the ``end`` alias.end)lower)rangess    r#   _has_end_aliasr+   H   s    FLLN""r"   c                \    | j                         dk(  r|t        d      |S t        |       S )zConvert a single page-number token to a 1-based integer.

    The literal ``end`` (case-insensitive) is resolved to ``total_pages``. If
    ``total_pages`` is None, an error is raised.
    r(   zC'end' was used in --pages but the total page count is not yet known)r)   r   int)tokentotal_pagess     r#   _resolve_page_tokenr0   M   s:     {{}U  u:r"   c                   g }| j                  dd      j                  d      }|D ]q  }|s	 |j                  d      \  }}	 t        ||      }t        ||      }t        t	        |dz
  |            }	|	st        d| d| d      d|j                  |	       s |st        d
|  d      t        |      st        j                  d       t        d |D              rt        d      t        j                  d|       t        |      S # t        $ r t        d| d      dw xY w# t        $ rA 	 |j                  t        ||      dz
         n# t        $ r t        d	| d      dw xY wY Iw xY w)a&  Convert page range string to set of 0-based page numbers.

    The token ``end`` (case-insensitive) is an alias for the last page of the
    document. It is resolved using ``total_pages``; if ``end`` appears in the
    string and ``total_pages`` is None, a :class:`BadArgsError` is raised.
      ,-   zinvalid page subrange ''Nzinvalid page number 'zThe string of page ranges 'z/' did not contain any recognizable page ranges.zQList of pages to process contains duplicate pages, or pages that are out of orderc              3  &   K   | ]	  }|d k    yw)r   Nr!   ).0pages     r#   	<genexpr>z%_pages_from_ranges.<locals>.<genexpr>   s     
&4!8
&s   z)pages refers to a page number less than 1zOCRing only these pages: %s)replacesplitr0   listranger   extend
ValueErrorappendr   logwarninganydebugset)
r*   r/   pagespage_groupsgroupstartr(   start_nend_n	new_pagess
             r#   _pages_from_rangesrO   \   s    E..b)//4K Q	QS)JE3
Q-e[A+C= w{E!:;	 &1%#a@  Y''Q. )& 2 
 	

 U	
 
&
&&FGGII+U3u:%  Q"%<UG1#EFDPQ  	OO0DqHI O"%:5'#CD$NO J	Os6   D&AD		D#&	E00EE0E))E0/E0c                     e Zd ZU dZded<   ded<   dZded<   dZded	<   dZded
<    ed       Z	ded<   dZ
ded<   ej                  Zded<   ed|d       Zed|d       Zed|d       ZdZded<   dZded<   dZded<   dZded<   dZd ed!<   dZded"<   dZded#<   dZded$<   dZded%<   dZded&<   dZded'<   dZded(<   dZded)<   dZd ed*<   dZ d+ed,<   dZ!d-ed.<   dZ"d/ed0<   dZ#ded1<   e$j                  Z%d2ed3<   dZ&d4ed5<   dZ'd4ed6<   dZ(d4ed7<   dZ)d4ed8<   d9Z*d ed:<   dZ+ded;<   dZ,ded<<   d=Z-d>ed?<   ed@        Z.e.j^                  dA        Z.dZ0dedB<   dZ1d-edC<   dZ2dedD<   dZ3dedE<   dZ4dedF<   e5Z6d>edG<   dZ7dHedI<   dZ8dHedJ<   dKZ9d>edL<   dZ:dMedN<   g Z;dedO<   dZ<dedP<   dZ=dedQ<   dZ>dedR<   dZ?d-edS<   dZ@d-edT<   dUZAd edV<   dZBdMedW<   dZCd4edX<   dYZDdedZ<   d=Z-d>ed?<   dZEd[ed\<    eeFdd]^      ZGd_ed`<    eHd      eIda               ZJ eHd      eIdb               ZK eHdD      eIdc               ZL eHdF      eIdd               ZM eHd&      eIde               ZN eHd      eIdf               ZO eHd!      eIdg               ZP eHd*      eIdh               ZQ eHdC      eIdi               ZR eHdG      eIdj               ZS eHd5d6d8d7      eIdk               ZT eHd0      eIdl               ZU eHd,dmn      eIdo               ZV eWdmn      eIdp               ZX eWdqn      dr        ZY eWdqn      ds        ZZedt        Z[d}duZ\eId~dv       Z] e^dwddx      Z_eIddy       Z`ddzZadd{Zby)
OcrOptionszInternal options model that can masquerade as argparse.Namespace.

    This model provides proper typing and validation while maintaining
    compatibility with existing code that expects argparse.Namespace behavior.
    PathOrIO
input_fileoutput_fileNzPathOrIO | NonesidecarzPath | Noneoutput_folderwork_folderc                     t         gS Nr   r!   r"   r#   <lambda>zOcrOptions.<lambda>   s
    :J9K r"   )default_factoryz	list[str]	languagesautostroutput_typer   modeboolc                <    | j                   t        j                  k(  S )z>Backward compatibility alias for mode == ProcessingMode.force.)ra   r   r   selfs    r#   	force_ocrzOcrOptions.force_ocr   s     yyN0000r"   c                <    | j                   t        j                  k(  S )z=Backward compatibility alias for mode == ProcessingMode.skip.)ra   r   r   rd   s    r#   	skip_textzOcrOptions.skip_text        yyN////r"   c                <    | j                   t        j                  k(  S )z=Backward compatibility alias for mode == ProcessingMode.redo.)ra   r   r   rd   s    r#   redo_ocrzOcrOptions.redo_ocr   ri   r"   
int | NonejobsTuse_threadsprogress_barFquietr   r-   verbosekeep_temporary_files	image_dpideskewcleanclean_finalrotate_pagesremove_backgroundremove_vectors
oversamplezlist[str] | Noneunpaper_argszfloat | Noneskip_bigzstr | set[int] | NonerH   invalidate_digital_signaturesr%   tagged_pdf_modez
str | Nonetitleauthorsubjectkeywordsr6   optimizejpg_qualitypng_qualityg333333?floatjbig2_thresholdc                    | j                   S )$Compatibility alias for jpg_quality.r   rd   s    r#   jpeg_qualityzOcrOptions.jpeg_quality   s     r"   c                    || _         y)r   Nr   )re   values     r#   r   zOcrOptions.jpeg_quality   s     !r"   no_overwritemax_image_mpixelspdf_renderer
ocr_engine
rasterizerrotate_pages_thresholdzos.PathLike | None
user_wordsuser_patternsg      ?fast_web_viewzbool | Nonecontinue_on_soft_render_errortesseract_configtesseract_pagesegmodetesseract_oemtesseract_thresholdingtesseract_timeouttesseract_non_ocr_timeouti  tesseract_downsample_above!tesseract_downsample_large_imagespdfa_image_compressionLeaveColorUnchangedcolor_conversion_strategyzSequence[Path | str] | Noneplugins_extra_attrs)r\   excludealiaszdict[str, Any]extra_attrsc                    |st         gS |S )z#Ensure languages list is not empty.rZ   clsvs     r#   validate_languageszOcrOptions.validate_languages  s     $%%r"   c                2    h d}||vrt        d|       |S )z2Validate output type is one of the allowed values.>   pdfa-1pdfa-2pdfa-3pdfr^   nonepdfazoutput_type must be one of rA   )r   r   valid_typess      r#   validate_output_typezOcrOptions.validate_output_type  s*     TK:;-HIIr"   c                D    h d}ddh}||z  }||vrt        d|       |S )z3Validate PDF renderer is one of the allowed values.>   r^   fpdf2sandwichhocr	hocrdebugzpdf_renderer must be one of r   )r   r   valid_rendererslegacy_renderersall_accepteds        r#   validate_pdf_rendererz OcrOptions.validate_pdf_renderer  s?     8"K0&)99L ;L>JKKr"   c                2    h d}||vrt        d|       |S )z1Validate rasterizer is one of the allowed values.>   r^   pypdfiumghostscriptzrasterizer must be one of r   )r   r   valid_rasterizerss      r#   validate_rasterizerzOcrOptions.validate_rasterizer%  s.     @%%9:K9LMNNr"   c                \    |r)t        |d      rd|j                  v rd|j                  d<   |S )z/If clean_final is True, also set clean to True.dataru   T)hasattrr   )r   r   infos      r#   validate_clean_finalzOcrOptions.validate_clean_final.  s.     v&7dii+?!%DIIgr"   c                4    ||dk  s|dkD  rt        d      |S )z%Validate jobs is a reasonable number.r      zjobs must be between 0 and 256r   r   s     r#   validate_jobszOcrOptions.validate_jobs6  s&     =a!eq3w=>>r"   c                0    |dk  s|dkD  rt        d      |S )zValidate verbose level.r      zverbose must be between 0 and 2r   r   s     r#   validate_verbosezOcrOptions.validate_verbose>  s"     q5AE>??r"   c                0    |dk  s|dkD  rt        d      |S )zValidate oversample DPI.r   i  z%oversample must be between 0 and 5000r   r   s     r#   validate_oversamplezOcrOptions.validate_oversampleF  s"     q5AHDEEr"   c                *    ||dk  rt        d      |S )zValidate max image megapixels.r   z&max_image_mpixels must be non-negativer   r   s     r#   validate_max_image_mpixelsz%OcrOptions.validate_max_image_mpixelsN  s      =QUEFFr"   c                0    |dk  s|dkD  rt        d      |S )z Validate rotate pages threshold.r   i  z1rotate_pages_threshold must be between 0 and 1000r   r   s     r#   validate_rotate_pages_thresholdz*OcrOptions.validate_rotate_pages_thresholdV  s"     q5AHPQQr"   c                    ||S |D ]_  }t        j                  |      dk(  st        |      dk\  s*t        t        |            dd j	                         }t        d| d| d       |S )zGValidate metadata strings don't contain unsupported Unicode characters.NCoi   r   z8Metadata string contains unsupported Unicode character: z (U+))unicodedatacategoryordhexupperrA   )r   r   charhexchars       r#   validate_metadata_unicodez$OcrOptions.validate_metadata_unicode^  s     9H 	D##D)T1SY'5Ic$i.,224 NfD	, 	 r"   c                ^    ||S t        |t              r|S t        |      r|S t        |      S )zConvert page ranges string to set of page numbers.

        If the string uses the ``end`` alias, the original string is preserved
        so that resolution can happen later, once the document's page count is
        known.
        )
isinstancerG   r+   rO   r   s     r#   validate_pages_formatz OcrOptions.validate_pages_formatn  s7     9HaH!H "!$$r"   before)ra   c                    ||S t        |t              rt        j                  |      }t        |t              rt        d |D              rt        d      |S t        dt        |             )zANormalize unpaper_args from string to list and validate security.c              3  @   K   | ]  }d |v xs |dk(  xs |dk(    yw)/.z..Nr!   )r9   args     r#   r;   z3OcrOptions.validate_unpaper_args.<locals>.<genexpr>  s)     JC3J;#*;t;Js   z&No filenames allowed in --unpaper-argsz+unpaper_args must be a string or list, got )r   r_   shlexr=   r>   rE   rA   typer   s     r#   validate_unpaper_argsz OcrOptions.validate_unpaper_args  se     9HaAAaJJJ !IJJHFtAwiPQQr"   c                   t        |t              rOd|v r	d|vrd|d<   |j                  dd      }|j                  dd      }|j                  dd      }|t        j                  f|t        j
                  f|t        j                  fg}|D cg c]  \  }}|s	||f }}}t        |      }	|j                  dt        j                        }
t        |
t              rt        |
      }
|
t        j                  k7  }|	d	kD  rt        d
      |	d	k(  rP|d   d	   }|rA|
|k7  r<d|j                  j                  dd       d}t        d|
j                   d| d      ||d<   |S c c}}w )z>Handle special cases for API compatibility and legacy options.rV   rT   z	/dev/nullrf   Nrh   rk   ra   r6   z8Choose only one of --force-ocr, --skip-text, --redo-ocr.r   z--_r5   z-ocrzConflicting options: --mode z cannot be used with z or similar legacy flag.)r   dictpopr   r   r   r   lengetr   r_   rA   r   r<   )r   r   r   r   r   
legacy_setvalra   legacy_truelegacy_countcurrent_modemode_is_setexpected_modelegacy_flags                 r#   handle_special_caseszOcrOptions.handle_special_cases  s    dD!$&=+D&1]# HH[$/E88K.D88J-D ,,-~**+~**+J
 9CJ93cC;JKJ{+L  88FN,B,BCL,,-l;&.*@*@@Ka N  q  +Aq 1<=#@$&}':':'B'B3'L&MT"RK$6|7I7I6J K//:m;SU 
  -V3 Ks   
E#E#afterc                    | j                   t        j                  k(  r/| j                  s| j                  s| j
                  rt        d      | S )z+Validate options compatible with redo mode.zm--redo-ocr (or --mode redo) is not currently compatible with --deskew, --clean-final, and --remove-background)ra   r   r   rt   rv   rx   rA   rd   s    r#   validate_redo_ocr_optionsz$OcrOptions.validate_redo_ocr_options  sG     99+++KK4++t/E/EC  r"   c                    | j                   dk(  r@t        | j                        t        j                  dfvrt        d| j                   d      | S )z4Validate output type is compatible with output file.r   r5   z:Since you specified `--output-type none`, the output file zI cannot be produced. Set the output file to `-` to suppress this message.)r`   r_   rT   osdevnullrA   rd   s    r#   "validate_output_type_compatibilityz-OcrOptions.validate_output_type_compatibility  sc     v%#d.>.>*?JJH
 +
 L##$ %01 
 r"   c                    t        | j                  | j                  | j                  t        j
                  k(  | j                  g       }|S )z9Determine lossless_reconstruction based on other options.)rE   rt   rv   ra   r   r   rx   )re   losslesss     r#   lossless_reconstructionz"OcrOptions.lossless_reconstruction  sJ       		^111&&	
 
 r"   c                f  	 | j                         }	fd	i }|j                         D ]  \  }} 	|      }||||<    | j                  rK| j                  j                         D ci c]  \  }}|j                  d      s|| }}}|r 	|      |d<   t	        j
                  |      S c c}}w )zCSerialize to JSON with special handling for non-serializable types.c                   t        | t              rdt        |       dS t        | t        t        z        st        | d      st        | d      rdddS t        | d      rd| j                  j                  v rdddS t        | t              ry t        | t        t        z        r| D cg c]
  } |       c}S t        | t              r*| j                         D ci c]  \  }}| |       c}}S | S c c}w c c}}w )	Nr   )__type__r   readwriteStreamstream	__class__Iterator)r   r   r_   r	   r   r   r  r   propertyr>   tupler   items)r   itemkr   _serialize_values       r#   r  z9OcrOptions.model_dump_json_safe.<locals>._serialize_value  s    %&$*SZ@@5(V"345&)5'* %-x@@,u?W?W1W$,x@@E8,E4%<0;@A4(.AAE4(;@;;=I41a+A..II	 BIs   )C7C<_plugin_cache_r   )
model_dumpr  r   
startswithjsondumps)
re   r   serializable_datakeyr   serialized_valuer  r   filtered_extrar  s
            @r#   model_dump_json_safezOcrOptions.model_dump_json_safe  s      	0 **, 	:JC/6+)9!#&	:  !,,224Aq||$45 1N 
 4D^4T!.1zz+,,s   *B-c                    t        j                  |      }fdi }i }|j                         D ]  \  }}|dk(  r	 |      } |      ||<      | di |}||_        |S )zGReconstruct from JSON with special handling for non-serializable types.c                V   t        | t              r,d| v r(| d   dk(  rt        | d         S | d   dk(  r| d   S | d   S t        | t              r| D cg c]
  } |       c}S t        | t              r*| j	                         D ci c]  \  }}| |       c}}S | S c c}w c c}}w )Nr  r   r   r  )r   r   r   r>   r  )r   r  r  r   _deserialize_values       r#   r!  z?OcrOptions.model_validate_json_safe.<locals>._deserialize_value  s    %&:+>$.g//:&(2 >) >)E4(=BCT*40CCE4(=B[[]KTQ-a00KK	 DKs   B B%r   r!   )r  loadsr  r   )	r   json_strr   deserialized_datar   r  r   instancer!  s	           @r#   model_validate_json_safez#OcrOptions.model_validate_json_safe  s     zz(#	" **, 	CJCn$07);E)B!#&		C +*+*r"   forbid)extraarbitrary_types_allowedvalidate_assignmentc                .    t         j                  |       y)zRegister plugin option model classes for nested access.

        Args:
            models: Dictionary mapping namespace to model class
        N)r   update)r   modelss     r#   register_plugin_modelsz!OcrOptions.register_plugin_modelsB  s     	$$V,r"   c                   d| }|| j                   v r| j                   |   S |t        vrt        d| d      t        |   }d }i }|j                  D ]  }| d| }|t        j                  v rt        | |      }|, ||      ||<   8|| j                   v r| j                   |   }|X ||      ||<   d|t        j                  v rt        | |      }| ||      ||<   |dk(  r3|dk(  r.dt        j                  v s| j                  }| ||      ||<   |dk(  s|dk(  sd	t        j                  v s| j                  }| ||      ||<     |d
i |}	|	| j                   |<   |	S )aZ  Get or create a plugin options instance for the given namespace.

        This method creates plugin option instances lazily from flat field values.

        Args:
            namespace: The plugin namespace (e.g., 'tesseract', 'optimize')

        Returns:
            An instance of the plugin's option model, or None if not registered
        r  zPlugin namespace 'zE' is not registered. Ensure setup_plugin_infrastructure() was called.c                d    t        | t        j                        rt        j                  |       S | S )z8Convert value to be compatible with plugin model fields.)r   r   PathLikefspath)r   s    r#   _convert_valuez6OcrOptions._get_plugin_options.<locals>._convert_valued  s$    %-yy''Lr"   r   r   levelr   r   r!   )r   r   AttributeErrormodel_fieldsrQ   getattrr   r   )
re   	namespace	cache_keymodel_classr3  kwargs
field_name	flat_namer   r%  s
             r#   _get_plugin_optionszOcrOptions._get_plugin_optionsL  s    %YK0	(((##I..11 $YK 0C D 
 ,I6	 %22 	CJ$+Qzl3IJ333i0$)7)>F:& d...((3$)7)>F:&z666j1$)7)>F:&j(Z7-B!8!88 MME(-;E-Bz*j(Z>-I J$;$;; ,,E(-;E-Bz*?	CD ((&.#r"   c                @   |j                  d      r%t        dt        |       j                   d| d      |t        v r| j                  |      S d| j                  v r|| j                  v r| j                  |   S t        dt        |       j                   d| d      )a!  Support dynamic access to plugin option namespaces.

        This allows accessing plugin options like:
            options.tesseract.timeout
            options.optimize.level

        Plugin models must be registered via register_plugin_models() for
        namespace access to work. Built-in plugins register their models
        during initialization.

        Args:
            name: Attribute name

        Returns:
            Plugin options instance if name is a registered namespace,
            otherwise raises AttributeError
        r   r7   z' object has no attribute 'r   )r  r5  r   r   r   r>  __dict__r   )re   names     r#   __getattr__zOcrOptions.__getattr__  s    & ??3 DJ''((CD6K 
 ((++D11 DMM)dd6F6F.F##D))T
##$$?vQG
 	
r"   )returnrb   )rC  r_   )r#  r_   rC  rQ   )r-  r   rC  None)r8  r_   rC  r   )rA  r_   rC  r   )cr   r   r   r   __annotations__rU   rV   rW   r   r]   r`   r   r   ra   r  rf   rh   rk   rm   rn   ro   rp   rq   rr   rs   rt   ru   rv   rw   rx   ry   rz   r{   r|   rH   r}   r%   r~   r   r   r   r   r   r   r   r   r   setterr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   classmethodr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r&  r   model_configr.  r>  rB  r!   r"   r#   rQ   rQ      sn    #G_#!%M;%#K# !1KLIyLK)11D.1 1 1 0 0 0 0
 D*KL$E4GS!&$& !Iz FDE4KL$#t# ND J%)L") "Hl!#'E '*/!4/%2%:%:O]: E:FJGZHj Hc"K""K"!OU!     ! !
 L$ '+|*L#JJ$BEB%)J")(,M%,M515!;5 #%i$(,:, $M:$)-J-&*|*.2|2&++59%{9 *.J-%:s: "OU! ,0G(/ #(d.#K  [!  " ]#  $ ^$  % \"  # ]#  $ V   Y    \"  # ()  * -.  / Wh
I>  ? W%  %$ ^(3
R  4
R (#+  $+Z '"	 #	 '" # 
 
.-` # #J  $ L - -DL#
r"   rQ   )r*   r_   rC  rb   )r.   r_   r/   rl   rC  r-   rY   )r*   r_   r/   rl   rC  zset[int]).r   
__future__r   r  loggingr   r   r   collections.abcr   enumr   ior   pathlibr   typingr   r	   pydanticr
   r   r   r   r   ocrmypdf._defaultsr   r   ocrmypdf.exceptionsr   ocrmypdf.helpersr   	getLoggerr   rC   r   rE  r_   bytesrR   r   r%   r+   r0   rO   rQ   r!   r"   r#   <module>rV     s    + "   	   $      S S O , &
 g! *,  +ft#c)E1W *G #
/dg
 g
r"   