GIF Encoder (uncompressed)

Just starting out? Need help? Post your questions and find answers here.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

GIF Encoder (uncompressed)

Post by Mijikai »

Does anyone know how to create an animated GIF with only the global 256 color palette and without compression?
The GIF header/struct gives me a headace... :?

About the file format:
https://en.wikipedia.org/wiki/GIF
User avatar
idle
Always Here
Always Here
Posts: 5040
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: GIF Encoder (uncompressed)

Post by idle »

There are a couple of tools around to work with GIF
one from wilbert
viewtopic.php?t=66497
and netmaestro's gif workshop
viewtopic.php?t=57410
not sure if that's the right version though
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: GIF Encoder (uncompressed)

Post by Mijikai »

Thanks :)

I still dont understand how to disable the compression.
Specification: https://www.w3.org/Graphics/GIF/spec-gif89a.txt

Here is my code so far:

Code: Select all

EnableExplicit

Structure GIF_RGBA_STRUCT
  rgba.a[4]
EndStructure

Structure GIF_RGB_STRUCT
  rgb.a[3]
EndStructure

Structure GIF_PALETTE_STRUCT
  color.GIF_RGBA_STRUCT[256]
EndStructure

Structure GIF_IMAGE_STRUCT
  seperator.a
  left.u
  top.u
  width.u
  height.u
  packed.a
EndStructure

Structure GIF_CONTROL_STRUCT
  introducer.a
  label.a
  blocksize.a
  packed.a
  delay.u
  transparent.a
EndStructure

Structure GIF_NETSCAPE_STRUCT
  initiator.a
  label.a
  blocksize.a
  name.a[11]
  subblocksize.a
  packed.a
  loopcount.u
  blockend.a
EndStructure

Structure GIF_HEADER_STRUCT
  signature.a[3]
  version.a[3]
  width.u
  height.u
  packed.a
  background.a
  apspect.a
  color.GIF_RGB_STRUCT[256]
  netscape.GIF_NETSCAPE_STRUCT
EndStructure

Structure GIF_STRUCT
  *vtable
  file.s
  handle.i
  framesize.i
  framedecoder.i
  frameblock.i
  frameloop.i
  header.GIF_HEADER_STRUCT
  control.GIF_CONTROL_STRUCT;graphic control extention
  image.GIF_IMAGE_STRUCT;image descriptor
EndStructure

