o
    iEc                     @   s   d Z ddlmZmZ ddlmZ ddlmZmZm	Z	 ddl
mZ ddlmZ ddlmZ erJddlmZ dd	lmZ dd
lmZmZ ddlmZmZ eeB eB ZG dd dZeG dd deeZ G dd dZ!G dd de	ddZ"dS )z'Common objects for pixel data handling.    )Enumunique)import_module)TYPE_CHECKINGAny	TypedDict)warn_and_log)as_pixel_options)UID)Callable)Dataset)DecodeOptionsDecodeFunction)EncodeOptionsEncodeFunctionc                   @   s  e Zd ZdZdededdfddZded	eeef ddfd
dZ	de
eeeeef f  ddfddZedeedf fddZedefddZedefddZedefddZede
e fddZdeddfddZedefddZ	d$dedeed f eed!f B fd"d#ZdS )%	CoderBasez#Base class for Decoder and Encoder.uiddecoderreturnNc                 C   s   || _ i | _i | _|| _dS )a  Create a new data decoder or encoder.

        Parameters
        ----------
        uid : pydicom.uid.UID
            The supported *Transfer Syntax UID*.
        decoder : bool
            ``True`` for a decoder subclass, ``False`` for an encoder subclass.
        N)_uid
_available_unavailable_decoder)selfr   r    r   K/mnt/sdb/aimis/docanh/lib/python3.10/site-packages/pydicom/pixels/common.py__init__   s   
zCoderBase.__init__labelimport_pathc                 C   s   || j v s
|| jv rtdt| j d| dt|d }|| jr0t||d | j |< dS | j	r7|j
}n|j}| j|vrLtd| d| jj d|| j | j|< dS )a  Add a plugin to the class instance.

        .. warning::

            This method is not thread-safe.

        The requirements for encoding plugins are available
        :doc:`here</guides/encoding/encoder_plugins>`, while the requirements
        for decoding plugins are available :doc:`here
        </guides/decoding/decoder_plugins>`.

        Only encoding plugins should be added to
        :class:`~pydicom.pixels.encoders.base.Encoder` class instances
        and only decoding plugins should be added to
        :class:`~pydicom.pixels.decoders.base.Decoder` class instances.

        Parameters
        ----------
        label : str
            The label to use for the plugin, should be unique.
        import_path : Tuple[str, str]
            The module import path and the function's name (e.g.
            ``('pydicom.pixels.encoders.pylibjpeg', 'encode_pixel_data')`` or
            ``('pydicom.pixels.decoders.pylibjpeg', 'decode_pixel_data')``).

        Raises
        ------
        ModuleNotFoundError
            If the module import path is incorrect or unavailable.
        AttributeError
            If the plugin's required functions and attributes aren't found in
            the module.
        'z' already has a plugin named 'r      zThe 'z' plugin doesn't support 'N)r   r   
ValueErrortype__name__r   is_availabler
   getattrr   DECODER_DEPENDENCIESENCODER_DEPENDENCIESname)r   r   r   moduledepsr   r   r   
add_plugin,   s   "
zCoderBase.add_pluginpluginsc                 C   s   |D ]
\}}|  || qdS )a?  Add multiple plugins to the class instance.

        .. warning::

            This method is not thread-safe.

        The requirements for encoding plugins are available
        :doc:`here</guides/encoding/encoder_plugins>`, while the requirements
        for decoding plugins are available :doc:`here
        </guides/decoding/decoder_plugins>`.

        Only encoding plugins should be added to
        :class:`~pydicom.pixels.encoders.base.Encoder` class instances
        and only decoding plugins should be added to
        :class:`~pydicom.pixels.decoders.base.Decoder` class instances.

        Parameters
        ----------
        plugins : list[tuple[str, tuple[str, str]]]
            A list of [label, import path] for the plugins, where:

            * `label` is the label to use for the plugin, which should be unique.
            * `import path` is the module import path and the function's
              name (e.g. ``('pydicom.pixels.encoders.pylibjpeg', 'encode_pixel_data')``
              or ``('pydicom.pixels.decoders.pylibjpeg', 'decode_pixel_data')``).
        N)r+   )r   r,   r   r   r   r   r   add_pluginsf   s   zCoderBase.add_plugins.c                 C   s   t t| j S )z,Return a tuple containing available plugins.)tuplesortedr   keysr   r   r   r   available_plugins   s   zCoderBase.available_pluginsc                 C   s   | j r	| jjs	dS t| jS )zyReturn ``True`` if plugins are available that can be used to encode or
        decode data, ``False`` otherwise.
        T)r   r
   is_encapsulatedboolr   r1   r   r   r   r$      s   
