
     i(              	       j   d Z ddlmZmZmZmZ ddlZddlZddlZ	ddl
mZ d Zd Z edd	ddd
d
d          Zd Ze	j        e	j        e	j        e	j        e	j        e	j        dZd Zd Zd Z ed           ed          dZddZd Zd Zd Z dej!        z   ej"        z   ej#        z   Z$d Z%d Z&d Z'dS )a  
utils
-----

Utility functions used by the other modules in the mrcfile package.

Functions
---------

* :func:`data_dtype_from_header`: Work out the data :class:`dtype
  <numpy.dtype>` from an MRC header.
* :func:`data_shape_from_header`: Work out the data array shape from an MRC
  header
* :func:`mode_from_dtype`: Convert a :class:`numpy dtype <numpy.dtype>` to an
  MRC mode number.
* :func:`dtype_from_mode`: Convert an MRC mode number to a :class:`numpy dtype
  <numpy.dtype>`.
* :func:`pretty_machine_stamp`: Get a nicely-formatted string from a machine
  stamp.
* :func:`machine_stamp_from_byte_order`: Get a machine stamp from a byte order
  indicator.
* :func:`byte_orders_equal`: Compare two byte order indicators for equal
  endianness.
* :func:`normalise_byte_order`: Convert a byte order indicator to ``<`` or
  ``>``.
* :func:`spacegroup_is_volume_stack`: Identify if a space group number
  represents a volume stack.

    )absolute_importdivisionprint_functionunicode_literalsN   )IMAGE_STACK_SPACEGROUPc                 h    | j         }t          |                              |j        j                  S )a_  Return the data dtype indicated by the given header.
    
    This function calls :func:`dtype_from_mode` to get the basic dtype, and
    then makes sure that the byte order of the new dtype matches the byte order
    of the header's ``mode`` field.
    
    Args:
        header: An MRC header as a :class:`numpy record array
            <numpy.recarray>`.
    
    Returns:
        The :class:`numpy dtype <numpy.dtype>` object for the data array
        corresponding to the given header.
    
    Raises:
        :exc:`ValueError`: If there is no corresponding dtype for the given
            mode.
    )modedtype_from_modenewbyteorderdtype	byteorder)headerr
   s     W/srv/www/vhosts/g4struct/public_html/venv/lib/python3.11/site-packages/mrcfile/utils.pydata_dtype_from_headerr   .   s,    & ;D4  --dj.BCCC    c                 "   t          | j                  }t          | j                  }t          | j                  }t          | j                  }t          | j                  r
||z  |||f}n | j        t          k    r|dk    r||f}n|||f}|S )a  Return the data shape indicated by the given header.
    
    Args:
        header: An MRC header as a :class:`numpy record array
            <numpy.recarray>`.
    
    Returns:
        The shape tuple for the data array corresponding to the given header.
    r   )intnxnynzmzspacegroup_is_volume_stackispgr   )r   r   r   r   r   shapes         r   data_shape_from_headerr   E   s     
VYB	VYB	VYB	VYB!&+.. r2r2&	.	.	.277RRLr               )f2f4i1i2u1u2c8c                     | j         t          | j                  z   }|t          v rt          |         S t	          d                    |                     )a  Return the MRC mode number corresponding to the given :class:`numpy
    dtype <numpy.dtype>`.
    
    The conversion is as follows:
    
    * float16   -> mode 12
    * float32   -> mode 2
    * int8      -> mode 0
    * int16     -> mode 1
    * uint8     -> mode 6 (data will be widened to 16 bits in the file)
    * uint16    -> mode 6
    * complex64 -> mode 4
    
    Note that there is no numpy dtype which corresponds to MRC mode 3.
    
    Args:
        dtype: A :class:`numpy dtype <numpy.dtype>` object.
    
    Returns:
        The MRC mode number.
    
    Raises:
        :exc:`ValueError`: If there is no corresponding MRC mode for the given
            dtype.
    z3dtype '{0}' cannot be converted to an MRC file mode)kindstritemsize_dtype_to_mode
