C # Bitmap in BitmapData razumevanje
C Bitmap Bitmapdata Understanding
Številne naloge obdelave slik so najpreprostejše pretvorbe datotek, na primer pretvorba 32-bitne globine v 8-bitno globino, neposreden dostop do nizov slikovnih pik pa je veliko bolj učinkovit kot uporaba GetPixel in SetPixel.
Morda boste ugotovili, da DotNet uporablja mehanizem gostovanja, v večini primerov pa vam Microsoft priporoči uporabo upravljane kode iz priročnih in varnih razlogov. V praksi redko upravljamo s podatkovnimi bloki v pomnilniku. Vendar je obdelava slik le eden redkih primerov, ker je neučinkovitost uporabe upravljane kode nevzdržna, zlasti pri ogromnih količinah. Zaradi slik tukaj razpravljamo o novem pristopu.
Kako uporabljati neupravljano kodo je odvisno od jezika. V C # lahko kazalnik pokličemo skozi nevarno ključno besedo za neposredno obdelavo bitnih podatkov v pomnilniku. VB uporablja metodo v razredu Marshal, kar bo povzročilo nekaj zmogljivosti. Izguba, zato učinkovitost ni tako dobra kot prejšnja.
Zakleni bitni tok
Razred Bitmap uporablja metode LockBits in UnLockBits za shranjevanje matrike podatkov bitne slike v pomnilnik. 、 Neposredno operirajte , Končno, spremenjeni podatki se uporabljajo za zamenjavo prvotnih podatkov v bitni sliki. LockBits vrne položaj in distribucijo opisanih podatkov v zaklenjeni matrici z razredom vsakega BitmapData.
Razred BitmapData vključuje naslednje pomembne lastnosti:
- Scan0: naslov podatkovne matrike v pomnilniku.
- Stride: Širina črte v podatkovni matriki, v bajtih. Razširi lahko nekaj bajtov, ki bodo predstavljeni kasneje.
- PixelFormat: oblika pikslov, ki je pomembna za pozicioniranje bajtov v matriki.
- Širina: širina bitne slike.
- Višina: višina bitne slike.
Specifično razmerje je prikazano na naslednji sliki:
Kot je prikazano na sl. Atribut stride predstavlja širino črte matrike bitnih podatkov , V bajtih . Širina črte matrike zaradi učinkovitosti ni ravno celo število, večkratnik števila pik na vrstico, sistem pa jo navadno zajema v celoštevilske večkratnike štirih. Na primer, za 24-bitno globino 17-slikovne slike je atribut stride 52 količina podatkov na vrstico 17 3 = 51, sistem samodejno enkapsulira en bajt, zato je njegov korak 52 bajtov (ali 13 4 bajtov). Za 4-bitno indeksno karto širine 17 pik je korak 12, od tega se 9 bajtov (natančno 8,5 bajtov) uporablja za zapis podatkov o podatkih, vsaka vrstica pa se samodejno doda s 3 (3,5) bajti, da se zagotovi, da je 4. Celo število več.
Porazdelitev določenih podatkov se razlikuje glede na obliko slikovnih pik. 24-bitna globoka slika vsebuje nabor informacij RGB na vsake 3 bajte 32-bitna slika vsebuje nabor informacij RGBA na vsake 4 bajte. Oblike slikovnih pik, ki vsebujejo več slikovnih pik na bajt, na primer 4-bitne indeksirane slike ali 1-bitne indeksirane slike, je treba skrbno obdelati, da zagotovite, da se sosednji bajti v istem bajtu ne zamenjajo.
natančno pozicioniranje kazalcev
32-bitni RGB: ob predpostavki, da sta X in Y koordinati slikovne pike v bitni sliki, njen naslov v pomnilniku je scan0 + Y korak + X 4. Na tej točki kazalec kaže na modro, nato zeleno, rdečo in alfa komponente.
24-bitni RGB: skeniranje0 + Y korak + X 3. Kazalec zdaj kaže na modro, ki ji sledita zelena in rdeča.
8-bitni indeks: scan0 + Y Stride + X. Trenutni kazalec kaže na paleto slike.
4-bitni indeks: scan0 + Y Korak + (X / 2). Bajt, ki ga kaže trenutni kazalec, vključuje dve slikovni piki, 16-tonsko barvno kolo pa indeksirajo zgornji in spodnji bit, kjer zgornji bit predstavlja levo piko, spodnji bit pa desno pikslo.
1-bitni indeks: scan0 + Y * stride + X / 8. Vsak bit v bajtu, ki ga kaže trenutni kazalec, predstavlja indeksno barvo ene slikovne pike, paleta je dve barvi, skrajno leva slikovna pika je 8 in skrajno desna slikovna pika nič.
z uporabo iteratorjev med slikovnimi pikami
Naslednji primer nastavi modro komponento vseh slikovnih pik na 32-bitni globinski sliki na največ (255):
BitmapData bmd = bm.LockBits (nov pravokotnik (0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)
int PixelSize = 4
for(int y=0 y > 1) byte currentByte = ((byte *)bmd.Scan0)[offset] if((x&1) == 1) currentByte &= 0xF0 currentByte else currentByte &= 0x0F currentByte ((byte *)bmd.Scan0)[offset]=currentByte Handling the code for a 1-bit index: byte* p=(byte*)bmd.Scan0.ToPointer() int index=y*bmd.Stride+(x>>3) byte mask=(byte)(0x80>>(x&0x7)) if(pixel) p[index]|=mask else p[index]&=(byte)(mask^0xff) Finally, after all the processing is done, don't forget to use the Unlockbits command to unlock.