o
    9ήc`                     @   s   d Z ddlmZ ddlZddlZddlmZmZmZmZm	Z	m
Z
mZ ddlZddlmZ eeZG dd dZG d	d
 d
ZG dd deZdd ZdS )u   Read SPE files.

Backend: internal

This plugin supports reading files saved in the Princeton Instruments
SPE file format.

Parameters for reading
----------------------
char_encoding : str
    Character encoding used to decode strings in the metadata. Defaults
    to "latin1".
check_filesize : bool
    The number of frames in the file is stored in the file header. However,
    this number may be wrong for certain software. If this is `True`
    (default), derive the number of frames also from the file size and
    raise a warning if the two values do not match.
sdt_meta : bool
    If set to `True` (default), check for special metadata written by the
    `SDT-control` software. Does not have an effect for files written by
    other software.

Metadata for reading
--------------------
ROIs : list of dict
    Regions of interest used for recording images. Each dict has the
    "top_left" key containing x and y coordinates of the top left corner,
    the "bottom_right" key with x and y coordinates of the bottom right
    corner, and the "bin" key with number of binned pixels in x and y
    directions.
comments : list of str
    The SPE format allows for 5 comment strings of 80 characters each.
controller_version : int
    Hardware version
logic_output : int
    Definition of output BNC
amp_hi_cap_low_noise : int
    Amp switching mode
mode : int
    Timing mode
exp_sec : float
    Alternative exposure in seconds
date : str
    Date string
detector_temp : float
    Detector temperature
detector_type : int
    CCD / diode array type
st_diode : int
    Trigger diode
delay_time : float
    Used with async mode
shutter_control : int
    Normal, disabled open, or disabled closed
absorb_live : bool
    on / off
absorb_mode : int
    Reference strip or file
can_do_virtual_chip : bool
    True or False whether chip can do virtual chip
threshold_min_live : bool
    on / off
threshold_min_val : float
    Threshold minimum value
threshold_max_live : bool
    on / off
threshold_max_val : float
    Threshold maximum value
time_local : str
    Experiment local time
time_utc : str
    Experiment UTC time
adc_offset : int
    ADC offset
adc_rate : int
    ADC rate
adc_type : int
    ADC type
adc_resolution : int
    ADC resolution
adc_bit_adjust : int
    ADC bit adjust
gain : int
    gain
sw_version : str
    Version of software which created this file
spare_4 : bytes
    Reserved space
readout_time : float
    Experiment readout time
type : str
    Controller type
clockspeed_us : float
    Vertical clock speed in microseconds
readout_mode : ["full frame", "frame transfer", "kinetics", ""]
    Readout mode. Empty string means that this was not set by the
    Software.
window_size : int
    Window size for Kinetics mode
file_header_ver : float
    File header version
chip_size : [int, int]
    x and y dimensions of the camera chip
virt_chip_size : [int, int]
    Virtual chip x and y dimensions
pre_pixels : [int, int]
    Pre pixels in x and y dimensions
post_pixels : [int, int],
    Post pixels in x and y dimensions
geometric : list of {"rotate", "reverse", "flip"}
    Geometric operations
sdt_major_version : int
    (only for files created by SDT-control)
    Major version of SDT-control software
sdt_minor_version : int
    (only for files created by SDT-control)
    Minor version of SDT-control software
sdt_controller_name : str
    (only for files created by SDT-control)
    Controller name
exposure_time : float
    (only for files created by SDT-control)
    Exposure time in seconds
color_code : str
    (only for files created by SDT-control)
    Color channels used
detection_channels : int
    (only for files created by SDT-control)
    Number of channels
background_subtraction : bool
    (only for files created by SDT-control)
    Whether background subtraction war turned on
em_active : bool
    (only for files created by SDT-control)
    Whether EM was turned on
em_gain : int
    (only for files created by SDT-control)
    EM gain
modulation_active : bool
    (only for files created by SDT-control)
    Whether laser modulation (“attenuate”) was turned on
pixel_size : float
    (only for files created by SDT-control)
    Camera pixel size
sequence_type : str
    (only for files created by SDT-control)
    Type of sequnce (standard, TOCCSL, arbitrary, …)
grid : float
    (only for files created by SDT-control)
    Sequence time unit (“grid size”) in seconds
n_macro : int
    (only for files created by SDT-control)
    Number of macro loops
delay_macro : float
    (only for files created by SDT-control)
    Time between macro loops in seconds
n_mini : int
    (only for files created by SDT-control)
    Number of mini loops
delay_mini : float
    (only for files created by SDT-control)
    Time between mini loops in seconds
n_micro : int (only for files created by SDT-control)
    Number of micro loops
delay_micro : float (only for files created by SDT-control)
    Time between micro loops in seconds
n_subpics : int
    (only for files created by SDT-control)
    Number of sub-pictures
delay_shutter : float
    (only for files created by SDT-control)
    Camera shutter delay in seconds
delay_prebleach : float
    (only for files created by SDT-control)
    Pre-bleach delay in seconds
bleach_time : float
    (only for files created by SDT-control)
    Bleaching time in seconds
recovery_time : float
    (only for files created by SDT-control)
    Recovery time in seconds
comment : str
    (only for files created by SDT-control)
    User-entered comment. This replaces the "comments" field.
datetime : datetime.datetime
    (only for files created by SDT-control)
    Combines the "date" and "time_local" keys. The latter two plus
    "time_utc" are removed.
modulation_script : str
    (only for files created by SDT-control)
    Laser modulation script. Replaces the "spare_4" key.

    )datetimeN)AnyCallableDictMappingOptionalSequenceUnion   )Formatc                   @   sx  e Zd ZdZdddddddZi d	d
ddeg ddfdddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,i d-d.d/d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?d@dAdBdCdDdEdFdGdHdIdJdKdLdMdNdOdPdQdRdSdTdUddVdWdXdYddZZd[Zeej	eej
eejeejeejd\Zg d]Zg d^Zd_gZd`S )aSpecaW  SPE file specification data

    Tuples of (offset, datatype, count), where offset is the offset in the SPE
    file and datatype is the datatype as used in `numpy.fromfile`()

    `data_start` is the offset of actual image data.

    `dtypes` translates SPE datatypes (0...4) to numpy ones, e. g. dtypes[0]
    is dtype("<f") (which is np.float32).

    `controllers` maps the `type` metadata to a human readable name

    `readout_modes` maps the `readoutMode` metadata to something human readable
    although this may not be accurate since there is next to no documentation
    to be found.
    )l   <h)*   <H)i  r   )i  z<Q)i  z<i)i  <f)datatypexdimydimxml_footer_offset	NumFramesfile_header_verNumROI)i  r   ROIsi  ))startxr   )endxr   )groupxr   )startyr   )endyr   )groupyr   
   xDimDet)   r   yDimDet)   r   	VChipXdim)   r   	VChipYdim)   r   controller_version)r   r   logic_output)r
   r   amp_high_cap_low_noise)   r   mode)   r   exposure_sec)r    r   date)   z<10Sdetector_temp)$   r   detector_type)(   r   st_diode),   r   
