GIF-kuvan tallennin 1.5 (Animaatiotuella!)

Oletko tehnyt jotain, mistä muut voisivat hyötyä. Postita vinkit tänne.
User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

GIF-kuvan tallennin 1.5 (Animaatiotuella!)

Post by axu » Mon Mar 14, 2011 11:06 pm

Kyllä, luit otsikon oikein: Tässä on funktio, jolla voit tallentaa kuvan GIF-muotoon. Myös läpinäkyvyys ja animointi on tuettua. Tarvitset vain yhden funktion!
Alla olevassa esimerkkikoodissa ladataan "Note.bmp" ja tallennetaan se "TestiGIF.gif"-tiedostoon animaatioksi.

Code: Select all

img = LoadImage("Media/Note.bmp")
DrawImage img, 0, 0
Text 0, 40, "Press key to save this animation to TestiGIF.gif"
Text 0, 60, "Folder containing this file will then open."
Text 0, 280, "If you're coward, press ESC!"
DrawScreen
WaitKey
SaveGIF(img, "TestiGIF.gif", 255, 0, 255, 32, 32, 8, 20)
Execute "."


//SaveGIF(Img, Path$, [MaskRed, MaskGreen, MaskBlue, AnimWidth, AnimHeight, AnimFrames, AnimSpeed, Compression])
//Tallentaa kuvan GIF-muodossa.
//Img           - Kuvamuuttuja, joka tallennetaan
//Path          - Tiedostopolku
//Mask*****     - Läpinäkyvä väri. Jos ei ilmoitettu, ei käytetä läpinäkyvyyttä (ensimmäinen arvo -1)
//AnimWidth     - Animaatioframen leveys (jätä nollaksi jos et animoi)
//AnimHeight    - Animaatioframen korkeus (jätä nollaksi jos et animoi)
//AnimFrames    - Animaatioframejen määrä (still-kuva = 1)
//AnimSpeed     - Animaation päivitysnopeus. 1/100 sekunteja, pienempi nopeampi
//Compression   - Pakkauksen laatu. Arvo väliltä 1-4096, suurempi tehokkaampi (vie enemmän muistia, hyötyä vasta suurilla kuvilla)
Function SaveGIF(Img, Path$, MaskRed = -1, MaskGreen = 0, MaskBlue = 0, AnimWidth = 0, AnimHeight = 0, AnimFrames = 1, AnimSpeed = 0, Compression = 2048)
    AnimFrames = AnimFrames - 1
    Width = ImageWidth(Img)
    Height = ImageHeight(Img)
    If AnimWidth = 0 Then
        AnimWidth = Width
        AnimHeight = Height
    EndIf
    Fra_Size = AnimWidth * AnimHeight
    Img_Size = Width * Height
    Img_MEM = MakeMEMBlock(Img_Size)                //Tähän tallennetaan kuva pakkaamattomassa GIF-muodossa (jono viittauksia palettiin)
    Palette = MakeMEMBlock(8 * 3)
////////////PALETIN LUONTI (huom. olettaa, että kuva on max. 256-värinen)
    Lock Image(Img)
        Pixel = 0
        PaletteCount = 0
        If MaskRed > -1 Then                                    //Jos maskiväri on määritelty,
            PokeByte Palette, PaletteCount * 3, MaskRed         //asetetaan se paletin ensimmäiseksi.
            PokeByte Palette, PaletteCount * 3 + 1, MaskGreen
            PokeByte Palette, PaletteCount * 3 + 2, MaskBlue
            PaletteCount + 1
        EndIf
        For Frame = 0 To AnimFrames
            XStart = (Frame Mod (Width / AnimWidth)) * AnimWidth
            YStart = (Frame / (Width / AnimWidth)) * AnimHeight
            For y = YStart To YStart + AnimHeight - 1
                For x = XStart To XStart + AnimWidth - 1
                    PickImageColor2 Img, x, y
                    r = getRGB(RED) : g = getRGB(GREEN) : b = getRGB(BLUE)
                    
                    NewCol = True
                    For i = 0 To PaletteCount - 1               //Tutkitaan löytyykö väri paletista
                        If r = PeekByte(Palette, i * 3) And g = PeekByte(Palette, i * 3 + 1) And b = PeekByte(Palette, i * 3 + 2) Then
                            NewCol = False
                            
                            PokeByte Img_MEM, Pixel, i          //Tallennetaan indeksi muistipalaan
                            
                            Exit
                        EndIf
                    Next i
                    If NewCol = True And PaletteCount < 256 Then//Lisätään väri palettiin
                        If PaletteCount * 3 => MEMBlockSize(Palette) Then ResizeMEMBlock Palette, MEMBlockSize(Palette) * 2
                        PokeByte Palette, PaletteCount * 3, r
                        PokeByte Palette, PaletteCount * 3 + 1, g
                        PokeByte Palette, PaletteCount * 3 + 2, b
                        PokeByte Img_MEM, Pixel, PaletteCount
                        
                        PaletteCount + 1
                    End If
                    Pixel = Pixel + 1
                Next x
            Next y
        Next Frame
    Unlock Image(Img)
    For i = 2 To 8                                      //Optimoidaan paletin koko
        If PaletteCount <= 2^i Then PaletteSize = 2^i : PaletteBits = i : Exit
    Next i
    
    If FileExists(Path) Then DeleteFile Path
    f = OpenToEdit(Path)                                //Avataan muokattavaksi, jotta SeekFile toimii
