visual tutorial studio examples application .net wpf

.net - tutorial - Dibujo de píxeles en WPF



wpf vs winforms (5)

¿cómo gestionaría la representación píxel por píxel en WPF (como, por ejemplo, para un raytracer)? Mi conjetura inicial fue crear un BitmapImage, modificar el búfer y mostrarlo en un control de imagen, pero no pude encontrar la manera de crear uno (el método create requiere un bloque de memoria no administrada)


Puede agregar pequeñas rectas si lo desea, pero cada una de ellas es un FrameworkElement, por lo que probablemente sea un poco pesado. La otra opción es crear un DrawingVisual, dibujar sobre él, renderizarlo y luego pegarlo en una imagen:

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); }


Recomiendo encarecidamente en contra de las dos sugerencias anteriores. La clase WriteableBitmap proporciona lo que necesita suponiendo que está utilizando 3.5 SP1. Antes de SP1 no hay una respuesta realmente buena a esta pregunta en WPF a menos que recurras a algún truco serio.


podrías colocar objetos Rectángulo 1X1 en un Lienzo

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); }

Eso debería ser muy parecido a lo que quieres


Si está pensando en hacer algo así como un rastreador de rayos en el que necesitará trazar muchos puntos, probablemente querrá dibujar el espacio de memoria del mapa de bits directamente en lugar de atravesar las capas de abstracción. Este código le dará tiempos de renderización significativamente mejores, pero tiene el costo de necesitar un código "inseguro", que puede o no ser una opción para usted.

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 }

Para limpiar el hBitmap necesitarás declararlo cerca de la parte superior de tu archivo de clase:

[System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject);

También tenga en cuenta que deberá configurar las propiedades del proyecto para permitir código inseguro. Puede hacer esto haciendo clic derecho en el proyecto en el explorador de soluciones y seleccionando propiedades. Ir a la pestaña Construir Marca la casilla "Permitir código no seguro". También creo que deberá agregar una referencia a System.Drawing.


Aquí hay un método que usa 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)); }

Y para usarlo:

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 }