delay_time).   r   shutter_control)2   r   absorb_live)4   r   absorb_mode)6   r   can_do_virtual_chip)8   r   threshold_min_live):   r   threshold_min_val)<   r   threshold_max_live)@   r   threshold_max_val)B   r   
time_local)   <7Stime_utc)   rL   
adc_offset)   r   adc_rate)   r   adc_type)   r   adc_resolution)   r   adc_bit_adjust)   r   gain)   r   comments)   z<80S   	geometric)iX  r   )i  z<16S)i  z<436S)b   r   )d   r   )f   r   )h   r   )i  r   )i  r   )i  r   )i  r   )i  r   )
sw_versionspare_4
XPrePixelsXPostPixels
YPrePixelsYPostPixelsreadout_timer   typeclockspeed_usreadout_modewindow_sizer   i  )r      r
      r.   )znew120 (Type II)zold120 (Type I)ST130ST121ST138zDC131 (PentaMax)zST133 (MicroMax/Roper)zST135 (GPIB)VTCCDzST116 (GPIB)zOMA3 (GPIB)OMA4)z
full framezframe transferkineticsrd   N)__name__
__module____qualname____doc__basicnpdtypemetadata
data_startfloat32int32int16uint16uint32dtypescontrollersreadout_modes	no_decode r   r   :/tmp/pip-target-vg8gfxp4/lib/python/imageio/plugins/spe.pyr      s    	
 #$%&'()*+,-./012345D