////////////HEADER
        WriteByte f, 71                                 //G     Formaatti, täytyy olla GIF
        WriteByte f, 73                                 //I
        WriteByte f, 70                                 //F
        WriteByte f, 56                                 //8     Versio
        If MaskRed > -1 Or AnimFrames > 0 Then
            WriteByte f, 57                             //9     Tarvitaan uudempi 89a versio
        Else
            WriteByte f, 55                             //7     Suuremman yhteensopivuuden vuoksi käytetään 87a versiota (ei tarvetta 89a:lle)
        EndIf
        WriteByte f, 97                                 //a
        
////////////LOOGISEN KUVAN TIEDOT
        WriteShort f, AnimWidth                         //GIF-kuvan koko. Yhtä kuvaa tallennettaessa sama kuin kuvan koko
        WriteShort f, AnimHeight
        
        WriteByte f, 127 + PaletteBits                  //Bitteinä 1000 0XXX, luettuna oikealta vasemmalle:
                                                        //Ensimmäiset 3 (XXX): Paletin koko kahden potenssina (lukuun lisätään 1)
                                                        //Seuraava    1 (0)  : Onko paletti järjestetty tärkeysjärjestykseen; version ollessa 87a tämä on aina "0"
                                                        //Seuraavat   3 (000): Alkuperäisen paletin koko? dunno.
                                                        //Viimeinen   1 (1)  : Käytetäänkö globaalia palettia?
        WriteByte f, 0                                  //Taustavärin indeksi (jos koko loogista kuvaa ei täytetä)
        WriteByte f, 0                                  //Pikselin leveyden ja korkeuden suhde. "0" = Ei käytössä
        
////////////GLOBAALI PALETTI
        For i1 = 0 To PaletteSize - 1                   //Paletti, sarja tavuja "Punainen", "Vihreä", "Sininen", "Punainen" jne.
            For i2 = 0 To 2
                WriteByte f, PeekByte(Palette, i1 * 3 + i2) 'Palette(i1, i2)
            Next i2
        Next i1
        
////////////ANIMOINTI
        If AnimFrames > 0 Then
            WriteByte f, 33                             //Ilmoitetaan annettevaksi ylimääräisiä tietoja
            WriteByte f, 255                            //"Application Extension"
            WriteByte f, 11                             //Seuraavat 11 merkkiä:
            WriteByte f, 78                             //N
            WriteByte f, 69                             //E
            WriteByte f, 84                             //T
            WriteByte f, 83                             //S
            WriteByte f, 67                             //C
            WriteByte f, 65                             //A
            WriteByte f, 80                             //P
            WriteByte f, 69                             //E
            WriteByte f, 50                             //2
            WriteByte f, 46                             //.
            WriteByte f, 48                             //0
            
            WriteByte f, 3                              //Blockin koko
            WriteByte f, 1
            WriteShort f, 0                             //Kuinka monta kertaa animaatio toistetaan, 0 = loputon
            WriteByte f, 0
        EndIf
        For Frame = 0 To AnimFrames
        
////////////KUVAN LISÄTIEDOT (vain 89a, pitää tulla ennen itse kuvaa)
            If MaskRed > -1 Or AnimFrames > 0 Then
                WriteByte f, 33                             //Ilmoitetaan, että annetaan kuvalle ylimääräisiä tietoja
                WriteByte f, 249                            //"Graphic Control Extension"
                WriteByte f, 4                              //Palikan koko tavuina
                
                WriteByte f, 8 + (MaskRed > -1)             //Bitteinä 0000 0001, luettuna oikealta vasemmalle:
                                                            //Ensimmäinen 1 (1)  : Käytetäänkö läpinäkyvää väriä
                                                            //Seuraava    1 (0)  : Halutaanko ohjelman odottavan käyttäjän toimintaa?
                                                            //Seuraavat   3 (000): Mitä tapahtuu kuvan piirtämisen jälkeen: "000" = ei oteta kantaa, "001" = jätä kuva pyyhkimättä, "010" = tyhjennä taustavärillä, "011" = palauta edellinen kuva
                                                            //Viimeiset   3 (000): Ei käytössä
                WriteShort f, AnimSpeed                     //Animaation viivästysaika (2 tavua), 1/100 sekunteja
                
                WriteByte f, 0                              //Läpinäkyvän värin indeksi
                WriteByte f, 0                              //Lopetustavu
            EndIf
            
////////////KUVAN TIEDOT
            WriteByte f, 44                                 //Erotin, tästä eteenpäin itse kuvan tiedot:
            WriteShort f, 0                                 //Kuvan sijainti X (2 tavua)
            WriteShort f, 0                                 //Y (2 tavua)
            WriteShort f, AnimWidth                         //Leveys (2 tavua)
            WriteShort f, AnimHeight                        //Korkeus (2 tavua)
            
            WriteByte f, 0                                  //Bitteinä 0000 0000, luettuna oikealta vasemmalle:
                                                            //Ensimmäinen 1 (0)  : Käytetäänkö paikallista palettia?
                                                            //Toinen      1 (0)  : Onko kuva lomitettu?
                                                            //Kolmas      1 (0)  : Onko paikallinen paletti järjestetty tärkeysjärjestykseen; version ollessa 87a tämä on aina "0"
                                                            //Seuraavat   3 (000): Ei käytössä
                                                            //Viimeiset   3 (000): Paikallisen paletin koko.
            
