U
    Z$d`                     @   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                0   @   s  e Zd ZdZdddddddZd	d
eddddddg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/d0d1d2d3d4d5d6d7d8dd9d:d;d<dd=/Zd>Zeej	eej
eejeejeejd?Zd@dAdBdCdDdEdFdGdHdIdJdKgZdLdMdNgZdOgZdPS )Q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)i  r   i  )startxr   )endxr   )groupxr   )startyr   )endyr   )groupyr   
   )   r   )   r   )   r   )   r   )r   r   )r
   r   )   r   )   r   )r   r   )   z<10S)$   r   )(   r   ),   r   ).   r   )2   r   )4   r   )6   r   )8   r   ):   r   )<   r   )@   r   )B   r   )   <7S)   r3   )   r   )   r   )   r   )   r   )   r   )   r   )   z<80S   )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   )/NumROIROIsxDimDetyDimDet	VChipXdim	VChipYdimZcontroller_versionZlogic_outputZamp_high_cap_low_noisemodeexposure_secdateZdetector_tempZdetector_typeZst_diodeZ
delay_timeZshutter_controlabsorb_liveZabsorb_modecan_do_virtual_chipthreshold_min_liveZthreshold_min_valthreshold_max_liveZthreshold_max_val
time_localtime_utcZ
adc_offsetZadc_rateZadc_typeZadc_resolutionZadc_bit_adjustZgaincomments	geometricZ
sw_versionspare_4
XPrePixelsXPostPixels
YPrePixelsYPostPixelsZreadout_timer   typeZclockspeed_usreadout_modeZwindow_sizer   i  )r      r
      r$   znew120 (Type II)zold120 (Type I)ZST130ZST121ZST138zDC131 (PentaMax)zST133 (MicroMax/Roper)zST135 (GPIB)ZVTCCDzST116 (GPIB)zOMA3 (GPIB)ZOMA4z
full framezframe transferkineticsrR   N)__name__
__module____qualname____doc__basicnpdtypemetadata
data_startZfloat32Zint32Zint16Zuint16Zuint32dtypescontrollersreadout_modes	no_decode ri   ri   7/tmp/pip-unpacked-wheel-zwww1ayp/imageio/plugins/spe.pyr      s   
D




	
r   c                       sP  e Zd ZdZ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ededdeededdeededde	ededde
dededde	ededdeeddd d! edd"d#d! eded$d"eedd%d&d! eded'd$e
d(ededd fd)d!ededd'e
dededdeededd*e
d+ededdeeded*d$e
dededdeeded$d,e
dededde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
dd0Zeee	 eed1f d2d3d4Zee	e	eed1f d5 fd6d7Zed<ee	d9 fd:d;Z  ZS )=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.
    rY   r
   rZ   r#   r<   r      r$   	   r         )u   JänJanFebu   MärMarAprZMaiMayJunJulAugSepZOktOctNovZDezDecstandardZTOCCSLr[   	arbitrary)ZSEQUZSETOZKINEZSEARc                   @   sl   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eeeege	f ee ddd	ZdS )
zSDTControlSpec.CommentDescz>Describe how to extract a metadata entry from a comment stringnslicecvtNscaler~   r   r   r   c                 C   s   || _ || _|| _|| _d S Nr   )selfr~   r   r   r   ri   ri   rj   __init__  s    z#SDTControlSpec.CommentDesc.__init__)r\   r]   r^   r_   int__annotations__r   r   strr   r	   floatr   r   ri   ri   ri   rj   CommentDescz  s   
r   r1   D   F   r   r0   I   gư>r!      r"   c                 C   s   | dkS )NBri   xri   ri   rj   <lambda>      zSDTControlSpec.<lambda>    c                 C   s   | dkS )NEri   r   ri   ri   rj   r     r      !   c                 C   s   | dkS )NAri   r   ri   ri   rj   r     r      g?c                    s
    j |  S r   )sequence_typesr   	__class__ri   rj   r     r      gMbP?%   O   r)   7   )Zsdt_major_versionZsdt_minor_versionZsdt_controller_nameZexposure_timeZ
color_codeZdetection_channelsZbackground_subtractionZ	em_activeZem_gainZmodulation_activeZ
pixel_sizeZsequence_typeZgridZn_macroZdelay_macroZn_miniZ
delay_miniZn_microZdelay_microZ	n_subpicsZdelay_shutterZdelay_prebleachZbleach_timeZrecovery_timeN)rP   returnc                 C   s   i }| d dd dkr&t d dS i }tj D ]x\}}z.|| |j |j }|jdk	rh||j9 }W n8 t	k
r } zt d| d|  W 5 d}~X Y nX |||< q4| 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   NZ
COMVER0500zSDT-control comments not found.z-Failed to decode SDT-control metadata field "z": r   r
   comment)loggerdebugrk   rP   itemsr   r~   r   r   	Exceptionstrip)rP   Zsdt_mdnamespecver   ri   ri   rj   parse_comments  s$    


zSDTControlSpec.parse_comments)rI   timer   c              
      s   zb j | dd  }tt| dd |t| dd t|dd t|dd t|dd W S  tk
r } ztd| d W 5 d	}~X Y nX d	S )
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<   rm   r   r#   r   z1Failed to decode date from SDT-control metadata: .N)monthsr   r   r   r   info)rI   r   monthr   r   ri   rj   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k
r   td Y nX | 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.
        rP   NrI   rN   r   rR   Zmodulation_scriptzHFailed to decode SDT-control laser modulation script. Bad char_encoding?rO   rH   )r   popupdater   decodeUnicodeDecodeErrorr   warning)r   r   sdt_metadtZsp4r   ri   rj   extract_metadata  s(    





zSDTControlSpec.extract_metadata)r   )r\   r]   r^   r_   r   r   r   r   r   r   r   rP   staticmethodr   r	   r   r   r   r   r   r   __classcell__ri   ri   r   rj   rk   T  sx   
  
! rk   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kS r   )	extension
extensionsr   requestri   ri   rj   	_can_read  s    zSpeFormat._can_readc                 C   s   dS )NFri   r   ri   ri   rj   
_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 | _|| _|r|d dkrr|d ntj| j  }|tj }|| j
d | j
d	  | j	j  }|| jkrtd
| j j| j| t|| j| _d | _d S )Nr   r   r   r   r   rZ   r   r   rY   zSThe file header of %s claims there are %s frames, but there are actually %s frames.)r   Zget_file_file_char_encoding_parse_headerr   r`   _file_header_verre   _dtype_shape_len	_sdt_metaospathgetsizeZget_local_filenamerd   itemsizer   r   filenamemin_meta)r   r   Zcheck_filesizer   r   Zdata_endlineri   ri   rj   _open"  s0    




 
zSpeFormat.Reader._openc                 C   s,   | j d kr&| jdk r|   n|   | j S )NrZ   )r   r   _init_meta_data_pre_v3_init_meta_data_post_v3)r   indexri   ri   rj   _get_meta_dataE  s
    