zCoderBase.is_availablec                 C   s   | j jS )zlReturn ``True`` if the decoder is for an encapsulated transfer
        syntax, ``False`` otherwise.
        )r
   r3   r1   r   r   r   r3         zCoderBase.is_encapsulatedc                 C   s   | j  S )zfReturn ``True`` if the decoder is for an native transfer
        syntax, ``False`` otherwise.
        )r3   r1   r   r   r   	is_native   r5   zCoderBase.is_nativec              
   C   s   g }| j  D ]8\}}|s|| d qt|dkr3|| dd|dd  d|d   q|| d|d   q|S )	z:Return nice strings for plugins with missing dependencies.z& - plugin indicating it is unavailabler     - requires , N and r   )r   itemsappendlenjoin)r   sr   r*   r   r   r   missing_dependencies   s   .zCoderBase.missing_dependenciesc                 C   s<   || j v r| j |= dS || jv r| j|= dS td| d)zRemove a plugin.

        .. warning::

            This method is not thread-safe.

        Parameters
        ----------
        label : str
            The label of the plugin to remove.
        zUnable to remove 'z', no such plugin'N)r   r   r!   )r   r   r   r   r   remove_plugin   s
   

zCoderBase.remove_pluginc                 C      | j S )zLReturn the corresponding *Transfer Syntax UID* as :class:`~pydicom.uid.UID`.)r   r1   r   r   r   r
         zCoderBase.UID pluginr   r   c                 C   sV  | j r	| jjs	i S |r}|| jv r|| j| iS | j|d }r[|d }t|dkr:d|dd  d|d  }| j rLt	d| jj
 d| d	| t	d
| jj
 d| d	| d| d| jj t| j d}| jry|dd| j 7 }t|| jr| j S ddd | jD }| j rt	d| jj
 d| t	d
| jj
 d| )a  Return available plugins.

        Parameters
        ----------
        plugin : str, optional
            If not used (default) then return all available plugins, otherwise
            only return the plugin with a matching name (if it's available).

        Returns
        -------
        dict[str, DecodeFunction] | dict[str, EncodeFunction]
            A dict of available {plugin name: decode/encode function} that can
            be used to decode/encode the corresponding pixel data.
        Nr   r    r8   r9   r:   zUnable to decompress 'zD' pixel data because the specified plugin is missing dependencies:
	r7   z)Unable to compress the pixel data using 'z9' because the specified plugin is missing dependencies:
	zNo plugin named 'z' has been added to 'r   z, available plugins are: 
c                 S   s   g | ]}d | qS )	r   ).0r?   r   r   r   
<listcomp>   s    z/CoderBase._validate_plugins.<locals>.<listcomp>z;' pixel data because all plugins are missing dependencies:
z0' because all plugins are missing dependencies:
)r   r
   r3   r2   r   r   getr=   r>   RuntimeErrorr(   keywordr"   r#   r!   copyr@   )r   rE   r*   missingmsgr   r   r   _validate_plugins   sZ   
 
zCoderBase._validate_plugins)rD   )r#   
__module____qualname____doc__r
   r4   r   strr.   r+   listr-   propertyr2   r$   r3   r6   r@   rA   dictrP   r   r   r   r   r      s0    &:	r   c                   @   sR   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdefddZdS )PhotometricInterpretationz3Values for (0028,0004) *Photometric Interpretation*MONOCHROME1MONOCHROME2PALETTE COLORRGBYBR_FULLYBR_FULL_422YBR_ICTYBR_RCTHSVARGBCMYKYBR_PARTIAL_422YBR_PARTIAL_420r   c                 C   s
   t | S N)rT   __str__r1   r   r   r   rg   !  s   
