U
    cqe><  ã                   @   sè   d Z ddlZddlmZmZ ddlmZmZ ddlm	Z	 ddl
mZ G dd„ de	ƒZG d	d
„ d
eƒZG dd„ deƒZG dd„ dƒZG dd„ dƒZG dd„ dƒZdd„ ZG dd„ dƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZdS )zdObjects related to parsing headers of JPEG image streams.

Includes both JFIF and Exif sub-formats.
é    N)ÚJPEG_MARKER_CODEÚ	MIME_TYPE)Ú
BIG_ENDIANÚStreamReader)ÚBaseImageHeader)ÚTiffc                   @   s(   e Zd ZdZedd„ ƒZedd„ ƒZdS )ÚJpegz(Base class for JFIF and EXIF subclasses.c                 C   s   t jS )zWMIME content type for this image, unconditionally `image/jpeg` for JPEG
        images.)r   ZJPEG©Úself© r   ú3/tmp/pip-unpacked-wheel-gx5hpqp3/docx/image/jpeg.pyÚcontent_type   s    zJpeg.content_typec                 C   s   dS )z8Default filename extension, always 'jpg' for JPG images.Zjpgr   r	   r   r   r   Údefault_ext   s    zJpeg.default_extN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úpropertyr   r   r   r   r   r   r      s
   
r   c                   @   s   e Zd ZdZedd„ ƒZdS )ÚExifz*Image header parser for Exif image format.c                 C   s8   t  |¡}|jj}|jj}|jj}|jj}| ||||ƒS )z[Return |Exif| instance having header properties parsed from Exif image in
        `stream`.)Ú_JfifMarkersÚfrom_streamÚsofÚpx_widthÚ	px_heightÚapp1Úhorz_dpiÚvert_dpi©ÚclsÚstreamÚmarkersr   r   r   r   r   r   r   r       s    
zExif.from_streamN©r   r   r   r   Úclassmethodr   r   r   r   r   r      s   r   c                   @   s   e Zd ZdZedd„ ƒZdS )ÚJfifz*Image header parser for JFIF image format.c                 C   s8   t  |¡}|jj}|jj}|jj}|jj}| ||||ƒS )zXReturn a |Jfif| instance having header properties parsed from image in
        `stream`.)r   r   r   r   r   Úapp0r   r   r   r   r   r   r   2   s    
zJfif.from_streamNr!   r   r   r   r   r#   /   s   r#   c                       sX   e Zd ZdZ‡ fdd„Zdd„ Zedd„ ƒZedd	„ ƒZ	ed
d„ ƒZ
edd„ ƒZ‡  ZS )r   zfSequence of markers in a JPEG file, perhaps truncated at first SOS marker for
    performance reasons.c                    s   t t| ƒ ¡  t|ƒ| _d S ©N)Úsuperr   Ú__init__ÚlistÚ_markers)r
   r    ©Ú	__class__r   r   r'   D   s    z_JfifMarkers.__init__c                 C   sN   d}d}g }| j D ]&}| ||j|jt|jƒ|jf ¡ q|g| }d |¡S )z{Returns a tabular listing of the markers in this instance, which can be handy
        for debugging and perhaps other uses.z4 offset  seglen  mc  name
=======  ======  ==  =====z%7d  %6d  %02X  %sÚ
)r)   ÚappendÚoffsetÚsegment_lengthÚordÚmarker_codeÚnameÚjoin)r
   ÚheaderÚtmplZrowsÚmarkerÚlinesr   r   r   Ú__str__H   s    
üÿÿ	
z_JfifMarkers.__str__c                 C   s>   t  |¡}g }| ¡ D ]}| |¡ |jtjkr q6q| |ƒS )zrReturn a |_JfifMarkers| instance containing a |_JfifMarker| subclass instance
        for each marker in `stream`.)Ú_MarkerParserr   Úiter_markersr-   r1   r   ZSOS)r   r   Zmarker_parserr    r6   r   r   r   r   [   s    

z_JfifMarkers.from_streamc                 C   s,   | j D ]}|jtjkr|  S qtdƒ‚dS )z#First APP0 marker in image markers.zno APP0 marker in imageN)r)   r1   r   ÚAPP0ÚKeyError©r
   Úmr   r   r   r$   g   s    