ValueErrorformat)r   kind_and_sizes     r   mode_from_dtyper0   a   sR    4 JU^!4!44M&&m,,
 ++16%==: : :r   )r   r   r   r    r   r   c                 &   t          | t          j                  r.| j        dk    rt	          d          |                                 } | t          v rt          j        t          |                    S t	          d                    |                     )a  Return the :class:`numpy dtype <numpy.dtype>` corresponding to the given
    MRC mode number.
    
    The mode parameter may be given as a Python scalar, numpy scalar or
    single-item numpy array.
    
    The conversion is as follows:
    
    * mode 0 -> int8
    * mode 1 -> int16
    * mode 2 -> float32
    * mode 4 -> complex64
    * mode 6 -> uint16
    * mode 12 -> float16
    
    Note that modes 3 and 101 are not supported as there is no matching numpy dtype.
    
    Args:
        mode: The MRC mode number. This may be given as any type which can be
            converted to an int, for example a Python scalar (``int`` or
            ``float``), a numpy scalar or a single-item numpy array.
    
    Returns:
        The :class:`numpy dtype <numpy.dtype>` object corresponding to the
        given mode.
    
    Raises:
        :exc:`ValueError`: If there is no corresponding dtype for the given
            mode, or if ``mode`` is an array and does not contain exactly one
            item.
    r   z*Mode array should contain exactly one itemzUnrecognised mode '{0}')	
isinstancenpndarraysizer-   item_mode_to_dtyper   r.   )r
   s    r   r   r      s}    @ $
## 9>>IJJJyy{{~xt,---299$??@@@r   c                 @    d                     d | D                       S )z7Return a human-readable hex string for a machine stamp. c              3   @   K   | ]}d                      |          V  dS )z0x{:02x}N)r.   ).0bytes     r   	<genexpr>z'pretty_machine_stamp.<locals>.<genexpr>   s0      ??J%%d++??????r   )join)machsts    r   pretty_machine_stampr@      s#    88????????r   c                     | d         dk    r| d         dv rdS | d         dk    r| d         dk    rdS t          |           }t          d|z             )	a  Return the byte order corresponding to the given machine stamp.
    
    Args:
        machst: The machine stamp, as a :class:`bytearray` or a :class:`numpy
            array <numpy.ndarray>` of bytes.
    
    Returns:
        ``<`` if the machine stamp represents little-endian data, or ``>`` if
        it represents big-endian.
    
    Raises:
        :exc:`ValueError`: If the machine stamp is invalid.
    r   D   r   )rB   A   <   >zUnrecognised machine stamp: )r@   r-   )r?   pretty_bytess     r   byte_order_from_machine_stamprH      si     ayDVAY,66s
)t

q	T 1 1s+F337,FGGGr   )rB   rB   r   r   )rE   rE   r   r   )rD   rF   =c                 :    t          |           } t          |          S )ax  Return the machine stamp corresponding to the given byte order
    indicator.
    
    Args:
        byte_order: The byte order indicator: one of ``=``, ``<`` or ``>``, as
            defined and used by numpy dtype objects.
    
    Returns:
        The machine stamp which corresponds to the given byte order, as a
        :class:`bytearray`. This will be either ``(0x44, 0x44, 0, 0)`` for
        little-endian or ``(0x11, 0x11, 0, 0)`` for big-endian. If the given
        byte order indicator is ``=``, the native byte order is used.
    
    Raises:
        :exc:`ValueError`: If the byte order indicator is unrecognised.
    )normalise_byte_order_byte_order_to_machine_stamp