r   c                       s  e Zd ZdZi ddddddddd	dd
dddddddddddddddddddddddZdd d!d"d#ZG d$d% d%Zi d&eded'd(ed)eded(d*ed+eded,de	d-eded.d/e
d0d1ededd2e	d3eded4d5ed6edd2d7d8 d9edd:d;d8 d<eded=d:ed>edd?d@d8 dAededBd=e
dCdDededd fdEd8dFeded5dBe
d0dGeded,dedHededdIe
dJdKededdedLededId=e
d0ededdeeded=dMe
d0ededdeeded/dNe
d0ededMdOe
d0ededOdPe
d0ededPd.e
d0dQZedRee	 dSeedTf fdUdVZedWe	dXe	dSeedTf f fdYdZZed`d\ed]e	f fd^d_Z  ZS )aSDTControlSpeca&  Extract metadata written by the SDT-control software

    Some of it is encoded in the comment strings
    (see :py:meth:`parse_comments`). Also, date and time are encoded in a
    peculiar way (see :py:meth:`get_datetime`). Use :py:meth:`extract_metadata`
    to update the metadata dict.
    u   Jänrn   JanFebr
   u   Märro   MarAprr,   Mair]   MayJunr"   Jul   Augr.   Sep	   Oktr    OctNov   Dez   DecstandardTOCCSLru   	arbitrary)SEQUSETOKINESEARc                
   @   sz   e Zd ZU dZeed< 	 eed< 	 eege	f ed< 	 e
def ed< 	 edfdededeege	f dee fddZdS )	zSDTControlSpec.CommentDescz>Describe how to extract a metadata entry from a comment stringnslicecvtNscalec                 C   s   || _ || _|| _|| _d S N)r   r   r   r   )selfr   r   r   r   r   r   r   __init__  s   
z#SDTControlSpec.CommentDesc.__init__)rv   rw   rx   ry   int__annotations__r   r   strr   r	   floatr   r   r   r   r   r   CommentDescz  s*   
 r   sdt_major_versionrI   D   sdt_minor_versionF   sdt_controller_namer   exposure_timerG   I   gư>
color_coder&   detection_channels   r(   background_subtractionc                 C      | dkS )NBr   xr   r   r   <lambda>      zSDTControlSpec.<lambda>	em_active    c                 C   r   )NEr   r   r   r   r   r     r   em_gain   modulation_active!   c                 C   r   )NAr   r   r   r   r   r     r   
pixel_size   g?sequence_typec                    s
    j |  S r   )sequence_typesr   	__class__r   r   r     s   
 gridn_macrodelay_macro   gMbP?n_mini
delay_mini%   O   r9   7   )n_microdelay_micro	n_subpicsdelay_shutterdelay_prebleachbleach_timerecovery_timer[   returnNc                 C   s   i }| d dd dkrt d dS i }tj D ]=\}}z|| |j |j }|jdur4||j9 }W n t	yR } zt d| d|  W Y d}~nd}~ww |||< q| d | d	  }|
 |d
< |S )a6  Extract SDT-control metadata from comments

        Parameters
        ----------
        comments
            List of SPE file comments, typically ``metadata["comments"]``.

        Returns
        -------
        If SDT-control comments were detected, return a dict of metadata, else
        `None`.
        r,   r   N
COMVER0500zSDT-control comments not found.z-Failed to decode SDT-control metadata field "z": r   r
   comment)loggerdebugr   r[   itemsr   r   r   r   	Exceptionstrip)r[   sdt_mdnamespecver   r   r   r   parse_comments  s*   



zSDTControlSpec.parse_commentsr0   timec              
      s   z1 j | dd  }tt| dd |t| dd t|dd t|dd t|dd W S  tyM } ztd| d W Y d	}~d	S d	}~ww )
ai  Turn date and time saved by SDT-control into proper datetime object

        Parameters
        ----------
        date
            SPE file date, typically ``metadata["date"]``.
        time
            SPE file date, typically ``metadata["time_local"]``.

        Returns
        -------
        File's datetime if parsing was succsessful, else None.
        r
   r]   r   r   r,   r"   z1Failed to decode date from SDT-control metadata: .N)monthsr   r   r   r   info)r0   r   monthr   r   r   r   get_datetime  s    zSDTControlSpec.get_datetimelatin1metachar_encodingc                    s     | d }|sdS | d | |  | d | d }|r/|| d< | d | d | d }z||| d< | d W n tyO   td Y nw | d	 | d
 dS )ar  Extract SDT-control metadata from SPE metadata

        SDT-control stores some metadata in comments and other fields.
        Extract them and remove unused entries.

        Parameters
        ----------
        meta
            SPE file metadata. Modified in place.
        char_encoding
            Character encoding used to decode strings in the metadata.
        r[   Nr0   rJ   r   rd   modulation_scriptzHFailed to decode SDT-control laser modulation script. Bad char_encoding?rM   r/   )r   popupdater   decodeUnicodeDecodeErrorr   warning)r   r   sdt_metadtsp4r   r   r   extract_metadata  s*   




zSDTControlSpec.extract_metadata)r   )rv   rw   rx   ry   r   r   r   r   r   r   r   r[   staticmethodr   r	   r   r   r   r   r   r   __classcell__r   r   r   r   r   T  s    	
	
 !$"r   c                   @   s2   e Zd ZdZdd Zdd ZG dd dejZdS )		SpeFormatzSee :mod:`imageio.plugins.spe`c                 C   s   |j | jv S r   )	extension
extensionsr   requestr   r   r   	_can_read  s   zSpeFormat._can_readc                 C   s   dS )NFr   r  r   r   r   
_can_write  s   zSpeFormat._can_writec                   @   sN   e Zd ZdddZdd Zdd Zd	d
 Zdd Zdd Zdd Z	dd Z
dS )zSpeFormat.Readerr   Tc                 C   s   | j  | _|| _| tj}|d | _tj|d  | _	|d |d f| _
|d | _|| _|rn|d dkr9|d ntj| j  }|tj }|| j
d | j
d	  | j	j  }|| jkrntd
| j j| j| t|| j| _d | _d S )Nr   r   r   r   r   ro   r   r   rn   zSThe file header of %s claims there are %s frames, but there are actually %s frames.)r  get_file_file_char_encoding_parse_headerr   rz   _file_header_verr   _dtype_shape_len	_sdt_metaospathgetsizeget_local_filenamer~   itemsizer   r   filenamemin_meta)r   r   check_filesizer   r   data_endliner   r   r   _open"  s0   




 

zSpeFormat.Reader._openc                 C   s0   | j d u r| jdk r|   | j S |   | j S )Nro   )r  r  _init_meta_data_pre_v3_init_meta_data_post_v3)r   indexr   r   r   _get_meta_dataE  s   

zSpeFormat.Reader._get_meta_datac                 C   s   d S r   r   r   r   r   r   _closeM  s   zSpeFormat.Reader._closec                 C   s  |  tj| _| jdd }|dk rdn|}t| jd d | | jd< | jdd | jdd g| jd< | jdd | jdd g| jd	< | jd
d | jdd g| jd< | jdd | jdd g| jd< dd | jd D | jd< g }| jdd}|d@ r|d |d@ r|d |d@ r|d || jd< | jd }d|  krttjkrn ntj|d  | jd< nd| jd< | jd }d|  krttj	krn ntj	|d  | jd< nd| jd< dD ]}t
| j| | j|< q| j| jd< | jr	t| j| j d S d S )Nr   rn   r   r!   r#   	chip_sizer%   r'   virt_chip_sizere   rg   
pre_pixelsrf   rh   post_pixelsc                 S   s   g | ]}t |qS r   )r   ).0cr   r   r   
<listcomp>k  s    z;SpeFormat.Reader._init_meta_data_pre_v3.<locals>.<listcomp>r[   r^   r   rotater
   reverser,   fliprj    rl   )r<   r@   rB   rF   frame_shape)r  r   r}   r  r   roi_array_to_dictappendlenr   r   boolr  r  r   r   r  )r   nrgftmkr   r   r   r  Q  sP   











z'SpeFormat.Reader._init_meta_data_pre_v3c              	      s   i }t  fdd}| D ]_\}} j|d  t|dk r#dn|d }t j j|d |d}|jjdkrU|t	j
vrUz||}W n tyT   td	| Y nw z| }W n tyi   t |}Y nw |||< q|S )
Nc                    s   |   jS r   )r   r  r   r#  r   r   r     s    z0SpeFormat.Reader._parse_header.<locals>.<lambda>r   ro   rn   r
   r|   countSzGFailed to decode "{}" metadata string. Check `char_encoding` parameter.)r{   	vectorizer   r  seekr3  fromfiler|   kindr   r   r   r   r   formatitem
ValueErrorsqueeze)r   r   retr   r   spcntr   r   r#  r   r    s,   
zSpeFormat.Reader._parse_headerc                 C   s4   |  tj}| j|d  | j }d|i| _d S )Nr   __xml)r  r   rz   r  r?  readr  )r   r   xmlr   r   r   r     s   
z(SpeFormat.Reader._init_meta_data_post_v3c                 C   s   | j jd dv r
dS | jS )Nrn   vV)r  r-   r  r#  r   r   r   _get_length  s   zSpeFormat.Reader._get_lengthc                 C   s
  |dk r
t d| || jkrt d|| jf | jjd dv rO|dkr(t d| jtj tj	| j| j
| jd | jd  | j d}|| jf| j }n/| jtj|| jd  | jd  | j
j   tj	| j| j
| jd | jd  d}|| j}|| |fS )Nr   zImage index %i < 0zImage index %i > %irn   rL  z"Index has to be 0 in v and V modesr;  )
IndexErrorr  r  r-   r  r?  r   r~   r{   r@  r  r  reshaper  r"  )r   r!  datar   r   r   	_get_data  s0   
zSpeFormat.Reader._get_dataN)r   TT)rv   rw   rx   r  r"  r$  r  r  r   rM  rQ  r   r   r   r   Reader!  s    
#CrR  N)rv   rw   rx   ry   r  r	  r   rR  r   r   r   r   r    s
    r  c           	      C   sd   g }| g d } | D ]%\}}}}}}t |t |gt |t |gt |t |gd}|| q
|S )a  Convert the `ROIs` structured arrays to :py:class:`dict`

    Parameters
    ----------
    a : numpy.ndarray:
        Structured array containing ROI data

    Returns
    -------
    list of dict
        One dict per ROI. Keys are "top_left", "bottom_right", and "bin",
        values are tuples whose first element is the x axis value and the
        second element is the y axis value.
    )r   r   r   r   r   r   )top_leftbottom_rightbin)r   r2  )	a	dict_listsxsyexeygxgyroi_dictr   r   r   r1    s   r1  )ry   r   loggingr  typingr   r   r   r   r   r   r	   numpyr{   corer   	getLoggerrv   r   r   r   r  r1  r   r   r   r   <module>   s     C$
  E B