////////////KUVA
            LZW_MEM = MakeMEMBlock((Compression * PaletteSize) * 2)   //Luodaan muistipala, jossa on varattu tilaa jokaisen koodin + merkin yhdistelmälle 2 tavua (Short)
            CurIndex = PaletteSize + 2                      //Indeksit ovat tästä ylöspäin (0-(PaletteSize-1) ovat paletin indeksejä, (PaletteSize) on tyhjennyskäsky ja (PaletteSize + 1) on EOF-merkki)
            CodeBits = PaletteBits + 1                      //Kuinka monta bittiä tulee koodia kohden aluksi
            
            Output = PaletteSize                            //Annetaan aluksi tyhjennyskäsky
            OutBits = CodeBits
            
            If Frame = 0 Then
                Pixel = 0                                   //Monesko pikseli on meneillään
            Else
                Pixel = Pixel + 1
            End If
            
            WriteByte f, CodeBits - 1                       //Kuinka monen bitin koodeilla aloitetaan.
            
            BlockSize = 0
            
            LastIndex = PeekByte(Img_MEM, Pixel)            //Luetaan ensimmäinen pikseli
            While Pixel < (Frame * Fra_Size) + Fra_Size - 1
                Pixel = Pixel + 1
                NextIndex = PeekByte(Img_MEM, Pixel)        //Luetaan seuraava pikseli
                
                Found = PeekShort(LZW_MEM, (LastIndex * PaletteSize + NextIndex) * 2)
                If Found > 0 Then                           //Jos uusi yhdistelmä löytyy, niin asetetaan se nykyisen tilalle
                    LastIndex = Found
                Else
                    Output = Output + LastIndex Shl OutBits //Lisätään aina uusi koodi vanhan päälle (vanhat bitit LSB, uudet MSB)
                    OutBits = OutBits + CodeBits            //Pidetään kirjaa siitä, kuinka monta bittiä on tallennettu Output-muuttujaan
                    While OutBits > 8                       //Löytyykö kokonaisia tavuja kirjoitettavaksi
                        If BlockSize = 0 Then
                            WriteByte f, 255                //Merkataan seuraavaksi kirjoitettavan palikan koko
                            BlockSize = 255
                        EndIf
                        WriteByte f, Output                 //Kirjoitetaan tavu (CB leikkaa automaattisesti ylimääräiset bitit pois, ts. Output Mod 256)
                        BlockSize = BlockSize - 1
                        Output = Output / 256               //Siirretään bitit alkuun (LSB:tä kohti, ts. Output Shr 8)
                        OutBits = OutBits - 8
                    Wend
                    
                    
                    If CurIndex < 4096 Then
                        If CurIndex < Compression Then
                            PokeShort LZW_MEM, (LastIndex * PaletteSize + NextIndex) * 2, CurIndex
                        EndIf
                        CurIndex = CurIndex + 1
                        If CurIndex > 2^CodeBits Then CodeBits = CodeBits + 1   //Jos tarvitaan lisää bittejä seuraavaa koodia varten, lisätään yksi bitti
                    EndIf
                                                            //Aloitetaan uusi jono
                    LastIndex = NextIndex
                EndIf
            Wend
            
            Output = Output + LastIndex Shl OutBits         //Merkataan viimeinenkin koodi
            OutBits = OutBits + CodeBits
            While OutBits > 0
                If BlockSize = 0 Then
                    WriteByte f, 255                        //Merkataan seuraavaksi kirjoitettavan palikan koko
                    BlockSize = 255
                EndIf
                WriteByte f, Output
                BlockSize = BlockSize - 1
                Output = Output Shr 8
                OutBits = OutBits - 8
            Wend
            
            SeekFile f, FileOffset(f) - (255 - BlockSize) - 1
            WriteByte f, 255 - BlockSize                    //Palataan ja merkataan viimeisen blockin oikea koko
            SeekFile f, FileOffset(f) + (255 - BlockSize)
            
            WriteByte f, 0                                  //Merkataan kuva päättyneeksi (nollan kokoinen blocki)
            DeleteMEMBlock LZW_MEM
        Next Frame
        
////////////LOPETUSMERKKI
        WriteByte f, 59                                 //Lopetusmerkki
    CloseFile f
    
    DeleteMEMBlock Img_MEM                              //Siivotaan jäljet
    DeleteMEMBlock Palette