zSpeFormat.Reader._get_meta_datac                 C   s   d S r   ri   r   ri   ri   rj   _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@ r8|d || jd< | jd }d|  krjt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 )NrA   rY   rB   rC   rD   Z	chip_sizerE   rF   Zvirt_chip_sizerS   rU   Z
pre_pixelsrT   rV   Zpost_pixelsc                 S   s   g | ]}t |qS ri   )r   ).0cri   ri   rj   
<listcomp>k  s     z;SpeFormat.Reader._init_meta_data_pre_v3.<locals>.<listcomp>rP   rQ   r   rotater
   reverser#   ZfliprW    rX   )rJ   rK   rL   rM   Zframe_shape)r   r   rc   r   r   roi_array_to_dictappendlenrf   rg   boolr   r   rk   r   r   )r   nrgftmkri   ri   rj   r   Q  sN    











"

"
z'SpeFormat.Reader._init_meta_data_pre_v3c              	      s   i }t  fdd}| D ]\}} j|d  t|dk rFdn|d }t j j|d |d}|jjdkr|t	j
krz||}W n$ tk
r   td	| Y nX z| }W n tk
r   t |}Y nX |||< q|S )
Nc                    s   |   jS r   )r   r   r   r   ri   rj   r     r   z0SpeFormat.Reader._parse_header.<locals>.<lambda>r   rZ   rY   r
   rb   countSzGFailed to decode "{}" metadata string. Check `char_encoding` parameter.)ra   Z	vectorizer   r   seekr   fromfilerb   kindr   rh   r   r   r   formatitem
ValueErrorZsqueeze)r   r   retr   r   spZcntr   ri   r   rj   r     s*    

zSpeFormat.Reader._parse_headerc                 C   s4   |  tj}| j|d  | j }d|i| _d S )Nr   Z__xml)r   r   r`   r   r   readr   )r   r   xmlri   ri   rj   r     s    
z(SpeFormat.Reader._init_meta_data_post_v3c                 C   s   | j jd dkrdS | jS d S )NrY   vV)r   rG   r   r   ri   ri   rj   _get_length  s    zSpeFormat.Reader._get_lengthc                 C   s
  |dk rt d| || jkr0t d|| jf | jjd dkr|dkrPt 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 > %irY   r   z"Index has to be 0 in v and V modesr   )
IndexErrorr   r   rG   r   r   r   rd   ra   r   r   r   Zreshaper   r   )r   r   datari   ri   rj   	_get_data  s4    
  zSpeFormat.Reader._get_dataN)r   TT)r\   r]   r^   r   r   r   r   r   r   r   r   ri   ri   ri   rj   Reader!  s   
#Cr   N)r\   r]   r^   r_   r   r   r   r   ri   ri   ri   rj   r     s   r   c           	      C   sl   g }| ddddddg } | D ]J\}}}}}}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   )Ztop_leftZbottom_rightbin)r   r   )	aZ	dict_listZsxZsyexZeyZgxgyZroi_dictri   ri   rj   r     s    r   )r_   r   loggingr   typingr   r   r   r   r   r   r	   Znumpyra   corer   	getLoggerr\   r   r   rk   r   r   ri   ri   ri   rj   <module>   s    C$
  E B