## The Python Imaging Library.# $Id$## FLI/FLC file handling.## History:# 95-09-01 fl Created# 97-01-03 fl Fixed parser, setup decoder tile# 98-07-15 fl Renamed offset attribute to avoid name clash## Copyright (c) Secret Labs AB 1997-98.# Copyright (c) Fredrik Lundh 1995-97.## See the README file for information on usage and redistribution.#from__future__importannotationsimportosfrom.importImage,ImageFile,ImagePalettefrom._binaryimporti16leasi16from._binaryimporti32leasi32from._binaryimporto8from._utilimportDeferredError## decoderdef_accept(prefix:bytes)->bool:return(len(prefix)>=6andi16(prefix,4)in[0xAF11,0xAF12]andi16(prefix,14)in[0,3]# flags)### Image plugin for the FLI/FLC animation format. Use the <b>seek</b># method to load individual frames.
[docs]classFliImageFile(ImageFile.ImageFile):format="FLI"format_description="Autodesk FLI/FLC Animation"_close_exclusive_fp_after_loading=Falsedef_open(self)->None:# HEADs=self.fp.read(128)ifnot(_accept(s)ands[20:22]==b"\x00\x00"):msg="not an FLI/FLC file"raiseSyntaxError(msg)# framesself.n_frames=i16(s,6)self.is_animated=self.n_frames>1# image characteristicsself._mode="P"self._size=i16(s,8),i16(s,10)# animation speedduration=i32(s,16)magic=i16(s,4)ifmagic==0xAF11:duration=(duration*1000)//70self.info["duration"]=duration# look for palettepalette=[(a,a,a)forainrange(256)]s=self.fp.read(16)self.__offset=128ifi16(s,4)==0xF100:# prefix chunk; ignore itself.__offset=self.__offset+i32(s)self.fp.seek(self.__offset)s=self.fp.read(16)ifi16(s,4)==0xF1FA:# look for palette chunknumber_of_subchunks=i16(s,6)chunk_size:int|None=Nonefor_inrange(number_of_subchunks):ifchunk_sizeisnotNone:self.fp.seek(chunk_size-6,os.SEEK_CUR)s=self.fp.read(6)chunk_type=i16(s,4)ifchunk_typein(4,11):self._palette(palette,2ifchunk_type==11else0)breakchunk_size=i32(s)ifnotchunk_size:breakself.palette=ImagePalette.raw("RGB",b"".join(o8(r)+o8(g)+o8(b)for(r,g,b)inpalette))# set things up to decode first frameself.__frame=-1self._fp=self.fpself.__rewind=self.fp.tell()self.seek(0)def_palette(self,palette:list[tuple[int,int,int]],shift:int)->None:# load palettei=0foreinrange(i16(self.fp.read(2))):s=self.fp.read(2)i=i+s[0]n=s[1]ifn==0:n=256s=self.fp.read(n*3)forninrange(0,len(s),3):r=s[n]<<shiftg=s[n+1]<<shiftb=s[n+2]<<shiftpalette[i]=(r,g,b)i+=1
def_seek(self,frame:int)->None:ifisinstance(self._fp,DeferredError):raiseself._fp.exifframe==0:self.__frame=-1self._fp.seek(self.__rewind)self.__offset=128else:# ensure that the previous frame was loadedself.load()ifframe!=self.__frame+1:msg=f"cannot seek to frame {frame}"raiseValueError(msg)self.__frame=frame# move to next frameself.fp=self._fpself.fp.seek(self.__offset)s=self.fp.read(4)ifnots:msg="missing frame size"raiseEOFError(msg)framesize=i32(s)self.decodermaxblock=framesizeself.tile=[ImageFile._Tile("fli",(0,0)+self.size,self.__offset)]self.__offset+=framesize