z_JfifMarkers.app0c                 C   s,   | j D ]}|jtjkr|  S qtdƒ‚dS )z#First APP1 marker in image markers.zno APP1 marker in imageN)r)   r1   r   ÚAPP1r<   r=   r   r   r   r   o   s    

z_JfifMarkers.app1c                 C   s,   | j D ]}|jtjkr|  S qtdƒ‚dS )z4First start of frame (SOFn) marker in this sequence.z(no start of frame (SOFn) marker in imageN)r)   r1   r   ÚSOF_MARKER_CODESr<   r=   r   r   r   r   w   s    

z_JfifMarkers.sof)r   r   r   r   r'   r8   r"   r   r   r$   r   r   Ú__classcell__r   r   r*   r   r   @   s   


r   c                       s4   e Zd ZdZ‡ fdd„Zedd„ ƒZdd„ Z‡  ZS )r9   zUService class that knows how to parse a JFIF stream and iterate over its
    markers.c                    s   t t| ƒ ¡  || _d S r%   )r&   r9   r'   Ú_stream)r
   Ústream_readerr*   r   r   r'   „   s    z_MarkerParser.__init__c                 C   s   t |tƒ}| |ƒS )zFReturn a |_MarkerParser| instance to parse JFIF markers from `stream`.)r   r   )r   r   rC   r   r   r   r   ˆ   s    
z_MarkerParser.from_streamc                 c   sP   t  | j¡}d}d}|tjkrL| |¡\}}t|| j|ƒ}|V  ||j }qdS )z…Generate a (marker_code, segment_offset) 2-tuple for each marker in the JPEG
        `stream`, in the order they occur in the stream.r   N)Ú_MarkerFinderr   rB   r   ZEOIÚnextÚ_MarkerFactoryr/   )r
   Zmarker_finderÚstartr1   Úsegment_offsetr6   r   r   r   r:   Ž   s    
z_MarkerParser.iter_markers)	r   r   r   r   r'   r"   r   r:   rA   r   r   r*   r   r9   €   s
   
r9   c                       sL   e Zd ZdZ‡ fdd„Zedd„ ƒZdd„ Zdd	„ Zd
d„ Z	dd„ Z
‡  ZS )rD   zFService class that knows how to find the next JFIF marker in a stream.c                    s   t t| ƒ ¡  || _d S r%   )r&   rD   r'   rB   )r
   r   r*   r   r   r'   ž   s    z_MarkerFinder.__init__c                 C   s   | |ƒS )zCReturn a |_MarkerFinder| instance to find JFIF markers in `stream`.r   )r   r   r   r   r   r   ¢   s    z_MarkerFinder.from_streamc                 C   sH   |}| j |d}| j|d d\}}|dkr.q||d  }}q@q||fS )aX  Return a (marker_code, segment_offset) 2-tuple identifying and locating the
        first marker in `stream` occuring after offset `start`.

        The returned `segment_offset` points to the position immediately following the
        2-byte marker code, the start of the marker segment, for those markers that have
        a segment.
        )rG   é   ó    )Ú_offset_of_next_ff_byteÚ_next_non_ff_byte)r
   rG   ÚpositionÚbyte_r1   rH   r   r   r   rE   §   s    z_MarkerFinder.nextc                 C   s<   | j  |¡ |  ¡ }|dkr&|  ¡ }q| j  ¡ d }||fS )uù   Return an offset, byte 2-tuple for the next byte in `stream` that is not
        'Ã¿', starting with the byte at offset `start`.

        If the byte at offset `start` is not 'Ã¿', `start` and the returned `offset`
        will be the same.
        ó   ÿrI   ©rB   ÚseekÚ
_read_byteÚtell)r
   rG   rN   Zoffset_of_non_ff_byter   r   r   rL   ½   s    
