Ako vykreslit velku bitmapu (8000x6000) v C# tak aby to nebolo pomale? Chcem ju prezerat v okne, ale jej posuvanie je hrozne pomale.
Fórum › .NET
Bitmapa
PictureBox na tohle neni staveny. Ja bych se poohledl po nejakem reseni pres DirectX, OpenGL nebo neco podobneho. Podle me zadna klasicka GDI komponenta tohle zvladat poradne nebude.
To dannyk : No ok, ale napr. v Skicari alebo v Paint.NET (ktory je robeny v C#) ide posuvanie aj obrovskych obrazkov plynule a tie programi zrejme pouzivaju len GDI. Ci sa mylim?
Fakticky netusim, mozna by pomohlo u PictureBoxu pouzit DoubleBuffering, ale zvysi to pametovou narocnost, ovsem mohlo by to vyresit ten problem. Nicmene celkove bych se poohlidl po nejakem jinem reseni na Google.
Jeste me napada jedna moznost, a to primo vykreslovat do nejakeho rectangle. Ale jak na to musis pohledat.
Tak jako tak si musíš bitmapu natáhnout do paměti. Takže o paměť se strachovat nemusíš. A pak vykresluj jenom požadovanou část (výřez). V C# jsem takovou věc neřešil, takže nevím, jestli je tam pro to nějaká přímá podpora (letmo jsem nahlédl do MSDN a našel DrawCachedBitmap, ale má nějak málo parametrů :smile1: ). Ve Win32 s pomocí GDI by se to řešilo načtením bitmapy, vytvoření MemoryDC a při vykreslování by se dělal pouze BitBlt výřezu (což je opravdu rychlé). Můžeš to použít i v tvém programu, ale pokud to chceš čislě v C#, tak musíš pohledat.
To liborb : Robim to asi takto:
Najskor si vytvorim Bitmapu:
bm = new Bitmap(4000, 3000);
Graphics gr = Graphics.FromImage(bm);
gr.Clear(Color.White);
gr.Dispose();
Do tejto Bitmapy sa kresli, podobne ako v skicary ciary a pod. a bitmapa sa vykresluje v panely.
Rectangle vysec = new Rectangle(new Point(panel1.AutoScrollPosition.Y*(-1), panel1.AutoScrollPosition.X*(-1)), new Size(panel1.Width, panel1.Height));
Rectangle cast = new Rectangle();
cast = vysec;
cast.X = 0;
cast.Y = 0;
Graphics grfx = e.Graphics;
panel1.AutoScrollMinSize = bm.Size;
grfx.DrawImage(bm,cast, vysec, GraphicsUnit.Pixel);
grfx.Dispose();
vykresluje sa len cast nie cela bitmapa, a je to pomale ako keby som ju vykresloval rovno celu...
Nemam moc skusenosti co sa taky takychto narocnejsich veci s grafikou, neviem ako by som to urobil rychlejsim ...
To liborb : Nepmohlo to, ide to stale rovnako. A DirectX vobec neovladam, akurat tak trosicka XNA a openGL,SDL pod C++, ten prvy sposob sa mi celkom poydava len by som potreboval nejaku ukazku zdrojoveho kodu...
Nu dobrá, tak to zkus přes BitBlt. Nejprve potřebuješ importovat použité funkce:
[DllImport("gdi32.DLL")]
static extern Boolean BitBlt(IntPtr hdcDest, Int32 nXDest, Int32 nYDest, Int32 nWidth, Int32 nHeight, IntPtr hdcSrc, Int32 nXSrc, Int32 nYSrc, UInt32 dwRop);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
static extern bool DeleteObject(IntPtr hObject);
jednu konstantu a 2 proměnné:
private const UInt32 SRCCOPY = 0x00CC0020;
IntPtr pSource;
IntPtr pOrig;
Načteš bitmapu (bmp) jako předtím. Při prvním vykreslení si vytvoříš MemoryDC a přiřadíš mu svojí bitmapu:
//OnPaint(PaintEventArgs e)
IntPtr pTarget = e.Graphics.GetHdc();
if (pSource == IntPtr.Zero) {
pSource = CreateCompatibleDC(pTarget);
pOrig = SelectObject(pSource, bmp.GetHbitmap());
}
následně už můžeš vykreslovat přes BitBlt (co znamenají ty čísla si najdeš v dokumentaci):
BitBlt(pTarget, 0, 0, 100, 100, pSource, 0, 0, SRCCOPY);
a nakonec vykreslení nesmíš zapomenout uvolnit získané HDC:
e.Graphics.ReleaseHdc(pTarget);
A samozřejmě musíš v Dispose uvolnit alokované zdroje:
IntPtr pNew = SelectObject(pSource, pOrig);
DeleteObject(pNew);
DeleteDC(pSource);
To liborb : Moc to pomohlo, je to velmi rychle. Dik za pomoc ;)
To liborb : A este jedna otazka. Ako data naspat vratim Bitmape? Pokial otvorim Bitmapu len na citanie tak to staci ale ked do nej nieco vykreslim a chcem to ulozit na disk tak mi ulozi len stav Bitmapy uplne na zaciatku.
Kreslit musíš do DC pSource, ale to už si asi zjistil, tj. budeš modifikovat bitmapu. A jak ji pak uložíš? To už to asi musíš s Win32 API funkcema dotáhnout až do konce :smile1: .
bmp.GetHbitmap() vrací handle bitmapy a spolu s pSource se ti hodí k použití funkce GetDIBits http://msdn.microsoft.com/en-us/library/dd144879%28VS.85%29.aspx (je tam dokonce i příklad na uložení). Samozřejmě ji musíš naimportovat jako ty předchozí atd. atd.
To liborb : Vyriesil som to pomerne jednoducho:
IntPtr pNew = SelectObject(pSource, pOrig);
bm = System.Drawing.Bitmap.FromHbitmap(pNew);
bm.Save(@"C:\test.bmp");
Jeden problem som vyriesil a prisiel zase druhy... Ked mam velmi velku bitmapu (8000x6000) tak mi pri pokuse o :
BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
Vypise kompilator chybu, ze "Out of memory", neviem kde je problem, asi dana funkcia nedokaze pracovat s takymi velkymi udajmy...
To liborb : No to bude isto tym. A este taka malicka otazka, dalo by sa nejako vytvorit premennu typu IntPtr a do nej ulozit hodnotu pSource?, to preto aby som mohol si zapamatat stav bitmapy v urcitom okamihu, ked som skusal napr. IntPtr cache = pSource; tak to neslo, rovnako tiez metodou BitBlt(cache, 0, 0, 100, 100, pSource, 0, 0, SRCCOPY);
pSource je vlastně HBITMAP. Je to "jenom" handle, nejsou to ty data. Takže cache = pSource neudělá vlastně nic. Přes BitBlt by to šlo, ale to by sis musel vytvořit "záložní" bitmapu (ve Win32 CreateCompatibleBitmap), vytvořit si zase HDC, přiřadit jí tuhle novou bitmapu a pak by si mohl udělat BitBlt.
Pokud si chtěl zálohu dat, tak přes ten LockBits to bylo správně.
Ovšem opět stejná otázka, je nutné dělat kopii celého toho billboardu, co máš místo "normální" bitmapy? :smile1:
Proč to vlastně chceš udělat? Pro různé varianty jsou různé možnosti ....
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Bitmapa do nekolika MovieClip — založil Martin
Binární data - bitmapa — založil Petrr
Bitmapa,zvuk a alpha v java aplikaci — založil greengold
Moderátoři diskuze