
    j5jsB                       U d Z ddlm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mZ dd	lmZm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  ej:                  e      Z e        Z!de"d<    G d de      Z# G d de      Z$	 	 	 	 	 	 ddZ% G d de      Z&ed        Z'ed        Z(ed        Z)ed        Z*d dZ+	 	 	 	 	 	 d!dZ,ed        Z-y)"zIBuilt-in plugin to implement PDF page rasterization and PDF/A production.    )annotationsN)StrEnum)Path)	Annotated)Version)NamePdfStream)	BaseModelField)hookimplghostscript)ProcessingMode)MissingDependencyError)check_external_programzfrozenset[Version]BLACKLISTED_GS_VERSIONSc                  $    e Zd ZdZdZdZdZdZdZy)ColorConversionStrategyz(Ghostscript color conversion strategies.CMYKGrayLeaveColorUnchangedRGBUseDeviceIndependentColorN)	__name__
__module____qualname____doc__r   GRAYLEAVE_COLOR_UNCHANGEDr   USE_DEVICE_INDEPENDENT_COLOR     Z/var/www/html/qr/venv/lib/python3.12/site-packages/ocrmypdf/builtin_plugins/ghostscript.pyr   r      s     2DD1
C#> r#   r   c                      e Zd ZdZdZdZdZy)PdfaImageCompressionz PDF/A image compression methods.autojpeglosslessN)r   r   r   r   AUTOJPEGLOSSLESSr"   r#   r$   r&   r&   '   s    *DDHr#   r&   c                V    | t         j                  k(  r|dk(  rt         j                  S | S )aI  Resolve 'auto' image compression based on the optimization level.

    At ``-O0`` (no optimization) ``auto`` maps to ``lossless`` so Ghostscript
    will not transcode lossless images to JPEG during PDF/A generation. At all
    other levels ``auto`` defers to Ghostscript's heuristic, which may
    recompress images lossily.

    ``-O1`` is a historical exception: although it is otherwise a
    lossless-only optimization level, coercing ``auto`` to ``lossless`` there
    can bloat output substantially (Ghostscript's heuristic often picks JPEG
    for photographic content), so the default is left alone for backwards
    compatibility. Users who want guaranteed lossless image handling at any
    level can pass ``--pdfa-image-compression=lossless`` explicitly.

    Explicit ``jpeg`` and ``lossless`` choices are always respected.
    r   )r&   r*   r,   )compressionoptimize_levels     r$   _resolve_auto_compressionr0   /   s,    & *///Na4G#,,,r#   c                      e Zd ZU dZej
                  Zded<   ej                  Z
ded<   dZded<   dZd	ed
<   eddd       Zy)GhostscriptOptionsz+Options specific to Ghostscript operations.z^Annotated[ColorConversionStrategy, Field(description='Ghostscript color conversion strategy')]color_conversion_strategyzTAnnotated[PdfaImageCompression, Field(description='PDF/A image compression method')]pdfa_image_compressionNzAnnotated[int | None, Field(ge=0, le=100, description="JPEG quality (0-100) for Ghostscript image recompression during PDF/A generation; None uses Ghostscript's default.")]jpeg_qualityzyAnnotated[int | None, Field(ge=1, description='Maximum DPI for Ghostscript image downsampling during PDF/A generation.')]jpeg_maxdpic           	        |j                  dd      }|j                  ddt        t        D cg c]  }|j                   c}t        j
                  j                  d       |j                  dt        D cg c]  }|j                   c}t        j                  j                  d	       |j                  d