z_MarkerFinder._next_non_ff_bytec                 C   s8   | j  |¡ |  ¡ }|dkr&|  ¡ }q| j  ¡ d }|S )uç   Return the offset of the next 'Ã¿' byte in `stream` starting with the byte
        at offset `start`.

        Returns `start` if the byte at that offset is a hex 255; it does not necessarily
        advance in the stream.
        rO   rI   rP   )r
   rG   rN   Zoffset_of_ff_byter   r   r   rK   Ë   s    
z%_MarkerFinder._offset_of_next_ff_bytec                 C   s   | j  d¡}|stdƒ‚|S )zeReturn the next byte read from stream.

        Raise Exception if stream is at end of file.
        rI   zunexpected end of file)rB   ÚreadÚ	Exception)r
   rN   r   r   r   rR   Ù   s    z_MarkerFinder._read_byte)r   r   r   r   r'   r"   r   rE   rL   rK   rR   rA   r   r   r*   r   rD   ›   s   
rD   c                 C   sB   | t jkrt}n$| t jkr t}n| t jkr0t}nt}| || |¡S )znReturn |_Marker| or subclass instance appropriate for marker at `offset` in
    `stream` having `marker_code`.)	r   r;   Ú_App0Markerr?   Ú_App1Markerr@   Ú
_SofMarkerÚ_Markerr   )r1   r   r.   Z
marker_clsr   r   r   rF   ä   s    


rF   c                       s\   e Zd ZdZ‡ fdd„Zedd„ ƒZedd„ ƒZedd	„ ƒZ	ed
d„ ƒZ
edd„ ƒZ‡  ZS )rY   zqBase class for JFIF marker classes.

    Represents a marker and its segment occuring in a JPEG byte stream.
    c                    s$   t t| ƒ ¡  || _|| _|| _d S r%   )r&   rY   r'   Ú_marker_codeÚ_offsetÚ_segment_length)r
   r1   r.   r/   r*   r   r   r'   ø   s    z_Marker.__init__c                 C   s&   t  |¡rd}n
| |¡}| |||ƒS )zhReturn a generic |_Marker| instance for the marker at `offset` in `stream`
        having `marker_code`.r   )r   Zis_standaloneÚ
read_short)r   r   r1   r.   r/   r   r   r   r   þ   s    

z_Marker.from_streamc                 C   s   | j S )um   The single-byte code that identifies the type of this marker, e.g. ``'Ã '``
        for start of image (SOI).)rZ   r	   r   r   r   r1     s    z_Marker.marker_codec                 C   s   t j| j S r%   )r   Zmarker_namesrZ   r	   r   r   r   r2     s    z_Marker.namec                 C   s   | j S r%   )r[   r	   r   r   r   r.     s    z_Marker.offsetc                 C   s   | j S )z-The length in bytes of this marker's segment.)r\   r	   r   r   r   r/     s    z_Marker.segment_length)r   r   r   r   r'   r"   r   r   r1   r2   r.   r/   rA   r   r   r*   r   rY   ò   s   
	


