December 03, 2020, 08:16:04 PM

Author Topic: [bb] GIFLoad Module for B3D/B+ by markcw [ 1+ years ago ]  (Read 625 times)

Offline BlitzBot

  • Jr. Member
  • **
  • Posts: 1
[bb] GIFLoad Module for B3D/B+ by markcw [ 1+ years ago ]
« on: June 29, 2017, 12:28:42 AM »
Title : GIFLoad Module for B3D/B+
Author : markcw
Posted : 1+ years ago

Description : This page used to have a LoadImageGIF function which could load most single-frame gif files. Then I decided to work on animated gifs and discovered that the LoadImageGIF function didn't follow the gif spec properly.

I have been over the gif89a spec several times and written and rewritten the code and have finally got some solid code to load animated gifs. I am sharing it so that anyone who would like to use gifs for their game can now do so without having to use a dll or a workaround with OpenMovie.

To have the GIFLoad functions highlighted, create a file in your userlibs folder called "gifload.decls" and copy/paste this code into it.
Code: [Select]
.lib " "

;GIFLoad Module Decls
GIFLoadImage%(filename$,firstframe,numframes)
GIFDelayTimes%(filename$,firstframe,numframes)
GIFFrames%(filename$,firstframe,numframes)
GIFLoops%(filename$)
GIFHeight%(filename$)
GIFWidth%(filename$)
GIFLoad%(filename$,GIFCLASS*)
GIFOutLine%(Buffer,Width,Height,GIFCLASS*)
GIFNextCode%(file,GIFCLASS*)

Save this code entry as "gifload.bb" and then include it in your main program. You can find example usage below. [/i]

