UPDATED: Load Animated GIF frames

Share your advanced PureBasic knowledge/code with the community.
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

Here is a version with some improvements :

- No more APIs (multi-platform)
- Corrects colors artefacts (transparency based on index in palette and not on resulting color)
- Full alphachannel support
- Unicode compliant
- Respects interframe delay

Code: Select all

; Original PB code by "hagibaba" (Purebasic.fr forums) based on "loadgif.c" for ImageShop32 by John Findlay
; Gif Anim support by localmotion34 (Purebasic.fr forums)
; Updated & Extended by Dean Williams - resplace.net
; APIs free, alpha channel support and bug fixes by Niffo (Purebasic.fr forums)

; Please help development and report any problems or improvements/bug fixes you may have on
; if we all work together we can have some really nice GIF support in PureBasic!
; http://www.purebasic.fr/english/viewtopic.php?f=12&t=27575

EnableExplicit

;{ - Structures

CompilerIf Defined(BITMAPINFOHEADER, #PB_Structure)
CompilerElse
   Structure BITMAPINFOHEADER
      biSize.l
      biWidth.l
      biHeight.l
      biPlanes.w
      biBitCount.w
      biCompression.l
      biSizeImage.l
      biXPelsPerMeter.l
      biYPelsPerMeter.l
      biClrUsed.l
      biClrImportant.l
   EndStructure
   
   #BI_RGB = 0
   
   Structure RGBQUAD
      rgbBlue.a
      rgbGreen.a
      rgbRed.a
      rgbReserved.a
   EndStructure
CompilerEndIf
  
Structure GIF_Frame
   Image.l
   DelayTime.w
EndStructure
  
Structure GIFHEADER ;Header
   ghSig.b[6] ;Signature & Version
   ghWidth.w ;Logical Screen Width
   ghHeight.w ;Logical Screen Height
   ghPkFields.b ;Global Color Table Flag
   ghBkColIndex.b ;Background Color Index
   ghAspRatio.b ;Pixel Aspect Ratio
EndStructure

Structure GIFIMAGE ;Image Descriptor
   imSep.b ;Image Separator
   imLeft.w ;Image Left Position
   imTop.w ;Image Top Position
   imWidth.w ;Image Width
   imHeight.w ;Image Height
   impkFields.b ;Local Color Table Flag
EndStructure

Structure GIFCLASS ;This is instead of using globals
   *lpBytes.Byte ;Pointer to next byte in block
   Pass.l ;First pass for interlaced images in OutLineGIF()
   Line.l ;Offset for addressing the bits in OutLineGIF()
   lpBits.l ;Scanline for bits
   pitch.l ;Bytes are rounded up for image lines
   CurrCodeSize.l ;The current code size
   BitsLeft.l ;Used in NextCodeGIF()
   BytesLeft.l ;Used in NextCodeGIF()
   CurrByte.l ;Current byte
   bUseGlobalColMap.b ;Is the color table global
   GlobColRes.l ;Color Resolution, bits '6' '5' '4'
   bImInterLace.b ;Is the image interlaced
   ImgColRes.l ;Color Resolution
EndStructure
    
;}

Procedure GIF_OutLine(lpPixels.l,LineLen.l,height.l,*cl.GIFCLASS)
   ;Outputs the pixel color index data to the DIB
   ;lpPixels -> Memory block that holds the color index value
   ;LineLen -> Length of the line of pixels
   ;Height -> im\imHeight
   ;Gif images are 2, 16 or 256 colors, poking the values into memory
   ;requires a different method for each case. If gif is interlaced,
   ;that is dealt with here.
  
   Protected ib.l,pixel.l,byte.l,BitCnt.l,CntBk.l,ColRes.l,Bits.l
  
   Bits=*cl\lpBits-(*cl\Line * *cl\pitch) ;Pointer to bits
  
   If *cl\bUseGlobalColMap
     ColRes=*cl\GlobColRes
   Else
     ColRes=*cl\ImgColRes
   EndIf
  
   Select ColRes
    
     Case 1
       byte=0
       For pixel=0 To LineLen-1 Step 8
         ib=0
         CntBk=7
         For BitCnt=0 To 8-1
           If PeekB(lpPixels+BitCnt+pixel)
             ib=ib | (1 << CntBk)
           EndIf
           CntBk-1
         Next
         PokeB(Bits+byte,ib)
         byte+1
       Next
      
     Case 4
       byte=0
       For pixel=0 To LineLen-1 Step 2
         ib=((PeekB(lpPixels+pixel) & 255) << 4)
         ib | (PeekB(lpPixels+pixel+1) & 255)
         PokeB(Bits+byte,ib)
         byte+1
       Next
      
     Case 8
       For pixel=0 To LineLen-1
         ib=PeekB(lpPixels+pixel) & 255
         PokeB(Bits+pixel,ib)
       Next
      
   EndSelect
  
   If *cl\bImInterLace ;Set Line for different passes when Interlaced
    
     Select *cl\Pass
      
       Case 0 ;Pass 1
         If *cl\Line<height-8
           *cl\Line+8
         Else
           *cl\Line=4 : *cl\Pass+1 ;Set Line for second pass
         EndIf
        
       Case 1 ;Pass 2
         If *cl\Line<height-8
           *cl\Line+8
         Else
           *cl\Line=2 : *cl\Pass+1 ;Set Line for third pass
         EndIf
        
       Case 2 ;Pass 3
         If *cl\Line<height-4
           *cl\Line+4
         Else
           *cl\Line=1 : *cl\Pass+1 ;Set Line for fourth pass
         EndIf
        
       Case 3 ;Pass 4
         If *cl\Line<height-2
           *cl\Line+2
         EndIf
        
     EndSelect
    
   Else ;When not Interlaced increment Line
    
     *cl\Line+1
    
   EndIf
  
EndProcedure

Procedure.l GIF_NextCode(file.l,Array CharBuff.b(1),Array CodeMask.l(1),*cl.GIFCLASS)
   ;Reads the next code from the data stream
   ;Returns the LZW CODE or ERROR
  
   Protected count.l,Char.l,ret.l
  
   If *cl\BitsLeft=0 ;Any bits left in byte?
    
     If *cl\BytesLeft<=0 ;If not get another block
      
       *cl\lpBytes=@CharBuff(0) ;Set byte pointer
       *cl\BytesLeft=ReadByte(file) & 255
      
       If *cl\BytesLeft<0
         ProcedureReturn *cl\BytesLeft ;Return if error
       ElseIf *cl\BytesLeft
         For count=0 To *cl\BytesLeft-1
           Char=ReadByte(file) & 255
           If Char<0 : ProcedureReturn Char : EndIf
           CharBuff(count)=Char ;Fill the char buffer with the new block
         Next
       EndIf
      
     EndIf
    
     *cl\CurrByte=*cl\lpBytes\b & 255 ;Get a byte
     *cl\lpBytes+1 ;Increment index pointer
     *cl\BitsLeft=8 ;Set bits left in the byte
     *cl\BytesLeft-1 ;Decrement the bytes left counter
    
   EndIf
  
   ;Shift off any previously used bits
   ret=*cl\CurrByte >> (8-*cl\BitsLeft)
  
   While *cl\CurrCodeSize>*cl\BitsLeft
    
     If *cl\BytesLeft<=0
      
       ;Out of bytes in current block
       *cl\lpBytes=@CharBuff(0) ;Set byte pointer
       *cl\BytesLeft=ReadByte(file) & 255
      
       If *cl\BytesLeft<0
         ProcedureReturn *cl\BytesLeft ;Return if error
       ElseIf *cl\BytesLeft
         For count=0 To *cl\BytesLeft-1
           Char=ReadByte(file) & 255
           If Char<0 : ProcedureReturn Char : EndIf
           CharBuff(count)=Char ;Fill the char buffer with the current block
         Next
       EndIf
      
     EndIf
    
     *cl\CurrByte=*cl\lpBytes\b & 255 ;Get a byte
     *cl\lpBytes+1 ;Increment index pointer
     ret | (*cl\CurrByte << *cl\BitsLeft) ;Add remaining bits to return
     *cl\BitsLeft+8 ;Set bit counter
     *cl\BytesLeft-1 ;Decrement bytesleft counter
    
   Wend
  
   *cl\BitsLeft-*cl\CurrCodeSize ;Subtract the code size from bitsleft
   ret & CodeMask(*cl\CurrCodeSize) ;Mask off the right number of bits
   ProcedureReturn ret
  
EndProcedure

Procedure GIF_CreateDIImage(Image.l, *dib.BITMAPINFOHEADER, TransColIndex.w)
   Define *Bits = *dib+*dib\biSize+(*dib\biClrUsed*4)
   Define.l Image = CreateImage(#PB_Any, *dib\biWidth, *dib\biHeight, 32)
   Define.l X, Y, RGBA, Col
   Define *Pal = *dib + *dib\biSize
   Define.a ColInd, Alpha
   Define.l dibPitch = *dib\biSizeImage/*dib\biHeight

   StartDrawing(ImageOutput(Image))
   DrawingMode(#PB_2DDrawing_AllChannels)

;   Define *BufAddr = DrawingBuffer()
;   Define.l BufPitch = DrawingBufferPitch()
   For Y = 0 To *dib\biHeight - 1
      For X = 0 To *dib\biWidth - 1
         
         Select *dib\biBitCount
            Case 8
               ColInd = PeekA(*Bits + Y*dibPitch+X)
            Case 4
               ;If X % 2
               ;   ColInd = PeekA(*Bits + Y*dibPitch+X) & $F
               ;Else
               ;   ColInd = PeekA(*Bits + Y*dibPitch+X) >> 4
               ;EndIf
               ColInd = PeekA(*Bits + Y*dibPitch+X/2) >> (4*(1-X%2)) & $F
         EndSelect         

         If ColInd = TransColIndex : Alpha = 0 : Else : Alpha = 255 : EndIf
         Col = PeekL(*Pal+ColInd*4)

         ; Plot
         RGBA = RGBA(Blue(Col), Green(Col), Red(Col), Alpha)
         Plot(X, *dib\biHeight-1-Y, RGBA)

;          ; Direct Buffer Write (not faster !?)
;          If DrawingBufferPixelFormat() & #PB_PixelFormat_32Bits_RGB
;             RGBA = RGBA(Blue(Col), Green(Col), Red(Col), Alpha)
;          ElseIf DrawingBufferPixelFormat() & #PB_PixelFormat_32Bits_BGR
;             RGBA = RGBA(Red(Col), Green(Col), Blue(Col), Alpha)
;          EndIf
;          If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY
;             PokeL(*BufAddr + (Y*BufPitch+X*4), RGBA)
;          Else
;             PokeL(*BufAddr + ((*dib\biHeight-1-Y)*BufPitch+X*4), RGBA)
;          EndIf
         
      Next X
   Next Y

   StopDrawing()

   ProcedureReturn Image

EndProcedure

Procedure.l GIF_LoadFrames(filename.s,Array GIF_Frames.GIF_Frame(1))
   ;From "loadgif.c" for ImageShop32 by John Findlay
   ;Loads LZW Graphics Interchange Format files
   ;Uses NextCodeGIF() and OutLineGIF()
  
   Protected Dim stack.b(4096) ;Stack for storing pixels
   Protected Dim suffix.b(4096) ;Suffix table, max number of LZW codes
   Protected Dim prefix.l(4096) ;Prefix linked list (these are longs)
   Protected Dim CharBuff.b(279) ;Current block
   Protected Dim GlobalCols.l(256) ;Global colors of gif
   Protected Dim localCols.l(256) ;Local image colors of gif
   Protected Dim CodeMask.l(16) ;Masks for LZW compression algorithm
   Protected gh.GIFHEADER
   Protected im.GIFIMAGE
   Protected cl.GIFCLASS
   Protected bi.BITMAPINFOHEADER
   Protected *pal.RGBQUAD
   Protected *lpSP.Byte ;Pointer to stack
   Protected *lpBuffPtr.Byte ;Pointer to buffer
   Protected bGlobColsSorted.b ;Sort Flag  bit '3' (this is unused)
   Protected file.l,sig.s,PkFields.l,bGlobColTable.b,GlobColBytes.l
   Protected GlobColors.l,count.l,Red.l,Green.l,Blue.l
   Protected width.l,height.l,impkFields.l,bImColsSorted.b
   Protected bImColTable.b,ImgColBytes.l,LZWCodeSize.l,TopSlot.l
   Protected ClearCode.l,ImgColors.l,EndingCode.l,NewCodes.l,Slot.l
   Protected lpBUFF.l,TempOldCode.l,OldCode.l,BufCnt.l,bitcount.l
   Protected ncolors.l,Len.l,hDIB.l,cc.l,code.l
   Protected *dib.BITMAPINFOHEADER
  
   CodeMask( 0)=$0000 : CodeMask( 1)=$0001
   CodeMask( 2)=$0003 : CodeMask( 3)=$0007
   CodeMask( 4)=$000F : CodeMask( 5)=$001F
   CodeMask( 6)=$003F : CodeMask( 7)=$007F
   CodeMask( 8)=$00FF : CodeMask( 9)=$01FF
   CodeMask(10)=$03FF : CodeMask(11)=$07FF
   CodeMask(12)=$0FFF : CodeMask(13)=$1FFF
   CodeMask(14)=$3FFF : CodeMask(15)=$7FFF
  
   ;Open the file
   file=ReadFile(#PB_Any,filename)
   If file=0
     MessageRequester("GIF Load Error!" , "Could not open the GIF image file for reading.")
     ProcedureReturn #False
   EndIf
  
   ;Read the file header and logical screen descriptor
   ReadData(file,gh,SizeOf(gh))
  
   sig=PeekS(@gh\ghSig,6,#PB_Ascii) ;Get the header version string
   If sig<>"GIF89a" And sig<>"GIF87a"
     CloseFile(file)
     MessageRequester("GIF Load Error!" , "File was not a valid GIF image file")
     ProcedureReturn #False ;NOT_VALID
   EndIf
  
   Define.l realwidth=gh\ghWidth
   Define.l realheight=gh\ghHeight
  
   ;Store gh\ghPkFields for bit manipulation
   PkFields=gh\ghPkFields & 255
  
   ;Global Color Table Flag bit '7'
   bGlobColTable=(PkFields & (1 << 7)) >> 7
  
   If bGlobColTable
     cl\bUseGlobalColMap=#True
    
     GlobColBytes=3*(1 << ((PkFields & $07)+1)) ;Table size in bytes
     GlobColors=GlobColBytes/3 ;Number of colors
    
     ;Some gif encoders do not follow the gif spec very well,
     ;so make cl\GlobColRes from GlobColors.
     ;Also gif's are used on different platforms, which do
     ;have different bits per pixel. i.e. 32 colors is 5 bits/pixel.
     If GlobColors<=2
       cl\GlobColRes=1
     ElseIf GlobColors<=16
       cl\GlobColRes=4
     Else
       cl\GlobColRes=8
     EndIf
    
     For count=0 To GlobColors-1 ;Get the global screen colors
       Red=ReadByte(file) & 255
       Green=ReadByte(file) & 255
       Blue=ReadByte(file) & 255
       GlobalCols(count)=RGB(Red,Green,Blue)
     Next
   EndIf

   Define.w TransColorIndex = -1
   count=0
   While count<>$2C ;Search for im\imSep
     count=ReadByte(file) & 255
     If count = $F9
       ReadByte(file)
       Define.b tflag = ReadByte(file) & 1
       Define.w delaytime = ReadWord(file)
       Define.a transparent = ReadByte(file)
       If tflag : TransColorIndex = transparent : EndIf
     EndIf
   Wend
   FileSeek(file,Loc(file)-1) ;Seek to im\imSep
  
   ReadData(file,im,SizeOf(im)) ;Read the image descriptor
  
   ;Store im\imPkFields for bit manipulation
   impkFields=im\impkFields & 255
  
   ;Is the image interlaced
   cl\bImInterLace=(impkFields & (1 << 6)) >> 6
  
   ;Is the local color table sorted
   bImColsSorted=(impkFields & (1 << 5)) >> 5
  
   ;Is there a local color table
   bImColTable=(impkFields & (1 << 7)) >> 7
  
   If bImColTable
     cl\bUseGlobalColMap=#False
    
     ImgColBytes=3*(1 << ((impkFields & $07)+1)) ;Table size in bytes
     ImgColors=ImgColBytes/3 ;Number of colors
    
     If ImgColors<=2 ;Make sure image bit depth is 1, 4 or 8
       cl\ImgColRes=1
     ElseIf ImgColors<=16
       cl\ImgColRes=4
     Else
       cl\ImgColRes=8
     EndIf
    
     For count=0 To ImgColors-1 ;Get the local image colors
       Red=ReadByte(file) & 255
       Green=ReadByte(file) & 255
       Blue=ReadByte(file) & 255
       localCols(count)=RGB(Red,Green,Blue)
     Next
     ;transcolor=LocalCols(TByte)
   Else ;No local color table
     If cl\bUseGlobalColMap=#False ;No global color table
       CloseFile(file)
       MessageRequester("GIF Load Error!" , "The GIF image does not contain a valid color table.")
       ProcedureReturn #False ;NO_COLORTABLE
     EndIf
   EndIf
  
   width=im\imWidth & $FFFF ;Image width
   height=im\imHeight & $FFFF ;Image height
  
   ;Get the first byte of the new block of image data.
   ;Should be the bit size
   LZWCodeSize=ReadByte(file) & 255
  
   ;Bit size is normally the same as the color resolution.
   ;i.e. 8 for 256 colors
   If LZWCodeSize<2 Or LZWCodeSize>8
     CloseFile(file)
     MessageRequester("GIF Load Error!" , "LZW code size is not valid!")
     ProcedureReturn #False ;BAD_CODE_SIZE
   EndIf
  
   ;Initialise the variables for the decoder for reading a new image.
   cl\CurrCodeSize=LZWCodeSize+1
   TopSlot=1 << cl\CurrCodeSize ;Highest code for current size
   ClearCode=1 << LZWCodeSize ;Value for a clear code
   EndingCode=ClearCode+1 ;Value for an ending code
   NewCodes=ClearCode+2 ;First available code
   Slot=NewCodes ;Last read code
   cl\BitsLeft=0
   cl\BytesLeft=0
  
   ;Just in case...
   TempOldCode=0 : OldCode=0
  
   ;Allocate space for the decode buffer
   lpBUFF=AllocateMemory(width+8) ;+8 just in case
  
   ;Set up the stack pointer, decode buffer pointer and line counter
   *lpSP=@stack(0)
   *lpBuffPtr=lpBUFF
   BufCnt=width ;Count for pixel line length
  
   ;Start creating the DIB
   If cl\bUseGlobalColMap ;Global color table
     bitcount=cl\GlobColRes
   Else ;Local color table
     bitcount=cl\ImgColRes
   EndIf
  
   bi\biSize=SizeOf(bi)
   bi\biWidth=width
   bi\biHeight=height
   bi\biPlanes=1
   bi\biBitCount=bitcount ;BitCount will be 1, 4 or 8
   bi\biCompression=#BI_RGB
   bi\biSizeImage=0
   bi\biXPelsPerMeter=0
   bi\biYPelsPerMeter=0
   If cl\bUseGlobalColMap ;Global color table
     bi\biClrUsed=GlobColors
   Else ;Local color table
     bi\biClrUsed=ImgColors
   EndIf
   bi\biClrImportant=0
  
   ;With the BITMAPINFO format headers, the size of the palette is
   ;in biClrUsed, whereas in the BITMAPCORE - style headers, it is
   ;dependent on the Bits per pixel (2 to the power of bitsperpixel).
   If bi\biClrUsed<>0
     ncolors=bi\biClrUsed
   Else ;We don't have an optimal palette
     ncolors=1 << bi\biBitCount
   EndIf
  
   cl\pitch=(((bitcount*width)+31) >> 5) << 2 ;Bytes per line
   Len=bi\biSize+(ncolors*4)+(cl\pitch*height) ;Size of DIB
  
   bi\biSizeImage=cl\pitch*height ;Fill in biSizeImage
  
   ;Allocate memory block to store our DIB
   hDIB=AllocateMemory(Len)
   If hDIB=0
     FreeMemory(lpBUFF)
     ;CloseFile(file)
     MessageRequester("GIF Load Error!" , "Memory allocation failed!")
     ProcedureReturn #False ;NO_DIB
   EndIf
  
   ;Fill first part of DIB with the BITMAPINFOHEADER
   CopyMemory(bi,hDIB,SizeOf(bi))
  
   ;Set the colors in the DIB (or masks for the new DIB formats)
   *pal=hDIB+SizeOf(bi)
   If cl\bUseGlobalColMap
     For count=0 To bi\biClrUsed-1
       *pal\rgbBlue=Blue(GlobalCols(count))
       *pal\rgbGreen=Green(GlobalCols(count))
       *pal\rgbRed=Red(GlobalCols(count))
       *pal+4
     Next
   Else
     For count=0 To bi\biClrUsed-1
       *pal\rgbBlue=Blue(localCols(count))
       *pal\rgbGreen=Green(localCols(count))
       *pal\rgbRed=Red(localCols(count))
       *pal+4
     Next
   EndIf
  
   cl\Line=0 ;Set address offset for OutLineGIF()
   cl\Pass=0 ;For interlaced images in OutLineGIF()
  
   ;Image data bits of DIB
   cl\lpBits=hDIB+bi\biSize+(ncolors*4)+(cl\pitch*(height-1))
  
   ;This is the main loop. For each code we get we pass through the
   ;linked list of prefix codes, pushing the corresponding "character"
   ;for each code onto the stack. When the list reaches a single
   ;"character" we push that on the stack too, and then start
   ;unstacking each character for output in the correct order.
   ;Special handling is included for the clear code, and the whole
   ;thing ends when we get an ending code.
   While cc<>EndingCode
    
     cc=GIF_NextCode(file,CharBuff(),CodeMask(),cl)
    
     If cc<0 ;If a file error, return without completing the decode
       FreeMemory(lpBUFF)
       ;CloseFile(file)
       MessageRequester("GIF Load Error!" , "LZW code size is not valid!")
       ProcedureReturn #False ;FILE_ERROR
     EndIf
    
     ;If the code is a clear code, re-initialise all necessary items.
     If cc=ClearCode
      
       cl\CurrCodeSize=LZWCodeSize+1
       Slot=NewCodes
       TopSlot=1 << cl\CurrCodeSize
      
       ;Continue reading codes until we get a non-clear code
       ;(another unlikely, but possible case...)
       While cc=ClearCode
         cc=GIF_NextCode(file,CharBuff(),CodeMask(),cl)
       Wend
      
       ;If we get an ending code immediately after a clear code
       ;(yet another unlikely case), then break out of the loop.
       If cc=EndingCode
         Break ;end loop
       EndIf
      
       ;Finally, if the code is beyond the range of already set codes,
       ;(This one had better not happen, I have no idea what will
       ;result from this, but I doubt it will look good)
       ;then set it to color zero.
       If cc>=Slot
         cc=0
       EndIf
      
       OldCode=cc
       TempOldCode=OldCode
      
       ;And let us not forget to put the char into the buffer, and if,
       ;on the off chance, we were exactly one pixel from the end of
       ;the line, we have to send the buffer to the OutLineGIF() routine
       *lpBuffPtr\b=cc
       *lpBuffPtr+1
       BufCnt-1
      
       If BufCnt=0
         GIF_OutLine(lpBUFF,width,height,cl)
         *lpBuffPtr=lpBUFF
         BufCnt=width
       EndIf
      
     Else
      
       ;In this case, it's not a clear code or an ending code, so it
       ;must be a code code. So we can now decode the code into a
       ;stack of character codes (Clear as mud, right?).
       code=cc
      
       If code=Slot
         code=TempOldCode
         *lpSP\b=OldCode
         *lpSP+1
       EndIf
      
       ;Here we scan back along the linked list of prefixes, pushing
       ;helpless characters (i.e. suffixes) onto the stack as we do so.
       While code>=NewCodes
         *lpSP\b=suffix(code)
         *lpSP+1
         code=prefix(code)
       Wend
      
       ;Push the last character on the stack, and set up the new
       ;prefix and suffix, and if the required slot number is greater
       ;than that allowed by the current bit size, increase the bit
       ;size. (Note - if we are all full, we *don't* save the new
       ;suffix and prefix. I'm not certain if this is correct,
       ;it might be more proper to overwrite the last code.
       *lpSP\b=code
       *lpSP+1
      
       If Slot<TopSlot
         OldCode=code
         suffix(Slot)=OldCode
         prefix(Slot)=TempOldCode
         Slot+1
         TempOldCode=cc
       EndIf
      
       If Slot>=TopSlot
         If cl\CurrCodeSize<12
           TopSlot=TopSlot << 1
           cl\CurrCodeSize+1
         EndIf
       EndIf
      
       ;Now that we've pushed the decoded string (in reverse order)
       ;onto the stack, lets pop it off and put it into our decode
       ;buffer, and when the decode buffer is full, write another line.
       While *lpSP>@stack(0)
         *lpSP-1
         *lpBuffPtr\b=*lpSP\b
         *lpBuffPtr+1
         BufCnt-1
        
         If BufCnt=0
           GIF_OutLine(lpBUFF,width,height,cl)
           *lpBuffPtr=lpBUFF
           BufCnt=width
         EndIf
       Wend
      
     EndIf
   Wend
  
   If BufCnt<>width ;If there are any left, output the bytes
     GIF_OutLine(lpBUFF,width-BufCnt-1,height,cl)
   EndIf
   *dib=hDIB
   If *dib=0 ;Avoid errors
     ProcedureReturn #False
   EndIf
  
   Define.l Bits=*dib+*dib\biSize+(*dib\biClrUsed*4) ;Pointer to bits
  
   ;Create the DDB bitmap
   Define.l hImage=GIF_CreateDIImage(#PB_Any, *dib, TransColorIndex)
   Define.l pbimage=CreateImage(#PB_Any,realwidth,realheight, 32 | #PB_Image_Transparent) ; Create initial "screen"
   StartDrawing(ImageOutput(pbimage))
   DrawingMode(#PB_2DDrawing_AlphaBlend)
   ;Box(0,0,realwidth,realheight,$FFFFFF)
   DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
   StopDrawing()
   FreeImage(hImage)
   FreeMemory(hDIB)
   ;imageArray(0)=ImageID(pbimage)
   GIF_Frames(0)\Image = pbimage
   GIF_Frames(0)\DelayTime = delaytime
   Define.l numberimages=1
  
   ;===========================
   ;- continue to other frames
   ;===========================
 
   ; Read through the various image blocks
   Define.l NotatEnd=1
   While NotatEnd=1
     Define.w TransColorIndex = -1
     Define.l n
     While n<>$2C
       n=ReadByte(file) & 255
       If n=$3B
         NotatEnd=0
         CloseFile(file)
         FreeMemory(lpBUFF)
         ProcedureReturn numberimages
       ElseIf n=$F9
         ;Graphics control extension
         n=ReadByte(file) & 255
         Define.l Size = n
         n=ReadByte(file) ;& 255 ; packedfields
         ;Define.b packedfields = n &$FF
         Define.l disposalmethod = (n & %00011100) >>2
         tflag = n & %00000001
         delaytime = ReadWord(file)
         Define.a transparent = ReadByte(file)
         If tflag : TransColorIndex = transparent : EndIf
       ElseIf n=$FF
         ;application extension
       ElseIf n=$FE
         ;comment extention
         n=ReadByte(file) & 255
         FileSeek(file,Loc(file)+n)
       ElseIf n= $01
         ;"plain text extention"
         ;Debug "text"
         ; n=ReadByte(file) & 255
         ;FileSeek(file,Loc(file)+n& $FF)
       ElseIf n =$21
         ;"A Extension_block
       EndIf
     Wend
     n=0
    
     ; done with reading the image blocks for this frame
   FileSeek(file,Loc(file)-1)
   count=0
   While count<>$2C ;Search for im\imSep
     count=ReadByte(file) & 255
   Wend
   FileSeek(file,Loc(file)-1) ;Seek to im\imSep
  
   ReadData(file,im,SizeOf(im)) ;Read the image descriptor
  
   ;Store im\imPkFields for bit manipulation
   impkFields=im\impkFields & 255
  
   ;Is the image interlaced
   cl\bImInterLace=(impkFields & (1 << 6)) >> 6
  
   ;Is the local color table sorted
   bImColsSorted=(impkFields & (1 << 5)) >> 5
  
   ;Is there a local color table
   bImColTable=(impkFields & (1 << 7)) >> 7
  
   If bImColTable
     cl\bUseGlobalColMap=#False
    
     ImgColBytes=3*(1 << ((impkFields & $07)+1)) ;Table size in bytes
     ImgColors=ImgColBytes/3 ;Number of colors
    
     If ImgColors<=2 ;Make sure image bit depth is 1, 4 or 8
       cl\ImgColRes=1
     ElseIf ImgColors<=16
       cl\ImgColRes=4
     Else
       cl\ImgColRes=8
     EndIf
    
     For count=0 To ImgColors-1 ;Get the local image colors
       Red=ReadByte(file) & 255
       Green=ReadByte(file) & 255
       Blue=ReadByte(file) & 255
       localCols(count)=RGB(Red,Green,Blue)
     Next
     ;loctranscolor=localCols(transparent& $FF)
     ;transcolor=localCols(transparent& $FF)
   Else ;No local color table
     If cl\bUseGlobalColMap=#False ;No global color table
       CloseFile(file)
       MessageRequester("GIF Load Error!" , "The GIF image does not contain a valid color table.")
       ProcedureReturn #False ;NO_COLORTABLE
     EndIf
     ;transcolor=GlobalCols(transparent& $FF)
   EndIf
  
   width=im\imWidth & $FFFF ;Image width
   height=im\imHeight & $FFFF ;Image height
  
   ;Get the first byte of the new block of image data.
   ;Should be the bit size
   LZWCodeSize=ReadByte(file) & 255
  
   ;Bit size is normally the same as the color resolution.
   ;i.e. 8 for 256 colors
   If LZWCodeSize<2 Or LZWCodeSize>8
     CloseFile(file)
     MessageRequester("GIF Load Error!" , "LZW code size is not valid!")
     ProcedureReturn #False ;BAD_CODE_SIZE
   EndIf
  
   ;Initialise the variables for the decoder for reading a new image.
   cl\CurrCodeSize=LZWCodeSize+1
   TopSlot=1 << cl\CurrCodeSize ;Highest code for current size
   ClearCode=1 << LZWCodeSize ;Value for a clear code
   EndingCode=ClearCode+1 ;Value for an ending code
   NewCodes=ClearCode+2 ;First available code
   Slot=NewCodes ;Last read code
   cl\BitsLeft=0
   cl\BytesLeft=0
  
   ;Just in case...
   TempOldCode=0 : OldCode=0
  
   ;Allocate space for the decode buffer
   lpBUFF=AllocateMemory(width+8) ;+8 just in case
  
   ;Set up the stack pointer, decode buffer pointer and line counter
   *lpSP=@stack(0)
   *lpBuffPtr=lpBUFF
   BufCnt=width ;Count for pixel line length
  
   ;Start creating the DIB
   If cl\bUseGlobalColMap ;Global color table
     bitcount=cl\GlobColRes
   Else ;Local color table
     bitcount=cl\ImgColRes
   EndIf
  
   bi\biSize=SizeOf(bi)
   bi\biWidth=width
   bi\biHeight=height
   bi\biPlanes=1
   bi\biBitCount=bitcount ;BitCount will be 1, 4 or 8
   bi\biCompression=#BI_RGB
   bi\biSizeImage=0
   bi\biXPelsPerMeter=0
   bi\biYPelsPerMeter=0
   If cl\bUseGlobalColMap ;Global color table
     bi\biClrUsed=GlobColors
   Else ;Local color table
     bi\biClrUsed=ImgColors
   EndIf
   bi\biClrImportant=0
  
   ;With the BITMAPINFO format headers, the size of the palette is
   ;in biClrUsed, whereas in the BITMAPCORE - style headers, it is
   ;dependent on the Bits per pixel (2 to the power of bitsperpixel).
   If bi\biClrUsed<>0
     ncolors=bi\biClrUsed
   Else ;We don't have an optimal palette
     ncolors=1 << bi\biBitCount
   EndIf
  
   cl\pitch=(((bitcount*width)+31) >> 5) << 2 ;Bytes per line
   Len=bi\biSize+(ncolors*4)+(cl\pitch*height) ;Size of DIB
  
   bi\biSizeImage=cl\pitch*height ;Fill in biSizeImage
  
   ;Allocate memory block to store our DIB
   hDIB=AllocateMemory(Len)
   If hDIB=0
     FreeMemory(lpBUFF)
     CloseFile(file)
     MessageRequester("GIF Load Error!" , "Memory allocation failed!")
     ProcedureReturn #False ;NO_DIB
   EndIf
  
   ;Fill first part of DIB with the BITMAPINFOHEADER
   CopyMemory(bi,hDIB,SizeOf(bi))
  
   ;Set the colors in the DIB (or masks for the new DIB formats)
   *pal=hDIB+SizeOf(bi)
   If cl\bUseGlobalColMap
     For count=0 To bi\biClrUsed-1
       *pal\rgbBlue=Blue(GlobalCols(count))
       *pal\rgbGreen=Green(GlobalCols(count))
       *pal\rgbRed=Red(GlobalCols(count))
       *pal+4
     Next
   Else
     For count=0 To bi\biClrUsed-1
       *pal\rgbBlue=Blue(localCols(count))
       *pal\rgbGreen=Green(localCols(count))
       *pal\rgbRed=Red(localCols(count))
       *pal+4
     Next
   EndIf
  
   cl\Line=0 ;Set address offset for OutLineGIF()
   cl\Pass=0 ;For interlaced images in OutLineGIF()
  
   ;Image data bits of DIB
   cl\lpBits=hDIB+bi\biSize+(ncolors*4)+(cl\pitch*(height-1))
  
   ;This is the main loop. For each code we get we pass through the
   ;linked list of prefix codes, pushing the corresponding "character"
   ;for each code onto the stack. When the list reaches a single
   ;"character" we push that on the stack too, and then start
   ;unstacking each character for output in the correct order.
   ;Special handling is included for the clear code, and the whole
   ;thing ends when we get an ending code.
   cc=0
  
   While cc<>EndingCode
    
     cc=GIF_NextCode(file,CharBuff(),CodeMask(),cl)
    
     If cc<0 ;If a file error, return without completing the decode
       FreeMemory(lpBUFF)
       CloseFile(file)
       MessageRequester("GIF Load Error!", "GIF image contained an in-valid LZW code.")
       ProcedureReturn #False ;FILE_ERROR
     EndIf
    
     ;If the code is a clear code, re-initialise all necessary items.
     If cc=ClearCode
      
       cl\CurrCodeSize=LZWCodeSize+1
       Slot=NewCodes
       TopSlot=1 << cl\CurrCodeSize
      
       ;Continue reading codes until we get a non-clear code
       ;(another unlikely, but possible case...)
       While cc=ClearCode
         cc=GIF_NextCode(file,CharBuff(),CodeMask(),cl)
       Wend
      
       ;If we get an ending code immediately after a clear code
       ;(yet another unlikely case), then break out of the loop.
       If cc=EndingCode
         Break ;end loop
       EndIf
      
       ;Finally, if the code is beyond the range of already set codes,
       ;(This one had better not happen, I have no idea what will
       ;result from this, but I doubt it will look good)
       ;then set it to color zero.
       If cc>=Slot
         cc=0
       EndIf
      
       OldCode=cc
       TempOldCode=OldCode
      
       ;And let us not forget to put the char into the buffer, and if,
       ;on the off chance, we were exactly one pixel from the end of
       ;the line, we have to send the buffer to the OutLineGIF() routine
       *lpBuffPtr\b=cc
       *lpBuffPtr+1
       BufCnt-1
      
       If BufCnt=0
         GIF_OutLine(lpBUFF,width,height,cl)
         *lpBuffPtr=lpBUFF
         BufCnt=width
       EndIf
      
     Else
      
       ;In this case, it's not a clear code or an ending code, so it
       ;must be a code code. So we can now decode the code into a
       ;stack of character codes (Clear as mud, right?).
       code=cc
      
       If code=Slot
         code=TempOldCode
         *lpSP\b=OldCode
         *lpSP+1
       EndIf
      
       ;Here we scan back along the linked list of prefixes, pushing
       ;helpless characters (i.e. suffixes) onto the stack as we do so.
       While code>=NewCodes
         *lpSP\b=suffix(code)
         *lpSP+1
         code=prefix(code)
       Wend
      
       ;Push the last character on the stack, and set up the new
       ;prefix and suffix, and if the required slot number is greater
       ;than that allowed by the current bit size, increase the bit
       ;size. (Note - if we are all full, we *don't* save the new
       ;suffix and prefix. I'm not certain if this is correct,
       ;it might be more proper to overwrite the last code.
       *lpSP\b=code
       *lpSP+1
      
       If Slot<TopSlot
         OldCode=code
         suffix(Slot)=OldCode
         prefix(Slot)=TempOldCode
         Slot+1
         TempOldCode=cc
       EndIf
      
       If Slot>=TopSlot
         If cl\CurrCodeSize<12
           TopSlot=TopSlot << 1
           cl\CurrCodeSize+1
         EndIf
       EndIf
      
       ;Now that we've pushed the decoded string (in reverse order)
       ;onto the stack, lets pop it off and put it into our decode
       ;buffer, and when the decode buffer is full, write another line.
       While *lpSP>@stack(0)
         *lpSP-1
         *lpBuffPtr\b=*lpSP\b
         *lpBuffPtr+1
         BufCnt-1
        
         If BufCnt=0
           GIF_OutLine(lpBUFF,width,height,cl)
           *lpBuffPtr=lpBUFF
           BufCnt=width
         EndIf
       Wend
      
     EndIf
    
   Wend
  
   If BufCnt<>width ;If there are any left, output the bytes
     GIF_OutLine(lpBUFF,width-BufCnt-1,height,cl)
   EndIf
  
   ;Create the DDB bitmap
   *dib=hDIB
   If *dib=0 ;Avoid errors
     ProcedureReturn #False
   EndIf
  
   Bits=*dib+*dib\biSize+(*dib\biClrUsed*4) ;Pointer to bits
  
   ;- create the bitmap
   ;Create the DDB bitmap
   Define.l hImage = GIF_CreateDIImage(#PB_Any, *dib, TransColorIndex)
   pbimage=CreateImage(#PB_Any,realwidth,realheight, 32 | #PB_Image_Transparent)
   StartDrawing(ImageOutput(pbimage))
   DrawingMode(#PB_2DDrawing_AlphaBlend)
   ; For some retarded reason, we have to draw and redraw the GIF frames over the previous image imagenumber-1
  
 ;   If bUseGlobalColMap ; if a local color table, then draw previous image in array, and then dray new hbitmap with transparency
 ;     Box(0,0,realwidth,realheight,$FFFFFF)
 ;     DrawImage(imageArray(numberimages-1),0,0)
 ;     If tflag=1
 ;       ;loc
 ;       DrawTransparentImage(drawdc,hBitmap,im\imLeft,im\imTop,im\imWidth,im\imHeight,transcolor)
 ;     Else
 ;       DrawImage(hBitmap,im\imLeft,im\imTop,im\imWidth,im\imHeight)
 ;     EndIf
 ;   Else
    
     If disposalmethod = 1
       ;Box(0,0,realwidth,realheight,$FFFFFF)
       DrawImage(ImageID(GIF_Frames(numberimages-1)\Image),0,0)
       DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
     ElseIf disposalmethod = 2
       ;Box(0,0,realwidth,realheight,$FFFFFF)
       ;DrawImage(ImageID(GIF_Frames(1)),0,0)
       DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
     Else
       ;Box(0,0,realwidth,realheight,$FFFFFF)
       DrawImage(ImageID(GIF_Frames(numberimages-1)\Image),0,0)
       ;DrawImage(hBitmap,im\imLeft,im\imTop)
       DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
     EndIf
 ;   EndIf
   StopDrawing()
   FreeImage(hImage)
   FreeMemory(hDIB) ;Free the DIB
   ReDim GIF_Frames(numberimages)
   GIF_Frames(numberimages)\Image = pbimage
   GIF_Frames(numberimages)\DelayTime = delaytime
   numberimages + 1
 Wend
 ProcedureReturn numberimages
EndProcedure

#Gif_Test = #True
CompilerIf #Gif_Test ;{

Define.w a
Dim Frames.GIF_Frame(0)

OpenWindow(0, 0, 0, 800, 600, "Gif_Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget)
ButtonGadget(0,10,10,80,20,"Open File")
ImageGadget(1,50,50,0,0,0, #PB_Image_Border)

AddWindowTimer(0, 0, 100)

Repeat
   Select WaitWindowEvent()
     Case #PB_Event_Gadget
       Select EventGadget()
         Case 0
           Define.s Pattern="All Supported Formats|*.gif"
           Define.s filename=OpenFileRequester("Choose An Image File To Open","",Pattern,0)
           If filename
             If GIF_LoadFrames(filename,Frames())
               ResizeGadget(1, #PB_Ignore, #PB_Ignore, ImageWidth(Frames(0)\Image), ImageHeight(Frames(0)\Image))
               ;SetGadgetState(0, ImageID(Frames(0)\Image))
             EndIf
           EndIf
       EndSelect

     Case #PB_Event_CloseWindow
       Break
   
     Case #PB_Event_Timer 
         RemoveWindowTimer(0, 0) 
         If a > ArraySize(Frames()) : a = 0 : EndIf
         If IsImage(Frames(a)\Image)
            SetGadgetState(1, ImageID(Frames(a)\Image))
            AddWindowTimer(0, 0, Frames(a)\DelayTime * 10)
         Else
            AddWindowTimer(0, 0, 100)
         EndIf
         a + 1   
   EndSelect

ForEver

CompilerEndIf ;}
Last edited by Niffo on Thu Mar 15, 2012 9:11 pm, edited 1 time in total.
Niffo
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: UPDATED: Load Animated GIF frames

Post by ts-soft »

Image
This is great :D
The first version in this thread, that is working for me.

Many thanks
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

Before to have the obligation to have a code who works on MacOS, i also used GDI+ ;-) (http://www.purebasic.fr/english/viewtop ... 7&p=376400)
Niffo
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: UPDATED: Load Animated GIF frames

Post by ts-soft »

Here is a version with some improvements :
; + added Catch-Support
; + added reading of complete giffile into memory, this should be faster ;-)
; + optimized Variabletypes for better support 64-Bit Programs
; + changed Syntax of GIF_LoadFrames() to:
; GIF_LoadFrames(Array GIF_Frames.GIF_Frame(1), filename.s = "", *memory = 0, memsize = 0)
[GIFanimation.pbi]

Code: Select all

; Original PB code by "hagibaba" (Purebasic.fr forums) based on "loadgif.c" for ImageShop32 by John Findlay
; Gif Anim support by localmotion34 (Purebasic.fr forums)
; Updated & Extended by Dean Williams - resplace.net
; APIs free, alpha channel support and bug fixes by Niffo (Purebasic.fr forums)

; #######################################
; enhanced and optimized by Thomas <ts-soft> Schulz (www.realsource.de)
; + added Catch-Support
; + added reading of complete giffile into memory, this should be faster ;-)
; + optimized Variabletypes for better support 64-Bit Programs
; + changed Syntax of GIF_LoadFrames() to:
; GIF_LoadFrames(Array GIF_Frames.GIF_Frame(1), filename.s = "", *memory = 0, memsize = 0)
; changed MessageRequester to Debug.
; #######################################
; Please help development and report any problems or improvements/bug fixes you may have on
; if we all work together we can have some really nice GIF support in PureBasic!
; http://www.purebasic.fr/english/viewtopic.php?f=12&t=27575

;{ - Structures

CompilerIf Defined(BITMAPINFOHEADER, #PB_Structure)
CompilerElse
Structure BITMAPINFOHEADER
  biSize.l
  biWidth.l
  biHeight.l
  biPlanes.w
  biBitCount.w
  biCompression.l
  biSizeImage.l
  biXPelsPerMeter.l
  biYPelsPerMeter.l
  biClrUsed.l
  biClrImportant.l
EndStructure

#BI_RGB = 0

Structure RGBQUAD
  rgbBlue.a
  rgbGreen.a
  rgbRed.a
  rgbReserved.a
EndStructure
CompilerEndIf

Structure GIF_Frame
  Image.i
  DelayTime.w
EndStructure

Structure GIFHEADER ;Header
  ghSig.b[6] ;Signature & Version
  ghWidth.w ;Logical Screen Width
  ghHeight.w ;Logical Screen Height
  ghPkFields.b ;Global Color Table Flag
  ghBkColIndex.b ;Background Color Index
  ghAspRatio.b ;Pixel Aspect Ratio
EndStructure

Structure GIFIMAGE ;Image Descriptor
  imSep.b ;Image Separator
  imLeft.w ;Image Left Position
  imTop.w ;Image Top Position
  imWidth.w ;Image Width
  imHeight.w ;Image Height
  impkFields.b ;Local Color Table Flag
EndStructure

Structure GIFCLASS ;This is instead of using globals
  *lpBytes.Byte ;Pointer to next byte in block
  Pass.l ;First pass for interlaced images in OutLineGIF()
  Line.l ;Offset for addressing the bits in OutLineGIF()
  lpBits.l ;Scanline for bits
  pitch.l ;Bytes are rounded up for image lines
  CurrCodeSize.l ;The current code size
  BitsLeft.l ;Used in NextCodeGIF()
  BytesLeft.l ;Used in NextCodeGIF()
  CurrByte.l ;Current byte
  bUseGlobalColMap.b ;Is the color table global
  GlobColRes.l ;Color Resolution, bits '6' '5' '4'
  bImInterLace.b ;Is the image interlaced
  ImgColRes.l ;Color Resolution
EndStructure

;}

Procedure GIF_OutLine(lpPixels.l,LineLen.l,height.l,*cl.GIFCLASS)
  ;Outputs the pixel color index data to the DIB
  ;lpPixels -> Memory block that holds the color index value
  ;LineLen -> Length of the line of pixels
  ;Height -> im\imHeight
  ;Gif images are 2, 16 or 256 colors, poking the values into memory
  ;requires a different method for each case. If gif is interlaced,
  ;that is dealt with here.
  
  Protected ib.l,pixel.l,byte.l,BitCnt.l,CntBk.l,ColRes.l,Bits.l
  
  Bits=*cl\lpBits-(*cl\Line * *cl\pitch) ;Pointer to bits
  
  If *cl\bUseGlobalColMap
    ColRes=*cl\GlobColRes
  Else
    ColRes=*cl\ImgColRes
  EndIf
  
  Select ColRes
      
    Case 1
      byte=0
      For pixel=0 To LineLen-1 Step 8
        ib=0
        CntBk=7
        For BitCnt=0 To 8-1
          If PeekB(lpPixels+BitCnt+pixel)
            ib=ib | (1 << CntBk)
          EndIf
          CntBk-1
        Next
        PokeB(Bits+byte,ib)
        byte+1
      Next
      
    Case 4
      byte=0
      For pixel=0 To LineLen-1 Step 2
        ib=((PeekB(lpPixels+pixel) & 255) << 4)
        ib | (PeekB(lpPixels+pixel+1) & 255)
        PokeB(Bits+byte,ib)
        byte+1
      Next
      
    Case 8
      For pixel=0 To LineLen-1
        ib=PeekB(lpPixels+pixel) & 255
        PokeB(Bits+pixel,ib)
      Next
      
  EndSelect
  
  If *cl\bImInterLace ;Set Line for different passes when Interlaced
    
    Select *cl\Pass
        
      Case 0 ;Pass 1
        If *cl\Line<height-8
          *cl\Line+8
        Else
          *cl\Line=4 : *cl\Pass+1 ;Set Line for second pass
        EndIf
        
      Case 1 ;Pass 2
        If *cl\Line<height-8
          *cl\Line+8
        Else
          *cl\Line=2 : *cl\Pass+1 ;Set Line for third pass
        EndIf
        
      Case 2 ;Pass 3
        If *cl\Line<height-4
          *cl\Line+4
        Else
          *cl\Line=1 : *cl\Pass+1 ;Set Line for fourth pass
        EndIf
        
      Case 3 ;Pass 4
        If *cl\Line<height-2
          *cl\Line+2
        EndIf
        
    EndSelect
    
  Else ;When not Interlaced increment Line
    
    *cl\Line+1
    
  EndIf
  
EndProcedure

Procedure.l GIF_NextCode(*mem, mempos, *pos.long, Array CharBuff.b(1),Array CodeMask.l(1),*cl.GIFCLASS)
  ;Reads the next code from the data stream
  ;Returns the LZW CODE or ERROR
  
  Protected count.l,Char.l,ret.l
  
  If *cl\BitsLeft=0 ;Any bits left in byte?
    
    If *cl\BytesLeft<=0 ;If not get another block
      
      *cl\lpBytes=@CharBuff(0) ;Set byte pointer
      *cl\BytesLeft = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      
      If *cl\BytesLeft<0
        *pos\l = mempos
        ProcedureReturn *cl\BytesLeft ;Return if error
      ElseIf *cl\BytesLeft
        For count=0 To *cl\BytesLeft-1
          Char = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
          *pos\l = mempos
          If Char<0 : ProcedureReturn Char : EndIf
          CharBuff(count)=Char ;Fill the char buffer with the new block
        Next
      EndIf
      
    EndIf
    
    *cl\CurrByte=*cl\lpBytes\b & 255 ;Get a byte
    *cl\lpBytes+1 ;Increment index pointer
    *cl\BitsLeft=8 ;Set bits left in the byte
    *cl\BytesLeft-1 ;Decrement the bytes left counter
    
  EndIf
  
  ;Shift off any previously used bits
  ret=*cl\CurrByte >> (8-*cl\BitsLeft)
  
  While *cl\CurrCodeSize>*cl\BitsLeft
    
    If *cl\BytesLeft<=0
      
      ;Out of bytes in current block
      *cl\lpBytes=@CharBuff(0) ;Set byte pointer
      *cl\BytesLeft = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      
      If *cl\BytesLeft<0
        *pos\l = mempos
        ProcedureReturn *cl\BytesLeft ;Return if error
      ElseIf *cl\BytesLeft
        For count=0 To *cl\BytesLeft-1
          Char = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
          *pos\l = mempos
          If Char<0 : ProcedureReturn Char : EndIf
          CharBuff(count)=Char ;Fill the char buffer with the current block
        Next
      EndIf
      
    EndIf
    
    *cl\CurrByte=*cl\lpBytes\b & 255 ;Get a byte
    *cl\lpBytes+1 ;Increment index pointer
    ret | (*cl\CurrByte << *cl\BitsLeft) ;Add remaining bits to return
    *cl\BitsLeft+8 ;Set bit counter
    *cl\BytesLeft-1 ;Decrement bytesleft counter
    
  Wend
  
  *cl\BitsLeft-*cl\CurrCodeSize ;Subtract the code size from bitsleft
  ret & CodeMask(*cl\CurrCodeSize) ;Mask off the right number of bits
  *pos\l = mempos
  ProcedureReturn ret
  
EndProcedure

Procedure GIF_CreateDIImage(*dib.BITMAPINFOHEADER, TransColIndex.w)
  Protected *Bits = *dib+*dib\biSize+(*dib\biClrUsed*4)
  Protected Image = CreateImage(#PB_Any, *dib\biWidth, *dib\biHeight, 32)
  Protected.l X, Y, RGBA, Col
  Protected *Pal = *dib + *dib\biSize
  Protected.a ColInd, Alpha
  Protected.l dibPitch = *dib\biSizeImage/*dib\biHeight
  
  StartDrawing(ImageOutput(Image))
  DrawingMode(#PB_2DDrawing_AllChannels)
  
  ;   Define *BufAddr = DrawingBuffer()
  ;   Define.l BufPitch = DrawingBufferPitch()
  For Y = 0 To *dib\biHeight - 1
    For X = 0 To *dib\biWidth - 1
      
      Select *dib\biBitCount
        Case 8
          ColInd = PeekA(*Bits + Y*dibPitch+X)
        Case 4
          ;If X % 2
          ;   ColInd = PeekA(*Bits + Y*dibPitch+X) & $F
          ;Else
          ;   ColInd = PeekA(*Bits + Y*dibPitch+X) >> 4
          ;EndIf
          ColInd = PeekA(*Bits + Y*dibPitch+X/2) >> (4*(1-X%2)) & $F
      EndSelect         
      
      If ColInd = TransColIndex : Alpha = 0 : Else : Alpha = 255 : EndIf
      Col = PeekL(*Pal+ColInd*4)
      
      ; Plot
      RGBA = RGBA(Blue(Col), Green(Col), Red(Col), Alpha)
      Plot(X, *dib\biHeight-1-Y, RGBA)
      
      ;          ; Direct Buffer Write (not faster !?)
      ;          If DrawingBufferPixelFormat() & #PB_PixelFormat_32Bits_RGB
      ;             RGBA = RGBA(Blue(Col), Green(Col), Red(Col), Alpha)
      ;          ElseIf DrawingBufferPixelFormat() & #PB_PixelFormat_32Bits_BGR
      ;             RGBA = RGBA(Red(Col), Green(Col), Blue(Col), Alpha)
      ;          EndIf
      ;          If DrawingBufferPixelFormat() & #PB_PixelFormat_ReversedY
      ;             PokeL(*BufAddr + (Y*BufPitch+X*4), RGBA)
      ;          Else
      ;             PokeL(*BufAddr + ((*dib\biHeight-1-Y)*BufPitch+X*4), RGBA)
      ;          EndIf
      
    Next X
  Next Y
  
  StopDrawing()
  
  ProcedureReturn Image
  
EndProcedure

Procedure.i GIF_LoadFrames(Array GIF_Frames.GIF_Frame(1), filename.s = "", *memory = 0, memsize = 0)
  ;From "loadgif.c" for ImageShop32 by John Findlay
  ;Loads LZW Graphics Interchange Format files
  ;Uses NextCodeGIF() and OutLineGIF()
  
  Protected Dim stack.b(4096) ;Stack for storing pixels
  Protected Dim suffix.b(4096) ;Suffix table, max number of LZW codes
  Protected Dim prefix.l(4096) ;Prefix linked list (these are longs)
  Protected Dim CharBuff.b(279) ;Current block
  Protected Dim GlobalCols.l(256) ;Global colors of gif
  Protected Dim localCols.l(256) ;Local image colors of gif
  Protected Dim CodeMask.l(16) ;Masks for LZW compression algorithm
  Protected gh.GIFHEADER
  Protected im.GIFIMAGE
  Protected cl.GIFCLASS
  Protected bi.BITMAPINFOHEADER
  Protected *pal.RGBQUAD
  Protected *lpSP.Byte ;Pointer to stack
  Protected *lpBuffPtr.Byte ;Pointer to buffer
  Protected bGlobColsSorted.b ;Sort Flag  bit '3' (this is unused)
  Protected file.l,sig.s,PkFields.l,bGlobColTable.b,GlobColBytes.l
  Protected GlobColors.l,count.l,Red.l,Green.l,Blue.l
  Protected width.l,height.l,impkFields.l,bImColsSorted.b
  Protected bImColTable.b,ImgColBytes.l,LZWCodeSize.l,TopSlot.l
  Protected ClearCode.l,ImgColors.l,EndingCode.l,NewCodes.l,Slot.l
  Protected lpBUFF.l,TempOldCode.l,OldCode.l,BufCnt.l,bitcount.l
  Protected ncolors.l,Len.l,hDIB.l,cc.l,code.l
  Protected *dib.BITMAPINFOHEADER
  
  CodeMask( 0)=$0000 : CodeMask( 1)=$0001
  CodeMask( 2)=$0003 : CodeMask( 3)=$0007
  CodeMask( 4)=$000F : CodeMask( 5)=$001F
  CodeMask( 6)=$003F : CodeMask( 7)=$007F
  CodeMask( 8)=$00FF : CodeMask( 9)=$01FF
  CodeMask(10)=$03FF : CodeMask(11)=$07FF
  CodeMask(12)=$0FFF : CodeMask(13)=$1FFF
  CodeMask(14)=$3FFF : CodeMask(15)=$7FFF
  
  Protected mempos, newpos, *mem
  If filename <> ""
    ;Open the file
    file=ReadFile(#PB_Any,filename)
    If file=0
      Debug "GIF Load Error! Could not open the GIF image file for reading."
      ProcedureReturn #False
    EndIf
    ;Read the file header and logical screen descriptor
    memsize = Lof(file)
    *mem = AllocateMemory(memsize)
    If *mem = 0
      Debug "GIF Load Error! Could not allocate Memory for GIF image."
      ProcedureReturn #False
    EndIf
    ReadData(file, *mem, memsize)
    CloseFile(file)
  ElseIf *memory
    *mem = AllocateMemory(memsize)
    If *mem
      CopyMemory(*memory, *mem, memsize)
    EndIf
  EndIf
  If *mem = 0
    Debug "GIF Load Error! Could not find Memory for GIF image."
    ProcedureReturn #False    
  EndIf
  CopyMemory(*mem, gh, SizeOf(gh))
  mempos + SizeOf(gh)
  sig=PeekS(@gh\ghSig,6,#PB_Ascii) ;Get the header version string
  
  If sig<>"GIF89a" And sig<>"GIF87a"
    FreeMemory(*mem)
    Debug "GIF Load Error! File was not a valid GIF image file"
    ProcedureReturn #False ;NOT_VALID
  EndIf
  Protected.l realwidth=gh\ghWidth
  Protected.l realheight=gh\ghHeight
  
  ;Store gh\ghPkFields for bit manipulation
  PkFields=gh\ghPkFields & 255
  
  ;Global Color Table Flag bit '7'
  bGlobColTable=(PkFields & (1 << 7)) >> 7
  
  If bGlobColTable
    cl\bUseGlobalColMap=#True
    
    GlobColBytes=3*(1 << ((PkFields & $07)+1)) ;Table size in bytes
    GlobColors=GlobColBytes/3 ;Number of colors
    
    ;Some gif encoders do not follow the gif spec very well,
    ;so make cl\GlobColRes from GlobColors.
    ;Also gif's are used on different platforms, which do
    ;have different bits per pixel. i.e. 32 colors is 5 bits/pixel.
    If GlobColors<=2
      cl\GlobColRes=1
    ElseIf GlobColors<=16
      cl\GlobColRes=4
    Else
      cl\GlobColRes=8
    EndIf
    
    For count=0 To GlobColors-1 ;Get the global screen colors
      Red = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      Green = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      Blue = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      GlobalCols(count)=RGB(Red,Green,Blue)
    Next
  EndIf
  
  Protected.w TransColorIndex = -1
  count=0
  While count<>$2C ;Search for im\imSep
    count = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
    If count = $F9
      mempos + SizeOf(Byte)
      Protected.b tflag = PeekB(*mem + mempos) & 1 : mempos + SizeOf(Byte)
      Protected.w delaytime = PeekW(*mem + mempos) : mempos + SizeOf(Word)
      Protected.a transparent = PeekB(*mem + mempos) : mempos + SizeOf(Byte)
      If tflag : TransColorIndex = transparent : EndIf
    EndIf
  Wend
  mempos - SizeOf(byte);Seek to im\imSep
  CopyMemory(*mem + mempos, im, SizeOf(im)) ;Read the image descriptor
  mempos + SizeOf(im)
  ;Store im\imPkFields for bit manipulation
  impkFields=im\impkFields & 255
  
  ;Is the image interlaced
  cl\bImInterLace=(impkFields & (1 << 6)) >> 6
  
  ;Is the local color table sorted
  bImColsSorted=(impkFields & (1 << 5)) >> 5
  
  ;Is there a local color table
  bImColTable=(impkFields & (1 << 7)) >> 7
  
  If bImColTable
    cl\bUseGlobalColMap=#False
    
    ImgColBytes=3*(1 << ((impkFields & $07)+1)) ;Table size in bytes
    ImgColors=ImgColBytes/3 ;Number of colors
    
    If ImgColors<=2 ;Make sure image bit depth is 1, 4 or 8
      cl\ImgColRes=1
    ElseIf ImgColors<=16
      cl\ImgColRes=4
    Else
      cl\ImgColRes=8
    EndIf
    
    For count=0 To ImgColors-1 ;Get the local image colors
      Red = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      Green = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      Blue = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      localCols(count)=RGB(Red,Green,Blue)
    Next
    ;transcolor=LocalCols(TByte)
  Else ;No local color table
    If cl\bUseGlobalColMap=#False ;No global color table
      FreeMemory(*mem)
      Debug "GIF Load Error! The GIF image does not contain a valid color table."
      ProcedureReturn #False ;NO_COLORTABLE
    EndIf
  EndIf
  
  width=im\imWidth & $FFFF ;Image width
  height=im\imHeight & $FFFF ;Image height
  
  ;Get the first byte of the new block of image data.
  ;Should be the bit size
  LZWCodeSize = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
  ;Bit size is normally the same as the color resolution.
  ;i.e. 8 for 256 colors
  If LZWCodeSize<2 Or LZWCodeSize>8
    FreeMemory(*mem)
    Debug "GIF Load Error! LZW code size is not valid!"
    ProcedureReturn #False ;BAD_CODE_SIZE
  EndIf
  
  ;Initialise the variables for the decoder for reading a new image.
  cl\CurrCodeSize=LZWCodeSize+1
  TopSlot=1 << cl\CurrCodeSize ;Highest code for current size
  ClearCode=1 << LZWCodeSize ;Value for a clear code
  EndingCode=ClearCode+1 ;Value for an ending code
  NewCodes=ClearCode+2 ;First available code
  Slot=NewCodes ;Last read code
  cl\BitsLeft=0
  cl\BytesLeft=0
  
  ;Just in case...
  TempOldCode=0 : OldCode=0
  
  ;Allocate space for the decode buffer
  lpBUFF=AllocateMemory(width+8) ;+8 just in case
  
  ;Set up the stack pointer, decode buffer pointer and line counter
  *lpSP=@stack(0)
  *lpBuffPtr=lpBUFF
  BufCnt=width ;Count for pixel line length
  
  ;Start creating the DIB
  If cl\bUseGlobalColMap ;Global color table
    bitcount=cl\GlobColRes
  Else ;Local color table
    bitcount=cl\ImgColRes
  EndIf
  
  bi\biSize=SizeOf(bi)
  bi\biWidth=width
  bi\biHeight=height
  bi\biPlanes=1
  bi\biBitCount=bitcount ;BitCount will be 1, 4 or 8
  bi\biCompression=#BI_RGB
  bi\biSizeImage=0
  bi\biXPelsPerMeter=0
  bi\biYPelsPerMeter=0
  If cl\bUseGlobalColMap ;Global color table
    bi\biClrUsed=GlobColors
  Else ;Local color table
    bi\biClrUsed=ImgColors
  EndIf
  bi\biClrImportant=0
  
  ;With the BITMAPINFO format headers, the size of the palette is
  ;in biClrUsed, whereas in the BITMAPCORE - style headers, it is
  ;dependent on the Bits per pixel (2 to the power of bitsperpixel).
  If bi\biClrUsed<>0
    ncolors=bi\biClrUsed
  Else ;We don't have an optimal palette
    ncolors=1 << bi\biBitCount
  EndIf
  
  cl\pitch=(((bitcount*width)+31) >> 5) << 2 ;Bytes per line
  Len=bi\biSize+(ncolors*4)+(cl\pitch*height) ;Size of DIB
  
  bi\biSizeImage=cl\pitch*height ;Fill in biSizeImage
  
  ;Allocate memory block to store our DIB
  hDIB=AllocateMemory(Len)
  If hDIB=0
    FreeMemory(lpBUFF)
    FreeMemory(*mem)
    Debug "GIF Load Error! Memory allocation failed!"
    ProcedureReturn #False ;NO_DIB
  EndIf
  
  ;Fill first part of DIB with the BITMAPINFOHEADER
  CopyMemory(bi,hDIB,SizeOf(bi))

  ;Set the colors in the DIB (or masks for the new DIB formats)
  *pal=hDIB+SizeOf(bi)
  If cl\bUseGlobalColMap
    For count=0 To bi\biClrUsed-1
      *pal\rgbBlue=Blue(GlobalCols(count))
      *pal\rgbGreen=Green(GlobalCols(count))
      *pal\rgbRed=Red(GlobalCols(count))
      *pal+4
    Next
  Else
    For count=0 To bi\biClrUsed-1
      *pal\rgbBlue=Blue(localCols(count))
      *pal\rgbGreen=Green(localCols(count))
      *pal\rgbRed=Red(localCols(count))
      *pal+4
    Next
  EndIf
  
  cl\Line=0 ;Set address offset for OutLineGIF()
  cl\Pass=0 ;For interlaced images in OutLineGIF()
  
  ;Image data bits of DIB
  cl\lpBits=hDIB+bi\biSize+(ncolors*4)+(cl\pitch*(height-1))
  
  ;This is the main loop. For each code we get we pass through the
  ;linked list of prefix codes, pushing the corresponding "character"
  ;for each code onto the stack. When the list reaches a single
  ;"character" we push that on the stack too, and then start
  ;unstacking each character for output in the correct order.
  ;Special handling is included for the clear code, and the whole
  ;thing ends when we get an ending code.
  While cc<>EndingCode
    
    cc=GIF_NextCode(*mem, mempos, @newpos, CharBuff(),CodeMask(),cl)
    mempos = newpos
    If cc<0 ;If a file error, return without completing the decode
      FreeMemory(lpBUFF)
      FreeMemory(*mem)
      Debug "GIF Load Error! LZW code size is Not valid!"
      ProcedureReturn #False ;FILE_ERROR
    EndIf
    
    ;If the code is a clear code, re-initialise all necessary items.
    If cc=ClearCode
      
      cl\CurrCodeSize=LZWCodeSize+1
      Slot=NewCodes
      TopSlot=1 << cl\CurrCodeSize
      
      ;Continue reading codes until we get a non-clear code
      ;(another unlikely, but possible case...)
      While cc=ClearCode
        cc=GIF_NextCode(*mem, mempos, @newpos,CharBuff(),CodeMask(),cl)
         mempos = newpos
      Wend
      
      ;If we get an ending code immediately after a clear code
      ;(yet another unlikely case), then break out of the loop.
      If cc=EndingCode
        Break ;end loop
      EndIf
      
      ;Finally, if the code is beyond the range of already set codes,
      ;(This one had better not happen, I have no idea what will
      ;result from this, but I doubt it will look good)
      ;then set it to color zero.
      If cc>=Slot
        cc=0
      EndIf
      
      OldCode=cc
      TempOldCode=OldCode
      
      ;And let us not forget to put the char into the buffer, and if,
      ;on the off chance, we were exactly one pixel from the end of
      ;the line, we have to send the buffer to the OutLineGIF() routine
      *lpBuffPtr\b=cc
      *lpBuffPtr+1
      BufCnt-1
      
      If BufCnt=0
        GIF_OutLine(lpBUFF,width,height,cl)
        *lpBuffPtr=lpBUFF
        BufCnt=width
      EndIf
      
    Else
      
      ;In this case, it's not a clear code or an ending code, so it
      ;must be a code code. So we can now decode the code into a
      ;stack of character codes (Clear as mud, right?).
      code=cc
      
      If code=Slot
        code=TempOldCode
        *lpSP\b=OldCode
        *lpSP+1
      EndIf
      
      ;Here we scan back along the linked list of prefixes, pushing
      ;helpless characters (i.e. suffixes) onto the stack as we do so.
      While code>=NewCodes
        *lpSP\b=suffix(code)
        *lpSP+1
        code=prefix(code)
      Wend
      
      ;Push the last character on the stack, and set up the new
      ;prefix and suffix, and if the required slot number is greater
      ;than that allowed by the current bit size, increase the bit
      ;size. (Note - if we are all full, we *don't* save the new
      ;suffix and prefix. I'm not certain if this is correct,
      ;it might be more proper to overwrite the last code.
      *lpSP\b=code
      *lpSP+1
      
      If Slot<TopSlot
        OldCode=code
        suffix(Slot)=OldCode
        prefix(Slot)=TempOldCode
        Slot+1
        TempOldCode=cc
      EndIf
      
      If Slot>=TopSlot
        If cl\CurrCodeSize<12
          TopSlot=TopSlot << 1
          cl\CurrCodeSize+1
        EndIf
      EndIf
      
      ;Now that we've pushed the decoded string (in reverse order)
      ;onto the stack, lets pop it off and put it into our decode
      ;buffer, and when the decode buffer is full, write another line.
      While *lpSP>@stack(0)
        *lpSP-1
        *lpBuffPtr\b=*lpSP\b
        *lpBuffPtr+1
        BufCnt-1
        
        If BufCnt=0
          GIF_OutLine(lpBUFF,width,height,cl)
          *lpBuffPtr=lpBUFF
          BufCnt=width
        EndIf
      Wend
      
    EndIf
  Wend
  
  If BufCnt<>width ;If there are any left, output the bytes
    GIF_OutLine(lpBUFF,width-BufCnt-1,height,cl)
  EndIf
  *dib=hDIB
  If *dib=0 ;Avoid errors
    ProcedureReturn #False
  EndIf
  
  Protected.i Bits=*dib+*dib\biSize+(*dib\biClrUsed*4) ;Pointer to bits
  
  ;Create the DDB bitmap
  Protected.i hImage=GIF_CreateDIImage(*dib, TransColorIndex)
  Protected.i pbimage=CreateImage(#PB_Any,realwidth,realheight, 32 | #PB_Image_Transparent) ; Create initial "screen"
  StartDrawing(ImageOutput(pbimage))
  DrawingMode(#PB_2DDrawing_AlphaBlend)
  ;Box(0,0,realwidth,realheight,$FFFFFF)
  DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
  StopDrawing()
  FreeImage(hImage)
  FreeMemory(hDIB)
  ;imageArray(0)=ImageID(pbimage)
  GIF_Frames(0)\Image = pbimage
  GIF_Frames(0)\DelayTime = delaytime
  Protected.l numberimages=1
  
  ;===========================
  ;- continue to other frames
  ;===========================
  
  ; Read through the various image blocks
  Protected NotatEnd=1
  While NotatEnd=1
    TransColorIndex = -1
    Protected.i n
    While n<>$2C
      n=PeekA(*mem + mempos) : mempos + SizeOf(Byte)
      If n=$3B
        NotatEnd=0
        FreeMemory(*mem)
        FreeMemory(lpBUFF)
        ProcedureReturn numberimages
      ElseIf n=$F9
        ;Graphics control extension
        n=PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        Protected.l Size = n
        n=PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        ;Define.b packedfields = n &$FF
        Protected.l disposalmethod = (n & %00011100) >>2
        tflag = n & %00000001
        delaytime = PeekW(*mem + mempos) : mempos + SizeOf(Word)
        transparent = PeekB(*mem + mempos) : mempos + SizeOf(Byte)
        If tflag : TransColorIndex = transparent : EndIf
      ElseIf n=$FF
        ;application extension
      ElseIf n=$FE
        ;comment extention
        n=PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        mempos + n
      ElseIf n= $01
        ;"plain text extention"
        ;Debug "text"
        ; n=ReadByte(file) & 255
        ;FileSeek(file,Loc(file)+n& $FF)
      ElseIf n =$21
        ;"A Extension_block
      EndIf
    Wend
    n=0
    
    ; done with reading the image blocks for this frame
    mempos - SizeOf(Byte)
    count=0
    While count<>$2C ;Search for im\imSep
      count = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
    Wend
    mempos - SizeOf(Byte) ;Seek to im\imSep
    CopyMemory(*mem + mempos, im, SizeOf(im)) ;Read the image descriptor
    mempos + SizeOf(im)
    ;Store im\imPkFields for bit manipulation
    impkFields=im\impkFields & 255
    
    ;Is the image interlaced
    cl\bImInterLace=(impkFields & (1 << 6)) >> 6
    
    ;Is the local color table sorted
    bImColsSorted=(impkFields & (1 << 5)) >> 5
    
    ;Is there a local color table
    bImColTable=(impkFields & (1 << 7)) >> 7
    
    If bImColTable
      cl\bUseGlobalColMap=#False
      
      ImgColBytes=3*(1 << ((impkFields & $07)+1)) ;Table size in bytes
      ImgColors=ImgColBytes/3 ;Number of colors
      
      If ImgColors<=2 ;Make sure image bit depth is 1, 4 or 8
        cl\ImgColRes=1
      ElseIf ImgColors<=16
        cl\ImgColRes=4
      Else
        cl\ImgColRes=8
      EndIf
      
      For count=0 To ImgColors-1 ;Get the local image colors
        Red = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        Green = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        Blue = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
        localCols(count)=RGB(Red,Green,Blue)
      Next
      ;loctranscolor=localCols(transparent& $FF)
      ;transcolor=localCols(transparent& $FF)
    Else ;No local color table
      If cl\bUseGlobalColMap=#False ;No global color table
        FreeMemory(*mem)
        Debug "GIF Load Error! The GIF image does not contain a valid color table."
        ProcedureReturn #False ;NO_COLORTABLE
      EndIf
      ;transcolor=GlobalCols(transparent& $FF)
    EndIf
    
    width=im\imWidth & $FFFF ;Image width
    height=im\imHeight & $FFFF ;Image height
    
    ;Get the first byte of the new block of image data.
    ;Should be the bit size
    LZWCodeSize = PeekA(*mem + mempos) : mempos + SizeOf(Byte)
    
    ;Bit size is normally the same as the color resolution.
    ;i.e. 8 for 256 colors
    If LZWCodeSize<2 Or LZWCodeSize>8
      FreeMemory(*mem)
      Debug "GIF Load Error! LZW code size is Not valid!"
      ProcedureReturn #False ;BAD_CODE_SIZE
    EndIf
    
    ;Initialise the variables for the decoder for reading a new image.
    cl\CurrCodeSize=LZWCodeSize+1
    TopSlot=1 << cl\CurrCodeSize ;Highest code for current size
    ClearCode=1 << LZWCodeSize ;Value for a clear code
    EndingCode=ClearCode+1 ;Value for an ending code
    NewCodes=ClearCode+2 ;First available code
    Slot=NewCodes ;Last read code
    cl\BitsLeft=0
    cl\BytesLeft=0
    
    ;Just in case...
    TempOldCode=0 : OldCode=0
    
    ;Allocate space for the decode buffer
    lpBUFF=AllocateMemory(width+8) ;+8 just in case
    
    ;Set up the stack pointer, decode buffer pointer and line counter
    *lpSP=@stack(0)
    *lpBuffPtr=lpBUFF
    BufCnt=width ;Count for pixel line length
    
    ;Start creating the DIB
    If cl\bUseGlobalColMap ;Global color table
      bitcount=cl\GlobColRes
    Else ;Local color table
      bitcount=cl\ImgColRes
    EndIf
    
    bi\biSize=SizeOf(bi)
    bi\biWidth=width
    bi\biHeight=height
    bi\biPlanes=1
    bi\biBitCount=bitcount ;BitCount will be 1, 4 or 8
    bi\biCompression=#BI_RGB
    bi\biSizeImage=0
    bi\biXPelsPerMeter=0
    bi\biYPelsPerMeter=0
    If cl\bUseGlobalColMap ;Global color table
      bi\biClrUsed=GlobColors
    Else ;Local color table
      bi\biClrUsed=ImgColors
    EndIf
    bi\biClrImportant=0
    
    ;With the BITMAPINFO format headers, the size of the palette is
    ;in biClrUsed, whereas in the BITMAPCORE - style headers, it is
    ;dependent on the Bits per pixel (2 to the power of bitsperpixel).
    If bi\biClrUsed<>0
      ncolors=bi\biClrUsed
    Else ;We don't have an optimal palette
      ncolors=1 << bi\biBitCount
    EndIf
    
    cl\pitch=(((bitcount*width)+31) >> 5) << 2 ;Bytes per line
    Len=bi\biSize+(ncolors*4)+(cl\pitch*height) ;Size of DIB
    
    bi\biSizeImage=cl\pitch*height ;Fill in biSizeImage
    
    ;Allocate memory block to store our DIB
    hDIB=AllocateMemory(Len)
    If hDIB=0
      FreeMemory(lpBUFF)
      FreeMemory(*mem)
      Debug "GIF Load Error! Memory allocation failed!"
      ProcedureReturn #False ;NO_DIB
    EndIf
    
    ;Fill first part of DIB with the BITMAPINFOHEADER
    CopyMemory(bi,hDIB,SizeOf(bi))
    ;Set the colors in the DIB (or masks for the new DIB formats)
    *pal=hDIB+SizeOf(bi)
    If cl\bUseGlobalColMap
      For count=0 To bi\biClrUsed-1
        *pal\rgbBlue=Blue(GlobalCols(count))
        *pal\rgbGreen=Green(GlobalCols(count))
        *pal\rgbRed=Red(GlobalCols(count))
        *pal+4
      Next
    Else
      For count=0 To bi\biClrUsed-1
        *pal\rgbBlue=Blue(localCols(count))
        *pal\rgbGreen=Green(localCols(count))
        *pal\rgbRed=Red(localCols(count))
        *pal+4
      Next
    EndIf
    
    cl\Line=0 ;Set address offset for OutLineGIF()
    cl\Pass=0 ;For interlaced images in OutLineGIF()
    
    ;Image data bits of DIB
    cl\lpBits=hDIB+bi\biSize+(ncolors*4)+(cl\pitch*(height-1))
    
    ;This is the main loop. For each code we get we pass through the
    ;linked list of prefix codes, pushing the corresponding "character"
    ;for each code onto the stack. When the list reaches a single
    ;"character" we push that on the stack too, and then start
    ;unstacking each character for output in the correct order.
    ;Special handling is included for the clear code, and the whole
    ;thing ends when we get an ending code.
    cc=0
    
    While cc<>EndingCode
      
      cc=GIF_NextCode(*mem, mempos, @newpos,CharBuff(),CodeMask(),cl)
      mempos = newpos
      If cc<0 ;If a file error, return without completing the decode
        FreeMemory(lpBUFF)
        FreeMemory(*mem)
        Debug "GIF Load Error!GIF image contained an in-valid LZW code."
        ProcedureReturn #False ;FILE_ERROR
      EndIf
      
      ;If the code is a clear code, re-initialise all necessary items.
      If cc=ClearCode
        
        cl\CurrCodeSize=LZWCodeSize+1
        Slot=NewCodes
        TopSlot=1 << cl\CurrCodeSize
        
        ;Continue reading codes until we get a non-clear code
        ;(another unlikely, but possible case...)
        While cc=ClearCode
          cc=GIF_NextCode(*mem, mempos, @newpos, CharBuff(), CodeMask(),cl)
          mempos = newpos
        Wend
        
        ;If we get an ending code immediately after a clear code
        ;(yet another unlikely case), then break out of the loop.
        If cc=EndingCode
          Break ;end loop
        EndIf
        
        ;Finally, if the code is beyond the range of already set codes,
        ;(This one had better not happen, I have no idea what will
        ;result from this, but I doubt it will look good)
        ;then set it to color zero.
        If cc>=Slot
          cc=0
        EndIf
        
        OldCode=cc
        TempOldCode=OldCode
        
        ;And let us not forget to put the char into the buffer, and if,
        ;on the off chance, we were exactly one pixel from the end of
        ;the line, we have to send the buffer to the OutLineGIF() routine
        *lpBuffPtr\b=cc
        *lpBuffPtr+1
        BufCnt-1
        
        If BufCnt=0
          GIF_OutLine(lpBUFF,width,height,cl)
          *lpBuffPtr=lpBUFF
          BufCnt=width
        EndIf
        
      Else
        
        ;In this case, it's not a clear code or an ending code, so it
        ;must be a code code. So we can now decode the code into a
        ;stack of character codes (Clear as mud, right?).
        code=cc
        
        If code=Slot
          code=TempOldCode
          *lpSP\b=OldCode
          *lpSP+1
        EndIf
        
        ;Here we scan back along the linked list of prefixes, pushing
        ;helpless characters (i.e. suffixes) onto the stack as we do so.
        While code>=NewCodes
          *lpSP\b=suffix(code)
          *lpSP+1
          code=prefix(code)
        Wend
        
        ;Push the last character on the stack, and set up the new
        ;prefix and suffix, and if the required slot number is greater
        ;than that allowed by the current bit size, increase the bit
        ;size. (Note - if we are all full, we *don't* save the new
        ;suffix and prefix. I'm not certain if this is correct,
        ;it might be more proper to overwrite the last code.
        *lpSP\b=code
        *lpSP+1
        
        If Slot<TopSlot
          OldCode=code
          suffix(Slot)=OldCode
          prefix(Slot)=TempOldCode
          Slot+1
          TempOldCode=cc
        EndIf
        
        If Slot>=TopSlot
          If cl\CurrCodeSize<12
            TopSlot=TopSlot << 1
            cl\CurrCodeSize+1
          EndIf
        EndIf
        
        ;Now that we've pushed the decoded string (in reverse order)
        ;onto the stack, lets pop it off and put it into our decode
        ;buffer, and when the decode buffer is full, write another line.
        While *lpSP>@stack(0)
          *lpSP-1
          *lpBuffPtr\b=*lpSP\b
          *lpBuffPtr+1
          BufCnt-1
          
          If BufCnt=0
            GIF_OutLine(lpBUFF,width,height,cl)
            *lpBuffPtr=lpBUFF
            BufCnt=width
          EndIf
        Wend
        
      EndIf
      
    Wend
    
    If BufCnt<>width ;If there are any left, output the bytes
      GIF_OutLine(lpBUFF,width-BufCnt-1,height,cl)
    EndIf
    
    ;Create the DDB bitmap
    *dib=hDIB
    If *dib=0 ;Avoid errors
      ProcedureReturn #False
    EndIf
    
    Bits=*dib+*dib\biSize+(*dib\biClrUsed*4) ;Pointer to bits
    
    ;- create the bitmap
    ;Create the DDB bitmap
    hImage = GIF_CreateDIImage(*dib, TransColorIndex)
    pbimage=CreateImage(#PB_Any,realwidth,realheight, 32 | #PB_Image_Transparent)
    StartDrawing(ImageOutput(pbimage))
    DrawingMode(#PB_2DDrawing_AlphaBlend)
    ; For some retarded reason, we have to draw and redraw the GIF frames over the previous image imagenumber-1
    
    ;   If bUseGlobalColMap ; if a local color table, then draw previous image in array, and then dray new hbitmap with transparency
    ;     Box(0,0,realwidth,realheight,$FFFFFF)
    ;     DrawImage(imageArray(numberimages-1),0,0)
    ;     If tflag=1
    ;       ;loc
    ;       DrawTransparentImage(drawdc,hBitmap,im\imLeft,im\imTop,im\imWidth,im\imHeight,transcolor)
    ;     Else
    ;       DrawImage(hBitmap,im\imLeft,im\imTop,im\imWidth,im\imHeight)
    ;     EndIf
    ;   Else
    
    If disposalmethod = 1
      ;Box(0,0,realwidth,realheight,$FFFFFF)
      DrawImage(ImageID(GIF_Frames(numberimages-1)\Image),0,0)
      DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
    ElseIf disposalmethod = 2
      ;Box(0,0,realwidth,realheight,$FFFFFF)
      ;DrawImage(ImageID(GIF_Frames(1)),0,0)
      DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
    Else
      ;Box(0,0,realwidth,realheight,$FFFFFF)
      DrawImage(ImageID(GIF_Frames(numberimages-1)\Image),0,0)
      ;DrawImage(hBitmap,im\imLeft,im\imTop)
      DrawImage(ImageID(hImage),im\imLeft,im\imTop,im\imWidth,im\imHeight)
    EndIf
    ;   EndIf
    StopDrawing()
    FreeImage(hImage)
    FreeMemory(hDIB) ;Free the DIB
    ReDim GIF_Frames(numberimages)
    GIF_Frames(numberimages)\Image = pbimage
    GIF_Frames(numberimages)\DelayTime = delaytime
    numberimages + 1
  Wend
  FreeMemory(*mem)
  ProcedureReturn numberimages
EndProcedure
[example1.pb]

Code: Select all

EnableExplicit
XIncludeFile "GIFanimation.pbi"

Define.w a
Dim Frames.GIF_Frame(0)

OpenWindow(0, 0, 0, 800, 600, "Gif_Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget)
ButtonGadget(0,10,10,80,20,"Open File")
ImageGadget(1,50,50,0,0,0, #PB_Image_Border)

AddWindowTimer(0, 0, 100)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          Define.s Pattern="All Supported Formats|*.gif"
          Define.s filename=OpenFileRequester("Choose An Image File To Open","",Pattern,0)
          If filename
            If GIF_LoadFrames(Frames(), filename)
              ResizeGadget(1, #PB_Ignore, #PB_Ignore, ImageWidth(Frames(0)\Image), ImageHeight(Frames(0)\Image))
              ;SetGadgetState(0, ImageID(Frames(0)\Image))
            EndIf
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      Break
      
    Case #PB_Event_Timer
      RemoveWindowTimer(0, 0)
      If a > ArraySize(Frames()) : a = 0 : EndIf
      If IsImage(Frames(a)\Image)
        SetGadgetState(1, ImageID(Frames(a)\Image))
        AddWindowTimer(0, 0, Frames(a)\DelayTime * 10)
      Else
        AddWindowTimer(0, 0, 100)
      EndIf
      a + 1   
  EndSelect
  
ForEver
[example2.pb] catches from memory

Code: Select all

EnableExplicit
XIncludeFile "GIFanimation.pbi"

Dim Frames.GIF_Frame(0)
Define i, count

If GIF_LoadFrames(Frames(), "", ?Loading2_gif_start, 7998)
  count = ArraySize(Frames())
  OpenWindow(0, #PB_Ignore, #PB_Ignore, ImageWidth(Frames(0)\Image) + 20, ImageHeight(Frames(0)\Image) + 20, "")
  ImageGadget(0, 10, 10, ImageWidth(Frames(0)\Image), ImageHeight(Frames(0)\Image), ImageID(Frames(0)\Image))
  AddWindowTimer(0, 1, Frames(0)\DelayTime * 10)
  
  i = 0
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Break
        
      Case #PB_Event_Timer
        Select EventTimer()
          Case 1
            SetGadgetState(0, ImageID(Frames(i)\Image))
            i + 1
            If i > count : i = 0 : EndIf
        EndSelect
    EndSelect
  ForEver  
EndIf

DataSection
  Loading2_gif_start:
    ; size : 7998 bytes
    Data.q $00A0613938464947,$7C7E7C0000F20014,$8A8CACAAACECEAEC,$F4848684FCFEFC8C,$04F9218C8E8CF4F2
    Data.q $0BFF210004000709,$455041435354454E,$0000000103302E32,$1400A0000000002C,$FEDCBA48FE030000
    Data.q $CDEB38BDAB49CA30,$9E69648E2860FFBB,$2C70BEEB6CAEAA68,$364860871C219BCF,$0213D22EDCB7F3AE
    Data.q $95320C47F148437D,$812350752963E4CE,$EC90020C0000A001,$43F05EB96B0DFBB6,$1D83B564CFAF2E8C
    Data.q $C741BCB6F6D38F37,$00845D020E6EEFBF,$8B8A888685831002,$82928D8F8785890F,$9A84900D958A8C94
    Data.q $0E8EA00B9E5D9C0C,$0FA95CA710036370,$B368B1AC77AA5EAB,$B8A6B9B5B7B0B2AE,$0CC2AF0DBFBBBDAD
    Data.q $C985CAC8B1058A5A,$BDCE84CCCDCFCBB7,$D55DD3D4D1D2D6D0,$5C5C890AA263DD9B,$DFA5E598E1E404E2
    Data.q $9FEDEF93EAEBE663,$73F8E9E7ECF3F0E0,$CFF3E205087F75C7,$B81188190342BF8F,$3C02160B84C16147
    Data.q $08AD1380C54ED0C8,$1D8D94C9E0343018,$92C6A3D1C1B034AB,$4B6504090C901922,$26450984C65C4D96
    Data.q $B3C9DCEA73389B8D,$4A1D0A83409FCFA7,$0000121AA3D1A8B4,$001300070904F921,$1400A0000000002C
    Data.q $8486840402048400,$AAACDCDADC4C4A4C,$F46C6A6C343234AC,$B4B2B45C5E5CF4F2,$E6E48C8E8C141614
    Data.q $548C8A8C3C3E3CE4,$343634ACAEAC5452,$62640000007C7E7C,$EC1C1A1CB4B6B464,$000000000000ECEA
    Data.q $0000000000000000,$0000000000000000,$648E24E0FE050000,$BEEB6CAEAA689E69,$AE78DF6D74CF2C70
    Data.q $62214315D3EF7CEF,$00506DA4C88EFCA8,$8EAD4A728B8F9F38,$BF5818A016A78A06,$900E9C2DAB735E60
    Data.q $776CD5A1507082C5,$1D7872E9BD4EDD7A,$7B807C7EE7DB8F75,$2509646409268367,$27520E018F120E17
    Data.q $9095269391128F8D,$9C8E949D979B2892,$989F24A5A0A38C99,$0823AF96A2ACA79E,$0496900425085B89
    Data.q $BC8FBABDBB97B928,$C412C2C5C001BE27,$D1B8CCCACDC8C626,$115AB50D25C3BFC1,$E08FDE280E96A725
    Data.q $DDE8E626E412E227,$EBF0EFE3EDE1DF96,$4EDAD9F4EDF2EA24,$0A5D8EF790B1F5DC,$05850681BFDCB008
    Data.q $AD0985C1DD308820,$007DAD04B0A87441,$8DB498F025C8916E,$C9193228EB059712,$422942EA387D238F
    Data.q $B91C7A5C13962FE5,$3042308812CBE692,$8A7CE74F88D52F85,$BF3CA2B7934A1A00,$3D56D36974409D09
    Data.q $131996A631352AA1,$88A9604070380807,$EBD5CAD1BABB5BAC,$568B3586C765B004,$3B65C0F96EB21DAC
    Data.q $DDE8C25D5A9604F7,$0AF80C011909834B,$100502820202EC1E,$90C7E3B1B8CC24EC,$10DF32B94C9E4B23
    Data.q $1D00070904F92100,$00A0000000002C00,$8684040204840014,$2CDCDADC4C4A4C84,$6C6A6CACAAAC2C2E
    Data.q $3A3C141614F4F2F4,$B45C5E5C8C8E8C3C,$E4E6E40C0E0CB4B2,$0604FCFAFC343634,$345452548C8A8C04
    Data.q $7C7E7CACAEAC3432,$92943C3E3C1C1A1C,$ECB4B6B464626494,$000000000000ECEA,$8E2760FE05000000
    Data.q $EB6CAEAA689E6964,$78DF6D74CF2C70BE,$818DA5FFEF7CEFAE,$0472A4C8806C30F2,$1A72064C112260C9
    Data.q $7AECB384ECD80050,$0694714B166B8E6F,$2CDFBAF83118F188,$3A624750259D4108,$07051914543A7096
    Data.q $83817F8482807E2A,$8D288B86888A8529,$2491969294898C87,$639D0C2319597A19,$1216A816121C250C
    Data.q $AE26ACAAA9A6275C,$A7ADB5A8B328ABA9,$B724BDB8BBA5B1B4,$00A21825C4BFB6B0,$05250B58CA0B2309
    Data.q $27D6D4D32805A8AF,$D2DEA9DC26DAAFD8,$E4D7D5E024E216D4,$11CA1126E5E823E6,$A801A7250FCFC923
    Data.q $59FCAAFBF92812FA,$FB057F89E03037D0,$0E7E412050982C1D,$7889621081342A01,$891EE0067BD01AA2
    Data.q $6192281C02050F5F,$A93C8E17B2219280,$4896492F7DCA24D2,$9DA2CF670763CCA0,$D53D70089D8FA57B
    Data.q $43A2BBE78DBA0AA5,$A55003B3EA337E8F,$8893EA24E3B292E3,$164B9862F82ACF50,$35F61582095BAEC2
    Data.q $0B408ACD625708D8,$231ED81DB55718AC,$F144734D0113A721,$E005090480A07131,$80BF213037FBE88A
    Data.q $C56170F89C207705,$6512592C42330D8C,$048660218EF20EB8,$025D1E88E06C4E9A,$A339DC14097A8282
    Data.q $66CB63A4CE808B39,$CEB40B0A05016151,$83C0DFEFB7BBCDDE,$21000847BC4E1F0B,$2C001400070904F9
    Data.q $001400A000000000,$4484868404020485,$2C2E2CD4D2D44442,$6264ACAAACECEAEC,$F43C3A3C14121464
    Data.q $5452548C8E8CF4F6,$7A7CB4B2B4E4E6E4,$34DCDADC0C0E0C7C,$0000001C1A1C3436,$4A4C8C8A8C040604
    Data.q $F4343234D4D6D44C,$6C6A6CACAEACF4F2,$FAFC3C3E3C141614,$B45C5E5C949294FC,$0000007C7E7CB4B6
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $2C48708A40FE0600,$3A6CC972A4C88F1A,$AF5AAD4A74A8D09F,$55BF7AEDCB76ACD8,$74E8C088E1232711
    Data.q $454A82407E598236,$CF7E8019231CFA00,$7A08204C80FFA828,$047A7B790D481608,$111D8B8B1D11450D
    Data.q $0200920214979681,$8A43768C9B041F46,$200B1B1A470400A1,$ABB0AEACAA4A1A06,$B7B2B4B6B149AFAD
    Data.q $1646C0B5B8B3B948,$43207AA6204487A6,$231605450E7BCA0E,$D7D6D3477E1623D5,$D5E048D8D6DB46D9
    Data.q $E5E8D2DEE1D4DAE2,$08A18447DDE444EA,$7ACF214309CF1E45,$024019AADC064521,$341DB90523C0E030
    Data.q $3C47017FC2DAD092,$291388C12050D224,$1567854869567844,$00B508A127E3DC86,$CB650236231E50D5
    Data.q $E6447984A64E486B,$53A98CDE5F2695CB,$24711F3E974FE125,$9400FC91041951F2,$533C9683C02EC224
    Data.q $4EAAD4E5B5100D3E,$A956EA9596B4D6A1,$A6DE645AF582595A,$1F614A5B3C1244A3,$A428CD39B9147F3F
    Data.q $60A5D01F5C8BDCE1,$9606FB7BA95E2F57,$248A0F5303C8D7EB,$D61B7E33884CC653,$276FB9B26E778D59
    Data.q $CCBBF3759C965E9F,$675B6437765B3194,$41409495A83E14D2,$4A021EB808A64F91,$30B0580C1A232A19
    Data.q $EEEF7CBDDE6E952C,$0787B922F137FB8D,$0245E5F1961CAE2F,$8BDA8348B64083CC,$EFA623AF448A3D1A
    Data.q $826460B3700C067F,$11C023DF611FB305,$2191086CA7F0F7F8,$CFDFEBF3F1688843,$A0280600FFFFBFBF
    Data.q $0904F9210000411A,$0000002C00140007,$020485001400A000,$D444424484868404,$ECEAEC2C2E2CD4D2
    Data.q $1214646264ACAAAC,$8CF4F6F43C3A3C14,$E4E6E45452548C8E,$0E0C7C7A7CB4B2B4,$1C343634DCDADC0C
    Data.q $0406040000001C1A,$D6D44C4A4C8C8A8C,$ACF4F2F4343234D4,$1416146C6A6CACAE,$9294FCFAFC3C3E3C
    Data.q $7CB4B6B45C5E5C94,$0000000000007C7E,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$FE06000000000000,$C88F1A2C48708A40,$A8D09F3A6CC972A4,$76ACD8AF5AAD4A74
    Data.q $9388A2E0BF7AEDCB,$C11ADAB4E1447091,$7D0022A541203F2C,$D61467CF600C918E,$16087B0820498180
    Data.q $450D047B7C7A0D48,$9782111D8C8C1D11,$491A06200B1B1A58,$A2041F4602009302,$470400A88B43778D
    Data.q $499F9DB14A9E9C9A,$BABCB4B69BB8B3B5,$C723160547B7B948,$4488AD16467F1623,$7CD20E43207BAD20
    Data.q $DB46CBC9C8C5450E,$C6C4E2C7E048CAC8,$E444EAE5E8DADEE1,$854706C7DC0648DD,$214309D71E4508A8
    Data.q $BD9E8F322884F6D7,$D91092341DB90523,$B0D2243C46F48242,$700B18871388BC9E,$1A59AE112233E38C
    Data.q $4A02FC21855AE152,$472D243263B1B228,$359647E5D3298478,$91E2E6731224DE6B,$A640F00B227F2F9E
    Data.q $0D29290A46D29091,$5A1CF2560080CA02,$CCCAAF558ECD0034,$32BF5BAED1AB142A,$F0148CD522162AA3
    Data.q $14A935C1244A7289,$B4511B91481C0600,$562F9678BDDE1A14,$DC782BB6001F7ABC,$A0F5683C8AE6A2C6
    Data.q $B80B5884D4693448,$3BC68996C4D85D61,$BF319A6D90DDD977,$3444D1691BF9BC3B,$6E0F91580160B018
    Data.q $022A14FAF0502527,$6A88CAF56ED887B4,$D60C3D6EAF7DAED6,$BC75A7137E45E0F0,$07C004ABCEE070B8
    Data.q $8238F9BB0691EAC1,$0CD5E04C529F2924,$720B04CA4166F018,$F0F0A3C047BECA43,$1086432210D94FE3
    Data.q $FFBFBFCFDFEBE4D9,$045380E0280600FF,$00070904F9210001,$A0000000002C0014,$8404020485001400
    Data.q $D4D2D44442448486,$AAACECEAEC2C2E2C,$3C141214646264AC,$8C8E8CF4F6F43C3A,$B2B4E4E6E4545254
    Data.q $DC0C0E0C7C7A7CB4,$1C1A1C343634DCDA,$8A8C040604000000,$34D4D6D44C4A4C8C,$ACAEACF4F2F43432
    Data.q $3E3C1416146C6A6C,$5C949294FCFAFC3C,$7C7E7CB4B6B45C5E,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$8A40FE0600000000,$72A4C88F1A2C4870
    Data.q $4A74A8D09F3A6CC9,$EDCB76ACD8AF5AAD,$70919388AAE0BF7A,$3F2CC11ADAB4E144,$918E7D0022A54120
    Data.q $8180D61467CF600C,$0D4816087B082049,$1D11450D047B7C7A,$1A489782111D8C8C,$9C9A4A1A06200B1B
    Data.q $1F4602009302499E,$00AC8B43778DA604,$A3B5499F9DA14704,$BF99BABCA0B69BB8,$1623C723160547B7
    Data.q $B11647CAC8C6C47F,$0E43207BB1204488,$CBC9C8C5450E7CD6,$CFC7CDDEE2CEDF46,$0648E1E8E3EAE0CC
    Data.q $46F523F3F106C7E0,$8609DB1E4508AC85,$F379114427B6D884,$7BC1E14E084119F2,$44C871164430890E
    Data.q $9A71B638058C487A,$CDB08919931C8D11,$47F90C2ADB0A90D2,$8C663A2390114250,$126D349A4BE3D219
    Data.q $1F9ECEDE1A132981,$A247267310780591,$841AD28224964601,$A91429DCB8010495,$15AA2D1E7D5698D1
    Data.q $38991E935BA0D72B,$33EECC0FB210A2B4,$0C29536D824894F5,$AAF6B2B822506824,$47BCDF6F7680A59A
    Data.q $76E11D6F0A1B7EF7,$359AA4507AC41E44,$2BCE70DC11B4426C,$B9921E5E89832262,$1CD46B30E6CB3BB0
    Data.q $A3002C160306889A,$4EDE1F22B0F55A85,$6A04562AF600A04A,$A9D391966B1DB90F,$D77008BC2D6EFF57
    Data.q $A0397C1E1EBF88A0,$3780D2358820FB00,$A98933F12490471F,$99602CDE03019AFB,$7808F7D6486E8160
    Data.q $64421B29FBBDBDE4,$F3F8FBFBDBA210C8,$00FFFFBFBFCFDFEB,$0904F9210004110E,$0000002C00140007
    Data.q $020485001400A000,$D444424484868404,$ECEAEC2C2E2CD4D2,$1214646264ACAAAC,$8CF4F6F43C3A3C14
    Data.q $E4E6E45452548C8E,$0E0C7C7A7CB4B2B4,$1C343634DCDADC0C,$0406040000001C1A,$D6D44C4A4C8C8A8C
    Data.q $ACF4F2F4343234D4,$1416146C6A6CACAE,$9294FCFAFC3C3E3C,$7CB4B6B45C5E5C94,$0000000000007C7E
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$FE06000000000000
    Data.q $C88F1A2C48708A40,$A8D09F3A6CC972A4,$76ACD8AF5AAD4A74,$C45130E0BF7AEDCB,$8D3D7AB1223848C9
    Data.q $801152A0901F9660,$0A33EFC00648C73E,$087C08204682816C,$0D047C7D7B0D4816,$83111D8D8D1D1145
    Data.q $4A1A06200B1B1A5F,$489F9D9BA09E9C9A,$AA041F4602009402,$470400B08C43788E,$A3B948A7A2A4A6A1
    Data.q $C723160546BDBF49,$CBC9C8C547801623,$89B51647CAC8C6C4,$DB0E43207CB52044,$D2E3D0D3CD450E7D
    Data.q $E9E448CFE8CCD4C7,$F34806C7CE0644E6,$8645FACEF847F6F4,$90C12E00F11410B0,$990FC22884F8E010
    Data.q $7117943C46F4863F,$700B1890F58690E2,$D3263B1B2336238C,$5DC09191C9638238,$130421855C01521A
    Data.q $279A47E4F212284A,$C8E2A771E934926D,$6492507805D0449B,$246A44968C01A247,$998041B72D224A82
    Data.q $AD1686C8A0CCC010,$76415BA3D7299596,$870D2145ABB10B0D,$AA8059C1F690A59E,$84052AEE004912A6
    Data.q $DA99CF7B34521709,$236EEB75F9F77CBE,$18A75BB696D17551,$B6D1141EB5079131,$6B9C37096F909BAD
    Data.q $7C898EAD33486F1C,$0CB8C5E8C859DC3E,$C3D66A97CC00B058,$BA07C8BADD78688C,$81160AFDB0281294
    Data.q $769B25BAD77A43DD,$FCAE2ED757B322EC,$00094531B0E49138,$79F7840D23D24210,$8BC3D295C0526914
    Data.q $16099882CE003019,$E248008F9DA48F00,$0C864421B287CBE3,$FFBFBFCFDFCDC421,$046180E0280600FF
    Data.q $00070904F9210001,$A0000000002C0014,$8404020485001400,$D4D2D44442448486,$AAACECEAEC2C2E2C
    Data.q $3C141214646264AC,$8C8E8CF4F6F43C3A,$B2B4E4E6E4545254,$DC0C0E0C7C7A7CB4,$1C1A1C343634DCDA
    Data.q $8A8C040604000000,$34D4D6D44C4A4C8C,$ACAEACF4F2F43432,$3E3C1416146C6A6C,$5C949294FCFAFC3C
    Data.q $7C7E7CB4B6B45C5E,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$8A40FE0600000000,$72A4C88F1A2C4870,$4A74A8D09F3A6CC9,$EDCB76ACD8AF5AAD
    Data.q $48C9C45530E0BF7A,$96608D3D7AB12238,$C73E801152A0901F,$816C0A33EFC00648,$4816087C08204682
    Data.q $11450D047C7D7B0D,$1A4F83111D8D8D1D,$9C9A4A1A06200B1B,$A6A1499F9D9BA09E,$041F460200940249
    Data.q $0400B38C43788EAD,$BC48BDA5A8A3A947,$1623C723160547A7,$C8C548CAC8C6C480,$1644D4CED146CBC9
    Data.q $43207CB8204489B8,$CFC7D6450E7DDF0E,$44D8E9CDD5EAD2CC,$F6F4F34806C7D206,$FCC8FC46FAD2F847
    Data.q $E40F11410B343111,$22884F8E41090C12,$3CA04237A3DDEB00,$238C700B1887168A,$721243263B1B2337
    Data.q $121C7E4526924784,$1855C81521A5DC81,$1E4F252284A1B082,$2B94CADF677239C9,$8ECA24C0F00B21B3
    Data.q $51297499351C0345,$020DF989125C91A3,$150A450A6E0086CD,$27DD2AB93EA6D0E4,$FC4ECD002146688D
    Data.q $B6096707DA42967A,$1814AD3901244AB2,$6DA45AED91787C36,$8DB9DDB4F68DB6DF,$10DE389C21130D45
    Data.q $88A0F5C03C8ED3C6,$E1B86B8C84E16FB7,$02163B0AEBC8D330,$00582C060D113159,$B355AD61EAF52BB6
    Data.q $EC1F226C365A8236,$045C2C48A0A04A52,$D76D174DF5910F7A,$6DF90A0D7ED48BB3,$48D6308410025C4C
    Data.q $F0549A451E8DE203,$B3800C0662EFF425,$EF6123C2058266A0,$6CA1F0F7F8120023,$F3F1730843219108
    Data.q $00FFFFBFBFCFDFEB,$04F9210010451806,$00002C0014000709,$0485001400A00000,$4442448486840402
    Data.q $EAEC2C2E2CD4D2D4,$14646264ACAAACEC,$F4F6F43C3A3C1412,$E6E45452548C8E8C,$0C7C7A7CB4B2B4E4
    Data.q $343634DCDADC0C0E,$06040000001C1A1C,$D44C4A4C8C8A8C04,$F4F2F4343234D4D6,$16146C6A6CACAEAC
    Data.q $94FCFAFC3C3E3C14,$B4B6B45C5E5C9492,$00000000007C7E7C,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0600000000000000,$8F1A2C48708A40FE,$D09F3A6CC972A4C8
    Data.q $ACD8AF5AAD4A74A8,$58B0E0BF7AEDCB76,$CD78D11C2464E228,$A950480FCB304686,$FBE80324639F4008
    Data.q $08204383826D0519,$7D7E7C0D4816087D,$1D8E8E1D11450D04,$1A06200B1B1A8211,$9F9D9BA09E9C9A4A
    Data.q $0247A7A2A4A6A149,$8FB0041F46020095,$A9470400B68D4379,$23160547C0A5A8A3,$CAC8C6C4811623C7
    Data.q $CED146CBC9C8C548,$BB1646CFC7D645D4,$0E43207DBB20448A,$44D8DBCDD90E7EE3,$F206C7D20648D3DA
    Data.q $46FAF4F347F623F4,$E04C880115FCD2FC,$2E80F11410B64390,$881884FAE81090C1,$0B1890F58210E0CF
    Data.q $8638236EB8238C70,$36458FC8E471A64C,$112349E544792476,$21855D01521A61D0,$E263D269484A230C
    Data.q $20F00B225B3E9149,$990D1C03458EC964,$25429142A3512974,$41C735214CDC7312,$9EEC224EC01119C0
    Data.q $0FA1C52A74CA8D2A,$B6052D5448210A2C,$422D570B75A1EF69,$0295F74024895B58,$D48B95D4891388C4
    Data.q $9A2C6DAADCA7B46D,$63C716EFC6D95D78,$141EBB07909DD8F6,$371173909CAE3711,$A5C661C8596C4638
    Data.q $5F30C2C160306885,$91B5FADD82B75DAC,$C87B6D8EDF67B5D5,$6B4228281295BD87,$B5EB8D6A43E18117
    Data.q $174909BADE28373B,$281A46B184210012,$A75784A512490477,$39059C406032FF8B,$011FBB692E402C13
    Data.q $884364DF9FCBC691,$BFBFCFA3A842190C,$F480E0280600FFFF,$070904F921000105,$000000002C001400
    Data.q $04020485001400A0,$D2D4444244848684,$ACECEAEC2C2E2CD4,$141214646264ACAA,$8E8CF4F6F43C3A3C
    Data.q $B4E4E6E45452548C,$0C0E0C7C7A7CB4B2,$1A1C343634DCDADC,$8C0406040000001C,$D4D6D44C4A4C8C8A
    Data.q $AEACF4F2F4343234,$3C1416146C6A6CAC,$949294FCFAFC3C3E,$7E7CB4B6B45C5E5C,$000000000000007C
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$40FE060000000000
    Data.q $A4C88F1A2C48708A,$74A8D09F3A6CC972,$CB76ACD8AF5AAD4A,$E22A58B0E0BF7AED,$4686CD78D11C2464
    Data.q $4008A950480FCB30,$0519FBE80324639F,$087D08204383826D,$0D047D7E7C0D4816,$57111D8E8E1D1145
    Data.q $9A4A1A06200B1B1A,$A1499F9D9BA09E9C,$48A3A948A7A2A4A6,$B3041F4602009502,$470400B98D43798F
    Data.q $23C723160546ADAF,$C4CBC9C8C5478116,$45D0D3CD48CAC8C6,$43D8DBD2CCD4C7D6,$207DBE20448ABE16
    Data.q $CFDED90E7EE70E43,$23F4F206C7CE0648,$CEFC46FAF4F347F6,$8211204C880115FC,$0788A085CA1C8EF5
    Data.q $C427D76084860976,$8C70088DC3067C40,$864C6E38C6233923,$FC8E4C4792476424,$1A572392C7A54458
    Data.q $2AEC0A90D30EC089,$98CBDF425148790C,$CC2360F00B22532F,$297498DD1C03458E,$B43905429142A351
    Data.q $B0839E70449AA4A9,$553DBC449F002293,$9E08428CD119CFBA,$DC0FB5052D1557BD,$5C5F42AE366B95C2
    Data.q $8A44C29607602489,$B729ECDB75D60F16,$1DF87C4B75E34C68,$444C6D170A437063,$62283D7C0F22E2B2
    Data.q $706E28EB213A5CEE,$582C060D10F2186C,$504661EAF52AE580,$B6D8ED35CC1D66AB,$BD87C91AFD911761
    Data.q $8117CB7228281295,$B67B86039D7043E1,$81085804A3D0426E,$4492411DCA0691AC,$180CC1E0E8CDA189
    Data.q $4B900B04CF016710,$E3F0F0A44047EECA,$EE1086432210D937,$FFFFBFBFCFDFEBE4,$F921001046080600
    Data.q $002C001400070904,$85001400A0000000,$4244848684040204,$EC2C2E2CD4D2D444,$646264ACAAACECEA
    Data.q $F6F43C3A3C141214,$E45452548C8E8CF4,$7C7A7CB4B2B4E4E6,$3634DCDADC0C0E0C,$040000001C1A1C34
    Data.q $4C4A4C8C8A8C0406,$F2F4343234D4D6D4,$146C6A6CACAEACF4,$FCFAFC3C3E3C1416,$B6B45C5E5C949294
    Data.q $000000007C7E7CB4,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$1A2C48708A40FE06,$9F3A6CC972A4C88F,$D8AF5AAD4A74A8D0,$B0E0BF7AEDCB76AC
    Data.q $78D11C2464E22C58,$50480FCB304686CD,$E80324639F4008A9,$204383826D0519FB,$7E7C0D4816087D08
    Data.q $8E8E1D11450D047D,$06200B1B1A47111D,$9D9BA09E9C9A4A1A,$48A7A2A4A6A1499F,$950247B0A5A8A3A9
    Data.q $798FB6041F460200,$1605460400BC8D43,$C8C547811623C723,$CD48CAC8C6C4CBC9,$D2CCD4C7D645D0D3
    Data.q $C11647CFDA44D8DB,$0E43207DC120448A,$06C7CE06450E7EEA,$FACEF847F6F4F348,$4237A3C9FCC8FC46
    Data.q $283411EEF5801120,$4BBC3C45042F10E4,$188A213EBBC42430,$3B1B2339E38C700B,$2692478472124326
    Data.q $224AE53298D47E45,$844893296B924F25,$8861577854869877,$607C7658128BC4E2,$30068F33A2D0E512
    Data.q $82914DA4D2E8926A,$8752AAD329C01644,$10754EC8539754DC,$AAB3A0F410045E7C,$83EA90AB4400850C
    Data.q $AE143B6DBED614B4,$2B68711AE767BB5C,$78B052CAEF04912C,$8B45B9448DB86331,$8318DD71E21B38AA
    Data.q $AB92C3E36B0CD21B,$4507B041E42CBE3D,$0DC5DDC42763A9D2,$A6566160B0183446,$353AED66BD5BADD5
    Data.q $7B6D96D35445DAEC,$5C007C87BCDBA837,$381182BA22828129,$4908BE023A97643E,$1A46A78421C0130F
    Data.q $5D87A51249047738,$059C406032FF8BA7,$1FBB692E602C133F,$4364DF9FCBC69101,$BFCFA3C442190C88
    Data.q $80E0280600FFFFBF,$0904F92100010450,$0000002C000E0007,$020484001400A000,$44D4D2D484868404
    Data.q $2C2E2CECEAEC4442,$0E0CF4F6F4ACAAAC,$3CE4E6E48C8E8C0C,$7C7A7CDCDADC3C3A,$8A8C040604000000
    Data.q $34F4F2F4D4D6D48C,$141214FCFAFC3432,$7E7C3C3E3C949294,$000000000000007C,$0000000000000000
    Data.q $FE05000000000000,$AA689E69648E23A0,$74CF2C70BEEB6CAE,$FFEF7CEFAE78DF6D,$8C851A2C4870A0C0
    Data.q $0B031E3C19628AC8,$A000152CC6AD48E5,$A0A030DA26294102,$3AA2418B090C4940,$CF729D9AB46DD7A7
    Data.q $F5F3AF0E59BA6FE3,$035A6203277D7627,$2553056186051426,$2804101893181004,$9694992797959491
    Data.q $A0939E269C9F9298,$A19BAA90A4A7A29D,$245D5A8C1025A89A,$011806261661B516,$18BFC0BE2806C093
    Data.q $C7C7C4C8C1C527C3,$CAD4C6CEC2CFBDC9,$B55925DAD6D8CDD3,$AE260B5ABA172515,$27E99AEA95E828A7
    Data.q $F2F4F0ECEEE7B7EB,$E40C22F8EEEDF7B3,$0981F00078901800,$80308142FC1ABF63,$A2785C39290C00C2
    Data.q $A894562EC188C3E1,$1C82331E8A4720F1,$C9A60411C09C8FF1,$C512B461D1369021,$9A4266224978361E
    Data.q $08A71326ACBA6C23,$C4D3BA14DE79339D,$A138002C492B4637,$4A8C655AB2872894,$A0369F55565413C2
    Data.q $72B55DAC56EAC23A,$1D60B283AC75E115,$BC722E44A0D5D034,$0320506100819C4C,$DED0175BC5CAED74
    Data.q $70071BEDCC4B7EBC,$D4B0A09F0C7EC261,$002AE914250382D0,$437C0225CBE58AD9,$60C886458284F100
    Data.q $C6092580805A4D1E,$B0D7E932A0905801,$DBEDB6BB4D9ECB63,$F921000108B373B8,$002C000B00070904
    Data.q $84001400A0000000,$D2D4848684040204,$F4444244ECEAECD4,$3C3E3CACAAACF4F6,$7A7CDCDADC8C8E8C
    Data.q $8C1412140000007C,$F4F2F4D4D6D48C8A,$00007C7E7CFCFAFC,$0000000000000000,$0000000000000000
    Data.q $0000000000000000,$0000000000000000,$0000000000000000,$9E69648E22E0FE05,$2C70BEEB6CAEAA68
    Data.q $7CEFAE78DF6D74CF,$1A2C4870A0C0FFEF,$11066CC90384AB8F,$080C3D50D180000C,$6BA9B96AC561E184
    Data.q $596FE251831DDB76,$44FBF5E6DB92F61D,$0911A0D40401DA90,$807E7C7A030D2244,$8A83817F7D7B2782
    Data.q $878B84888C858D86,$9095982596918926,$06265577770D269D,$A9A8A6280611A77F,$B2AAA8AC27AEADAB
    Data.q $25B8ADAFB7A5B5B0,$22C17FBF24BDA7B3,$A48A94270C52A251,$28D1CC25CE7E8EA0,$D2DACBD8D0D680D4
    Data.q $D585D9E023DED724,$01ADCF0977C80925,$F4F0DCEEA8EFEDD9,$F9F6F7ECF3A7F1F2,$65274BA046FA7FF8
    Data.q $262828020A802F9D,$4C38170C85429582,$50FAB68AC3D770B8,$3D1F8DC5A211388C,$10063218F0C8BC66
    Data.q $C2254928D1F12E73,$112249842A569B96,$C239A02A65354D4B,$E114F2753D9C4CE6,$202A8F42A2502773
    Data.q $9CE60D06818D00A8,$CF51AA09AA5502B8,$57AD554BB59A7D4C,$B2892C75812D5AB9,$01C2022B4D8AC960
    Data.q $05974B993AD80764,$B759480418C70084,$4C1DFC040216DFAF,$5E2B1388C3E1B0B8
    Data.b $CC,$D8,$70,$08,$00,$3B
  Loading2_gif_end:
EndDataSection
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

Nice improvements ! :D
Niffo
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: UPDATED: Load Animated GIF frames

Post by ts-soft »

Thanks, :D

but we have to optimize the speed. A GIF with over 300 KB loads in 2 seconds, this is to slow.
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

Even with debugger deactivated ?
Niffo
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: UPDATED: Load Animated GIF frames

Post by infratec »

The killer GIF for the program:

http://www.biologie.uni-hamburg.de/b-on ... movie2.gif

Bernd
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: UPDATED: Load Animated GIF frames

Post by infratec »

A fast try:

Code: Select all

EnableExplicit
XIncludeFile "GIFanimation.pbi"

Define.w a
Dim Frames.GIF_Frame(0)

InitSprite()

OpenWindow(0, 0, 0, 800, 600, "Gif_Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget)
ButtonGadget(0,10,10,80,20,"Open File")

AddWindowTimer(0, 0, 100)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0
          Define.s Pattern="All Supported Formats|*.gif"
          Define.s filename=OpenFileRequester("Choose An Image File To Open","",Pattern,0)
          If filename
            If GIF_LoadFrames(Frames(), filename)
              OpenWindowedScreen(WindowID(0), 50, 50, ImageWidth(Frames(0)\Image), ImageHeight(Frames(0)\Image), 0, 0, 0)
            EndIf
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      Break
      
    Case #PB_Event_Timer
      RemoveWindowTimer(0, 0)
      If a > ArraySize(Frames()) : a = 0 : EndIf
      If IsImage(Frames(a)\Image)
        StartDrawing(ScreenOutput())
        DrawImage(ImageID(Frames(a)\Image), 0, 0)
        StopDrawing()
        FlipBuffers()
        AddWindowTimer(0, 0, Frames(a)\DelayTime * 10)
      Else
        AddWindowTimer(0, 0, 100)
      EndIf
      a + 1
  EndSelect
  
ForEver
I'm not an expert with FlipBuffers() and so on.
So please look above that code.

Bernd
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

For information, this 1,2 MB Gif takes 1,244 seconds to load with debugger disabled on my 2.8Ghz Core Duo.
Last edited by Niffo on Thu May 03, 2012 2:24 pm, edited 1 time in total.
Niffo
Korolev Michael
Enthusiast
Enthusiast
Posts: 200
Joined: Wed Feb 01, 2012 5:30 pm
Location: Russian Federation

Re: UPDATED: Load Animated GIF frames

Post by Korolev Michael »

Hi to all. How I can implement a GIF animation, during a hard operation? Scanning, for example.

GIF animation function updates window by timer event. How I can use it, if my main program cycle starts by gadget event? GIF animation condition stops checking timer event, when base program cycle starts to work.

Code: Select all

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 0 ; button gadget pressed
          ImageGadget() ;creating area for animation
          AddWindowTimer(0,0,Frames(0)\DelayTime*5)
          ; And then program does some hard and long operations... here animation doesn't work
      EndSelect

    Case #PB_Event_CloseWindow
      Break

    Case #PB_Event_Timer
       ;GIF processing routine
  EndSelect
  
ForEver
Former user of pirated PB.
Now registered user :].
User avatar
graph100
Enthusiast
Enthusiast
Posts: 115
Joined: Tue Aug 10, 2010 3:17 pm

Re: UPDATED: Load Animated GIF frames

Post by graph100 »

In the Pb help you will find that timer event are not the priority : in Window : AddWindowTimer()

Try to do it with a thread ?
(After Reading through the topic, I didn't see the thread aspect so I don't know if it's thread safe. Just try)
_________________________________________________
My Website : CeriseCode (Warning : perpetual changes & not completed ;))
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Re: UPDATED: Load Animated GIF frames

Post by Niffo »

You can try API timers (timeSetEvent() on Windows, http://www.purebasic.fr/english/viewtop ... 19&t=37698), or Threads ...
Niffo
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: UPDATED: Load Animated GIF frames

Post by ts-soft »

You can load the GIF to a array, but better not in a thread.
You can Display the Animation in a thread, but enable Threadsafe,
is required for the ImageLib!
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Korolev Michael
Enthusiast
Enthusiast
Posts: 200
Joined: Wed Feb 01, 2012 5:30 pm
Location: Russian Federation

Re: UPDATED: Load Animated GIF frames

Post by Korolev Michael »

but enable Threadsafe, is required for the ImageLib!
Works without threadsafe mode.
You can Display the Animation in a thread
Look at the next code.

Code: Select all

Procedure Animation(param)
 Repeat
    Select event ;event var declared as global
      Case #PB_Event_Timer
       ; GIF updating routine. All vars declared as global.
    EndSelect
ForEver
EndProcedure

CreateThread(@Animation(), param)

Repeat
    event=WaitWindowEvent(10);

    Repeat
      x+1 ; here window hangs bacause of hard repeating process. Thread works correctly without this cycle.
    ForEver

Until event=#PB_Event_CloseWindow
I suppose, I need to close my cycle into thread too. Or I did a mistake in my logic?

Edited. My program logic structure:

1. Declaring vars, arrays
2. Loading GIF
3. Enumerating constants
4. Several procedures, including Animation() proc:

Code: Select all

Procedure Animation(param)
  Repeat
    Select event
      Case #PB_Event_Timer
        SetGadgetState(#Img_Scan,ImageID(Frames(i)\Image))
        i+1
        If i>count: i=0: EndIf
    EndSelect
  ForEver
EndProcedure
5. Drawing main window, initialization
6. Callback declared
7. Some short "If" conditions
8. Main program loop:

Code: Select all

Repeat
   all following code
Until event=#PB_Event_CloseWindow
8.1. Some "Select event - Case" procedures
8.2. Our turn. GIF animation launched by pressing button:

Code: Select all

ImageGadget(#Img_Scan,85,220,ImageWidth(Frames(0)\Image), ImageHeight(Frames(0)\Image),ImageID(Frames(0)\Image))
AddWindowTimer(#Window_Main,1,Frames(0)\DelayTime*5)
thread_anim=CreateThread(@Animation(),param)
8.2.1. All rest target code is long working with filesystem objects (dirs, folders..). And here animation is not working again :(

If all my work code replace by empty loop code:

Code: Select all

Repeat
Until event=#PB_Event_CloseWindow
Animation works!
Former user of pirated PB.
Now registered user :].
Post Reply