End Function
Siistin vähän tätä viestiä ja siirsin "tilapäivitykset" alas:
Historia:
  • 14.3.2011: Eli siis, sain eilen nerokkaan idean kirjoittaa CB:lle gif-kuvien tallennusfunktion (nerokkaan ideasta tekee se, ettei CB pysty edes avaamaan .gif-tiedostoja :D ). Alku hyvin niin kuin aina, mutta homma jäi Lempel-Ziv-Welch-pakkausformaatin opiskeluun toistaiseksi :( En kuitenkaan tätä aivan hukkaan halua heittää, onhan tämä jopa hyvin kommentoitu pätkä. Ennen kuin löydän hyvää materiaalia LZW-formaatista, en tätä pysty jatkamaan (ehkä joku haluaa jatkaa siitä, mihin jäin?). Koodista puuttuu siis vain paletin luonti sekä itse kuvan pakkaaminen ja kirjoittaminen. Tietääkö joku muuten tuosta LZW-pakkauksen käytöstä, miten ne lisenssisotkut menevät? Ainakin käsittääkseni siinä oli jotain?
  • 15.3.2011: Eli nyt se osaa luoda paletin kuvasta ja yrittää tallentaa kuvan pakkaamattomana. Ei silti vielä toimiva GIF :(
  • 16.3.2011: Nyt alkaa toimia :) Mutta miksi vain reilu puolet kuvasta tulee näkyviin? Sen lisäksi tämä minun merkkijonopohjainen tallennussysteemi on luvattoman hidas.
    Nykyinen koodi tallentaa 2 kuvaa, TestiBMP.bmp ja TestiGIF.gif, voit vertailla niitä.
  • 17.3.2011: NYT TOIMII!
  • 18.3.2011: 1.0 julkaisu. Hurjasti nopeutettu koodi, käytän jotain hashtablen tyylistä vekotinta pakkauksessa, en tiedä miksi tuota kutsuisi, mutta sain kaikki merkkijonopohjaiset systeemit tuhottua koodista. Enään ei myöskään kuvaa tallenneta ensin muistipalaan (jossa oli mahdollisuus jopa kirjoittaa yli :O ), vaan pakattu data tallennetaan suoraan tiedostoon. Myös pakkauksen tason saa määrittää, tosin sillä ei enää ole nopeuteen vaikutusta, ainoastaan hetkelliseen muistin käyttöön. Pistin oletukseksi puoliväliin, joka riittää mainiosti pienille kuville ilman mitään vaikutusta. Pakkaaja on myös siinä mielessä fiksu, että se tunnistaa, jos kuvassa käytetään vähemmän värejä, ja tallentaa pienemmän paletin (esimerkkikoodissa tallentuu 128 kokoinen paletti 256:n sijaan).
  • 20.3.2011: 1.5 julkaisu. Pieniä optimointeja ja uusi ominaisuus: animaatiotuki! Testiohjelmaa yksinkertaistettu huomattavasti. Enään ei tarvitse paletin taulukkomäärittelyä alkuun, se toimii muistipalalla ;)
Last edited by axu on Thu Mar 15, 2012 10:48 am, edited 9 times in total.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin (epävalmis)

Post by MaGetzUb » Mon Mar 14, 2011 11:16 pm

Tässä sinulle .GIF loaderi. :)

Code: Select all

img = LoadGif("imgsmile.gif")
MaskImage img, 0, 0, 255
Repeat 

    DrawImage img, 200, 150

DrawScreen
Forever 



Function LoadGIF(gif$)
    anim = PlayAnimation(gif$)
    img = MakeImage(AnimationWidth(anim), AnimationHeight(anim))
    DrawToImage img
        DrawAnimation anim, 0, 0
    DrawToScreen 
    StopAnimation anim
    Return img
EndFunction 
Attachments
imgsmile.gif
Ja vielä .gif tiedostokin.
imgsmile.gif (1 KiB) Viewed 6270 times
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (epävalmis)

Post by axu » Tue Mar 15, 2011 11:00 am

Mielenkiintoista. Toimii se näköjään noinkin. :D
Tutkin tänään lisää tuota LZW-pakkausta ja näyttää paljon selvemmältä kuin eilen. Paletin luontiinkin minulla on idea, saa nähdä jos sen tänään kirjoittaisi kun kotiin pääsee.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
atomimalli
Moderator
Moderator
Posts: 227
Joined: Wed Aug 29, 2007 3:55 pm

Re: GIF-kuvan tallennin (epävalmis)

Post by atomimalli » Tue Mar 15, 2011 3:28 pm

Paletin generointi ei ole niin helppoa kuin miltä kuulostaa. Tapoja ja algoritmejä on hurjasti ja ditheröintitapojakin on useita. Ditheröinnistä tulee vaikeaa varsinkin jos paletti ei ole tasavälinen. Siitä ei kyllä tarvitse vielä alkuvaiheessa välittää mutta suosittelen riemersmaa, sillä siinä yhdistyy patterniditheröinnin ja virheensiirtditheröinnin edut. Esimerkiksi imagemagick käyttää sitä. Se sopii erityisesti animaatioihin, jos niin pitkälle aiot edetä.

Joku voisi tehdä gifinlataajan, joka hakee animaatiosta animaation framejen välisen ajan ja toistaa animaatiot oikein.

Arvostan tätä projektia, vaikken nyt erityistä tarvetta itse keksi. Jos animaatiotuen jaksat kyhätä, niin animaatioeditoreille ainakin tulee tarpeeseen!