rY   c                       sL   e Zd ZdZ‡ fdd„Zedd„ ƒZedd„ ƒZdd	„ Ze	d
d„ ƒZ
‡  ZS )rV   z&Represents a JFIF APP0 marker segment.c                    s*   t t| ƒ |||¡ || _|| _|| _d S r%   )r&   rV   r'   Ú_density_unitsÚ
_x_densityÚ
_y_density)r
   r1   r.   ÚlengthÚdensity_unitsÚ	x_densityÚ	y_densityr*   r   r   r'     s    z_App0Marker.__init__c                 C   s   |   | j¡S ©z[Horizontal dots per inch specified in this marker, defaults to 72 if not
        specified.)Ú_dpir_   r	   r   r   r   r   '  s    z_App0Marker.horz_dpic                 C   s   |   | j¡S ©zYVertical dots per inch specified in this marker, defaults to 72 if not
        specified.)rf   r`   r	   r   r   r   r   -  s    z_App0Marker.vert_dpic                 C   s4   | j dkr|}n | j dkr,tt|d ƒƒ}nd}|S )z6Return dots per inch corresponding to `density` value.rI   é   gR¸…ëQ@éH   )r^   ÚintÚround)r
   ZdensityZdpir   r   r   rf   3  s    

z_App0Marker._dpic                 C   s@   |  |¡}| |d¡}|  |d¡}|  |d¡}| ||||||ƒS )zUReturn an |_App0Marker| instance for the APP0 marker at `offset` in
        `stream`.é	   é
   é   )r]   Z	read_byte)r   r   r1   r.   r/   rb   rc   rd   r   r   r   r   =  s    
     ÿz_App0Marker.from_stream)r   r   r   r   r'   r   r   r   rf   r"   r   rA   r   r   r*   r   rV     s   


rV   c                       s\   e Zd ZdZ‡ fdd„Zedd„ ƒZedd„ ƒZedd	„ ƒZ	ed
d„ ƒZ
edd„ ƒZ‡  ZS )rW   z-Represents a JFIF APP1 (Exif) marker segment.c                    s$   t t| ƒ |||¡ || _|| _d S r%   )r&   rW   r'   Ú	_horz_dpiÚ	_vert_dpi)r
   r1   r.   ra   r   r   r*   r   r   r'   W  s    z_App1Marker.__init__c                 C   sH   |  |¡}|  ||¡r&| |||ddƒS |  |||¡}| ||||j|jƒS )zmExtract the horizontal and vertical dots-per-inch value from the APP1 header
        at `offset` in `stream`.ri   )r]   Ú_is_non_Exif_APP1_segmentÚ_tiff_from_exif_segmentr   r   )r   r   r1   r.   r/   Ztiffr   r   r   r   \  s
    
z_App1Marker.from_streamc                 C   s   | j S re   )ro   r	   r   r   r   r   n  s    z_App1Marker.horz_dpic                 C   s   | j S rg   )rp   r	   r   r   r   r   t  s    z_App1Marker.vert_dpic                 C   s    |  |d ¡ | d¡}|dkS )z§Return True if the APP1 segment at `offset` in `stream` is NOT an Exif
        segment, as determined by the ``'Exif  '`` signature at offset 2 in the
        segment.rh   é   s   Exif  )rQ   rT   )r   r   r.   Zexif_signaturer   r   r   rq   z  s    
z%_App1Marker._is_non_Exif_APP1_segmentc                 C   s0   |  |d ¡ | |d ¡}t |¡}t |¡S )zoReturn a |Tiff| instance parsed from the Exif APP1 segment of
        `segment_length` at `offset` in `stream`.é   )rQ   rT   ÚioÚBytesIOr   r   )r   r   r.   r/   Zsegment_bytesZ	substreamr   r   r   rr   ƒ  s    
z#_App1Marker._tiff_from_exif_segment)r   r   r   r   r'   r"   r   r   r   r   rq   rr   rA   r   r   r*   r   rW   T  s   



rW   c                       sD   e Zd ZdZ‡ fdd„Zedd„ ƒZedd„ ƒZedd	„ ƒZ	‡  Z
S )
rX   z7Represents a JFIF start of frame (SOFx) marker segment.c                    s$   t t| ƒ |||¡ || _|| _d S r%   )r&   rX   r'   Ú	_px_widthÚ
_px_height)r
   r1   r.   r/   r   r   r*   r   r   r'   ‘  s    z_SofMarker.__init__c                 C   s2   |  |¡}|  |d¡}|  |d¡}| |||||ƒS )zJReturn an |_SofMarker| instance for the SOFn marker at `offset` in stream.é   é   )r]   )r   r   r1   r.   r/   r   r   r   r   r   r   –  s    

z_SofMarker.from_streamc                 C   s   | j S )zImage height in pixels.)rx   r	   r   r   r   r   ¥  s    z_SofMarker.px_heightc                 C   s   | j S )zImage width in pixels.)rw   r	   r   r   r   r   ª  s    z_SofMarker.px_width)r   r   r   r   r'   r"   r   r   r   r   rA   r   r   r*   r   rX   Ž  s   

rX   )r   ru   Zdocx.image.constantsr   r   Zdocx.image.helpersr   r   Zdocx.image.imager   Zdocx.image.tiffr   r   r   r#   r   r9   rD   rF   rY   rV   rW   rX   r   r   r   r   Ú<module>   s    @I*8: