Já si to myslel :-) Pro VB ale existují 2 cesty: - buď grafické transformace využívající transformačních matic - na to ale nepotřebujete žádné unsafe módy ani ukazatele, protože ta transformační matice se aplikuje přímo na bázový grafický typ při jeho vykreslování, třeba "školský" příklad pro inverzi barev: (můžou tam být překlepy - píšu to přímo do okna odpovědi):
' nejprve nadefinovat transformační matici
' různými hodnotami lze dosáhnout různých efektů
Dim TransformMatice as new ColorMatrix(New Single()() { _
New Single() {-1,0,0,0,0}, _
New Single() {0,-1,0,0,0}, _
New Single() {0,0,-1,0,0}, _
New Single() {0,0,0,1,0}, _
New Single() {1,1,1,0,1}})
' do vlastností obrázku vložíme naši matici jako barevnou transformaci
Dim AtribObr As new ImageAttributes()
AtribObr.SetColorMatrix(TransformMatice)
' a obrázek normálně vykreslíme, pouze pouřijeme jiné přetížení
GrafickyObjekt.DrawImage(PůvodníObrázek, _
ObdélníkKamVykreslit,0,0, _
PůvodníObrázek.Width,PůvodníObrázek.Height, _
GraphicsUnit.Pixel, AtribObr)
A obrázek se vykreslí včetně transformace. Druhou možností je práce přímo s bitovou mapou (tzn. jako při užití těch ukazatelů). Vypadá to sice složitě jak dvoják žebř, ale je to velejednoduché a dají se s tím dělat jakékoliv nepřístojnosti: Princip je asi takový:
' nejprve vytvoříme obdélník ohraničující plochu (obrázku), se kterou budeme pracovat
Dim Obdelnik as New rectangle (0,0,Obrázek.width, Obrázek.Height)
' teď si na chviličku zahraleme na "C-éčkaře a sáhneme si přímo do paměti
' nejprve data našeho obrázku uzamkneme v paměti, aby nám je GC někam nepřesunulo
Dim ObrazovaData as BitmapData = Obrázek.LockBits(Obdelnik, _
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
' a teď přichází ten "speciální" "řízený" ukazatel, který si nastavíme tak,
' aby nám ukazoval na začátek právě uzamknuté oblasti paměti
Dim DataZacatek As IntPtr = ObrazovaData.Scan0
' teď potřebujeme znát, jak "dlouhé" toto pole je.
' počet pixelů je jasný (šířka obrázku x výška) a počet
' byte pro každý pixel závisí na formátu, který jsme použili
' v příkaze LockBits (v našem případě 3 byty na 1 pixel)
Dim Bytes as integer = Obrázek.Width * Obrázek.Height * 3
' teď si vytvoříme pole (již v normální řízené oblasti paměti, tedy zcela obyčejné pole)
Dim HodnotyRGB(Bytes-1) As Byte
' a do takto vytvořeného pole překopírujeme tu naši zamknutou část paměti
System.Runtime.InteropServices.Marshal.Copy(DataZacatek, HodnotyRGB, 0, Bytes)
' a to je celá příprava, teď máme celý obrázek nasáčkován v našem poli,
' se kterým můžeme docela obyčejně pracovat
' formát je jasný, je to jednorozměrné pole, kde první prvek představuje
' složku R prvního pixelu, druhý prvek složku G a třetí prvek
' složku B, čtvrtý prvek pak složku R druhého pixelu atd...
' můžeme s tím udělat co se nám zlíbí, třeba ta minulá inverze
by vypadala třeba takto
For i As Integer = 0 To Bytes-1
HodnotyRGB(i)=Cbyte(255-HodnotyRGB(i)
Next
' zkrátka projdeme celé pole a hodnoty barevných složek zinvertujeme
' a na závěr zbývá už jen projít tu děsnou "přípravnou část" pěkně opačným postupem zpátky:
' nejprve data vrátíme tam, kam patří
System.Runtime.InteropServices.Marshal.Copy(HodnotyRGB, _
0, DataZacatek, Bytes)
' a odemkneme bitmapu
Obrázek.UnlockBits(ObrazovaData)
' toť vše, už zbývá obrázek pouze běžným způsobem vykreslit
' (v proměnné obrázek teď již máme obrázek zinvertovaný)
GrafickýObjekt.DrawImageUnscaled(Obrázek, New Point(0,0))
Skutečně je to mnohem jednodušší, než to na první pohled vypadá a přestože by člověk řekl, že to musí být šíleně pomalé (jak se stále něco někam znovu a znovu kopíruje), opak je pravdou, a většinou je to ještě o poznání rychlejší, než u té transformace pomocí matic. (záleží ale na typu transformace). P.S. neručím za funkčnost - datloval jsem to přímo, tak tam asi budou nějaké překlepy, ale metodika by měla fungovat)
|