Olen kuullut sellaisesta kikasta että täysivärikuvan voi giffinä tallentaa niin että tallentaa pienen osan kuvista eri animaation frameihin ja käyttää yhtä väriä maskivärinä tai jotain tämän kaltaista. En ole varma että onko sille virallista tukea.

Kannattaa myös tukea websafe-palettia historiallisista syistä :p siitä aloittamalla säästyy paletin valinnan miettimiseltä!

User avatar
legend
Advanced Member
Posts: 371
Joined: Wed Nov 18, 2009 9:06 pm

Re: GIF-kuvan tallennin (epävalmis)

Post by legend » Tue Mar 15, 2011 5:32 pm

Aika hienoa, jos saadaan gif kuvan tallenin coolbasicille. Mutta ihmettelen vaan, miksi et yritä tehdä samaa jpg:lle? Eikö se ole helpompaa?
EDIT:

Btw. On muuten kätevä toi valittava ominaisuus foorumilla, että uusimmat viestit tulee ylös, eikä perinteisesti alas... Säästyy paljon aikaa!


User avatar
atomimalli
Moderator
Moderator
Posts: 227
Joined: Wed Aug 29, 2007 3:55 pm

Re: GIF-kuvan tallennin (epävalmis)

Post by atomimalli » Tue Mar 15, 2011 7:27 pm

En nyt sanoisi jpgtä helpommaksi. Värijärjestelmät, taajuuskoodaukset ja pakkaus vaativat paljon työtä ja tutustumista erilaisiin algoritmeihin. Lisäksi jpegessä on hyvin paljon erilaisia versioita ja toteutustapoja, tulee valinnanvaikeus ja tutustuttavaa on entistä enempi.

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (epävalmis)

Post by axu » Wed Mar 16, 2011 11:39 am

Teinpäs eilen yksinkertaisen paletin luonnin. Se tosin ei osaa käsitellä kuvia joissa on enemmän kuin 256 väriä, mutta riittänee ensimmäiseksi versioksi. Toimintaperiaate on yksinkertainen: käydään läpi kuvan jokainen pikseli, ja tutkitaan löytyykö kyseistä väriä paletista. Jos löytyy, jatketaan eteenpäin. Jos ei, lisätään uusi väri palettiin jos siinä on tilaa.
Sitten aloin miettiä hieman optimointia ja päädyin siihen, että paletti olisi hyvä järjestää tärkeysjärjestyksen mukaan, että kuvaa lukiessa eniten käytetyt värit löytyvät vähemmällä taulukon läpikäymisellä. Lisäsin paletin luontiin pätkän, joka lisää värin "arvoa" joka kerta, kun samaa väriä löytyy. Tämän jälkeen tutustuin CombSort11-algoritmin toimintaan. Sen lätkäiseminen koodiin toimi yllättävänkin helposti. Tämän jälkeen huomasin, että minähän voin tallettaa kuvan jo etukäteen muistipalaan, jolloin kuvan toista läpikäyntiä ei tarvita. Näin korvasin melkein 30 riviä koodia 3 rivillä, ja tehokkuus paranee isoilla kuvilla melkein kaksinkertaisesti! Laitan tähän nyt kuitenkin tuon combsortin koodin jos joku haluaa sitä tutkia:

Code: Select all

//PALETIN JÄRJESTÄMINEN (käyttää CombSort11 -algoritmia)
Gap = PaletteCount                          //Käydään läpi vain paletin luotu osa
Repeat
    Gap = RoundDown(Gap / 1.247)
    If Gap = 9 Or Gap = 10 Then Gap = 11    //CombSort11
    Gap = Max(1, Gap)                       //Minimiaskel on 1
    
    Switched = False                        //Siirtoja ei vielä tapahtunut tällä kierroksella
    For i = 0 To PaletteCount - 1 - Gap
        If (Palette(i, 0) < Palette(i + Gap, 0)) Then
            For i2 = 0 To 3                 //Vaihdetaan kohteiden arvoja
                tmp = Palette(i, i2)
                Palette(i, i2) = Palette(i + Gap, i2)
                Palette(i + Gap, i2) = tmp
            Next i2
            
            Switched = True                 //Merkataan tarkistus vielä keskeneräiseksi
        EndIf
    Next i
Until Gap = 1 And Switched = False          //Lopetetaan, kun siirtoja ei enään tehdä
Ikävä kyllä en vieläkään ole onnistunut LZW:tä ujuttamaan tuohon koodiin. Itse algoritmin nyt osaan, mutta en löydä mistään tarkkaa tietoa siitä, miten sitä käytetään GIF-kuvassa. Ainoa tietoni on, että kuva jaetaan "blockeihin", joiden maksimikoko on 255. Kuva tallennetaan niin, että ensin tulee tavu, jossa on sitä seuraavan blockin koko, ja tämän jälkeen tulee sen sisältö LZW-muodossa. Viimeisen blockin jälkeen tulee tavu 0, joka merkkaa kuvatiedon päättyneeksi. Ongelmat: en tiedä, viitataanko blockin koolla sen pakkaamattomaan vai pakattuun kokoon. Enkä tiedä, kuinka isoa kirjastoa pakkauksessa käytetään (eli kuinka monta bittiä kutakin merkkiä kohden varataan), tai nollataanko kirjasto joka blockin välissä. Voin vain toivoa, ettei bittejä merkkiä kohden ole 9 tai muuta epäkahdeksalla jaollista lukua, kas kun CB:llä bittien käsittely pitää tapahtua aina tavujen kautta (joten pitää laatia pieniä kiertoreittejä näiden tallentamiseksi).
Päivitän nyt kuitenkin tuon paletin luonnin koodin ekaan viestiin.
EDIT:

Niin tosiaan, tuossa combsortissa järjestetään tuo paletti suurimmasta pienimpään. Värin "arvo" on tallennettu Palette(indeksi, 0) ja itse väri Palette(indeksi, {1, 2 tai 3}).
Tein muuten pikaisen vertailun, ja vaikka en pakkaisi ollenkaan tuota kuvaa LZW-tekniikalla, testikuvan koko oli silti BMP:hen verrattuna kolmasosa (tallennetaan vain yksi tavu pikseliä kohden kolmen sijasta). ;)

EDIT2:
YAY! Lisäsin yhden puuttuneen tavun tuonne ja nyt se on ainakin validi GIF-kuva! Minulta puuttui sieltä tavu, joka sisältää tiedon juuri tästä kirjaston koosta, en tiedä kuinka olin jättänyt tuon pienen kohdan lukematta :D Seuraavan vian kimppuun: miksi kuva on valkoinen? Paletti kuitenkin tallentui korrektisti (tarkistin Paint Shop Pro:lla), mutta koko kuva on valkoinen (eli viittaavat paletin indeksiin 0).
Vastoinkäymiset kuitenkin jatkuvat: toistaiseksi paras tietolähteeni fileformat.info on saavuttamattomissa... mutta löysin compuserven oman dokumentaation GIF:stä, joten eiköhän kohta synny tuloksia.

EDIT3:
Aijaijaijaijai... Jo on kierosti laadittu tuo LZW-variantti GIF:iä varten: Yhden merkin pituus vaihtelee sen mukaan, kuinka pitkällä ollaan. Eli aluksi se on 9 bittiä, sitten 10, seuraavaksi 11 ja lopulta 12. Nyt pitää alkaa miettimään, miten tämä kannattaisi cb:llä tehdä.
Hyviin uutisiin: Tein tuen läpinäkyvyydelle. Enkooderi osaa myös automaattisesti tallentaa kuvan uuteen ( :D ) 89a-versioon, tai jos ei ole tarvetta, vanhaan 87a-versioon suuremman yhteensopivuuden vuoksi. En tiedä kyllä onko tuota vanhaa versiota käyttäviä ohjelmia enää olemassakaan, mutta eihän sitä koskaan tiedä. 89a julkaistiin 1990.

Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin (lähempänä valmista kuin viimeksi)

Post by MaGetzUb » Wed Mar 16, 2011 5:00 pm

PNG:n tallennusjärjestelmästä olisi enemmän hyötyä. :) Sen uskoisin olevan iisimpi kuin .jpg:n. :P Btw, projektina .gif järjestelmä on mielenkiintoinen. :D
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (lähempänä valmista kuin viimeksi)

Post by axu » Wed Mar 16, 2011 5:31 pm

Muuten olisin ehkä sen PNG:n tehnyt, mutta nopealla silmäyksellä se oli vaikeampi. Sen lisäksi ei pidä sivuuttaa sitä faktaa, että GIF:ssä on animaatiotuki. Sitten kun perustallennin on tehty, animaation lisäys on pieni homma.
Itse projektin edistymisestä: kaikki muu valmista, paitsi sen tiedon tallentaminen. Jopa pakkaaja on valmis.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin (lähempänä valmista kuin viimeksi)

Post by MaGetzUb » Thu Mar 17, 2011 3:40 am

axu wrote:Muuten olisin ehkä sen PNG:n tehnyt, mutta nopealla silmäyksellä se oli vaikeampi. Sen lisäksi ei pidä sivuuttaa sitä faktaa, että GIF:ssä on animaatiotuki.
Tjaa... mikäs sitten tämä: http://people.mozilla.com/~dolske/apng/ ... evious.png on?
Eli siis; kyllä PNG formaatti sisältää myös animaatiotuen.
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (lähempänä valmista kuin viimeksi)

Post by axu » Thu Mar 17, 2011 9:39 am

MaGetzUb wrote:Eli siis; kyllä PNG formaatti sisältää myös animaatiotuen.
Mutta tukeeko APNG:tä yhtä useat ohjelmat? En ole ainakaan törmännyt aiemmin animoituihin PNG-kuviin, vaikka olen niistä lukenut.
Seuraavaksi aion alkaa optimoimaan tätä, vaihdan merkkijonopohjaisen pakkaussysteemin muistipaloilla toimivaan. Sitten varmaan järjestyksessä animaatiotuki, enemmän kuin 256 väriä sisältävien kuvien tallennus (käyttäen atomin mainitsemaa menetelmää), ditheröinti.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
legend
Advanced Member
Posts: 371
Joined: Wed Nov 18, 2009 9:06 pm

Re: GIF-kuvan tallennin (TOIMIIII!)

Post by legend » Thu Mar 17, 2011 8:08 pm

Nyt vaan kysymään? saako tätä käyttää vapaasti projekteissa??

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (TOIMIIII!)

Post by axu » Thu Mar 17, 2011 11:34 pm

Ainiin, unohdin kertoa. Esimerkit ja tutoriaalit-alueella löytyvää materiaalia saa yleensä vapaasti käyttää, ja niin on tässäkin tapauksessa. Arvostan suuresti, jos kuitenkin nimeni mainitaan. Jos joku muokkaa tätä koodia, siitä olisi myös hyvä ilmoittaa minulle, lähinnä kehitystä ajatellen.
Vielä tuosta APNG:stä: se ei ole virallisesti hyväksytty PNG-standardiin, ja tuki on melko laihaa muutenkin.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin (TOIMIIII!)

Post by MaGetzUb » Fri Mar 18, 2011 2:46 am

axu wrote:Ainiin, unohdin kertoa. Esimerkit ja tutoriaalit-alueella löytyvää materiaalia saa yleensä vapaasti käyttää, ja niin on tässäkin tapauksessa. Arvostan suuresti, jos kuitenkin nimeni mainitaan. Jos joku muokkaa tätä koodia, siitä olisi myös hyvä ilmoittaa minulle, lähinnä kehitystä ajatellen.
Vielä tuosta APNG:stä: se ei ole virallisesti hyväksytty PNG-standardiin, ja tuki on melko laihaa muutenkin.
Kännykkäselaimeni ainakin tukee sitä. :P Mutta niin itse en oikein pidä gif formaatista koska laatu vaihtelee välillä niin paljon...
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin (TOIMIIII!)

Post by axu » Fri Mar 18, 2011 10:34 am

MaGetzUb wrote:Kännykkäselaimeni ainakin tukee sitä. :P Mutta niin itse en oikein pidä gif formaatista koska laatu vaihtelee välillä niin paljon...
Millä lailla laatu vaihtelee? Jos tarkoitat väripaletin rajoitusta, siihen on kiertokeinonsa. Jos pakkauksen tehokkuutta, useimmiten se voittaa PNG:n. Täytyy kyllä tunnustaa, että itse en pidä GIF:stä, vaan käytän aina PNG:tä.

Optimoinnissa tuli pieni mutka matkaan. Tein muistipaloilla toimivan systeemin, mutta se osoittautuikin hitaammaksi kuin merkkijonoihin perustunut. Vika on ilmeisesti luvun muuttamisessa binäärimuotoon, se on n. 4 kertaa raskaampi prosessi ilman Bin() käskyä. Kehittelen jo ideaa, jolla voi kiertää kokonaan tämän ongelman laskemalla suoraan, mitä tavuja pitää tallentaa. Sen lisäksi sulautan tuon tallennusosion tuohon pakkaukseen suoraan, joka säästää muistia ja nopeuttaa tallennusta.
EDIT:

Suurin aikasyöppö olikin itse pakkaus. Mitä pitemmälle edettiin, sitä enemmän koodeja piti läpikäydä. Siitä ei ole enään haittaa, kun vaihdoin sen hashtablen tyyppiseen vekottimeen. En tiedä onko se ihan se kun varsinaista hashausta ei tehdä, mutta tiedot haetaan taulukosta (lue = muistipalasta) sen arvon perusteella. Samalla julkistan ensimmäisen "virallisen" version.
Hymiön paikka :mrgreen:

Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin 1.0

Post by MaGetzUb » Sat Mar 19, 2011 3:14 am

Huomasin muuten tämän koodinpätkän:

Code: Select all

////////////HEADER
        WriteByte f, 71                                 //G     Formaatti, täytyy olla GIF
        WriteByte f, 73                                 //I
        WriteByte f, 70                                 //F
        WriteByte f, 56                                 //8     Versio
Eikö WriteString olisi hoitanut samaa asiaa? WriteString f, "GIF8" :)
offtopic 1.3k viesti! Lol mikä trölli oon.
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
Ilmuri
Developer
Developer
Posts: 277
Joined: Sun Aug 26, 2007 2:46 pm
Location: \o

Re: GIF-kuvan tallennin 1.0

Post by Ilmuri » Sat Mar 19, 2011 5:09 am

MaGetzUb wrote: Eikö WriteString olisi hoitanut samaa asiaa? WriteString f, "GIF8" :)
WriteString kirjoittaa tiedostoon myös merkkijonon pituuden, joka vie 4 tavua.
CoolBasic henkilökuntaa
Kehittäjä
CoolBasic Classic

User avatar
axu
Devoted Member
Posts: 854
Joined: Tue Sep 18, 2007 6:50 pm

Re: GIF-kuvan tallennin 1.5 (Animaatio)

Post by axu » Sun Mar 20, 2011 8:21 pm

Kauan(?) odotettu uusi ominaisuus: ANIMAATIO! Animaation tallentaminen on helppoa kuin perunan keitto: kerrot tallentajalle vain framen koko ja niiden määrä, sekä animaation nopeus. Nopeudet eivät ole samoja, jotka ilmoitat PlayObjectille, vaan odotettava tauko kahden framen välillä sadasosasekunteina. Yritän tässä selvittää, miten nämä kääntyisi keskenään (varmaan jotain tyyliin 0.1 / Toistonopeus_cbllä).
Tässäpä hienohko animaatio, jonka otin nyt avatariksenikin :)