t        dd| dd       |j                  dt        dd| dd       yc c}w c c}w )a  Add Ghostscript-specific arguments to the argument parser.

        Args:
            parser: The argument parser to add arguments to
            namespace: The namespace prefix for argument names (not used for ghostscript
                for backward compatibility)
        GhostscriptzAdvanced control of Ghostscriptz--color-conversion-strategystorez)Set Ghostscript color conversion strategy)actiontypechoicesdefaulthelpz--pdfa-image-compressiona  Specify how to compress images in the output PDF/A. 'auto' lets OCRmyPDF decide: at -O0 it uses lossless image compression so Ghostscript does not transcode lossless images to JPEG; at -O1 and above it defers to Ghostscript's heuristic, which may recompress images lossily.  'jpeg' changes all grayscale and color images to JPEG compression.  'lossless' uses PNG-style lossless compression for non-JPEG images and passes existing JPEGs through unchanged (re-encoding them losslessly would only inflate them).  Monochrome images are always compressed using a lossless codec.  Compression settings are applied to all pages, including those for which OCR was skipped.  Not supported for --output-type=pdf ; that setting preserves the original compression of all images.)r<   r=   r>   z--ghostscript-jpeg-qualityQN_jpeg_qualityad  Advanced: Set Ghostscript's -dJPEGQ for images that Ghostscript transcodes to JPEG during PDF/A generation. 0 is maximum compression; 100 is best quality. If omitted, Ghostscript's default is used. This only affects images Ghostscript chooses to recompress; for general JPEG quality tuning prefer --jpeg-quality, which is applied by the OCRmyPDF optimizer.)r;   metavarr=   destr>   z--ghostscript-jpeg-maxdpiDPI_jpeg_maxdpia  Advanced: Force Ghostscript to downsample color, grayscale, and monochrome images in PDF/A output to the given maximum DPI. Reducing JPEG quality usually gives better results than downsampling at the same file size, and can degrade quality of high-resolution monochrome masks.)	add_argument_groupadd_argumentstrr   valuer    r&   r*   int)clsparser	namespacegsccspcs         r$   add_arguments_to_parserz*GhostscriptOptions.add_arguments_to_parserg   s     &&}6WX
)*AB3SYYB+AAGG< 	 	
 	&(<="RXX=(--33@	 	 	
$ 	(;m,N 	 	
 	';l+7 	 	
K C >s   C(6C-
r   )rL   rG   )r   r   r   r   r   r    r3   __annotations__r&   r*   r4   r5   r6   classmethodrP   r"   r#   r$   r2   r2   G   su    5
 	 55    6 	!!   " 	  
 
( 	  	 	 ?
 ?
r#   r2   c                     dt         iS )z"Register Ghostscript option model.r   )r2   r"   r#   r$   register_optionsrT      s     -..r#   c                .    t         j                  |        y )N)r2   rP   )rK   s    r$   add_optionsrV      s     ..v6r#   c                    | j                   j                  d      rt        ddt        j                  d       t        j                         }|t
        v rt        d| d      t        d      |cxk  rt        d	      k  r>n n;| j                  t        j                  t        j                  fv rt        d
| d      |t        d      k\  rt        j                  d|       | j                   dk(  rd| _         | j                  j                  t        j                  vr"t!        d| j                  j                         | j                  j"                  dk7  r%| j                   dvrt        j                  d       yyy)z1Check that the options are valid for this plugin.pdfarM   r   z9.54)programpackageversion_checkerneed_versionzGhostscript zV contains serious regressions and is not supported. Please upgrade to a newer version.z10.0.0z10.02.1z2Ghostscript 10.0.0 through 10.02.0 (your version: a#  ) contain serious regressions that corrupt PDFs with existing text, such as those processed using --skip-text or --redo-ocr (or --mode skip/redo). Please upgrade to a newer version, or use --output-type pdf to avoid Ghostscript, or use --force-ocr (or --mode force) to discard existing text.10.6.0zGhostscript %s contains JPEG encoding errors that may corrupt images. OCRmyPDF will attempt to mitigate, but versions 10.6.0+ are strongly not recommended until this is fixed upstream.pdfa-2z#Invalid color conversion strategy: r'   )r'   rX   zpdfa-1r^   zpdfa-3zz--pdfa-image-compression argument only applies when --output-type is 'auto' or one of 'pdfa', 'pdfa-1', 'pdfa-2', 'pdfa-3'N)output_type
startswithr   r   versionr   r   r   moder   skipredologwarningr3   COLOR_CONVERSION_STRATEGIES
ValueErrorr4   )options
gs_versions     r$   check_optionsrk      s   
 %%f-!'//		
 !((*
00(zl +@ @  8
?WY-??LL^00.2E2EFF(DZL Q> >  **KKM 	 &("*G 	5566	7 1""<<=?
 	

 	22f<'UUU	
 V 	=r#   c                    |	|	j                   dk(  ryt        j                  d|       t        j                  | |||||||||

       |S )z8Rasterize a single page of a PDF file using Ghostscript.Npypdfiumz3Rasterizing page %d with the Ghostscript rasterizer)raster_device
raster_dpipagenopage_dpirotationfilter_vectorstop_on_erroruse_cropbox)
rasterizerre   debugr   rasterize_pdf)
input_fileoutput_filern   ro   rp   rq   rr   rs   stop_on_soft_errorri   ru   s              r$   rasterize_pdf_pager|      s]      w11Z?IICVL##( r#   c                    i d dfd	| j                   D ]T  }t        j                  |vr|t        j                     }t        j                  |vr< |t        j                            V S )zCollect all DCTDecode (JPEG) images from a PDF.

    Returns a dict mapping image signatures to a list of (stream, raw_bytes) tuples.
    The signature is (Width, Height, Filter, BitsPerComponent, ColorSpace).
    c                   | j                  t        j                        }|yt        |t              rt	        |      S 	 t        |      dkD  rt	        |d         S t	        |      S # t        t        f$ r t	        |      cY S w xY w)z&Get a hashable key for the colorspace.Nr   )getr   
ColorSpace
isinstancerG   len	TypeErrorKeyError)objcss     r$   get_colorspace_keyz5_collect_dctdecode_images.<locals>.get_colorspace_key  sr    WWT__%:b$r7N	!$R13r!u:9#b'98$ 	r7N	s   A& 
A& &BBc           
        | y|dkD  rt         j                  d       y| j                         D ]  }| |   }||j                  t        j
                        t        j                  k(  r|j                  t        j                        }|t        j                  k(  sot        |j                  t        j                  d            t        |j                  t        j                  d            t        |      t        |j                  t        j                  d             |      f}|j                         }|	vrg 	|<   	|   j                  ||f       +|j                  t        j
                        t        j                   k(  s]t        j"                  |v sq|t        j"                     }t        j$                  |v s 
