Jak zarządzać renderingiem piksel po pikselu w WPF (jak np. Raytracer)? Moim początkowym założeniem było stworzenie obrazu bitmapowego, zmodyfikowanie bufora i wyświetlenie go w formancie obrazu, ale nie mogłem wymyślić, jak go utworzyć (metoda tworzenia wymaga bloku niezarządzanej pamięci)Piksele rysunkowe w WPF
Odpowiedz
Gorąco polecam przeciwko dwa poprzednie sugestie. The WriteableBitmap class zapewnia to, czego potrzebujesz, zakładając, że używasz 3.5 SP1. Przed SP1 nie ma naprawdę dobrej odpowiedzi na to pytanie w WPF, chyba że uciekniesz się do jakiegoś poważnego oszustwa.
można umieścić 1X1 obiektów Rectangle na płótnie
private void AddPixel(double x, double y)
{
Rectangle rec = new Rectangle();
Canvas.SetTop(rec, y);
Canvas.SetLeft(rec, x);
rec.Width = 1;
rec.Height = 1;
rec.Fill = new SolidColorBrush(Colors.Red);
myCanvas.Children.Add(rec);
}
to powinno być dość blisko tego, co chcesz
Możesz dodać małe prostokąty, jeśli chcesz, ale każdy z nich jest FrameworkElement, więc to chyba trochę wagi ciężkiej. Inną opcją jest stworzenie sobie DrawingVisual, wyciągnąć z niego, czyni go potem trzymać go w obrazie:
private void DrawRubbish()
{
DrawingVisual dv = new DrawingVisual();
using (DrawingContext dc = dv.RenderOpen())
{
Random rand = new Random();
for (int i = 0; i < 200; i++)
dc.DrawRectangle(Brushes.Red, null, new Rect(rand.NextDouble() * 200, rand.NextDouble() * 200, 1, 1));
dc.Close();
}
RenderTargetBitmap rtb = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
rtb.Render(dv);
Image img = new Image();
img.Source = rtb;
MainGrid.Children.Add(img);
}
doskonałym rozwiązaniem. Pracował jak urok. Tylko jedna mała rzecz: dc.Close(); nie jest potrzebny. Używając wywołań Dispose(), który działa tak samo jak Close(). Sprawdziłem kod źródłowy WPF :-) –
Jeśli myślisz o zrobieniu czegoś takiego jak ray tracer, w którym będziesz musiał narysować wiele punktów, prawdopodobnie będziesz chciał narysować bezpośrednio w pamięci bitmapy zamiast przez warstwy abstrakcji. Ten kod zapewnia znacznie lepsze czasy renderowania, ale przychodzi to kosztem "niebezpiecznego" kodu, który może być opcją dla ciebie.
unsafe
{
System.Drawing.Point point = new System.Drawing.Point(320, 240);
IntPtr hBmp;
Bitmap bmp = new Bitmap(640, 480);
Rectangle lockRegion = new Rectangle(0, 0, 640, 480);
BitmapData data = bmp.LockBits(lockRegion, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* p;
p = (byte*)data.Scan0 + (point.Y * data.Stride) + (point.X * 3);
p[0] = 0; //B pixel
p[1] = 255; //G pixel
p[2] = 255; //R pixel
bmp.UnlockBits(data);
//Convert the bitmap to BitmapSource for use with WPF controls
hBmp = bmp.GetHbitmap();
Canvas.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbmpCanvas, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
Canvas.Source.Freeze();
DeleteObject(hBmp); //Clean up original bitmap
}
Aby oczyścić HBITMAP trzeba będzie zadeklarować to w górnej części pliku klasy:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
Należy również pamiętać, że trzeba będzie ustawić właściwości projektu w celu umożliwienia niebezpieczny kod. Możesz to zrobić, klikając prawym przyciskiem myszy projekt w eksploratorze rozwiązań i wybierając właściwości. Przejdź do karty Build. Zaznacz pole "Zezwalaj na niebezpieczny kod". Sądzę również, że będziesz musiał dodać odniesienie do System.Drawing.
Dzięki za to rozwiązanie. –
Oto metoda wykorzystująca WritableBitmap.
public void DrawRectangle(WriteableBitmap writeableBitmap, int left, int top, int width, int height, Color color)
{
// Compute the pixel's color
int colorData = color.R << 16; // R
colorData |= color.G << 8; // G
colorData |= color.B << 0; // B
int bpp = writeableBitmap.Format.BitsPerPixel/8;
unsafe
{
for (int y = 0; y < height; y++)
{
// Get a pointer to the back buffer
int pBackBuffer = (int)writeableBitmap.BackBuffer;
// Find the address of the pixel to draw
pBackBuffer += (top + y) * writeableBitmap.BackBufferStride;
pBackBuffer += left * bpp;
for (int x = 0; x < width; x++)
{
// Assign the color data to the pixel
*((int*)pBackBuffer) = colorData;
// Increment the address of the pixel to draw
pBackBuffer += bpp;
}
}
}
writeableBitmap.AddDirtyRect(new Int32Rect(left, top, width, height));
}
I z niego korzystać:
private WriteableBitmap bitmap = new WriteableBitmap(1100, 1100, 96d, 96d, PixelFormats.Bgr24, null);
private void Button_Click(object sender, RoutedEventArgs e)
{
int size = 10;
Random rnd = new Random(DateTime.Now.Millisecond);
bitmap.Lock(); // Lock() and Unlock() could be moved to the DrawRectangle() method. Just do some performance tests.
for (int y = 0; y < 99; y++)
{
for (int x = 0; x < 99; x++)
{
byte colR = (byte)rnd.Next(256);
byte colG = (byte)rnd.Next(256);
byte colB = (byte)rnd.Next(256);
DrawRectangle(bitmap, (size + 1) * x, (size + 1) * y, size, size, Color.FromRgb(colR, colG, colB));
}
}
bitmap.Unlock(); // Lock() and Unlock() could be moved to the DrawRectangle() method. Just do some performance tests.
image.Source = bitmap; // This should be done only once
}
- 1. Płótno profesjonalne efekty rysunkowe
- 2. KineticJS - linie rysunkowe z myszą
- 3. Jak przekonwertować Twips na piksele w .NET?
- 4. piksele Direct2D
- 5. Java: Czcionki i piksele
- 6. CSS - Procenty lub piksele?
- 7. Jak odczytać piksele ekranu?
- 8. CGContextDrawImage w siatkówce rysuje piksele obrazu?
- 9. Odejmij piksele od wartości procentowej w SASS?
- 10. Usuń 3 piksele w iOS/WebKit textarea
- 11. Wybierając piksele o największej intensywności w OpenCV
- 12. Piksele odczytu Androida od GL_TEXTURE_EXTERNAL_OES
- 13. Jak zapisywać i ładować linie rysunkowe iphone SDK
- 14. Koła rysunkowe na obrazie z matplotlib i numpy
- 15. Praca z bitmapą w WPF
- 16. Piksele bitmapowe Androida - napisz bezpośrednio do pliku?
- 17. Android Bitmap: Konwertuj przezroczyste piksele na kolor
- 18. Java Loop poprzez piksele na obrazie?
- 19. Android ListView bieżące położenie przewijania Y piksele
- 20. CALayer: Pojedyncza linia pikseli wygląda 2 piksele
- 21. Użyj płótna, aby zmienić nieprzezroczyste piksele, biały
- 22. Czy potrafisz przeglądać piksele w obrazie bez ładowania całego obrazu?
- 23. Konwertuj piksele na cale i na odwrót w C#
- 24. Utwórz nową bitmapę i narysuj w niej nowe piksele.
- 25. Jak przekonwertować wysokość elementu podanego w vh na piksele?
- 26. Struktura danych do rozpoznawania wzorców w oparciu o piksele
- 27. Zapobieganie piksele obrazów w systemie Windows Store App
- 28. Obrazy TIFF: jak piksele obrazu 16 bit-RGBA są przeplatane?
- 29. Spraw, aby wszystkie czarne piksele były przezroczyste za pomocą CIImage
- 30. Android: Uzyskaj rozdzielczość ekranu/piksele jako liczby całkowite
Klasa WriteableBitmap jest dostępna od .NET 3.0 i jest to pierwsza wersja WPF. Nie potrzebujesz .NET 3.5 do korzystania z tej klasy. –