Code: Select all

img = MakeImage(1000, 100)
DrawToImage img
    Color 32, 32, 32
    For i = 0 To 9
        Offset = 50 + i * 100
        
        For b = -9 To 9 Step 2 
            g = 255 - Abs(b) * 3
            Color g, g, g
            Box Offset + b * 5 - 5, 40, 20, 60
        Next b
        
        Color 32, 32, 32
        For s = 1 To 36
            r1 = 22 + (s Mod 2) * 5
            a1 = s * 10 + i * 2
            r2 = 22 + ((s-1) Mod 2) * 5
            a2 = (s-1) * 10 + i * 2
            Line Offset + Cos(a1) * r1, 70 + Sin(a1) * r1, Offset + Cos(a2) * r1, 70 + Sin(a2) * r1
            Line Offset + Cos(a2) * r1, 70 + Sin(a2) * r1, Offset + Cos(a2) * r2, 70 + Sin(a2) * r2
        Next s
        
        Line Offset - 50, 40, Offset + 49, 40
        Line Offset - 50, 99, Offset + 49, 99
        For b = -6 To 6
            X = b * 10 + i
            W = 5
            If X < -50 Then W = Max(0, 5 - (-50 - X))
            If X > 45 Then W = Max(0, 5 - (X - 45))
            X = Max(-50, Min(50, X))
            Box Offset + X, 40, W, 5
            
            X = b * 10 - i + 5
            W = 5
            If X < -50 Then W = Max(0, 5 - (-50 - X))
            If X > 45 Then W = Max(0, 5 - (X - 45))
            X = Max(-50, Min(50, X))
            Box Offset + X, 95, W, 5
        Next b
        
        Color 128, 128, 255
        CenterText Offset, -8 - Max(1, Min(4, Abs(i - 4))), "CB-powered", 2
        CenterText Offset, -22 - Max(1, Min(4, Abs(i - 4))), "ANIMATION", 2
        g = 50 - Abs(i - 4) * 10
        Color g + 100, g, g
        CenterText Offset + 1, -70, "AXU", 2
        CenterText Offset, -70, "AXU", 2
    Next i
DrawToScreen
DrawImage img, 0, 0
Color 255, 255, 255
Text 0, 100, "Press any key to save this to TestiGIF.gif."
Text 0, 120, "Or you can always press ESC if you're coward."
DrawScreen
WaitKey
SaveGIF(img, "TestiGIF.gif", -1, 0, 0, 100, 100, 10, 5)
Liitä tuon perään se funktio, joka löytyy ekasta koodista.
Jos tämä viesti on kirjoitettu alle 5 min. sitten, päivitä sivu. Se on saattanut jo muuttua :roll:
Image

User avatar
MaGetzUb
Guru
Posts: 1715
Joined: Sun Sep 09, 2007 12:35 pm
Location: Alavus

Re: GIF-kuvan tallennin 1.5 (Animaatio)

Post by MaGetzUb » Mon Mar 21, 2011 12:25 am

Aika hyvää jälkeä. :) Nyt vain tekemään Gifanimaattoria! :D
Solar Eclipse
Meneillä olevat Projektit:
We're in a simulation, and God is trying to debug us.

User avatar
CCE
Artist
Artist
Posts: 650
Joined: Mon Aug 27, 2007 9:53 pm

Re: GIF-kuvan tallennin 1.5 (Animaatio)

Post by CCE » Fri Mar 25, 2011 12:37 am

Tämähän on erinomaisen hauska lelu! Tein sillä yhden pienen efektinkin, sääli että selaimet taitavat olla aika hitaita näyttämään gif -animaatioita.

Image

Tässä vielä efektin lähdekoodi (tarvitsee savegif.cb tiedoston)

Code: Select all

Include "savegif.CB"

    img = MakeImage(1600, 100)
    DrawToImage img
        Color 32, 32, 32
        For i = 0 To 15
           For y=0 To 100
           For x=0 To 100
                b1x# = 42.0 + Cos((i*22.5)*2)*1
                b1y# = 40.0 + Sin(i*22.5)*2 + Sin(y*7+i*22.5)*Sin(x*8+i*22.5)*5

                dist# = 1000.0 / Max(0,( Distance(b1x, b1y, x, y) -(y*0.3+Sin(i*22.5)*2)))
                c# = Max(0,Min(255,d+dist))

                Color c,c,c
                Dot i*100+x,y
           Next x
           Next y
        Next i
    DrawToScreen
    
    Repeat
    Color 255, 255, 255
    Text 0, 100, "Press any key to save this to TestiGIF.gif."
    Text 0, 120, "Or you can always press ESC if you're coward."
     DrawImageBox img, 0, 0, i*100,0,100,100
     i + 1
     If i > 15 Then i = 0
   Wait 20
    DrawScreen
    Until GetKey() 
    SaveGIF(img, "TestiGIF.gif", 255, 0, 255, 100, 100, 16, 5)

Post Reply