a :jgǡ@sddlmZddlZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZmZmZmZmZmZmZddlmZdd lmZdd lmZe rdd lmZdd l m!Z!Gd ddeZ"e"j#Z$dddddZ%GdddejZ&ddddZ'dddddZ(ee)e*e+e,ejfZ-dddddd d!Z.dd"dd#d$d%d&Z/ddd'd(d)d*Z0Gd+d,d,eZ1dd"ddd$d-d.Z2dd"d/d#d0d1d2Z3d`dd"d/dd#d4d5d6Z4dd7dd8d9Z5d"dd:d7d#d;dd?Z7d3Z8ddd@dAdBdCZ9dd7dDdEdFZ:dddDdGdHZ;ddddIdJZd"dd:dd#dRdSdTZ?dadddUdVddWdXZ@dbdd:dZdOd[d\d]ZAeBe&jCe&e%eDe&jCe4eEe&jCe3eFe&jCd^eGe&jCd_dS)c) annotationsN)IntEnum)cached_property)IO TYPE_CHECKINGAnyLiteral NamedTupleUnion)Image ImageChops ImageFile ImageMathImageOps ImagePalette ImageSequence)i16le)o8)o16le)_imaging)Bufferc@seZdZdZdZdZdZdS)LoadingStrategyz.. versionadded:: 9.1.0rr N)__name__ __module__ __qualname____doc__RGB_AFTER_FIRST RGB_AFTER_DIFFERENT_PALETTE_ONLY RGB_ALWAYSr!r!}||rt d |}||_ |_ |j|_ |j|_d|_|ddS)N znot a GIF filer'version r backgroundr0RGBr)r*r+r( SyntaxErrorinfoi16_sizetiler4rrawglobal_palettepalette_fptell_GifImageFile__rewind _n_frames_seek)r,r-msgflagsbitsr/r!r!r"_openas&      zGifImageFile._openintcCs^|jdurX|}z||ddqWn tyL|d|_Yn0|||jS)Nr FrJrHrKEOFErrorseek)r,currentr!r!r"n_frames|s   zGifImageFile.n_framescCs^|jdur|jdkS|}|r$dSz|ddd}WntyNd}Yn0|||S)Nr TFrQ)r,rT is_animatedr!r!r"rVs      zGifImageFile.is_animated)framer&c Cs||sdS||jkr(d|_|d|j}t|jd|dD]P}z||WqBty}z$||d}t||WYd}~qBd}~00qBdS)Nrr no more images in GIF file)Z _seek_check_GifImageFile__frame_imrKr1rRrS)r,rWZ last_frameferLr!r!r"rSs    zGifImageFile.seekT)rW update_imager&cs0|dkrBd_d_d_jjd_djvrTjd=njrT|rT |jdkrtd|}t |j_ jrj j rqd_j d}|r|dkrd}t|d}i}d}d}d} |sj d}|r|dkrqn|dkrjj d} } |dd kr|| dur|| d} | d@rL| d }t| dd |d <d | @} | d?} | rX| _n|ddkrd} | r| | 7} } qd|vr|dd| 7<n| |d<d}qn|ddkrX|dkrX| durX| j f|d<| dddkrX } | rXt| d krX| ddkrXt| djd< rqXn"|dkrj d}t|dt|d}}|t|d|t|d}}|jdks|jdkr|rt|jdt|jdf_tj||||f} |d} | d@dk}| d@rl| d@d}j d |>}|rhtd|}nd }j dd}j _qd}q|durd!}t||_|sdSg_jr؈jjj|dur|nj_|_|dkrnjr0t t!j"kr(|dur d"nd_#nd#_#nd$_#|rD|_$n(jrfdd%l%m%}|j_$nd_$n|j&d#krt t!j'ks|rd&jvrЈj(jd&dj)d"tj*j+_d"_#jd&=nd_#j)dtj*j+_d'd(d)fd*d+ }d_| _jrjjdkrjz4jdkrʈj\}}}}||||f}t|d#}j,d&|}|durj&d,vrd"}||d-}n&j,d.d}j&d,vrd}||}tj-.|||_nj/dur0jj_nh|durRj\}}}}||||f}t|d#}|}j&d,vr@d"}||d-}tj-.|||_Wnt1yhYn0|durd}|dur|dkrt t!j"kr|jd&<nj&d,vr|}t23d/||||fj|||fg_|,dr|djd<d0D]4}||vr||j|<n|jvrj|=qdS)1Nrcommentr zcannot seek to frame ;rX!r0r9durationr extensionr< NETSCAPE2.0loop, r'r8@r;r:r>Fzimage not found in GIF frameRGBAPL)copy transparencyrPztuple[int, int, int])colorr&csPjrB|ddtjjkr"d}tjj|d|ddS|||fSdS)Nr0r)_frame_paletter2rFtuple)rur,r!r"_rgbZs  z GifImageFile._seek.._rgbr>rp)rr=gif)rcri)4Z_GifImageFile__offsetZdisposerYrGrSrIZdisposal_methodr@rCload ValueErrorr*r.r+rRrArHr2sizemaxrBr Z_decompression_bomb_checkr4rrDimpastedispose_extentrErv_frame_transparencyLOADING_STRATEGYrr _moderFrsmoderputpalettealphaconvertDitherFLOYDSTEINBERGgetcorefillrZ_cropAttributeErrorr_Tile)r,rWr]rLr-rFr@Zframe_transparency interlaceZframe_dispose_extentblockrMZ dispose_bitsr_Zx0Zy0x1y1rNr/rsryZ dispose_sizeZ dispose_moderurtkr!rxr"rKs^             ""   &"                                   zGifImageFile._seekcs |jr dnd}d|_|jdkr@|jdurtj||j|j|_nT|j dvr|j|_|jrtjd|j|jpld|_|jj dg|j Rnd|_ |js|j dur|j|jjkrtj|jj |j}|jr|j dg|j R| |jd|jj||_||_d|_tdS)Nrqrrrrzr>rr)rv_prev_imrYrr rrr~rr putpalettegetdatarZrrsuper load_prepare)r,Z temp_mode expanded_im __class__r!r"rs,    $zGifImageFile.load_preparecCs|jdkr`|jdkr\ttjkr\|jdur@|j|jdd|_nd|_|j |jt j j |_dS|j sjdS|j|j jkr|jdurt jd|j}n.t jd|j}|dd|j| d}||j d|j j||_ |j dusJ|jdur|j|jd|j d}n |j d}|jdus2J|||j}|j |_|jj|_|jdkrr|j||j|n|j||jdS)Nrrqrpr>r)rYrrrr rrrrrr rrrr~rrr getpaletterrr)r,rZframe_imr!r!r"load_ends<        zGifImageFile.load_endcCs|jSN)rYrxr!r!r"rHszGifImageFile.tell)T)rrrformatformat_descriptionZ!_close_exclusive_fp_after_loadingrEr.r4rOpropertyrUrrVrSrKrrrH __classcell__r!r!rr"r)Ns$ 'r)rrrq)1rrrq Image.Image)rr&cCs|jtvr||St|jdkr|jdtjjd}|jdusFJ|jjdkr|jj D]&}|ddkrZ|jj ||j d<qqZ|S|d S) 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. :param im: Image object :returns: Image object r>rqrFNrpr0rrtrr) rRAWMODEr|r Z getmodebaserPaletteZADAPTIVErFcolorsr@)rZrgbar!r!r"_normalize_modes    rz_Palette | Nonedict[str, Any])rrFr@r&c Csd}|r>t|tttfr(t|dd}t|tjr>t|j}|jdkrl|s|d}|dusbJt|}n*|stddtdD}tjd|d|_|dusJ|rg}|jdusJtdt |d D]<}t |||d }|jj |}||vrd}| |qt|D]@\}}|durtt |D]} | |vr.| ||<qq.qg} |D]}|duslJ| |qZ|| }n`t||} | dur|| |}d |vrz| |d |d <Wnty|d =Yn0|S|jdusJ||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 Nirqcss|]}|dVqdS)r0Nr!.0r3r!r!r" 1rfz%_normalize_palette..r>rrr0rt) isinstancer# bytearraylistrrFrrr1r2rwrrappend enumerateZ remap_palette _get_optimizeindexr}) rrFr@Zsource_paletteZ im_paletteused_palette_colorsr3Z source_colorrjZdest_mapZoptimized_palette_colorsr!r!r"_normalize_palettesb                 rz IO[bytes]r5)rr*rFr&c Cst|}|jD] \}}t|tr|j||qt|||j}t||jD]}| |qNd}t |rr|dB}t ||d|dt |f|_ t ||t dd|jdt|jg| ddS)Nrrorr8r{)rr@itemsrstr encoderinfo setdefaultr_get_global_headerwrite get_interlace_write_local_headerZ encoderconfigr_saverr~rr)rr*rFZim_outrvr-rMr!r!r"_write_single_frame[s    rz4tuple[Image.Image, tuple[int, int, int, int] | None])base_imim_framer&cCsRdd||fD}|d|dkr6|d}|d}t||}||jddfS)NcSs"g|]}|jrt|jjndqS)rf)rFr#)rrr!r!r" zsz_getbbox..rr rpF)Z alpha_only)rr Zsubtract_moduloZgetbbox)rr palette_bytesdeltar!r!r"_getbboxws   rc@s&eZdZUded<ded<ded<dS)_Framerrz tuple[int, int, int, int] | NonebboxrrN)rrr__annotations__r!r!r!r"rs rc Cs|jd}|jd|jd}g}d}d}d}t|g|jdgD]} t| D]} t| } |dkr| j D]*\} } | dkrq~t | t r~|j | | q~|j} d| jvr| d| jdt | || } t |ttfr||| d<n$|durd| jvr| jd| d<t |ttfr8||| d<|d7}d}|r"|r"t|| \}}|s| drZ|djd| d7<qZ|djddkr|dur|jd|jdd }t| |}td | j|}|djjdusJ||djjt|| d}q&| d r&| jd kr&d| vrr| jdusHJz| j| | d<WntypYn0d| vr&| }td |j| d}|jd kr|\}}}}tjdd||||d}n>|jd krtd|j}|||}tjdd|d}|j |t!"|dnd}| }|#t$|p8| || qZqJt%|dkrxd|jvrt|djd|jd<dS|D]r}|j} |j&st'| |jD]}|(|qd}n*|sd|jd<| )|j&} |j&dd}t*|| ||jq|dS)NrcdisposalrZ append_imagesrtr r^r)rrrrqoptimizerrpcSs@|d|d|d|d|d|d|d|dddS) Nrrrgbarhrr!argsr!r!r"sz(_write_multiple_frames..)rrrrrrcSs|d|dddS)Nrrrhrr!rr!r!r"rrfr)maskFrTinclude_color_table)+rrr@ itertoolschainrIteratorrrsrrrrrrrwr_get_backgroundr newr~rrFrrZ_new_color_indexr}splitrZ lambda_evalZputdatarrrinvertrrr2rrrcrop_write_frame_data)rr*rFrcrZ im_framesZ previous_imZ frame_countZ background_imZ imSequencerrrrZ diff_framerrrur=rrrrrrZdelta_lZ frame_datar-offsetr!r!r"_write_multiple_framess                    rz str | bytes)rr*filenamer&cCst|||dddS)NT)save_all)r)rr*rr!r!r" _save_allsrF)rr*rrr&cCszd|jvsd|jvr,|jd|jd}nd}|jdd|rNt|||sZt||||dt|drv|dS)NrFrTr`flush) rr@rrrrrhasattrr)rr*rrrFr!r!r"r s   rrPcCs$|jdd}t|jdkr d}|S)Nrr r)rrminr~)rrr!r!r"rsrztuple[int, int])r*rrrMr&c Csnz|jd}Wnty$d}Yn0d|jvrDt|jdd}nd}t|jdd}|dusn|dksn|r|durzdnd}||d>O}|dtd td t|t|t|pdtd|jd }|rt|} t| } | r|d B}|| B}|d t|dt|dt|j dt|j dt||r\| r\|t | |tddS)Nrtrcr9rrr rrarbrnrr;rlr8) rKeyErrorrPrrro16_get_palette_bytes_get_color_table_sizer~_get_header_palette) r*rrrMrtrcrZ packed_flagrrcolor_table_sizer!r!r"r&sb           rc Cs(|}zt|d}|jdkr8tjd|g|tjdndd|g}dg}tj|tjtjd}tj||j|tjd}|jdusJ|j | } | rt | || } | rt | |Wdn1s0YWzt |WntyYn0n&zt |Wnty Yn00dS)Nwbr>Zppmtogif)stdoutstderrZppmquant256)stdinrr)_dumpopenr subprocess check_callDEVNULLPopenPIPErclosewaitCalledProcessErrorosunlinkOSError) rr*rtempfiler[Z quant_cmdZ togif_cmdZ quant_procZ togif_procretcoder!r!r" _save_netpbmXsD       , rzlist[int] | None)rr@r&cCs|jdvr|r|drtp$|jdk}|s:|j|jdkrg}t|D]\}}|rJ||qJ|svt|t |krz|S|j dusJt |j j t |j j}d|d >}t ||dkr|dkr|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 )rqrrrrriNr r)rr_FORCE_OPTIMIZEwidthheightrZ histogramrrr2rFr Z getmodebands bit_length)rr@Zoptimiserr3countZnum_palette_colorsZcurrent_palette_sizer!r!r"rs(   r)rr&cCs:|sdSt|dkrdSttt|dddSdS)Nrrmr r0r)r2mathceillog)rr!r!r"rs  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 rr0r)rr2r)rrZactual_target_size_diffr!r!r"rs rcsJ|js dSt|jj|jjdkrFdfddttdDS)z Gets the palette for inclusion in the gif header :param im: Image object :returns: Bytes, len<=768 suitable for inclusion in gif header rfrpc3s&|]}|d|ddVqdS)rnr0Nr!rrr!r"rrfz%_get_palette_bytes..r0)rFr#rjoinr1r2rr!rr"rs   $rz=int | tuple[int, int, int] | tuple[int, int, int, int] | None)rinfo_backgroundr&c Cspd}|rlt|trh|jdus Jz|j||}Wqltyd}zt|dvrPWYd}~qld}~00n|}|S)Nr)z$cannot allocate more than 256 colorsz/cannot add non-opaque RGBA color to RGB palette)rrwrFZgetcolorr}r)rrr=r\r!r!r"rs  rz list[bytes]c Csd}|jddksB|rFd|vsB|ddusB|dsB|drFd}t||d }t|}t|}d |t|jd t|jd t|d t|td t|g}|ddur| dtdtddtdtd t|dtd |drdtd}|d}t |t r.| }t d t|dD]*} || | d} |tt| | 7}q>|td 7}| ||S)z2Return a list of strings representing a GIF headers87ar7s89artrkNrcr_r=sGIFrr r;rarhr<rjr0re)r@rrrrrr~rrrrrencoder1r2) rr@r7r=rrheaderZ comment_blockr_r3Zsubblockr!r!r"rsp            r)r*rrparamsr&c CsZzN||_t|||dt||tdd|jdt|jg|dW|`n|`0dS)Nrr{rr) rrrrrr~rrr)r*rrrr!r!r"rBs rzdict[str, Any] | Nonez$tuple[list[bytes], list[int] | None]cCsd|dur i}t||}d|vr6d|jvr6|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@rrFrr)rrFr@rZim_modrr!r!r" getheader]s   rrr)rrrr&cKs>ddlm}Gddd|}||}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. To specify duration, add the time in milliseconds, e.g. ``getdata(im_frame, duration=1000)`` :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 r)BytesIOc@s eZdZgZdddddZdS)zgetdata..CollectorrrP)r.r&cSs|j|t|Sr)r.rr2)r,r.r!r!r"rs z getdata..Collector.writeN)rrrr.rr!r!r!r" Collectorsr)iorr|rr.)rrrrrr*r!r!r"r{s  rz.gifz image/gif)F)NN)r)H __future__rrrrrenumr functoolsrtypingrrrrr r r r rrrrr_binaryrrArrrrZ_typingrrrrr(r)rrr#rrrPZ_Paletterrrrrrrrrrr rrrrrrrrrZ register_openrZ register_saveZregister_save_allZregister_extensionZ register_mimer!r!r!r"sh    $       ) G { 220 >(