Pictureboxiin piirretyn kuvan pixelien väri on luettavissa Point-funktiolla, mikä vaikuttaa melko hitaalta. Onko siihen olemassa nopeampaa keinoa? Tarkoitus luoda kuvasta Long-tyypin taulukko. (VB5)
Tässä on Byte-taulukkoon versio:
Option Explicit Private Declare Function GetBitmapBits Lib "gdi32" (ByVal Bitmap As Long, ByVal BufferSize As Long, Buffer As Any) As Long Private Sub Form_Load() Dim Leveys As Long, Korkeus As Long, Rivi As Long, Tavut As Long Dim Pikselit() As Byte Leveys = Picture1.ScaleX(Picture1.Picture.Width, vbHimetric, vbPixels) Korkeus = Picture1.ScaleY(Picture1.Picture.Height, vbHimetric, vbPixels) Rivi = (Leveys * 3 + 3) And &HFFFFFFFC Tavut = Rivi * Korkeus ReDim Pikselit(0 To Tavut - 1) GetBitmapBits Picture1.Picture.Handle, Tavut, Pikselit(0) Debug.Print Hex$(Pikselit(0)), Hex$(Pikselit(1)), Hex$(Pikselit(2)) End Sub
Kuvaobjektit näyttäisivät säilövän kuvat aina 24-bittisinä, joten joutuisit luomaan oman 32-bittisen Device Independent Bitmapin APIn voimin ja sitten käyttämään esim. Picture1.Picture.Renderiä kopioidaksesi kuvan sinne, jonka jälkeen pystyt saamaan sieltä 32-bittistä dataa Long-taulukon täyttöä varten.
Vaihtoehto B on vähän helpompi: tee-se-itse -kopiointi. IDE:ssä aavistuksen hidas, mutta käännettynä salamannopea, varsinkin jos tärppää advanced optimizations -ikkunasta taulukoiden rajojen tarkistukset pois päältä. Jatkaen edellistä esimerkkiä:
Dim Taulu() As Long, I As Long ReDim Taulu(((Leveys + 3) \ 4) * Korkeus - 1) For I = 0 To UBound(Taulu) Taulu(I) = Pikselit(I * 3) Or Pikselit(I * 3 + 1) * &H100& Or Pikselit(I * 3 + 2) * &H10000 Next I Debug.Print Hex$(Taulu(0))
Ja nyt kuvan kaikki pikselit ovat suhteellisen nopeasti vietynä Long-taulukkossa.
Huom! Mikäli Picture on määrittelemättä, niin tämä ei tietenkään toimi. Tällöin voi myös Imagea käyttää Picturen sijasta, jolloin käytössä on PictureBoxin piirtobufferi. Tämä on kuitenkin huomattavasti isompi kuin mitä päälle päin näyttää ja saadut leveys- ja korkeustiedot ovat hieman eri luokkaa kuin mitä saatat odottaa. Image taisi myös toimia ainoastaan jos AutoRedraw on kytkettynä päälle, mutta en ole satavarma (mutten jaksa testata).
Suuret kiitokset ! Bytetaulukko on oikeastaan jopa parempi, en vain tullut ajatelleeksi. Piirretty kuva on imagena, jonka voi sitten jäädyttää pictureksi ja siirtää byte-taulukkoon. Löytyykö tähän vielä käänteinen toiminto, eli byte-taulukko takaisin pikseleiksi. Pset-käskyllä tietysti onnistuu mutta on hidas.
AutoRedraw on todellakin oltava päällä.
Jep, SetBitmapBits. Sen määritys on sama kuin GetBitmapBitsillä, eli teet vaan kopion rivistä ja vaihdat yhden kirjaimen. Kunhan pidät huolta siitä, että rivileveys pikselitaulukossa on aina jaollinen neljällä, niin ongelmia ei synny (sen takia tuolla on riveihin liittyen vähän hassun näköistä matikkaa).
Tosin näyttäisi että MSDN:n dokumentaatio suosittelee käyttämään SetDIBitsiä ja GetDIBitsiä, koska nämä BitmapBits-funktiot on 16-bittisen Windowsin ohjelmien tukemista varten... valitettavasti DIBits-funktiot ovat vähän monimutkaisempia.
Toisaalta kun kerta käytät VB5:ttä, niin eipä sinulle taida olla väliä moisilla yhteensopivuusseikoilla :)
Kiitoksia, tuo ainakin toimi hyvin, siis GetBitmapBits. Vielä en testannut nopeutta koska tuon Point-funktion nopeuden testaukseen riitti Timer-funktio.
Eikö rivin pituus pidä olla kolmella jaollinen eikä neljällä ?
Ei, koska jokainen bittikartta tallennetaan muistissa siten, että kuvan leveys on jaollinen neljällä. Jos sinulla on vaikka 1 x 2 -kokoinen 8-bittinen kuva, niin muistissa se vie 8 tavua, koska jokainen rivi vie 4 tavua, vaikka jokaiselta riviltä on käytössä vain se yksi tavu.
Aihe on jo aika vanha, joten et voi enää vastata siihen.