Code :
Code: BlitzBasic
  1. ;GIFLoad Module for B3D/B+
  2. ;Author: markcw, edited 26 Feb 2008
  3. ;LZW decoding based on C code by John Findlay for ImageShop32
  4. ;Create a file in your userlibs folder called "gifload.decls"
  5.  
  6. ;.lib " "
  7. ;
  8. ;;GIFLoad Module Decls
  9. ;GIFLoadImage%(filename$,firstframe,numframes)
  10. ;GIFDelayTimes%(filename$,firstframe,numframes)
  11. ;GIFFrames%(filename$,firstframe,numframes)
  12. ;GIFLoops%(filename$)
  13. ;GIFHeight%(filename$)
  14. ;GIFWidth%(filename$)
  15. ;GIFLoad%(filename$,GIFCLASS*)
  16. ;GIFOutLine%(Buffer,Width,Height,GIFCLASS*)
  17. ;GIFNextCode%(file,GIFCLASS*)
  18.  
  19. Type GIFCLASS ;This is instead of using globals
  20.  Field pCharBuff ;Pointer to next byte in block
  21.  Field iPass ;First pass for interlaced images in GIFOutLine
  22.  Field iLine ;Offset for addressing the bits in GIFOutLine
  23.  Field pBits ;Scanline for bits
  24.  Field Pitch ;Bytes are rounded up for image lines
  25.  Field CurrCodeSize ;The current code size
  26.  Field BitsLeft ;Used in GIFNextCode
  27.  Field BytesLeft ;Used in GIFNextCode
  28.  Field CurrByte ;Current byte
  29.  Field GlobalBpp ;Global bit depth
  30.  Field isInterlaced ;Is the image interlaced
  31.  Field LocalBpp ;Local bit depth
  32.  Field CodeMask[16] ;Masks for LZW compression algorithm
  33.  Field CharBuff[279] ;Current block
  34.  Field DIB ;DIB bank handle
  35.  Field NextFilePos ;Used to jump to the next block
  36.  Field isLocalTable ;Local Color Table Flag
  37.  Field bBackIndex ;Background Color Index
  38.  Field Disposal ;Disposal Method, 0..3
  39.  Field isTransparent ;Transparent Color Flag
  40.  Field wLeft ;Image Left Position
  41.  Field wTop ;Image Top Position
  42.  Field bTransIndex ;Transparent Color Index
  43. End Type
  44.  
  45. Function GIFLoadImage(filename$,firstframe=1,numframes=0)
  46.  ;Creates and returns an image from a gif, top-level function
  47.  ;firstframe -> The frame to start drawing from, 1=first frame
  48.  ;numframes -> The number of frames to draw, 0=all frames
  49.  ;Uses GIFFrames, GIFWidth, GIFHeight and GIFLoad
  50.  
  51.  Local cl.GIFCLASS=New GIFCLASS ;Gif type
  52.  Local frames,width,height,image,graphic,buffer,dib,bpp
  53.  Local bits,wWidth,wHeight,pitch,src,dest,ix,iy,offset
  54.  Local index,pixel,blue,green,red,rgb
  55.  
  56.  ;Set some initial variables
  57.  frames=GIFFrames(filename$) ;Number of frames
  58.  If firstframe>0 Then firstframe=firstframe-1 Else firstframe=0
  59.  If firstframe>frames-1 Then firstframe=frames-1 ;Limit firstframe
  60.  If numframes<=0 Then numframes=frames-firstframe ;Limit numframes
  61.  If numframes>frames-firstframe Then numframes=frames-firstframe
  62.  frames=firstframe+numframes ;Limit number of frames
  63.  width=GIFWidth(filename$) ;Screen width
  64.  height=GIFHeight(filename$) ;Screen height
  65.  image=CreateImage(width,height,numframes)
  66.  graphic=CreateImage(width,height,3) ;0=previous, 1=this, 2=empty
  67.  
  68.  For buffer=0 To frames-1 ;Loop through the frames
  69.  
  70.   dib=GIFLoad(filename$,cl) ;Load the next frame
  71.   If dib=0 ;Avoid errors
  72.    Delete cl ;Delete the class
  73.    FreeImage graphic ;Free the graphic
  74.    Return image ;Return the image
  75.   EndIf
  76.   bpp=PeekShort(dib,14) ;biBitCount
  77.   bits=40+(PeekInt(dib,32)*4) ;biSize+(biClrUsed*4)
  78.   wWidth=PeekInt(dib,4) ;biWidth
  79.   wHeight=PeekInt(dib,8) ;biHeight
  80.   pitch=((wWidth*bpp+31)/32)*4 ;DWORD-aligned
  81.  
  82.   If clDisposal=3 ;Restore to previous, store before drawing
  83.    src=ImageBuffer(graphic,1) ;Copy this graphic to previous graphic
  84.    dest=ImageBuffer(graphic,0)
  85.    CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  86.   EndIf
  87.  
  88.   ;Draw this graphic from the DIB
  89.   LockBuffer ImageBuffer(graphic,1)
  90.   For iy=0 To wHeight-1
  91.    offset=bits+(pitch*(wHeight-1-iy)) ;Next scanline
  92.    For ix=0 To wWidth-1
  93.     If ix+clwLeft<width And iy+clwTop<height ;Pixel in bounds
  94.      If bpp=1
  95.       index=PeekByte(dib,offset+(ix Shr 3)) ;Get bit
  96.       pixel=7-(ix Mod 8)
  97.       index=(index And (1 Shl pixel)) Shr pixel
  98.      ElseIf bpp=4
  99.       index=PeekByte(dib,offset+(ix Shr 1)) ;Get nibble
  100.       pixel=(1-(ix Mod 2)) Shl 2
  101.       index=(index And (15 Shl pixel)) Shr pixel
  102.      ElseIf bpp=8
  103.       index=PeekByte(dib,offset+ix) ;Get byte
  104.      EndIf
  105.      If clisTransparent And clTransIndex=index ;Transparent pixel
  106.      Else ;Normal pixel
  107.       index=40+(index Shl 2) ;Get palette index
  108.       blue=PeekByte(dib,index)
  109.  
  110.  
  111.       green=PeekByte(dib,index+1)
  112.       red=PeekByte(dib,index+2)
  113.       rgb=blue Or (green Shl 8) Or (red Shl 16)
  114.       If rgb=0 Then rgb=$080808 ;Avoid transparent pixels
  115.       WritePixelFast ix+clwLeft,iy+clwTop,rgb,ImageBuffer(graphic,1)
  116.      EndIf
  117.     EndIf
  118.    Next
  119.   Next
  120.   UnlockBuffer ImageBuffer(graphic,1)
  121.   FreeBank dib ;Free the DIB
  122.  
  123.   If buffer-firstframe>=0 ;If this frame is valid
  124.    src=ImageBuffer(graphic,1) ;Copy this graphic to this frame
  125.    dest=ImageBuffer(image,buffer-firstframe)
  126.    CopyRect 0,0,width,height,0,0,src,dest
  127.   EndIf
  128.  
  129.   ;Decide how to dispose of this graphic
  130.   If clDisposal<2 ;0=Not specified, 1=Do not dispose, both do nothing
  131.   ElseIf clDisposal=2 ;Restore to background
  132.    src=ImageBuffer(graphic,2) ;Copy empty graphic to this graphic
  133.    dest=ImageBuffer(graphic,1)
  134.    CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  135.   ElseIf clDisposal=3 ;Restore to previous
  136.    src=ImageBuffer(graphic,0) ;Copy previous graphic to this graphic
  137.    dest=ImageBuffer(graphic,1)
  138.    CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  139.   EndIf
  140.  
  141.  Next
  142.  
  143.  Delete cl ;Delete the class
  144.  FreeImage graphic ;Free the graphic
  145.  Return image ;Return the image
  146.  
  147. End Function
  148.  
  149. Function GIFDelayTimes(filename$,firstframe=1,numframes=0)
  150.  ;Creates and returns a bank with delay times for a gif
  151.  ;Bank values are in integers, the number of frames is at 0
  152.  ;and the delay time for frame 1 is at 1*4, etc
  153.  ;firstframe -> The frame to start reading from, 1=first frame
  154.  ;numframes -> The number of frames to read, 0=all frames
  155.  
  156.  Local file,count,Sig$,bank,bPacked,isColorTable,blocksize
  157.  Local byte,blocklabel,wDelayTime,frames
  158.  
  159.  file=ReadFile(filename$)
  160.  If file=0
  161.   RuntimeError "File could not be opened"
  162.  EndIf
  163.  
  164.  ;Header block
  165.  For count=0 To 2
  166.   Sig$=Sig$+Chr(ReadByte(file))
  167.  Next
  168.  If Sig$<>"GIF"
  169.   Return 0 ;Not a valid gif
  170.  EndIf
  171.  SeekFile(file,FilePos(file)+3) ;Skip Version
  172.  
  173.  bank=CreateBank(4) ;Create the delay times bank
  174.  
  175.  ;Logical Screen Descriptor block
  176.  SeekFile(file,FilePos(file)+4) ;Skip Screen Width/Height
  177.  bPacked=ReadByte(file) ;bPacked
  178.  SeekFile(file,FilePos(file)+2) ;Skip BackgroundColor/AspectRatio
  179.  
  180.  ;Global Color Table block
  181.  isColorTable=(bPacked And 128) Shr 7 ;Global Color Table Flag, bit 7
  182.  If isColorTable
  183.   blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  184.   SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  185.  EndIf
  186.  
  187.  ;Parse the blocks
  188.  While Not Eof(file)
  189.  
  190.   byte=ReadByte(file)
  191.  
  192.   If byte=$21 ;Extension block (89a)
  193.    blocklabel=ReadByte(file)
  194.  
  195.    If blocklabel=$01 ;Plain Text Extension block
  196.     blocksize=ReadByte(file) ;Should be 12
  197.     While blocksize>0 ;Skip sub-blocks
  198.      SeekFile(file,FilePos(file)+blocksize)
  199.      blocksize=ReadByte(file)
  200.     Wend
  201.  
  202.    ElseIf blocklabel=$F9 ;Graphic Control Extension block
  203.     blocksize=ReadByte(file) ;Should be 4
  204.     SeekFile(file,FilePos(file)+1) ;Skip bPacked
  205.     wDelayTime=ReadShort(file) ;100ths of a second (1/100)
  206.     SeekFile(file,FilePos(file)+1) ;Skip Transparent Color Index
  207.     blocksize=ReadByte(file) ;Should be 0
  208.     ResizeBank(bank,8+(frames Shl 2))
  209.     PokeInt bank,4+(frames Shl 2),wDelayTime*10 ;Convert to millisecs
  210.  
  211.    ElseIf blocklabel=$FE ;Comment Extension block
  212.     blocksize=ReadByte(file) ;Should be 1..255
  213.     While blocksize>0 ;Skip sub-blocks
  214.      SeekFile(file,FilePos(file)+blocksize)
  215.      blocksize=ReadByte(file)
  216.     Wend
  217.  
  218.    ElseIf blocklabel=$FF ;Application Extension block
  219.     blocksize=ReadByte(file) ;Should be 11
  220.     While blocksize>0 ;Skip sub-blocks
  221.      SeekFile(file,FilePos(file)+blocksize)
  222.      blocksize=ReadByte(file)
  223.     Wend
  224.  
  225.    EndIf
  226.   EndIf
  227.  
  228.   If byte=$2C ;Image Descriptor block (87a)
  229.    blocklabel=byte
  230.    SeekFile(file,FilePos(file)+8) ;Skip Image Left/Top/Width/Height
  231.    bPacked=ReadByte(file)
  232.    isColorTable=(bPacked And 128) Shr 7 ;Local Color Table Flag, bit 7
  233.    If isColorTable ;Local Color Table block
  234.     blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  235.     SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  236.    EndIf
  237.    frames=frames+1 ;Increment frames
  238.   EndIf
  239.  
  240.   If byte>1 And byte<13 ;Image Data block (87a)
  241.    blocklabel=byte ;LZW bit range is 2..12
  242.    blocksize=ReadByte(file) ;1..255
  243.    While blocksize>0 ;Skip sub-blocks
  244.     SeekFile(file,FilePos(file)+blocksize)
  245.     blocksize=ReadByte(file)
  246.    Wend
  247.   EndIf
  248.  
  249.  Wend
  250.  
  251.  ;Modify the bank according to optional parameters
  252.  If firstframe>0 Then firstframe=firstframe-1 Else firstframe=0
  253.  If firstframe>frames-1 Then firstframe=frames-1 ;Limit firstframe
  254.  If numframes<=0 Then numframes=frames-firstframe ;Limit numframes
  255.  If numframes>frames-firstframe Then numframes=frames-firstframe
  256.  For count=1 To numframes ;Move the values one at a time
  257.   PokeInt bank,count*4,PeekInt(bank,(count+firstframe)*4)
  258.  Next
  259.  ResizeBank(bank,4+(numframes*4))
  260.  PokeInt bank,0,numframes ;Store the frames
  261.  
  262.  CloseFile file ;Close the file
  263.  Return bank ;Return the delay times bank
  264.  
  265. End Function
  266.  
  267. Function GIFFrames(filename$,firstframe=1,numframes=0)
  268.  ;Returns the number of frames in a gif
  269.  ;For this we have to manually count them since gifs
  270.  ;don't have a field to store the number of frames
  271.  ;firstframe -> The frame to start counting from, 1=first frame
  272.  ;numframes -> The number of frames to count, 0=all frames
  273.  
  274.  Local file,count,Sig$,bPacked,isColorTable,blocksize
  275.  Local byte,blocklabel,frames
  276.  
  277.  file=ReadFile(filename$)
  278.  If file=0
  279.   RuntimeError "File could not be opened"
  280.  EndIf
  281.  
  282.  ;Header block
  283.  For count=0 To 2
  284.   Sig$=Sig$+Chr(ReadByte(file))
  285.  Next
  286.  If Sig$<>"GIF"
  287.   Return 0 ;Gif header not valid
  288.  EndIf
  289.  SeekFile(file,FilePos(file)+3) ;Skip Version
  290.  
  291.  ;Logical Screen Descriptor block
  292.  SeekFile(file,FilePos(file)+4) ;Skip Screen Width/Height
  293.  bPacked=ReadByte(file) ;bPacked
  294.  SeekFile(file,FilePos(file)+2) ;Skip BackgroundColor/AspectRatio
  295.  
  296.  ;Global Color Table block
  297.  isColorTable=(bPacked And 128) Shr 7 ;Global Color Table Flag, bit 7
  298.  If isColorTable
  299.   blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  300.   SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  301.  EndIf
  302.  
  303.  ;Parse the blocks
  304.  While Not Eof(file)
  305.  
  306.   byte=ReadByte(file)
  307.  
  308.   If byte=$21 ;Extension block (89a)
  309.    blocklabel=ReadByte(file)
  310.  
  311.    If blocklabel=$01 ;Plain Text Extension block
  312.     blocksize=ReadByte(file) ;Should be 12
  313.     While blocksize>0 ;Skip sub-blocks
  314.      SeekFile(file,FilePos(file)+blocksize)
  315.      blocksize=ReadByte(file)
  316.     Wend
  317.  
  318.    ElseIf blocklabel=$F9 ;Graphic Control Extension block
  319.     blocksize=ReadByte(file) ;Should be 4
  320.     SeekFile(file,FilePos(file)+blocksize)
  321.     blocksize=ReadByte(file) ;Should be 0
  322.  
  323.    ElseIf blocklabel=$FE ;Comment Extension block
  324.     blocksize=ReadByte(file) ;Should be 1..255
  325.     While blocksize>0 ;Skip sub-blocks
  326.      SeekFile(file,FilePos(file)+blocksize)
  327.      blocksize=ReadByte(file)
  328.     Wend
  329.  
  330.    ElseIf blocklabel=$FF ;Application Extension block
  331.     blocksize=ReadByte(file) ;Should be 11
  332.     While blocksize>0 ;Skip sub-blocks
  333.      SeekFile(file,FilePos(file)+blocksize)
  334.      blocksize=ReadByte(file)
  335.     Wend
  336.  
  337.    EndIf
  338.   EndIf
  339.  
  340.   If byte=$2C ;Image Descriptor block (87a)
  341.    blocklabel=byte
  342.    SeekFile(file,FilePos(file)+8) ;Skip Image Left/Top/Width/Height
  343.    bPacked=ReadByte(file)
  344.    isColorTable=(bPacked And 128) Shr 7 ;Local Color Table Flag, bit 7
  345.    If isColorTable ;Local Color Table block
  346.     blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  347.     SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  348.    EndIf
  349.    frames=frames+1 ;Increment frames
  350.   EndIf
  351.  
  352.   If byte>1 And byte<13 ;Image Data block (87a)
  353.    blocklabel=byte ;LZW bit range is 2..12
  354.    blocksize=ReadByte(file) ;1..255
  355.    While blocksize>0 ;Skip sub-blocks
  356.     SeekFile(file,FilePos(file)+blocksize)
  357.     blocksize=ReadByte(file)
  358.    Wend
  359.   EndIf
  360.  
  361.  Wend
  362.  
  363.  ;Modify the return value according to optional parameters
  364.  If firstframe>0 Then firstframe=firstframe-1 Else firstframe=0
  365.  If firstframe>frames-1 Then firstframe=frames-1 ;Limit firstframe
  366.  If numframes<=0 Then numframes=frames-firstframe ;Limit numframes
  367.  If numframes>frames-firstframe Then numframes=frames-firstframe
  368.  
  369.  CloseFile file ;Close the file
  370.  Return numframes ;Return the number of frames
  371.  
  372. End Function
  373.  
  374. Function GIFLoops(filename$)
  375.  ;Returns the number of loops in a gif, 0=forever
  376.  ;This is the number of times the animation is repeated
  377.  
  378.  Local file,count,Sig$,bPacked,isColorTable,blocksize
  379.  Local byte,blocklabel,app$,loops,frames
  380.  
  381.  file=ReadFile(filename$)
  382.  If file=0
  383.   RuntimeError "File could not be opened"
  384.  EndIf
  385.  
  386.  ;Header block
  387.  For count=0 To 2
  388.   Sig$=Sig$+Chr(ReadByte(file))
  389.  Next
  390.  If Sig$<>"GIF"
  391.   Return 0 ;Gif header not valid
  392.  EndIf
  393.  SeekFile(file,FilePos(file)+3) ;Skip Version
  394.  
  395.  ;Logical Screen Descriptor block
  396.  SeekFile(file,FilePos(file)+4) ;Skip Screen Width/Height
  397.  bPacked=ReadByte(file) ;bPacked
  398.  SeekFile(file,FilePos(file)+2) ;Skip BackgroundColor/AspectRatio
  399.  
  400.  ;Global Color Table block
  401.  isColorTable=(bPacked And 128) Shr 7 ;Global Color Table Flag, bit 7
  402.  If isColorTable
  403.   blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  404.   SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  405.  EndIf
  406.  
  407.  ;Parse the blocks
  408.  While Not Eof(file)
  409.  
  410.   byte=ReadByte(file)
  411.  
  412.   If byte=$21 ;Extension block (89a)
  413.    blocklabel=ReadByte(file)
  414.  
  415.    If blocklabel=$01 ;Plain Text Extension block
  416.     blocksize=ReadByte(file) ;Should be 12
  417.     While blocksize>0 ;Skip sub-blocks
  418.      SeekFile(file,FilePos(file)+blocksize)
  419.      blocksize=ReadByte(file)
  420.     Wend
  421.  
  422.    ElseIf blocklabel=$F9 ;Graphic Control Extension block
  423.     blocksize=ReadByte(file) ;Should be 4
  424.     SeekFile(file,FilePos(file)+blocksize)
  425.     blocksize=ReadByte(file) ;Should be 0
  426.  
  427.    ElseIf blocklabel=$FE ;Comment Extension block
  428.     blocksize=ReadByte(file) ;Should be 1..255
  429.     While blocksize>0 ;Skip sub-blocks
  430.      SeekFile(file,FilePos(file)+blocksize)
  431.      blocksize=ReadByte(file)
  432.     Wend
  433.  
  434.    ElseIf blocklabel=$FF ;Application Extension block
  435.     blocksize=ReadByte(file) ;Should be 11
  436.     app$=""
  437.     For count=1 To blocksize ;Read the info
  438.      app$=app$+Chr(ReadByte(file))
  439.     Next
  440.     If app$="NETSCAPE2.0" ;Netscape's looping extension
  441.      SeekFile(file,FilePos(file)+2) ;Skip 2 bytes
  442.      loops=ReadShort(file) ;Number of times to loop, 0=forever
  443.      SeekFile(file,FilePos(file)-4) ;Return to blocksize
  444.     EndIf
  445.     blocksize=ReadByte(file)
  446.     While blocksize>0 ;Skip sub-blocks
  447.      SeekFile(file,FilePos(file)+blocksize)
  448.      blocksize=ReadByte(file)
  449.     Wend
  450.  
  451.    EndIf
  452.   EndIf
  453.  
  454.   If byte=$2C ;Image Descriptor block (87a)
  455.    blocklabel=byte
  456.    SeekFile(file,FilePos(file)+8) ;Skip Image Left/Top/Width/Height
  457.    bPacked=ReadByte(file)
  458.    isColorTable=(bPacked And 128) Shr 7 ;Local Color Table Flag, bit 7
  459.    If isColorTable ;Local Color Table block
  460.     blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Table size, bits 0..2
  461.     SeekFile(file,FilePos(file)+blocksize) ;Skip table if present
  462.    EndIf
  463.    frames=frames+1 ;Increment frames
  464.   EndIf
  465.  
  466.   If byte>1 And byte<13 ;Image Data block (87a)
  467.    blocklabel=byte ;LZW bit range is 2..12
  468.    blocksize=ReadByte(file) ;1..255
  469.    While blocksize>0 ;Skip sub-blocks
  470.     SeekFile(file,FilePos(file)+blocksize)
  471.     blocksize=ReadByte(file)
  472.    Wend
  473.   EndIf
  474.  
  475.  Wend
  476.  
  477.  CloseFile file ;Close the file
  478.  Return loops ;Return the number of loops
  479.  
  480. End Function
  481.  
  482. Function GIFWidth(filename$)
  483.  ;Returns the screen width of a gif
  484.  ;This is the actual width of the image
  485.  
  486.  Local file,count,Sig$,wScreenWidth,wScreenHeight
  487.  
  488.  file=ReadFile(filename$)
  489.  If file=0
  490.   RuntimeError "File could not be opened"
  491.  EndIf
  492.  
  493.  ;Header block
  494.  For count=0 To 2
  495.   Sig$=Sig$+Chr(ReadByte(file))
  496.  Next
  497.  If Sig$<>"GIF"
  498.   Return 0 ;Gif header not valid
  499.  EndIf
  500.  SeekFile(file,FilePos(file)+3) ;Skip Version
  501.  
  502.  ;Logical Screen Descriptor block
  503.  wScreenWidth=ReadShort(file)
  504.  wScreenHeight=ReadShort(file)
  505.  
  506.  CloseFile file ;Close the file
  507.  Return wScreenWidth ;Return the width
  508.  
  509. End Function
  510.  
  511. Function GIFHeight(filename$)
  512.  ;Returns the screen height of a gif
  513.  ;This is the actual height of the image
  514.  
  515.  Local file,count,Sig$,wScreenWidth,wScreenHeight
  516.  
  517.  file=ReadFile(filename$)
  518.  If file=0
  519.   RuntimeError "File could not be opened"
  520.  EndIf
  521.  
  522.  ;Header block
  523.  For count=0 To 2
  524.   Sig$=Sig$+Chr(ReadByte(file))
  525.  Next
  526.  If Sig$<>"GIF"
  527.   Return 0 ;Gif header not valid
  528.  EndIf
  529.  SeekFile(file,FilePos(file)+3) ;Skip Version
  530.  
  531.  ;Logical Screen Descriptor block
  532.  wScreenWidth=ReadShort(file)
  533.  wScreenHeight=ReadShort(file)
  534.  
  535.  CloseFile file ;Close the file
  536.  Return wScreenHeight ;Return the height
  537.  
  538. End Function
  539.  
  540. Function GIFLoad(filename$,cl.GIFCLASS)
  541.  ;Creates and returns a bank with a DIB for a gif frame
  542.  ;Uses GIFOutLine and GIFNextCode, used by GIFLoadImage
  543.  
  544.  Local Stack[4096] ;Stack for storing pixels, bytes
  545.  Local Suffix[4096] ;Suffix table, max number of LZW codes, bytes
  546.  Local Prefix[4096] ;Prefix linked list, integers
  547.  Local GlobalCols[256]
  548.  Local LocalCols[256]
  549.  Local file,count,Sig$,bPacked,isGlobalTable,blocksize
  550.  Local GlobalColors,byte,blocklabel,wWidth,wHeight,LocalColors
  551.  Local red,green,blue,frames,LZWCodeSize,BitCount,ncolors,size
  552.  Local dib,pal,TopSlot,ClearCode,EndingCode,NewCodes,Slot,cc
  553.  Local TempOldCode,OldCode,pStack,pBuffer,BufCount,Buffer,Code
  554.  
  555.  file=ReadFile(filename$)
  556.  If file=0
  557.   RuntimeError "File could not be opened"
  558.  EndIf
  559.  
  560.  ;Header block
  561.  For count=0 To 2
  562.   Sig$=Sig$+Chr(ReadByte(file))
  563.  Next
  564.  If Sig$<>"GIF"
  565.   CloseFile file ;Close the file
  566.   Return 0 ;Gif header not valid
  567.  EndIf
  568.  SeekFile(file,FilePos(file)+3) ;Skip Version, both are supported
  569.  
  570.  clCodeMask[0]=$0000 ;LZW Code Masks
  571.  clCodeMask[1]=$0001 : clCodeMask[2]=$0003 : clCodeMask[3]=$0007
  572.  clCodeMask[4]=$000F : clCodeMask[5]=$001F : clCodeMask[6]=$003F
  573.  clCodeMask[7]=$007F : clCodeMask[8]=$00FF : clCodeMask[9]=$01FF
  574.  clCodeMask[10]=$03FF : clCodeMask[11]=$07FF : clCodeMask[12]=$0FFF
  575.  clCodeMask[13]=$1FFF : clCodeMask[14]=$3FFF : clCodeMask[15]=$7FFF
  576.  
  577.  ;Logical Screen Descriptor block
  578.  SeekFile(file,FilePos(file)+4) ;Skip Screen Width/Height
  579.  bPacked=ReadByte(file) ;Packed Fields
  580.  clBackIndex=ReadByte(file) ;Background Color Index, ignored
  581.  isGlobalTable=(bPacked And 128) Shr 7 ;Global Color Table Flag, bit 7
  582.  blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Global Table size, bits 0..2
  583.  SeekFile(file,FilePos(file)+1) ;Skip Aspect Ratio
  584.  
  585.  GlobalColors=blocksize/3 ;Number of global colors
  586.  If GlobalColors<=2 ;Use number of colors to set bit depth
  587.   clGlobalBpp=1
  588.  ElseIf GlobalColors<=16
  589.   clGlobalBpp=4
  590.  Else
  591.   clGlobalBpp=8
  592.  EndIf
  593.  
  594.  ;Global Color Table block
  595.  If isGlobalTable
  596.   For count=0 To GlobalColors-1 ;Store global colors
  597.    red=ReadByte(file)
  598.    green=ReadByte(file)
  599.    blue=ReadByte(file)
  600.    GlobalCols[count]=(red Shl 16) Or (green Shl 8) Or blue
  601.   Next
  602.  Else
  603.   For count=0 To GlobalColors-1 ;Create a 2/16/256 greyscale palette
  604.    red=(255*count)/(GlobalColors-1)
  605.    green=(255*count)/(GlobalColors-1)
  606.    blue=(255*count)/(GlobalColors-1)
  607.    GlobalCols[count]=(red Shl 16) Or (green Shl 8) Or blue
  608.   Next
  609.  EndIf
  610.  
  611.  ;Return to where we left off reading last call
  612.  If clNextFilePos>0 Then SeekFile(file,clNextFilePos)
  613.  
  614.  clisTransparent=0 ;Make sure these extension variables are zero
  615.  clTransIndex=0
  616.  clDisposal=0
  617.  
  618.  ;Parse the blocks
  619.  While Not Eof(file)
  620.  
  621.   byte=ReadByte(file)
  622.  
  623.   If byte=$21 ;Extension block (89a)
  624.    blocklabel=ReadByte(file)
  625.  
  626.    If blocklabel=$01 ;Plain Text Extension block
  627.     blocksize=ReadByte(file) ;Should be 12
  628.     While blocksize>0 ;Skip sub-blocks
  629.      SeekFile(file,FilePos(file)+blocksize)
  630.      blocksize=ReadByte(file)
  631.     Wend
  632.  
  633.    ElseIf blocklabel=$F9 ;Graphic Control Extension block
  634.     blocksize=ReadByte(file) ;Should be 4
  635.     bPacked=ReadByte(file) ;Packed Fields
  636.     clDisposal=(bPacked And (4+8+16)) Shr 2 ;Disposal Method, bits 2..4
  637.     clisTransparent=bPacked And 1 ;Transparent Color Flag, bit 0
  638.     SeekFile(file,FilePos(file)+2) ;Skip Delay Time
  639.     clTransIndex=ReadByte(file) ;Transparent Color Index
  640.     blocksize=ReadByte(file) ;Block Terminator, always 0
  641.  
  642.    ElseIf blocklabel=$FE ;Comment Extension block
  643.     blocksize=ReadByte(file) ;Should be 1..255
  644.     While blocksize>0 ;Skip sub-blocks
  645.      SeekFile(file,FilePos(file)+blocksize)
  646.      blocksize=ReadByte(file)
  647.     Wend
  648.  
  649.    ElseIf blocklabel=$FF ;Application Extension block
  650.     blocksize=ReadByte(file) ;Should be 11
  651.     While blocksize>0 ;Skip sub-blocks
  652.      SeekFile(file,FilePos(file)+blocksize)
  653.      blocksize=ReadByte(file)
  654.     Wend
  655.  
  656.    EndIf
  657.   EndIf
  658.  
  659.   If byte=$2C ;Image Descriptor block (87a)
  660.    blocklabel=byte
  661.    clwLeft=ReadShort(file)
  662.    clwTop=ReadShort(file)
  663.    wWidth=ReadShort(file)
  664.    wHeight=ReadShort(file)
  665.    bPacked=ReadByte(file)
  666.    clisLocalTable=(bPacked And 128) Shr 7 ;Local Color Table Flag, bit 7
  667.    clisInterlaced=(bPacked And 64) Shr 6 ;Interlace Flag, bit 6
  668.    blocksize=3*(1 Shl ((bPacked And 7)+1)) ;Local Table size, bits 0..2
  669.    LocalColors=blocksize/3 ;Number of local colors
  670.    If LocalColors<=2 ;Use number of colors to set bit depth
  671.     clLocalBpp=1
  672.    ElseIf LocalColors<=16
  673.     clLocalBpp=4
  674.    Else
  675.     clLocalBpp=8
  676.    EndIf
  677.    If clisLocalTable ;Local Color Table block
  678.     For count=0 To LocalColors-1 ;Store local colors
  679.      red=ReadByte(file)
  680.      green=ReadByte(file)
  681.      blue=ReadByte(file)
  682.      LocalCols[count]=(red Shl 16) Or (green Shl 8) Or blue
  683.     Next
  684.    EndIf
  685.    frames=frames+1 ;Increment frames
  686.   EndIf
  687.  
  688.   If byte>1 And byte<13 ;Image Data block (87a)
  689.    LZWCodeSize=byte ;LZW bit range is 2..12
  690.  
  691.    count=FilePos(file) ;Store this block
  692.    blocksize=ReadByte(file) ;1..255
  693.    While blocksize>0 ;Skip sub-blocks
  694.     SeekFile(file,FilePos(file)+blocksize)
  695.     blocksize=ReadByte(file)
  696.    Wend
  697.    clNextFilePos=FilePos(file) ;Store the next block
  698.    SeekFile(file,count) ;Return to this block
  699.  
  700.    ;Set the bit depth and number of colors
  701.    If clisLocalTable
  702.     BitCount=clLocalBpp
  703.     ncolors=LocalColors
  704.    Else
  705.     BitCount=clGlobalBpp
  706.     ncolors=GlobalColors
  707.    EndIf
  708.    If ncolors=0 Then ncolors=1 Shl BitCount ;If no palette
  709.  
  710.    ;Allocate memory for DIB
  711.    clPitch=(((BitCount*wWidth)+31) Shr 5) Shl 2 ;Bytes per line
  712.    size=40+(ncolors*4)+(clPitch*wHeight) ;Size of DIB
  713.    dib=CreateBank(size)
  714.    clDIB=dib ;clDIB used in GIFOutLine
  715.  
  716.    ;Fill in the DIB info header
  717.    PokeInt dib,0,40 ;biSize, 40
  718.    PokeInt dib,4,wWidth ;biWidth
  719.    PokeInt dib,8,wHeight ;biHeight
  720.    PokeShort dib,12,1 ;biPlanes, 1
  721.    PokeShort dib,14,BitCount ;biBitCount, 1/4/8
  722.    PokeInt dib,16,0 ;biCompression, #BI_RGB=0
  723.    PokeInt dib,20,clPitch*wHeight ;biSizeImage
  724.    PokeInt dib,24,0 ;biXPelsPerMeter
  725.    PokeInt dib,28,0 ;biYPelsPerMeter
  726.    PokeInt dib,32,ncolors ;biClrUsed
  727.    PokeInt dib,36,0 ;biClrImportant
  728.  
  729.    pal=40 ;Fill in the DIB palette
  730.    If clisLocalTable
  731.     For count=0 To ncolors-1
  732.      PokeByte dib,pal,LocalCols[count] And $0000FF ;Blue
  733.      PokeByte dib,pal+1,(LocalCols[count] And $00FF00) Shr 8 ;Green
  734.      PokeByte dib,pal+2,(LocalCols[count] And $FF0000) Shr 16 ;Red
  735.      pal=pal+4
  736.     Next
  737.    Else
  738.     For count=0 To ncolors-1
  739.      PokeByte dib,pal,GlobalCols[count] And $0000FF ;Blue
  740.      PokeByte dib,pal+1,(GlobalCols[count] And $00FF00) Shr 8 ;Green
  741.      PokeByte dib,pal+2,(GlobalCols[count] And $FF0000) Shr 16 ;Red
  742.      pal=pal+4
  743.     Next
  744.    EndIf
  745.  
  746.    ;Init variables for the decoder for reading a new image
  747.    clCurrCodeSize=LZWCodeSize+1
  748.    TopSlot=1 Shl clCurrCodeSize ;Highest code for current size
  749.    ClearCode=1 Shl LZWCodeSize ;Value for a clear code
  750.    EndingCode=ClearCode+1 ;Value for an ending code
  751.    NewCodes=ClearCode+2 ;First available code
  752.    Slot=NewCodes ;Last read code
  753.    clBitsLeft=0 ;Make sure these LZW variables are zero
  754.    clBytesLeft=0
  755.    pStack=0 : pBuffer=0 ;Init the stack and decode buffer pointers
  756.    BufCount=wWidth ;Line counter (count for pixel line length)
  757.    cliLine=0 : cliPass=0 ;Init line offset and interlace pass
  758.    clpBits=40+(ncolors*4)+(clPitch*(wHeight-1)) ;Pointer to bits
  759.  
  760.    ;Allocate space for the decode buffer
  761.    Buffer=CreateBank(wWidth+16) ;+16 just in case
  762.  
  763.    ;This is the main loop. For each code we get we pass through the
  764.    ;linked list of prefix codes, pushing the corresponding "character"
  765.    ;for each code onto the stack. When the list reaches a single
  766.    ;"character" we push that on the stack too, and then start
  767.    ;unstacking each character for output in the correct order.
  768.    ;Special handling is included for the clear code, and the whole
  769.    ;thing ends when we get an ending code.
  770.    While cc<>EndingCode
  771.  
  772.     cc=GIFNextCode(file,cl)
  773.     If cc<0 Then Exit ;File error, exit without completing the decode
  774.  
  775.     ;If the code is a clear code, re-initialise all necessary items
  776.     If cc=ClearCode
  777.  
  778.      clCurrCodeSize=LZWCodeSize+1
  779.      Slot=NewCodes
  780.      TopSlot=1 Shl clCurrCodeSize
  781.  
  782.      ;Continue reading codes until we get a non-clear code
  783.      ;(another unlikely, but possible case...)
  784.      While cc=ClearCode
  785.       cc=GIFNextCode(file,cl)
  786.      Wend
  787.  
  788.      ;If we get an ending code immediately after a clear code
  789.      ;(yet another unlikely case), then break out of the loop
  790.      If cc=EndingCode Then Exit ;end loop
  791.  
  792.      ;Finally, if the code is beyond the range of already set codes,
  793.      ;(This one had better not happen, I have no idea what will
  794.      ;result from this, but I doubt it will look good)
  795.      ;then set it to color zero.
  796.      If cc>=Slot Then cc=0
  797.      OldCode=cc
  798.      TempOldCode=OldCode
  799.  
  800.      ;And let us not forget to put the char into the buffer, and if,
  801.      ;on the off chance, we were exactly one pixel from the end of
  802.      ;the line, we have to send the buffer to the GIFOutLine routine.
  803.      PokeByte Buffer,pBuffer,cc
  804.      pBuffer=pBuffer+1
  805.      BufCount=BufCount-1
  806.      If BufCount=0
  807.       GIFOutLine(Buffer,wWidth,wHeight,cl)
  808.       pBuffer=0
  809.       BufCount=wWidth
  810.      EndIf
  811.  
  812.     Else
  813.  
  814.      ;In this case, it's not a clear code or an ending code, so it
  815.      ;must be a code code. So we can now decode the code into a
  816.      ;stack of character codes (Clear as mud, right?).
  817.      Code=cc
  818.      If Code=Slot
  819.       Code=TempOldCode
  820.       Stack[pStack]=OldCode
  821.       pStack=pStack+1
  822.      EndIf
  823.  
  824.      ;Here we scan back along the linked list of prefixes, pushing
  825.      ;helpless characters (i.e. suffixes) onto the stack as we do so.
  826.      While Code>=NewCodes
  827.       Stack[pStack]=Suffix[Code]
  828.       pStack=pStack+1
  829.       Code=Prefix[Code]
  830.      Wend
  831.  
  832.      ;Push the last character on the stack, and set up the new
  833.      ;prefix and suffix, and if the required slot number is greater
  834.      ;than that allowed by the current bit size, increase the bit
  835.      ;size. (Note - if we are all full, we *don't* save the new
  836.      ;suffix and prefix. I'm not certain if this is correct,
  837.      ;it might be more proper to overwrite the last code.
  838.      Stack[pStack]=Code
  839.      pStack=pStack+1
  840.      If Slot<TopSlot
  841.       OldCode=Code
  842.       Suffix[Slot]=OldCode
  843.       Prefix[Slot]=TempOldCode
  844.       Slot=Slot+1
  845.       TempOldCode=cc
  846.      EndIf
  847.      If Slot>=TopSlot
  848.       If clCurrCodeSize<12
  849.        TopSlot=TopSlot Shl 1
  850.        clCurrCodeSize=clCurrCodeSize+1
  851.       EndIf
  852.      EndIf
  853.  
  854.      ;Now that we've pushed the decoded string (in reverse order)
  855.      ;onto the stack, lets pop it off and put it into our decode
  856.      ;buffer, and when the decode buffer is full, write another line.
  857.      While pStack>0
  858.       pStack=pStack-1
  859.       PokeByte Buffer,pBuffer,Stack[pStack]
  860.       pBuffer=pBuffer+1
  861.       BufCount=BufCount-1
  862.       If BufCount=0
  863.        GIFOutLine(Buffer,wWidth,wHeight,cl)
  864.        pBuffer=0
  865.        BufCount=wWidth
  866.       EndIf
  867.      Wend
  868.  
  869.     EndIf
  870.    Wend
  871.  
  872.    ;If there are any left, output the bytes
  873.    If BufCount<>wWidth
  874.     GIFOutLine(Buffer,wWidth-BufCount-1,wHeight,cl)
  875.    EndIf
  876.  
  877.    Exit ;End block parsing loop
  878.   EndIf
  879.  
  880.  Wend
  881.  
  882.  CloseFile file ;Close the file
  883.  FreeBank Buffer ;Free the buffer
  884.  Return dib ;Return the DIB
  885.  
  886. End Function
  887.  
  888. Function GIFOutLine(Buffer,Width,Height,cl.GIFCLASS)
  889.  ;Outputs the pixel color index data to the DIB
  890.  ;Buffer -> Memory block that holds the color index value
  891.  ;Width -> Length of the line of pixels, Height -> wHeight
  892.  ;Gif images are 2, 16 or 256 colors, poking the values into memory
  893.  ;requires a different method for each case. If gif is interlaced,
  894.  ;that is dealt with here.
  895.  ;Used by GIFLoad
  896.  
  897.  Local bits,bpp,count,pixel,byte,bitcount
  898.  
  899.  bits=clpBits-(cliLine*clPitch) ;Pointer to bits
  900.  
  901.  If cliLine>=Height Then Return False ;Avoid poking out of range
  902.  
  903.  If clisLocalTable
  904.   bpp=clLocalBpp
  905.  Else
  906.   bpp=clGlobalBpp
  907.  EndIf
  908.  
  909.  Select bpp
  910.   Case 1 ;1-bit DIB
  911.    count=0
  912.    For pixel=0 To Width-1 Step 8
  913.     byte=0
  914.     For bitcount=0 To 7
  915.      If PeekByte(Buffer,bitcount+pixel)
  916.       byte=byte Or (1 Shl (7-bitcount))
  917.      EndIf
  918.     Next
  919.     PokeByte clDIB,bits+count,byte
  920.     count=count+1
  921.    Next
  922.   Case 4 ;4-bit DIB
  923.    count=0
  924.    For pixel=0 To Width-1 Step 2
  925.     byte=PeekByte(Buffer,pixel) Shl 4
  926.     byte=byte Or PeekByte(Buffer,pixel+1)
  927.     PokeByte clDIB,bits+count,byte
  928.     count=count+1
  929.    Next
  930.   Case 8 ;8-bit DIB
  931.    For pixel=0 To Width-1
  932.     byte=PeekByte(Buffer,pixel)
  933.     PokeByte clDIB,bits+pixel,byte
  934.    Next
  935.  End Select
  936.  
  937.  If clisInterlaced ;Set iLine for different passes when interlaced
  938.   Select cliPass
  939.    Case 0 ;Pass 1
  940.     If cliLine<Height-8
  941.      cliLine=cliLine+8
  942.     Else
  943.      cliLine=4 : cliPass=cliPass+1 ;For 2nd pass
  944.     EndIf
  945.    Case 1 ;Pass 2
  946.     If cliLine<Height-8
  947.      cliLine=cliLine+8
  948.     Else
  949.      cliLine=2 : cliPass=cliPass+1 ;For 3rd pass
  950.     EndIf
  951.    Case 2 ;Pass 3
  952.     If cliLine<Height-4
  953.      cliLine=cliLine+4
  954.     Else
  955.      cliLine=1 : cliPass=cliPass+1 ;For 4th pass
  956.     EndIf
  957.    Case 3 ;Pass 4
  958.     If cliLine<Height-2
  959.      cliLine=cliLine+2
  960.     EndIf
  961.   End Select
  962.  Else ;When not interlaced increment iLine
  963.   cliLine=cliLine+1
  964.  EndIf
  965.  
  966. End Function
  967.  
  968. Function GIFNextCode(file,cl.GIFCLASS)
  969.  ;Reads the next code from the data stream
  970.  ;Returns the LZW code or error
  971.  ;Used by GIFLoad
  972.  
  973.  Local count,char,ret
  974.  
  975.  If clBitsLeft=0 ;Any bits left in byte?
  976.  
  977.   If clBytesLeft<=0 ;If not get another block
  978.    clpCharBuff=0 ;Reset byte pointer
  979.    clBytesLeft=ReadByte(file) ;Block size
  980.    If clBytesLeft=0 Then Return -2 ;Found block terminator
  981.    If Eof(file)<>0 Then Return -1 ;Stream error or end of file
  982.    For count=0 To clBytesLeft-1
  983.     char=ReadByte(file)
  984.     clCharBuff[count]=char ;Fill CharBuff with the new block
  985.    Next
  986.   EndIf
  987.  
  988.   clCurrByte=clCharBuff[clpCharBuff] ;Get a byte
  989.   clpCharBuff=clpCharBuff+1 ;Increment byte pointer
  990.   clBitsLeft=8 ;Set bits left in the byte
  991.   clBytesLeft=clBytesLeft-1 ;Decrement BytesLeft counter
  992.  
  993.  EndIf
  994.  
  995.  ;Shift off any previously used bits
  996.  ret=clCurrByte Shr (8-clBitsLeft)
  997.  
  998.  While clCurrCodeSize>clBitsLeft
  999.  
  1000.   If clBytesLeft<=0 ;Out of bytes in current block
  1001.    clpCharBuff=0 ;Set byte pointer
  1002.    clBytesLeft=ReadByte(file) ;Block size
  1003.    If clBytesLeft=0 Then Return -2 ;Found block terminator
  1004.    If Eof(file)<>0 Then Return -1 ;Stream error or end of file
  1005.    For count=0 To clBytesLeft-1
  1006.     char=ReadByte(file)
  1007.     clCharBuff[count]=char ;Fill CharBuff with current block
  1008.    Next
  1009.   EndIf
  1010.  
  1011.   clCurrByte=clCharBuff[clpCharBuff] ;Get a byte
  1012.   clpCharBuff=clpCharBuff+1 ;Increment byte pointer
  1013.   ret=ret Or (clCurrByte Shl clBitsLeft) ;Add remaining bits to ret
  1014.   clBitsLeft=clBitsLeft+8 ;Set bit counter
  1015.   clBytesLeft=clBytesLeft-1 ;Decrement BytesLeft counter
  1016.  
  1017.  Wend
  1018.  
  1019.  ;Subtract the code size from BitsLeft
  1020.  clBitsLeft=clBitsLeft-clCurrCodeSize
  1021.  ;Mask off the right number of bits
  1022.  ret=ret And clCodeMask[clCurrCodeSize]
  1023.  Return ret
  1024.  
  1025. End Function


Comments :


markcw(Posted 1+ years ago)

 GIFLoadImage takes 3 parameters. The first one is the filename, the next 2 are optional and allow you to load segments of an animated gif. If you don't specify the 2 extra parameters it will load all the frames.firstframe -> The frame to start drawing from, 1=first framenumframes -> The number of frames to draw, 0=all framesAlso shown in this example are the GIFDelayTimes, GIFFrames and GIFLoops functions.GIFDelayTimes returns a bank with the delay times for each frame stored as integers. The number of frames is at 0 and the delay time for frame 1 is at 1*4, etc. It has the same 2 optional parameters as GIFLoadImage.GIFFrames returns the number of frames in a gif. It also has the same 2 optional parameters as GIFLoadImage.GIFLoops returns the number of loops in a gif, 0=forever.This example plays a gif as it would appear in a browser.
Code: [Select]
;GIFLoadImage example

Include "gifload.bb" ;GIFLoad Module

Graphics 640,480,0,2
SetBuffer BackBuffer()

filename$="blitzlogo2i.gif"
filename$="arg-cannon-t.gif"
filename$="bridgerock.gif"
;filename$="an001.gif"
;filename$="avi250b.gif"

timetaken=MilliSecs()
image=GIFLoadImage(filename$)
bank=GIFDelayTimes(filename$) ;Delay times bank
frames=GIFFrames(filename$) ;Number of frames
loops=GIFLoops(filename$) ;Number of loops
timetaken=MilliSecs()-timetaken

timebegin=MilliSecs() ;Init timer

ClsColor 127,127,127 ;Grey background

While Not KeyHit(1)
 Cls

 timepast=MilliSecs() ;FPS timer
 If timepast-timebegin>PeekInt(bank,4+(framenum*4)) ;Delay time reached
  timebegin=timepast
  If loopnum<=loops Or loops=0 ;Last loop not reached
   framenum=framenum+1 ;Next frame
   If framenum>=frames Then framenum=0 : loopnum=loopnum+1 ;Next loop
  EndIf
 EndIf

 DrawImage image,MouseX(),MouseY(),framenum

 Text 0,0,"filename="+filename$
 Text 0,12,"filesize in Kb="+(FileSize(filename$)/1024.0)
 Text 0,24,"timetaken in seconds="+(timetaken/1000.0)
 Text 0,36,"image="+image+" frames="+frames+" loops="+loops
 Text 0,48,"framenum="+framenum+" loopnum="+loopnum

 Flip
Wend
End



DjBigWorm(Posted 1+ years ago)

 Oh Wow I have been hoping someone could take the time to add this,  Thank you so much you work is much appreciated thank you!!!  Works like a charm:)


