Noh, paljonko tämä systeemi sitten pakkaa niitä kuvia? Viisi prosenttia? Kymmenen prosenttia? Noh, sekin riippuu tietysti sisällöstä, mutta jos kuvassa on about 50% tasaisia alueita (esimerkiksi puhdasta mustaa), niin tiedoston koostakin säästyy noin 50%. Jos kuvan joka ikinen pikseli on erivärinen, kuva vain suurenee pakattaessa, joten tätä kuvaformaattia kannattaakin käyttää esimerkiksi kuvamuotoisten pelikenttien pakkaamiseen, jolloin tilaa säästyy eniten pelikenttien sisältämien tyhjien kohtien ansiosta.
Mutta hetkinen? Eikös PNG:kin ole häviötön, ja paljon tiheämpään pakkautuva kuvamuoto? Miksi hemmetissä kannattaisi käyttää CBI:tä? Jaa'a, ainoa syy jonka olen keksinyt on, ettei ihan kuka tahansa tavallinen pulliainen voi mennä sorkkimaan pelisi mediaa (CBI kuvia kun ei MS paint osaa avata), mutta siihen se sitten jääkin. Toiveeni olisikin, että te koodaustaitoiset ja/tai mielikuvitukselliset foorumilaiset voisitte hieman auttaa tämän formaatin kehittämisessä, jotta siitä saataisiin nopeampi ja tehokkaampi.
CBImage.cb - Liitä tämä tiedosto Includella projektisi koodiin, jos haluat käyttää CBI -kuvia.
Code: Select all
Function SaveCBImage(img,path$,grid=10)
If grid = 0 Then MakeError "CBI: The grid size has been set to automatic."+Chr(10)+Chr(13)+"This feature doesn't work yet!"
F = OpenToWrite(path$)
If F = 0 Then MakeError "CBI: File access error!"
WriteByte f,67 // C
WriteByte f,66 // B
WriteByte f,73 // I
WriteByte f,1 // CBI -kuvaformaatin versionumero. Tämän avulla formaattiin
// voidaan teoriassa tehdä muutoksia, mutta säilyttää vanhojenkin
// kuvien toimivuus.
WriteInt f,ImageWidth(img) // Kuvan leveys
WriteInt f,ImageHeight(img) // Kuvan korkeus
WriteInt f,grid // Ruudukon koko
WriteByte f, 0 // Tarpeeton numero, tulevaisuudessa esim. kuvan väritila (RGB, BW)
WriteInt f, 0 // Tarpeeton numero, tulevaisuudessa esim. kuvan bittisyys
WriteString f, "X" // Tarpeeton merkkijono, tulevaisuudessa esim. kuvan tekijänoikeustiedot
WriteString f, "Y" // Tarpeeton merkkijono, tulevaisuudessa esim. kuvan "otsikko"
// Luodaan taulukko kuvan väriarvojen säilömistä varten.
Dim BaseGrid(ImageWidth(img)/grid+1,ImageHeight(img)/grid+1,2) As Byte
// VAIHE 1:
// TALLENNETAAN KUVASTA PALIKKAMAINEN POHJARUUDUKKO.
Lock Image(img)
// Seuraavalta riviltä alkavan loopin voisi korvata
// For .. next -loopilla, mutta ikävä kyllä silloin
// ruudukon kokoa ei voisi muuttaa (step arvon on
// oltava vakio.
Repeat
If X > ImageWidth(img)-1 Then X = 0 : Y + grid
If X > ImageWidth(img)-1 Then X = ImageWidth(img)-1
If Y > ImageHeight(img)-1 Then Exit
PickImageColor2 img, X,Y
R = getRGB(1)
G = getRGB(2)
B = getRGB(3)
BaseGrid(X/grid,Y/grid,0)=R
BaseGrid(X/grid,Y/grid,1)=G
BaseGrid(X/grid,Y/grid,2)=B
// Tallennetaan tiedostoon yhden ruudun väriarvot.
// Jos arvot on samat kuin edellisessä ruudussa,
// säästetään tiedoston koosta kaksi tavua.
If EXR = R And EXG = G And EXB = B Then
WriteByte f,1
Else
R2 = R 'purkkaa
If R2 = 1 Then R2 = 2 'tikkaria
WriteByte f,R2
WriteByte f,G
WriteByte f,B
End If
// Pistetään tämän ruudun väriarvot muistiin,
// jotta niitä voidaan vertailla seuraavan ruudun
// väriarvoihin.
EXR = R
EXG = G
EXB = B
X + grid
Forever
Unlock
// Tallennetaan maagiset arvot, joista voidaan varmistaa,
// onko kaikki OK tähän asti...
WriteByte f,79
WriteByte f,75
WriteByte f,33
Dim DetGrid(ImageWidth(img),ImageHeight(img),2) As Byte
// VAIHE 2:
// VERRATAAN LUOTUA POHJARUUDUKKOA ALKUPERÄISEEN
// KUVAAN. POHJARUUDUKON PÄÄLLE LISÄTÄÄN YKSITTÄISIÄ,
// ERIVÄRISIÄ PIKSELEITÄ, JOISTA YKSITYISKOHDAT
// RAKENNETAAN.
Lock Image(img)
// Seuraavalta riviltä alkavan loopin voisi korvata
// For .. next -loopilla, mutta ikävä kyllä silloin
// ruudukon kokoa ei voisi muuttaa (step arvon on
// oltava vakio.
X = 0 : Y = 0
Repeat
If X > ImageWidth(img)-1 Then X = 0 : Y + 1
If Y > ImageHeight(img)-1 Then Exit
PickImageColor2 img, X,Y
// Jos pikseli poikkeaa pohjaruudukon väriarvoista, tallennetaan ko. pikselin arvot...
If getRGB(1) <> BaseGrid(X/grid,Y/grid,0) Or getRGB(2) <> BaseGrid(X/grid,Y/grid,1) Or getRGB(3) <> BaseGrid(X/grid,Y/grid,2) Then
R = getRGB(1)
If R = 1 Then R = 2
WriteByte f,R
WriteByte f,getRGB(2)
WriteByte f,getRGB(3)
Else
WriteByte f,1
// Tämä pikseli on samanvärinen kuin pohjaruudukko. Tallennetaan tähän "TYHJÄ"
// pikseli ja siirrytään seuraavaan. Tiedoston koossa säästetään kaksi tavua.
End If
X + 1
Forever
Unlock
CloseFile f
Return 1
EndFunction
Function LoadCBImage(path$)
F = OpenToRead(path$)
If F = 0 Then MakeError "CBI: File access error!"
If ReadByte(f)<> 67 Then MakeError "CBI: Not a proper CBimage file!"
If ReadByte(f)<> 66 Then MakeError "CBI: Not a proper CBimage file!"
If ReadByte(f)<> 73 Then MakeError "CBI: Not a proper CBimage file!"
If ReadByte(f) <> 1 Then MakeError "CBI: The version number was incorrect."
ImageW = ReadInt(f)
ImageH = ReadInt(f)
grid = ReadInt(f)
TempImg = MakeImage(ImageW,ImageH)
PointlessByte = ReadByte(f)
PointlessInt = ReadInt(f)
PointlessString = ReadString(f)
PointlessString2 = ReadString(f)
// VAIHE 1:
// LUETAAN JA LUODAAN KUVAN POHJARUUDUKKO
DrawToImage TempImg
Repeat
If X > ImageW-1 Then X = 0 : Y + grid
If Y > ImageH-1 Then Exit
R = ReadByte(f)
If R = 1 Then
R = EXR
G = EXG
B = EXB
Else
G = ReadByte(f)
B = ReadByte(f)
End If
Color R,G,B
Box X,Y,grid,grid
// Pistetään tämän ruudun väriarvot muistiin,
// jotta niitä voidaan vertailla seuraavan ruudun
// väriarvoihin.
EXR = R
EXG = G
EXB = B
X + grid
Forever
Unlock
DrawToScreen
// Tallennetaan maagiset arvot, joista voidaan varmistaa,
// onko kaikki OK tähän asti...
If ReadByte(f)<>79 Then MakeError "CBI: The file is corrupted."+Chr(10)+Chr(13)+"(Or we've screwed up at some point...)"
If ReadByte(f)<>75 Then MakeError "CBI: The file is corrupted."
If ReadByte(f)<>33 Then MakeError "CBI: The file is corrupted."
// VAIHE 2:
// LISÄTÄÄN POHJARUUDUKON PÄÄLLE YKSITTÄISIÄ PIKSELEITÄ,
// ELI RAKENNETAAN KUVAN YKSITYISKOHDAT
// Seuraavalta riviltä alkavan loopin voisi korvata
// For .. next -loopilla, mutta ikävä kyllä silloin
// ruudukon kokoa ei voisi muuttaa (step arvon on
// oltava vakio.
X = 0 : Y = 0
Lock Image(TempImg)
Repeat
If X > ImageW-1 Then X = 0 : Y + 1
If Y > ImageH-1 Then Exit
R = ReadByte(f)
If R = 1 Then
// Tämä pikseli on "TYHJÄ", ei tehdä mitään
Else
G = ReadByte(f)
B = ReadByte(f)
'SetWindow X+" "+Y
PutPixel X,Y,2,Image(TempImg)
End If
X + 1
Forever
Unlock
CloseFile f
Return TempImg
EndFunction
Function RGBToPixel(r,g,b)
Return b + (g Shl 8) + (r Shl 16) + (255 Shl 24)
EndFunction
SaveCBImage(Kuva, "Target.cbi", 10)
... jossa "kuva" on kuvamuuttuja, "Target.cbi" kohdetiedosto, ja 10 on pohjaruudukon koko. Anna sen olla se 10.
Voit ladata CBI muotoisen kuvan komennolla:
Kuva = LoadCBImage("TheImage.cbi")
... jossa ainoa parametri on kuvan polku. Kun CBI kuva on ladattu, sitä voidaan käsitellä samoilla komennoilla kuin LoadImagella ladattuja kuvia.
Muutama sana kuvaformaatin toimintaperiaatteesta (älä lue ellei sinua oikeasti kiinnosta ):
Idea on, että kuva jaetaan pieniin, esim. 10x10px kokoisiin ruutuihin. CBI tiedostoon tallennetaan jokaisen pienen ruudun RGB arvot. Nyt meillä on siis kasassa kuva, joka näyttää erittäin palikkamaiselta, mutta sen tallennus on vienyt vasta 1% alkuperäisen tiedoston koosta. Noh, nyt tuon ruman palikkakuvan päälle lisätään yksittäisiä pikseleitä sinne tänne, jotta kuvasta saadaan katselukelpoinen. Jos esimerkiksi kuvan vasemmassa yläreunassa oli 10x10 kokoinen musta laatikko, jonka sisällä yksi valkoinen pikseli, tallennetaan nyt tiedostoon kaikki tuon 10x10 kokoisen laatikon sisällä olleet pikselit... Mutta koska ne ovat suurin osa mustia kuten pohjaruudukossakin, kolmen tavun sijaan (RGB) tallennetaan vain ensimmäinen (R), ja näin ollen säästetään 2/3 tilaa. Kun tiedosto jälkeenpäin avataan, huomataan että "Jaahas, tuo tavun arvo on 1, se tarkoittaa että en lue enää kahta seuraavaa tavua saadakseni kasaan RGB arvon, vaan tähän kohtaan kuvaa ei tule pikseliä. Hyppäänpä tästä nyt seuraavaan pikseliin". Seuraavana tavoitteena olisi virittää systeemiä niin, että jos esim. ensimmäisen 10x10 kokoisen ruudukon sisällä kaikki pikselit ovat samanvärisiä, tallennetaan vain jokin tietty luku, esim. 0, ja sitten se RGB arvo, ja sen jälkeen hypättäisiin suoraan seuraavaan ruutuun, ja säästettäisiin hemmetisti enemmän tilaa.
Ohhoh, siitä tulikin vähän enemmän kuin "muutama" sanaa. Ja kukaan ei todennäköisesti edes lue koko tekstiä... No jaa.
Liitetiedosto sisältää yltälöytyvän koodin .cb tiedostona, esimerkit, sekä yhden esimerkkikuvan, jolla pakkaustehoa voi testata.
PS: Jos kokeilet funktioiden pakkauskykyä CB:n media -kansion tiedostoilla, pakatusta kuvasta tulee todennäköisesti pari kertaa isompi kuin alkuperäisestä, sillä suurin osa CoolBasicin kuvista on 8 bittisessä muodossa, mutta CBI kuvat tallennetaan aina 32 bittisinä, jolloin tilaa menee enemmän. Systeemillä kannattaakin siis pakata vain 32 bittisiä kuvia.
PSS: Koodissa on pieni puute: Looppi, joka alkaa riviltä 205 joutuu piirtämään kaikki pikselit PutPixelillä, sillä PutPixel2 aiheutti MAVin. Voisiko joku korjata tämän?
EDIT: Julistan projektin virallisesti jäätyneeksi. Sulattaminen aloitetaan, kun CoolBasicin kolmosversion myötä saadaan lisätehoa kuvien tarkempaan analysointiin.