Procedure.i GifRecordOpen(*Palette.GIF_PALETTE_STRUCT,Bits.i,Width.i,Height.i,Delay.i,File.s)
  Protected *gif.GIF_STRUCT
  Protected index.i
  With *gif
    If *Palette And Width > 0 And (Width % 2) = 0 And Height > 0 And (Height % 2) = 0 And File
      *gif = AllocateStructure(GIF_STRUCT) 
      If *gif
        \file = File
        \handle = CreateFile(#PB_Any,File)
        If \handle
          \framesize = Width * Height
          \framedecoder = ?gif_terminator - ?gif_table
          For index = 256 To 2 Step - 2;<- calculate block size
            If (\framesize % index) = 0
              \frameblock = index
              Break
            EndIf
          Next
          \frameloop = (\framesize / \frameblock) - 1
          CopyMemory(?gif_header,@\header,SizeOf(GIF_HEADER_STRUCT))
          If Bits = 32
            For index = 0 To 256
              \header\color[index]\rgb[0] = *Palette\color[index]\rgba[0]
              \header\color[index]\rgb[1] = *Palette\color[index]\rgba[1]
              \header\color[index]\rgb[2] = *Palette\color[index]\rgba[2]
            Next
          Else
            CopyMemory(*Palette,@\header\color,768)
          EndIf
          CopyMemory(?gif_control,@\control,SizeOf(GIF_CONTROL_STRUCT))
          CopyMemory(?gif_image,@\image,SizeOf(GIF_IMAGE_STRUCT))
          \header\width = Width
          \header\height = Height
          \control\delay = Delay
          \image\width = Width
          \image\height = Height
          If WriteData(\handle,@\header,SizeOf(GIF_HEADER_STRUCT)) = SizeOf(GIF_HEADER_STRUCT);<- when do i write this stuff
            If WriteData(\handle,@\control,SizeOf(GIF_CONTROL_STRUCT)) = SizeOf(GIF_CONTROL_STRUCT)
              ProcedureReturn *gif
            EndIf
          EndIf
          CloseFile(\handle)
          DeleteFile(\file)
        EndIf
        FreeStructure(*gif)
      EndIf
    EndIf
    ProcedureReturn #Null
  EndWith
EndProcedure

Procedure.i GifRecordFrame(*gif.GIF_STRUCT,*Frame)
  Protected index.i
  Protected count.i
  With *gif
    If *Frame
      If WriteData(\handle,@\image,SizeOf(GIF_IMAGE_STRUCT)) = SizeOf(GIF_IMAGE_STRUCT)
        If WriteData(\handle,?gif_table,\framedecoder) = \framedecoder 
          For index = 0 To \frameloop
            If WriteByte(\handle,\frameblock)
              count + Bool(WriteData(\handle,*Frame,\frameblock) = \frameblock)
            EndIf
            *Frame + \frameblock
          Next
          If WriteByte(\handle,$0) And (count - 1) = \frameloop
            ProcedureReturn #True
          EndIf
        EndIf
      EndIf
    EndIf
    ProcedureReturn #False
  EndWith
EndProcedure

Procedure.i GifRecordClose(*gif.GIF_STRUCT,Delete.i)
  Protected result.i
  With *gif
    result = Bool(WriteByte(\handle,$3B) <> #Null)
    CloseFile(\handle)
    If Delete Or result = #Null
      DeleteFile(\file)
    EndIf
    FreeStructure(*gif)
    ProcedureReturn result
  EndWith
EndProcedure

Procedure.i PaletteColor(*Palette,Index.i,Color.i)
  CopyMemory(@Color,*Palette + (Index * 3),3)
  ProcedureReturn #Null
EndProcedure

Procedure.i Main()
  Protected *palette
  Protected gif.i
  *palette = AllocateMemory(768)
  If *palette
    RandomData(*palette,768)
    gif = GifRecordOpen(*palette,24,8,8,4,"dummy.gif")
    If gif
      GifRecordFrame(gif,?dummy1)
      GifRecordFrame(gif,?dummy2)
      GifRecordClose(gif,#False)
    EndIf
    FreeMemory(*palette)
  EndIf
  ProcedureReturn #Null
EndProcedure

Main()

End

DataSection
  
  dummy1:
  Data.a 0,0,1,1,1,1,0,0
  Data.a 0,1,0,0,0,0,1,0
  Data.a 1,0,0,0,0,0,0,1
  Data.a 1,0,1,0,0,1,0,1
  Data.a 1,0,0,0,0,0,0,1
  Data.a 1,0,0,1,1,0,0,1
  Data.a 0,1,0,0,0,0,1,0
  Data.a 0,0,1,1,1,1,0,0
  dummy2:
  Data.a 0,0,2,2,2,2,0,0
  Data.a 0,2,0,0,0,0,2,0
  Data.a 2,0,0,0,0,0,0,2
  Data.a 2,0,2,0,0,2,0,2
  Data.a 2,0,0,0,0,0,0,2
  Data.a 2,0,0,2,2,0,0,2
  Data.a 0,2,0,0,0,0,2,0
  Data.a 0,0,2,2,2,2,0,0
  
  _vtablegif:
  ;//
  gif_header:
  Data.a 'G','I','F'
  Data.a '8','9','a'
  Data.u $0000;width
  Data.u $0000;height
  Data.a %11110111
  Data.a $00
  Data.a $00
  gif_netscape:
  Data.a $21
  Data.a $FF
  Data.a $0B
  Data.a 'N','E','T','S','C','A','P','E','2','.','0'
  Data.a $03
  Data.a $00
  Data.u $FFFF
  Data.a $00
  gif_control:
  Data.a $21
  Data.a $F9
  Data.a $04
  Data.a %00000000
  Data.u $0000
  Data.a $00
  gif_image:
  Data.a $2C
  Data.u $0000;left
  Data.u $0000;right
  Data.u $0000;width
  Data.u $0000;height
  Data.a %00000000
  gif_table:;<- HOW DOES THIS THING WORK -___________________-
  Data.u $100
  Data.a $28,$FF,$FF,$FF,$28,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
;   Data.a 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
;   Data.a 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
;   Data.a 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
;   Data.a 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
;   Data.a 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79
;   Data.a 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95
;   Data.a 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111
;   Data.a 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127
;   Data.a 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143
;   Data.a 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159
;   Data.a 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175
;   Data.a 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
;   Data.a 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
;   Data.a 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
;   Data.a 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
;   Data.a 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  Data.u $101
  gif_terminator:
  Data.a $3B
  gif_eod:
EndDataSection

wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: GIF Encoder (uncompressed)

Post by wilbert »

Mijikai wrote: Sun Aug 07, 2022 8:01 pm I still dont understand how to disable the compression.
There's not a simple option to disable it.
It seems you have to regularly emit CLEAR codes to make this happen.
https://en.wikipedia.org/wiki/GIF#Uncompressed_GIF

Is there any reason why you want to do this ?
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: GIF Encoder (uncompressed)

Post by netmaestro »

It would break my head if I tried to get into that again. Hard to believe that's nine years ago! Anyway you're welcome to any part of the work I did on it. It's here: viewtopic.php?f=12&t=57656
BERESHEIT
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: GIF Encoder (uncompressed)

Post by Mijikai »

@wilbert
I want to record gameplay as animated gif.
The gfx lib/game im working on has a 256 color palette and the framebuffer is just an index table into the palette.
A gif seemed nice as it features a global 256 color palette. :idea:
For assumed speed reasons and the complex compression algo. i thought about omitting the compression. :oops:

@netmaestro
Thank you for the link i will check it out :)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: GIF Encoder (uncompressed)

Post by wilbert »

Mijikai wrote: Mon Aug 08, 2022 8:58 am I want to record gameplay as animated gif.
The gfx lib/game im working on has a 256 color palette and the framebuffer is just an index table into the palette.
A gif seemed nice as it features a global 256 color palette. :idea:
For assumed speed reasons and the complex compression algo. i thought about omitting the compression. :oops:
If you are working with 256 colors, you still need the additional CLEAR and STOP codes.
So instead of 8 bits per pixel you need 9 bits per pixel and on a regular interval an additional CLEAR tag.
Because of the 9 bits per pixel you still need to shift bits to compute the bytes you need to write.
For a screen resolution of 1920 x 1080 this means about 2.2 MiB per frame.
I estimate that with additional codes to define the frames, if the game is 1920 x 1080 pixels and plays at 60 FPS, it will output about 135 MiB per second.
For a minute of gameplay that would be almost 8 GiB. The question would be if that is acceptable.
If it is retro gaming like 640 x 480 pixels and 30 fps it would be a lot smaller of course.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8425
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: GIF Encoder (uncompressed)

Post by netmaestro »

It's really a question of trying to put new wine in an old wineskin.
BERESHEIT
Post Reply