markcw(Posted 1+ years ago)

 Hi DJBigWorm. Glad someone likes it. Here is an extension to the module for B3D only, GIFLoadTexture. You've to add it to the module yourself. This code is the function with a working example.
Code: [Select]
;GIFLoadTexture example for Blitz3D

Include "gifload.bb" ;GIFLoad Module

Graphics3D 640,480,0,2
SetBuffer BackBuffer()

camera=CreateCamera()
light=CreateLight()
plane=CreatePlane()
cube=CreateCube()
PositionEntity camera,0,2,0
RotateEntity light,90,0,0
EntityColor plane,127,127,127 ;Grey plane
PositionEntity cube,0,2,5

filename$="bridgerock.gif"
;filename$="an001.gif"
;filename$="arg-cannon-t0.gif"
;filename$="box-rotate.gif"
;filename$="avi250b.gif"

timetaken=MilliSecs()
texture=GIFLoadTexture(filename$,1)
bank=GIFDelayTimes(filename$) ;Delay times bank
frames=GIFFrames(filename$) ;Number of frames
loops=GIFLoops(filename$) ;Number of loops
timetaken=MilliSecs()-timetaken

timebegin=MilliSecs() ;Init timer

While Not KeyDown(1)
 RenderWorld

 timepast=MilliSecs() ;FPS timer
 If timepast-timebegin>PeekInt(bank,4+(framenum*4)) ;Delay time reached
  timebegin=timepast
  If loopnum<=loops Or loops=0 ;Last loop not reached
   framenum=framenum+1 ;Next frame
   If framenum>=frames Then framenum=0 : loopnum=loopnum+1 ;Next loop
  EndIf
 EndIf

 EntityTexture cube,texture,framenum
 TurnEntity cube,0.2,0.1,0.2

 Text 0,0,"filename="+filename$
 Text 0,12,"filesize in Kb="+(FileSize(filename$)/1024.0)
 Text 0,24,"timetaken in seconds="+(timetaken/1000.0)
 Text 0,36,"texture="+texture+" frames="+frames+" loops="+loops
 Text 0,48,"framenum="+framenum+" loopnum="+loopnum

 Flip
