B ]_p@sNddlZddlmZmZmZmZmZddlmZm Z m Z m Z dZddZGdd d ejZd d d d Zd5ddZddZddZddZddZd6ddZddZddZddZd Zd d!Zd"d#Zd$d%Zd&d'Zd(d)Z d*d+Z!d,d-Z"d7d.d/Z#d8d1d2Z$e%ej&eee'ej&ee(ej&ee)ej&d3e*ej&d4dS)9N)Image ImageChops ImageFile ImagePalette ImageSequence)i8i16leo8o16lez0.9cCs|dddkS)N)sGIF87asGIF89a)prefixr r 4/tmp/pip-build-ktz6qwqq/Pillow/PIL/GifImagePlugin.py_accept)src@sleZdZdZdZdZdZddZddZe d d Z e d d Z d dZ ddZ ddZddZddZdS) GifImageFileZGIFzCompuserve GIFFNcCs,|jd}|r(t|r(|jt|SdS)Nr)fpreadr)selfsr r rdata:s  zGifImageFile.datacCsH|jd}|dddkr$td|dd|jd<t|ddt|ddf|_g|_t|d}|d@d }|d @rt|d |jd <|jd |>}xvtdt |d D]b}|d t||krt||d krt||dksnt d|}||_ |_ PqW|j|_|j|_d|_d|_|ddS)N r )sGIF87asGIF89aznot a GIF fileversion r backgroundrRGB)rr SyntaxErrorinfoi16_sizetilerrangelenrrawglobal_palettepalette_GifImageFile__fptell_GifImageFile__rewind _n_frames _is_animated_seek)rrflagsbitspir r r_open@s* "   D   zGifImageFile._opencCsb|jdkr\|}yx||dqWWn"tk rP|d|_YnX|||jS)Nr)r/r-seekEOFError)rcurrentr r rn_frames^s  zGifImageFile.n_framescCsj|jdkrd|jdk r"|jdk|_nB|}y|dd|_Wntk rXd|_YnX|||jS)NrTF)r0r/r-r7r8)rr9r r r is_animatedjs      zGifImageFile.is_animatedc Cs||sdS||jkr0|dkr&d|_|d|j}xRt|jd|dD]:}y||WqLtk r||tdYqLXqLWdS)Nrrzno more images in GIF file)Z _seek_check_GifImageFile__frameimr1r'r8r7)rframeZ last_framefr r rr7{s    zGifImageFile.seekc Cs|dkrDd|_d|_ddddg|_d|_|j|jd|_d|_n|j sR| ||jdkrlt d|||_g|_ |j|_ |jr|j |jx |rqWd|_|jr|j |j|jddlm}||j|_i}x|j d}|r|dkrPq|dkrR|j d}|}t|dkrt|d}|d@rNt|d |d <t|dd d |d <d |@}|d?}|r>||_nt|dkrx8|rd|kr|d|7<n||d<|}qWqnnt|dkr>||j f|d<|dddkr>|}t|d kr>t|ddkr>t|dd |d<x|rNq@Wq|dkr|j d}t|ddt|dd}} |t|dd| t|dd} } | |jdks| |jdkrt| |jdt| |jdf|_|| | | f|_t|d}|d@dk} |d@rJ|d@d} td|j d | >|_t|j d} |j |_d|| | | f|j| | ffg|_ PqqWyz|jdkrd|_nH|jdkrt|jtj d |j|j!d!|_n|j r|j |_|jr|"|j|j|_Wnt#t$fk r YnX|j s.t%xrAr#rblockr2Z dispose_bitsZx0Zy0Zx1y1 interlacer3kr r rr1s              "* "            zGifImageFile._seekcCs|jS)N)r<)rr r rr-'szGifImageFile.tellcCs\tj||jrL|jdkrL||j|j}|j||j|d|j|_|j |_dS)NrZRGBA) rload_endrUrVr^r=rTrYconvertrA)rupdatedr r rrf*s  zGifImageFile.load_endcCsBz4y|j|jkr|jWntk r0YnXWdd|_XdS)N)r,rcloser_)rr r r _close__fp7s   zGifImageFile._close__fp)__name__ __module__ __qualname__formatformat_descriptionZ!_close_exclusive_fp_after_loadingr*rr6propertyr:r;r7r1r-rfrjr r r rr2s  rrSrR)1rSrRFcCsp|jtkr||St|jdkrf|r\d}|jrJt|jdd}|jdtj |dS|dS|dS)a Takes an image (or frame), returns an image in a mode that is appropriate for saving in a Gif. It may return the original image, or it may return an image converted to palette or 'L' mode. UNDONE: What is the point of mucking with the initial call palette, for an image that shouldn't have a palette, or it would be a mode 'P' and get returned in the RAWMODE clause. :param im: Image object :param initial_call: Default false, set to true for a single frame. :returns: Image object r!rrrR)r+colorsrS) raRAWMODErWrZ getmodebaser+r(getdatargZADAPTIVE)r=Z initial_callZ palette_sizer r r_normalize_modeHs  rvc Csd}|rjt|tttfr(t|dd}t|tjrjttjt|j dd|j dd|j dd}|j dkr|s|j ddd}n*|stddt dD}tjd|d |_ t||}|dk r|||S||j _ |S) at Normalizes the palette for image. - Sets the palette to the incoming palette, if provided. - Ensures that there's a palette for L mode images - Optimizes the palette if necessary/desired. :param im: Image object :param palette: bytes object containing the source palette, or .... :param info: encoderinfo :returns: Image object NirrirRr!css|]}|dVqdS)rNr ).0r5r r r sz%_normalize_palette..)r+) isinstancebytes bytearraylistr itertoolschain from_iterablezipr+rar=Z getpaletter' _get_optimizeZ remap_palette)r=r+r#Zsource_paletteused_palette_colorsr r r_normalize_palettefs,       rc Cst|d}x$|jD]\}}|j||qWt|||j}xt||jD]}||qLWd}t|rr|dB}t ||d|dt|f|_ t ||dd|j dt|jfg|ddS)NTrrP)rrrrQ)rvr#items encoderinfo setdefaultr_get_global_headerwrite get_interlace_write_local_headerZ encoderconfigr_saverZrtra)r=rr+Zim_outrevrr2r r r_write_single_frames $rc Cs|jd|jd}|jd|jd}g}d}d}xt|g|jdgD]}xt|D]} t| } |dkrx$| j D]\} } |j | | qWt | ||j} |j} t |t tfr||| d<t |t tfr||| d<|d7}|r|d} | ddkrj|dkrdt||jd|jd}td | j|}||dd j|}n| d }t| t|krt| |}nt| d |d }|}|s|rh| d d| d7<qhnd}|| || d qhWqTWt|dkrx|D]~}|d } |dsJx"t| |d D]}||q0Wd}n*d|d d<| |d} |ddd}t|| ||d q WdSd|jkrt |jdt tfrt |jd|jd<dS)NrFdisposalrZ append_imagesrr@r rrRr=r!r)r=bboxrr)rrTinclude_color_table)!rgetr#r}r~rIteratorrvrArrrryr|tuple_get_backgroundrnewrZZ putpaletter+_get_palette_bytesrZsubtract_modulorgZgetbboxappendr(rrZcrop_write_frame_datasum)r=rr+rFrZ im_framesZ frame_countZ background_imZ imSequenceim_framererrpreviousrZbase_imdeltarZ frame_dataroffsetr r r_write_multiple_framessn"        rcCst|||dddS)NT)save_all)r)r=rfilenamer r r _save_allsrcCsd|jksd|jkr,|jd|jd}nd}|jdd|jd<|rTt|||s`t||||dt|dr||dS)Nr+optimizeTrBflush)rr#rrrrhasattrr)r=rrrr+r r rrs   rcCs$|jdd}t|jdkr d}|S)Nrdrr)rrminrZ)r=rdr r rr srcCsd}y|jd}Wntk r&YnJXt|}d}t||j}|dk rpy||}Wntk rnd}YnXd|jkrt|jdd}nd}t|jdd}|s|dks|r|rdnd} | |d >O} |sd}|d td td t| t |t|tdd |jkrdt |jd kr|d tdxLt dt |jd dD]2} |jd | | d} |tt | | qZW|tdd|jkr|jd} |d tdtddtdtdt | td|jd} | r*t |}t |}|r*|dB}||B}|dt |dt |dt |jdt |jdt|| r|r|t||tddS)NFrETrFrrrrr rCrDrOrIrHrJrLrs NETSCAPE2.0rrrrMr)rr`intrindexrXrrr o16r(r'r_get_color_table_sizerZ_get_header_palette)rr=rr2Ztransparent_color_existsrErrFrZ packed_flagr5ZsubblockZnumber_of_loopsr palette_bytescolor_table_sizer r rrs\     6   : B rc Csddl}ddlm}m}m}m}|}t|d} |jdkrjt|j d} |d|g| | dWdQRXn~dd|g} dg} t|j d&} || || d} || | j | | d }WdQRX| j | }|r||| | }|r||| WdQRXy| |Wntk rYnXdS) Nr)Popen check_callPIPECalledProcessErrorwbr!Zppmtogif)stdoutstderrZppmquantZ256)stdinrr)os subprocessrrrr_dumpopenradevnullrriwaitunlinkOSError)r=rrrrrrrtempfiler?rZ quant_cmdZ togif_cmdZ quant_procZ togif_procretcoder r r _save_netpbmds0      rcCs|jdkr|r|ddrtp&|jdk}|s<|j|jdkrg}x&t|D]\}}|rN||qNW|st|dkrt |t|kr|SdS)aL Palette optimization is a potentially expensive operation. This function determines if the palette should be optimized using some heuristics, then returns the list of palette entries in use. :param im: Image object :param info: encoderinfo :returns: list of indexes of palette entries in use, or None )rRrSrrrSirN) rar_FORCE_OPTIMIZEwidthheight enumerateZ histogramrr(r[)r=r#Zoptimiserr5countr r rrs   rcCsFddl}|sdSt|dkr dSt||t|dddSdS)NrrNrrr )mathr(rceillog)rrr r rrs  rcCs<t|}d|>t|d}|dkr8|tdd|7}|S)z Returns the palette, null padded to the next power of 2 (*3) bytes suitable for direct inclusion in the GIF header :param palette_bytes: Unpadded palette bytes, in RGBRGB form :returns: Null padded palette r rr)rr(r )rrZactual_target_size_diffr r rrs rcCs|jjS)z Gets the palette for inclusion in the gif header :param im: Image object :returns: Bytes, len<=768 suitable for inclusion in gif header )r+)r=r r rrsrcCs&d}|r"|}t|tr"|j|}|S)Nr)ryrr+Zgetcolor)r=ZinfoBackgroundrr r rrs   rcCsd}xndD]R}|r ||kr |dkr.||dks |dkrVdt||krRdksVq q d}Pq W|jd dkrtd}t||d }t|}t|}d |t|jdt|jdt|d t|tdt |gS) z2Return a list of strings representing a GIF headers87a)rErFrLrIrFrrIrrJs89arrsGIFr) r(r#rrrrrrZr r)r=r#rZ extensionKeyrrrr r rrs"  &" rc CsRzF||_t|||dt||dd|jdt|jfg|dWd|`XdS)NrrQ)rrr)rrrrrZrtrar)rrrparamsr r rrs rcCsdt||}|dkri}d|kr6d|jkr6|jd|d<t|||}|j|_|j|_t||}||fS)a Legacy Method to get Gif data from image. Warning:: May modify image data. :param im: Image object :param palette: bytes object containing the source palette, or .... :param info: encoderinfo :returns: tuple of(list of header items, optimized palette) Nr)rr#rr+r=r)r=r+r#rZim_modheaderr r r getheader+s   rrrcKs2Gdddt}||}t|||||jS)a Legacy Method Return a list of strings representing this image. The first string is a local image header, the rest contains encoded image data. :param im: Image object :param offset: Tuple of (x, y) pixels. Defaults to (0,0) :param \**params: E.g. duration or other encoder info parameters :returns: List of Bytes containing gif encoded frame data c@seZdZgZddZdS)zgetdata..CollectorcSs|j|dS)N)rr)rrr r rr[sz getdata..Collector.writeN)rkrlrmrrr r r r CollectorXsr)objectrWrr)r=rrrrr r rruIs ruz.gifz image/gif)F)F)NN)r)+r}rrrrr_binaryrr r$r r r __version__rrrtrvrrrrrrrrrrrrrrrrrruZ register_openrnZ register_saveZregister_save_allZregister_extensionZ register_mimer r r rs@   ,M  Q0%   '  !