z!PhotometricInterpretation.__str__N)r#   rQ   rR   rS   rY   rZ   PALETTE_COLORr\   r]   r^   r_   r`   ra   rb   rc   rd   re   rT   rg   r   r   r   r   rX     s     rX   c                   @   s  e Zd ZdZdeddfddZedefddZedefd	d
Z	edefddZ
deddfddZedeee ee f eeef B dB fddZdBdedeeB fddZdCdededefddZedefddZedefddZedefddZedefdd Zedefd!d"ZedDd$d%Zedefd&d'Zedefd(d)Zedefd*d+Zedefd,d-Zedefd.d/Z edefd0d1Z!ded2eddfd3d4Z"dEd6d7Z#dFd:d;Z$edefd<d=Z%dGd>d?Z&dGd@dAZ'dS )H
RunnerBasezABase class for the pixel data decoding/encoding process managers.tsyntaxr   Nc                 C   s"   i | _ | d| d| _d| _dS )zCreate a new runner for encoding/decoding data.

        Parameters
        ----------
        tsyntax : pydicom.uid.UID
            The transfer syntax UID corresponding to the pixel data to be
            decoded.
        transfer_syntax_uid)rk   	UNDEFINEDN)_opts
set_option_undeletable	_src_type)r   rj   r   r   r   r   (  s   

zRunnerBase.__init__c                 C   "   | j dd }dur|S td)z>Return the expected number of bits allocated used by the data.bits_allocatedNz*No value for 'bits_allocated' has been setrm   rJ   AttributeErrorr   valuer   r   r   rr   :     zRunnerBase.bits_allocatedc                 C   rq   )z;Return the expected number of bits stored used by the data.bits_storedNz'No value for 'bits_stored' has been setrs   ru   r   r   r   rx   B  rw   zRunnerBase.bits_storedc                 C   rq   )z2Return the expected number of columns in the data.columnsNz#No value for 'columns' has been setrs   ru   r   r   r   ry   J  rw   zRunnerBase.columnsr(   c                 C   s,   || j v rtd| d| j|d dS )z%Delete option `name` from the runner.z
Deleting 'z' is not allowedN)ro   r!   rm   pop)r   r(   r   r   r   
del_optionR  s   
zRunnerBase.del_optionc                 C   s   | j ddS )aR  Return the extended offsets table and lengths

        Returns
        -------
        tuple[list[int], list[int]] | tuple[bytes, bytes] | None
            Returns the extended offsets and lengths as either lists of int
            or their equivalent encoded values, or ``None`` if no extended
            offsets have been set.
        extended_offsetsNrm   rJ   r1   r   r   r   r|   Y  s   zRunnerBase.extended_offsetsbytesunitc                 C   s   | j | j | j }|dkr|S | jdkr0| jjr#|d |d dk }n|d }| r/t|}n|| jd 9 }| jt	j
krG| jjsG|d d }|S )a  Return the expected length (in number of bytes or pixels) of each
        frame of pixel data.

        Parameters
        ----------
        unit : str, optional
            If ``"bytes"`` then returns the expected length of the pixel data
            in whole bytes and NOT including an odd length trailing NULL
            padding byte. If ``"pixels"`` then returns the expected length of
            the pixel data in terms of the total number of pixels (default
            ``"bytes"``).

        Returns
        -------
        int | float
            The expected length of a single frame of pixel data in either whole
            bytes or pixels, excluding the NULL trailing padding byte for odd
            length data. For "pixels", an integer will always be returned. For
            "bytes", a float will be returned for images with BitsAllocated of
            1 whose frames do not consist of a whole number of bytes.
        pixelsr       r         )rowsry   samples_per_pixelrr   transfer_syntaxr3   
is_integerintphotometric_interpretationrX   r^   )r   r   lengthr   r   r   frame_lengthh  s    
zRunnerBase.frame_lengthdefaultc                 C   s   | j ||S )z&Return the value of the option `name`.r}   )r   r(   r   r   r   r   
get_option  s   zRunnerBase.get_optionc                 C   
   | j dkS )zFReturn ``True`` if the pixel data source is an :class:`~numpy.ndarray`Arrayrp   r1   r   r   r   is_array     
zRunnerBase.is_arrayc                 C   r   )z4Return ``True`` if the pixel data source is BinaryIOBinaryIOr   r1   r   r   r   	is_binary  r   zRunnerBase.is_binaryc                 C   r   )z9Return ``True`` if the pixel data source is a buffer-likeBufferr   r1   r   r   r   	is_buffer  r   zRunnerBase.is_bufferc                 C   r   )zOReturn ``True`` if the pixel data source is a :class:`~pydicom.dataset.Dataset`r   r   r1   r   r   r   
is_dataset  r   zRunnerBase.is_datasetc                 C   rq   )z1Return the expected number of frames in the data.number_of_framesNz,No value for 'number_of_frames' has been setrs   ru   r   r   r   r     rw   zRunnerBase.number_of_framesDecodeOptions | EncodeOptionsc                 C   rB   )z0Return a reference to the runner's options dict.rm   r1   r   r   r   options  rC   zRunnerBase.optionsc                 C   rq   )z;Return the expected photometric interpretation of the data.r   Nz6No value for 'photometric_interpretation' has been setrs   ru   r   r   r   r     rw   z%RunnerBase.photometric_interpretationc                 C   rq   )zReturn the expected pixel keyword of the data.

        Returns
        -------
        str
            One of ``"PixelData"``, ``"FloatPixelData"``, ``"DoubleFloatPixelData"``
        pixel_keywordNz)No value for 'pixel_keyword' has been setrs   ru   r   r   r   r     s   	zRunnerBase.pixel_keywordc                 C   rq   )z5Return the expected pixel representation of the data.pixel_representationNz0No value for 'pixel_representation' has been setrs   ru   r   r   r   r     rw   zRunnerBase.pixel_representationc                 C   s.   | j dd }dur|S | jjrdS td)z5Return the expected planar configuration of the data.planar_configurationNr   z0No value for 'planar_configuration' has been set)rm   rJ   r   is_compressedrt   ru   r   r   r   r     s
   zRunnerBase.planar_configurationc                 C   rq   )z/Return the expected number of rows in the data.r   Nz No value for 'rows' has been setrs   ru   r   r   r   r     rw   zRunnerBase.rowsc                 C   rq   )z<Return the expected number of samples per pixel in the data.r   Nz-No value for 'samples_per_pixel' has been setrs   ru   r   r   r   r     rw   zRunnerBase.samples_per_pixelrv   c                 C   s   |dkrt |trt|n|}|dv rtd| d d}n|dkr9|dkr)tj}zt| }W n	 ty8   Y nw || j|< dS )	zSet a runner option.

        Parameters
        ----------
        name : str
            The name of the option to be set.
        value : Any
            The value of the option.
        r   )Nr   zA value of 'zA' for (0028,0008) 'Number of Frames' is invalid, assuming 1 framer    r   r[   N)
isinstancerT   r   r   rX   rh   KeyErrorrm   )r   r(   rv   r   r   r   rn     s"   

zRunnerBase.set_optionkwargsc                 K   s"   |  D ]
\}}| || qdS )a   Set multiple runner options.

        Parameters
        ----------
        kwargs : dict[str, Any]
            A dictionary containing the options as ``{name: value}``, where
            `name` is the name of the option and `value` is it's value.
        N)r;   rn   )r   r   r(   rv   r   r   r   set_options  s   	zRunnerBase.set_optionsdsr   c                 C   s   | j di t| dS )zSet options using a dataset.

        Parameters
        ----------
        ds : pydicom.dataset.Dataset
            The dataset to use.
        Nr   )r   r	   )r   r   r   r   r   _set_options_ds&  s   zRunnerBase._set_options_dsc                 C   s
   | j d S )z>Return the expected transfer syntax corresponding to the data.rk   r   r1   r   r   r   r   0  r   zRunnerBase.transfer_syntaxc                 C   s   t t| j d)z5Validate the runner options and source data (if any).z$.validate() has not been implemented)NotImplementedErrorr"   r#   r1   r   r   r   validate5  s   zRunnerBase.validatec                 C   s  d}| j ddu rt| dd| j  krdkr(n n
| jdkr1| jd r1td| j d	d
| jvrd| j ddu rEt| dd| j  krV| j  krVdksdn td| j d| j d| j ddu rst| dd| j  k r~dksn td| j d| j ddur| jdk rtd| j d| j ddu rt| dzt	| j
  W n ty   | j
dkrtd| j
 dY nw d}| j|vrtd| j d| jdkr| j d du rt| d!| jd"vrtd#| j d$| j d%du rt| d&d| j  k rdks%n td'| j d| j d(du r5t| d)| jd*vrDtd+| j d,| jd-kri| j d.du rZt| d/| jd"vrktd0| j d$dS dS )1z?Validate the supplied options to ensure they meet requirements.zMissing required element: (0028rr   Nz,0100) 'Bits Allocated'r    @   r   z)A (0028,0100) 'Bits Allocated' value of 'zF' is invalid, it must be 1 or a multiple of 8 and in the range (1, 64)Floatrx   z,0101) 'Bits Stored'z&A (0028,0101) 'Bits Stored' value of 'zm' is invalid, it must be in the range (1, 64) and no greater than the (0028,0100) 'Bits Allocated' value of 'r   ry   z,0011) 'Columns'r   i  z"A (0028,0011) 'Columns' value of 'z0' is invalid, it must be in the range (1, 65535)r   z+A (0028,0008) 'Number of Frames' value of 'z3' is invalid, it must be greater than or equal to 1r   z#,0004) 'Photometric Interpretation'r[   z8Unknown (0028,0004) 'Photometric Interpretation' value ')	PixelDataFloatPixelDataDoubleFloatPixelDatazUnknown 'pixel_keyword' value 'r   r   z,0103) 'Pixel Representation')r   r    z/A (0028,0103) 'Pixel Representation' value of 'z' is invalid, it must be 0 or 1r   z,0010) 'Rows'zA (0028,0010) 'Rows' value of 'r   z,0002) 'Samples per Pixel')r    r   z,A (0028,0002) 'Samples per Pixel' value of 'z' is invalid, it must be 1 or 3r   r   z,0006) 'Planar Configuration'z/A (0028,0006) 'Planar Configuration' value of ')rm   rJ   rt   rr   r!   r   rx   ry   r   rX   r   r   r   r   r   r   )r   prefixkwr   r   r   _validate_options;  s   
$




zRunnerBase._validate_options)r~   rf   )r   r   )r   r   r   N)r   r   r   N)r   N)(r#   rQ   rR   rS   r
   r   rV   r   rr   rx   ry   rT   r{   r.   rU   r~   r|   floatr   r   r   r4   r   r   r   r   r   r   r   r   r   r   r   r   rn   r   r   r   r   r   r   r   r   r   ri   %  s^    "5



ri   c                   @   s   e Zd ZU dZeed< eed< eed< eed< eed< eed< eed< eed	< eed
< eed< eed< ee	e	f ee
e e
e f B ed< dS )RunnerOptionszOptions accepted by RunnerBaserr   rx   ry   r   r   r   r   r   r   rk   r   r|   N)r#   rQ   rR   rS   r   __annotations__rT   r
   r.   r~   rU   r   r   r   r   r     s   
 (r   F)totalN)#rS   enumr   r   	importlibr   typingr   r   r   pydicom.miscr   pydicom.pixels.utilsr	   pydicom.uidr
   collections.abcr   pydicom.datasetr   pydicom.pixels.decoders.baser   r   pydicom.pixels.encoders.baser   r   r~   	bytearray
memoryviewr   r   rT   rX   ri   r   r   r   r   r   <module>   s*    x  y