Wend
End

;Add the line below to "gifload.decls" add the function to "gifload.bb"

;GIFLoadTexture%(filename$,flags,firstframe,numframes)

Function GIFLoadTexture(filename$,flags=1,firstframe=1,numframes=0)
 ;Creates and returns a texture from a gif, top-level function
 ;flags -> The same as the flag parameter found in LoadTexture
 ;firstframe -> The frame to start drawing from, 1=first frame
 ;numframes -> The number of frames to draw, 0=all frames
 ;Uses GIFFrames, GIFWidth, GIFHeight and GIFLoad

 Local cl.GIFCLASS=New GIFCLASS ;Gif type
 Local frames,width,height,texture,graphic,buffer,dib,bpp,bits
 Local wWidth,wHeight,pitch,src,dest,ix,iy,offset,index,pixel
 Local blue,green,red,alpha,rgb

 ;Set some initial variables
 frames=GIFFrames(filename$) ;Number of frames
 If firstframe>0 Then firstframe=firstframe-1 Else firstframe=0
 If firstframe>frames-1 Then firstframe=frames-1 ;Limit firstframe
 If numframes<=0 Then numframes=frames-firstframe ;Limit numframes
 If numframes>frames-firstframe Then numframes=frames-firstframe
 frames=firstframe+numframes ;Limit number of frames
 width=GIFWidth(filename$) ;Screen width
 height=GIFHeight(filename$) ;Screen height
 texture=CreateTexture(width,height,flags,numframes)
 graphic=CreateTexture(width,height,flags,3) ;0=previous, 1=this, 2=empty

 ;Set alpha bytes to zero in empty graphic for transparency
 LockBuffer TextureBuffer(graphic,2)
 For iy=0 To height-1
  For ix=0 To width-1
   WritePixelFast ix,iy,0,TextureBuffer(graphic,2)
  Next
 Next
 UnlockBuffer TextureBuffer(graphic,2)

 For buffer=0 To frames-1 ;Loop through the frames

  dib=GIFLoad(filename$,cl) ;Load the next frame
  If dib=0 ;Avoid errors
   Delete cl ;Delete the class
   FreeTexture graphic ;Free the graphic
   Return texture ;Return the texture
  EndIf
  bpp=PeekShort(dib,14) ;biBitCount
  bits=40+(PeekInt(dib,32)*4) ;biSize+(biClrUsed*4)
  wWidth=PeekInt(dib,4) ;biWidth
  wHeight=PeekInt(dib,8) ;biHeight
  pitch=((wWidth*bpp+31)/32)*4 ;DWORD-aligned

  If buffer=0 And clDisposal=2 ;Restore to background, if first frame
   src=TextureBuffer(graphic,2) ;Copy empty graphic to this graphic
   dest=TextureBuffer(graphic,1)
   CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  ElseIf clDisposal=3 ;Restore to previous, store before drawing
   src=TextureBuffer(graphic,1) ;Copy this graphic to previous graphic
   dest=TextureBuffer(graphic,0)
   CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  EndIf

  ;Draw this graphic from the DIB
  LockBuffer TextureBuffer(graphic,1)
  For iy=0 To wHeight-1
   offset=bits+(pitch*(wHeight-1-iy)) ;Next scanline
   For ix=0 To wWidth-1
    If ix+clwLeft<width And iy+clwTop<height ;Pixel in bounds
     If bpp=1
      index=PeekByte(dib,offset+(ix Shr 3)) ;Get bit
      pixel=7-(ix Mod 8)
      index=(index And (1 Shl pixel)) Shr pixel
     ElseIf bpp=4
      index=PeekByte(dib,offset+(ix Shr 1)) ;Get nibble
      pixel=(1-(ix Mod 2)) Shl 2
      index=(index And (15 Shl pixel)) Shr pixel
     ElseIf bpp=8
      index=PeekByte(dib,offset+ix) ;Get byte
     EndIf
     If clisTransparent And clTransIndex=index ;Transparent pixel
     Else ;Normal pixel
      index=40+(index Shl 2) ;Get palette index
      blue=PeekByte(dib,index)
      green=PeekByte(dib,index+1)
      red=PeekByte(dib,index+2)
      If (flags And 2) Then alpha=(blue+green+red)/3 Else alpha=255
      rgb=blue Or (green Shl 8) Or (red Shl 16) Or (alpha Shl 24)
      WritePixelFast ix+clwLeft,iy+clwTop,rgb,TextureBuffer(graphic,1)
     EndIf
    EndIf
   Next
  Next
  UnlockBuffer TextureBuffer(graphic,1)
  FreeBank dib ;Free the DIB

  If buffer-firstframe>=0 ;If this frame is valid
   src=TextureBuffer(graphic,1) ;Copy this graphic to this frame
   dest=TextureBuffer(texture,buffer-firstframe)
   CopyRect 0,0,width,height,0,0,src,dest
  EndIf

  ;Decide how to dispose of this graphic
  If clDisposal<2 ;0=Not specified, 1=Do not dispose, both do nothing
  ElseIf clDisposal=2 ;Restore to background
   src=TextureBuffer(graphic,2) ;Copy empty graphic to this graphic
   dest=TextureBuffer(graphic,1)
   CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  ElseIf clDisposal=3 ;Restore to previous
   src=TextureBuffer(graphic,0) ;Copy previous graphic to this graphic
   dest=TextureBuffer(graphic,1)
   CopyRect clwLeft,clwTop,wWidth,wHeight,clwLeft,clwTop,src,dest
  EndIf

 Next

 Delete cl ;Delete the class
 FreeTexture graphic ;Free the graphic
 Return texture ;Return the texture