byte_orders    r   machine_stamp_from_byte_orderrO      s    $ &j11J'
33r   c                 B    t          |           t          |          k    S )a  Work out if the byte order indicators represent the same endianness.
    
    Args:
        a: The first byte order indicator: one of ``=``, ``<`` or ``>``, as
            defined and used by :class:`numpy dtype <numpy.dtype>` objects.
        b: The second byte order indicator.
    
    Returns:
        :data:`True` if the byte order indicators represent the same
        endianness.
    
    Raises:
        :exc:`ValueError`: If the byte order indicator is not recognised.
    )rK   )abs     r   byte_orders_equalrS      s       ""&:1&=&===r   c                     | dvr"t          d                    |                     | dk    rt          j        dk    rdndS | S )a  Convert a numpy byte order indicator to one of ``<`` or ``>``.
    
    Args:
        byte_order: One of ``=``, ``<`` or ``>``.
    
    Returns:
        ``<`` if the byte order indicator represents little-endian data, or
        ``>`` if it represents big-endian. Therefore on a little-endian
        machine, ``=`` will be converted to ``<``, but on a big-endian machine
        it will be converted to ``>``.
    
    Raises:
        :exc:`ValueError`: If ``byte_order`` is not one of ``=``, ``<`` or
            ``>``.
    )rD   rF   rI   z'Unrecognised byte order indicator '{0}'rI   littlerD   rF   )r-   r.   sysr   rM   s    r   rK   rK      sX      ((B &,,. . 	.Smx//ssS8r   c                 "    d| cxk    odk    nc S )a   Identify if the given space group number represents a volume stack.
    
    Args:
        ispg: The space group number, as an integer, numpy scalar or single-
            element numpy array.
    
    Returns:
        :data:`True` if the space group number is in the range 401--630.
    i  iv   )r   s    r   r   r     s&     $#r   r9   c                     	 t                               |           ot                               |           S # t          $ r/ 	 t	          d | D                       cY S # t
          $ r Y Y dS w xY ww xY w)zECheck if a string is entirely composed of printable ASCII characters.c              3   (   K   | ]}|t           v V  d S N)printable_chars)r;   chars     r   r=   z%is_printable_ascii.<locals>.<genexpr>'  s'      CC4t.CCCCCCr   F)r*   isprintableisasciiAttributeErrorallUnicodeDecodeErrorstring_s    r   is_printable_asciire     s    w''@CKK,@,@@   	CC7CCCCCCCC! 	 	 	555		s-   36 
A/AA/
A+&A/*A++A/c                     t                               | dd          }t          |          s,d                    t	          d |D                                 }|S )zVConvert bytes into a printable ASCII string by removing non-printable characters.
    asciiignoreencodingerrors c              3   8   K   | ]}t          |          |V  d S r[   )re   )r;   ss     r   r=   z.printable_string_from_bytes.<locals>.<genexpr>1  s0      KKQ5G5J5JKqKKKKKKr   )bytesdecodere   r>   list)bytes_rd   s     r   printable_string_from_bytesrs   ,  sY     ll6GHlEEGg&& M''$KK'KKKKKLLNr   c                 V    t                               t          |           dd          S )a7  Convert a string to bytes.

    Even though this is a one-liner, the details are tricky to get right so things work
    properly in both Python 2 and 3. It's broken out as a separate function so it can be
    thoroughly tested.

    Raises:
        UnicodeError: If the input contains non-ASCII characters.
    rg   strictri   )r*   encoderc   s    r   bytes_from_stringrw   5  s"     ::c'llWX:FFFr   )rI   )(__doc__
__future__r   r   r   r   stringrV   numpyr3   	constantsr   r   r   dictr,   r0   int8int16float32	complex64uint16float16r7   r   r@   rH   	bytearrayrL   rO   rS   rK   r   ascii_lettersdigitspunctuationr\   re   rs   rw   rX   r   r   <module>r      s   >* * * * * * * * * * * *  



     - - - - - -D D D.  4 aA!a@@@: : :B ghjliz$ $'A 'A 'AT@ @ @
H H H. &/Y/A%B%B%.Y/A%B%B D  D 4 4 4 4*> > >"  .
 
 
 ,,v}<v?QQ
 
 
  
G 
G 
G 
G 
Gr   