|t        j$                     |dz           y)z3Process an XObject dictionary for DCTDecode images.N
   z5Recursion depth exceeded in _collect_dctdecode_imagesr      )depth)re   rf   keysr   r   SubtypeImageFilter	DCTDecoderI   WidthHeightrG   BitsPerComponentread_raw_bytesappendForm	ResourcesXObject)xobjectsr   keyr   filtsig	raw_bytesresr   imagesprocess_xobject_dicts           r$   r   z7_collect_dctdecode_images.<locals>.process_xobject_dict)  sm   2:KKOP==? 	QC3-C{wwt||$

2wwt{{+4>>)CGGDJJ23CGGDKK34D	CGGD$9$91=>*3/C !$ 2 2 4I&(&(s3K&&Y'78&$))3>>S(dnn-C||s*,S->eaiP1	Qr#   )r   )pagesr   r   r   )pdfpage	resourcesr   r   r   s      @@@r$   _collect_dctdecode_imagesr     so     79FQB 		 6>>%(	<<y(Yt||456 Mr#   c                   d}d}t        j                  |       5 }t        j                  |d      5 }t        |      }t        |      }|j                         D ]  \  }}	||vr||   }
|	D ]  \  }}|
D ]  \  }}t	        |      }t	        |      }||z
  }d|cxk  rdk  sn /||d| k7  r8|st
        j                  d       d}t
        j                  d	|d    d
|d    d| d       |j                  |t        j                         |dz  }    |dkD  r*|j                  |       t
        j                  d| d       ddd       ddd       |dkD  S # 1 sw Y   xY w# 1 sw Y   |dkD  S xY w)a  Repair JPEG corruption caused by Ghostscript 10.6.

    Ghostscript 10.6 has a bug that truncates JPEG data by 1-15 bytes.
    This function detects and repairs such corruption by copying the
    original JPEG bytes from the input PDF.

    Returns True if any repairs were made.
    r   FT)allow_overwriting_inputr      NzVGhostscript 10.6 JPEG corruption detected. Repairing damaged images from original PDF.zReplacing corrupt JPEG image (xz, z bytes truncated))filterz	Repaired z' JPEG image(s) corrupted by Ghostscript)r	   openr   itemsr   re   errorrf   writer   r   saveinfo)input_pdf_pathoutput_pdf_pathrepaired_countfirst_error_logged	input_pdf
output_pdfinput_imagesoutput_imagesr   output_list
input_listoutput_streamoutput_bytes_input_streaminput_bytes	input_len
output_lendiffs                     r$   _repair_gs106_jpeg_corruptionr   U  s    N 	 5$-$?5CM 1;1*= !. 3 3 5 &	C,&%c*J/: !+|2< .M; #K 0I!$\!2J %z1DOO  ${;J'??  .		J .2*KKF81SVHBtf4EG "''##~~ (  #a'N?!&	P AOOO,HHN++RSg5 5n Ao5 5 5n As#   E&DEE&E#	E&&E3c                Z   |j                   j                  }|dk(  rd}t        |j                   j                  j                  |j                   j
                        }	t        j                  |g| ||	|j                   j                  j                  |j                   j                  j                  |j                   j                  j                  ||||
       t        j                         }
|
t        d      k\  r1t        |       dk(  r#t        | d         }t        |t        |             |S )z?Generate a PDF/A from the list of PDF pages and PDF/A metadata.rX   r^   )
	pdf_pagesrz   r.   r3   r5   r6   pdf_version	pdfa_partprogressbar_classrt   r]   r   r   )ri   r_   r0   r   r4   optimizegenerate_pdfar3   r5   r6   ra   r   r   r   r   )r   pdfmarkrz   contextr   r   r   r{   r_   r.   rj   r   s               r$   r   r     s     //--Kf+##::  K
 'Y'")//"="="W"W__00==OO//;;+( $$&JWX&&3y>Q+>1&	%ik1BCr#   )r.   r&   r/   rI   returnr&   )r   r	   r   z'dict[tuple, list[tuple[Stream, bytes]]])r   r   r   r   r   bool).r   
__future__r   loggingenumr   pathlibr   typingr   packaging.versionr   pikepdfr   r	   r
   pydanticr   r   ocrmypdfr   ocrmypdf._execr   ocrmypdf._optionsr   ocrmypdf.exceptionsr   ocrmypdf.subprocessr   	getLoggerr   re   	frozensetr   rQ   r   r&   r0   r2   rT   rV   rk   r|   r   r   r   r"   r#   r$   <module>r      s+   P "     % % % %  & , 6 6g! /8k + 9?g ?7 %7:0`
 `
F 
/ 
/
 
7 
7
 
5
 
5
p 
! 
!H>BFFF 
FR 
( 
(r#   