End Function



Snarkbait(Posted 1+ years ago)

 Do you know if there are still legal problems with using the GIF format in a commercial program? I know there used to be... Very good work, though, Mark!


xlsior(Posted 1+ years ago)

 Nope, the GIF patents expired in 2004.Unfortunately GIF also pretty much outlived its usefulness, being supplanted by JPG and PNG for the most part.


BlitzSupport(Posted 1+ years ago)

 Brilliant work! Seems to work on every animated GIF I've tried so far, but this file shows a bit of a problem with the background:<a href="../../www.hi-toro.com/images/bridgerock.html" target="_blank">Me flying under a bridge in BF1942![/url] [85K]IE6 and other viewers retain the background throughout, but the test program only seems to show the changes on each frame.Still, fantastic results on everything else -- this must have involved some serious hair-pulling!


markcw(Posted 1+ years ago)

 Hi BlitzSupport. Thanks for that example file, code fixed and updated. The reason it did that was because that gif was using transparency to not write over pixels from the first frame. My code was writing transparent pixels as black all the time which I see now was wrong, you just leave the pixel alone. Also, I fixed it to load gifs ok when the screen width/height is too small.I haven't tested 87a or restore to previous gifs as I couldn't find any.


markcw(Posted 1+ years ago)

 I found a few 87a gifs to test today and noticed a bug. I was treating the background color index as transparent but there is no transparency in 87a, the background color index is just the paper color, so I decided to just ignore the background color index, I've never seen it used anyway. I also fixed a minor memory leak I hadn't noticed in GIFLoad. Code updated.


BlitzSupport(Posted 1+ years ago)

 Only just checked this again -- thanks for the fix! It really is cool to have a native-Blitz GIF loader at last.


_33(Posted 1+ years ago)

 Fantastic code!!!  Thanks a million! [/i]

 

SimplePortal 2.3.6 © 2008-2014, SimplePortal