c# drawing objects at once instead of using a loop - c#

Hello i am trying to draw about 1000 images and between 10 to 100 rectangels and elipses.
But i need all of them to show up on screen only when they done loading(not in a loading screen but in a game or slideshow). so for example
texturegrass = MyApp.Properties.Resources.Grass
Rectangle[] rects;
recs = new Rectangle[1000]
for (int i = 0; i < rects.Length; i++)
{
g.DrawImage(texturegrass,rects[i]);
}
this is what i done so far but every rectangle is been drawn by it own what cause a flickering problam.
I have double bufferd the app.
I tried using parallel but the application keep crashing
I hope one of you guys can help me...
##*

You can use a Graphics object to create the image off-screen, and then draw the image on the screen using the screen's Graphics object.
var bmp = new Bitmap(MyWidth, CMyHeight);
var gOff = Graphics.FromImage(bmp);
gOff.FillRectangle(new SolidBrush(Color.White), 0, 0, bmp.Width, bmp.Height);
texturegrass = MyApp.Properties.Resources.Grass
Rectangle[] rects = ...;
recs = new Rectangle[1000]
for (int i = 0; i < rects.Length; i++) {
gOff.DrawImage(texturegrass,rects[i]);
}
At this point you can draw bmp all at once on the screen's Graphic.
Microsoft: How to Draw Images Off-Screen

Related

Custom bitmap object isn't displaying correctly in PictureBox

I'm trying to generate a custom Bitmap through code at a very small size and display it to a PictureBox, upscaled to fit said PictureBox. I am using the graphics object to do this in order to use NearestNeighbor interpolation to upscale single pixels perfectly.
I'm using the graphics object of a temporary default image that is in the PictureBoxs "Image" component on Form.Load, which is sized to be the perfect width and height to maintain the correct aspect ratio from the original Bitmap.
Here is the relevant code:
private void Form1_Load(object sender, EventArgs e)
{
bmp = new Bitmap(16, 9, PixelFormat.Format24bppRgb);
rnd = new Random();
GenerateImage();
}
private void GenerateImage()
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
int num = rnd.Next(2);
if (num == 0)
{
bmp.SetPixel(x, y, Color.White);
}
else
{
bmp.SetPixel(x, y, Color.Gold);
}
}
}
Bitmap image = new Bitmap(picOutput.Image);
grp = Graphics.FromImage(image);
grp.InterpolationMode = InterpolationMode.NearestNeighbor;
grp.DrawImage(
bmp,
new Rectangle(0, 0, image.Width, image.Height),
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel
);
grp.Dispose();
picOutput.Image = image;
}
The problem is that the Bitmap seems to be drawn incorrectly. About half a pixel from the original Bitmap is cut off on the left and top edges of the Bitmap when displayed through the PictureBox, and that roughly half a pixel shows up as the original default image on the right and bottom edges. It's almost like the Bitmap was offset up and to the left while being drawn by the graphics object, it doesn't perfectly cover up the original default image like it was supposed to.
My first thought was the PictureBoxs SizeMode, which is still set to "Normal," but none of them change the problem at all. Here is a picture of the problem. The black edges on the right and bottom are part of the temporary default image (the image I used graphics from), which is completely black and covers the entire PictureBox area.
Can anyone offer some insight?
As user Jimi pointed out in a comment, grp.PixelOffsetMode = PixelOffsetMode.Half from this post solved the issue.

drawing on image of a picturebox c#

Hello i am in problem with drawing in picturebox. I am trying to draw over a picturebox. picturebox contains an image.I draw a sine wave using drawline method. when the wave reaches the end of the width of picturebox then i use
g.Clear(pictureBox1.BackColor);
this clears the wave over the picturebox.But the problem is it also clears the image of the picturebox.I want draw a wave over a image and then clears it when it reaches the picturebox.width and again starts from the initial position. please help!
Graphics g;
g = pictureBox1.CreateGraphics();
g.DrawLine(System.Drawing.Pens.Crimson, ti, old_gval1, ti + trackBar1.Value, gval1);
usb.SpecifiedDevice.SendData(OUTBuffer);
old_gval1 = gval1;
ti = ti + trackBar1.Value;
if (ti > pictureBox1.Width) {
ti = 0;
g.Clear(pictureBox1.BackColor);
g.DrawLine(System.Drawing.Pens.Gray, 0, ((pictureBox1.Height - 1) - (gnd_val) * ((pictureBox1.Height - 10) / 1023f)), pictureBox1.Width, ((pictureBox1.Height - 1) - (gnd_val) * ((pictureBox1.Height - 10) / 1023f)));
g.DrawLine(System.Drawing.Pens.Gray, pictureBox1.Width / 2, 0, pictureBox1.Width/ 2,pictureBox1.Height);
}
You can use a special feature of the PictureBox:
It has not only the Image everybody is using but also a BackgroundImage usually overlooked.
You can paint freely on the Image and still keep a BackgroundImage untouched.
Obviosly you need to paint on a transparent Bitmap.
Here is some code:
// load the background image:
this.pictureBox1.BackgroundImage = new Bitmap(yourImageFileName);
// prepare the image:
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp) )
{
g.FillRectangle(Brushes.Transparent, new Rectangle(Point.Empty, bmp.Size) );
}
pictureBox1.Image = bmp;
Now paint stuff:
Random R = new Random();
private void button1_Click(object sender, EventArgs e)
{
Image bmp = pictureBox2.Image;
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawEllipse(Pens.Blue, R.Next(33), R.Next(33), R.Next(500), R.Next(500));
g.DrawEllipse(Pens.Red, R.Next(33), R.Next(33), R.Next(500), R.Next(500));
g.DrawEllipse(Pens.White, R.Next(33), R.Next(33), R.Next(500), R.Next(500));
}
pictureBox2.Image = bmp;
}
When your plotting has reached the right edge you would use a call to FillRectangle(Brushes.Transparent,.. to clear the foreground image and reset your x value.
Sounds like the cheapest solution to your problem.
You have two options here.
You could create your graphics from the image using Graphics.FromImage, then assign the image from that to the picture box.
Draw the image into your new Graphics object using Graphics.DrawImage.
It sounds like the latter might be a bit more appropriate for you, since you aren't actually altering the in-memory image. So every time you clear the Graphics instance, just draw in the Image.

c# drawing text using custom pixels

I'm wondering if that's possible:
I got a c# application with something like a display consisting of about 11000 circles drawn on the Form.
What I want to achieve is to be able to draw text on that display, but not using the "real" pixels, but using the circles (rectangles) drawn on the form as pixels.
Edit 1:
When drawing text in c#, you would i.e. use something like Graphics.DrawString(...), giving the method a rectangle (so coordinates) in which the text should be drawn in. That text then is drawn in that rectangle using the screen pixels. What I want to do is draw text as well but not using the screen pixels but my custom pixels of which my display consists.
Edit 2
Method used to draw the circles on the Form; Circles is a list consisting of Circle objects, where circleRectangle returns the coordinates in which the circle should be drawn and Filled tells the method if the circle should be filled or not.
public void DrawCircles(Graphics g)
{
graphics = g;
graphics.SmoothingMode =System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Pen pen = new Pen(Color.Black, penthickness);
SolidBrush brush = new SolidBrush(Color.White);
for (int j = 0; j < Circles.Count;j++ )
{
graphics.DrawEllipse(pen, Circles[j].CircleRectangle);
if (Circles[j].Filled)
brush.Color = fillColor;
else
brush.Color = Color.White;
graphics.FillEllipse(brush, Circles[j].CircleRectangle);
}
}
Is this possible and if yes, how would I do that?
You could write on an invisible BitMap with the DrawText method and then scan the bitmap's pixels and turn the corresponding circles on.
Did that last week with the cells of DataGridView. Real easy.
Here is some code:
public void drawText(string text, Font drawFont)
{
Bitmap bmp = new Bitmap(canvasWidth, canvasHeight);
Graphics G = Graphics.FromImage(bmp);
SolidBrush brush = new SolidBrush(paintColor);
Point point = new Point( yourOriginX, yourOriginY );
G.DrawString(text, drawFont, brush, point);
for (int x = 0; x < canvasWidth; x++)
for (int y = 0; y < canvasHeight; y++)
{
Color pix = bmp.GetPixel(x, y);
setCell(x, y, pix); //< -- set your custom pixels here!
}
bmp.Dispose();
brush.Dispose();
G.Dispose();
}
Edit: You would use your dimensions and your origin for the DrawString, of course

panel1.DrawToBitmap doesn't draw lines from DrawLine

I have a panel on which I'm drawing lines using:
Point PreviousPoint = new Point (0,0);
Point NewPoint = new Point (10,10);
Pen MyPen = new Pen(Color.Black, 2);
Graphics MyGraphics = panel1.CreateGraphics();
MyGraphics.DrawLine(MyPen, PreviousPoint, NewPoint);
This all works fine. I obviously change the points to draw more lines, but that doesn't matter for this question. I want to export that panel as a jpg file. I'm using this code:
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, panel1.Width, panel1.Height));
bmp.Save("C:\\panel.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
This outputs a blank jpg. The background of my panel is gray, and the background of the jpg is the same gray, so I know it's actually exporting the panel. Also, I added a button into the panel just to see if it would get saved, and it did. So for some reason the jpg isn't saving the lines being drawn.
So I made a workaround that solves the core problem. I made an array of the points I plotted to draw the lines, then I did this:
// make sure you actually drew something
if (MyLines.Length > 0)
{
// instantiate the stuff you need
Image img = new Bitmap(panel1.Width, panel1.Height);
Graphics g = Graphics.FromImage(img);
Pen pen = new Pen(Color.Black, 2);
// draw every line (from every even index to the one after it)
for (int i = 0; i < MyLines.Length; i++)
{
if (i % 2 == 0)
{
g.DrawLine(pen, MyLines[i], MyLines[i + 1]);
}
}
img.Save("C:\\panel.png", System.Drawing.Imaging.ImageFormat.Png);
}
}

Optimize drawing to buffer C#

Im trying to make a photoshop like application for my college project in c#
So far I,ve created a custom panel called canvas and overloaded the paint method to draw the canvasBuffer.
The project is called paint sharp.
I have an Class PaintSharpFile that stores the various layers of the image.
On the Canvas control, I draw the checked Transparent Background and then the layers in the paint sharp file on to the canvasBuffer. I finally paint this buffer(Double Buffering).
Now, I am writing the code for the brush tool.
I record the previous and the current point and then draw a series of circle between those two points using Bresenham's line algorithm on the canvasBuffer itself. This seems to work fast and fine.
Now since the brush tool will be working on an active layer selected, I tried drawing the points to the buffer of the layer. Then drew all the layer's buffer canvasBuffer. Doing this makes the drawing very slow.
Here's the code
public void PSF_Painted(PSF_PaintEvent e)
{
Graphics g = null;
Bitmap layerBuffer = psf.Layers[0].LayerBuffer;//Get selected layer here
g = Graphics.FromImage(layerBuffer);
Brush blackBrush = new SolidBrush(Color.Black);
Pen blackPen = new Pen(blackBrush);
blackPen.Width = 2;
List<Point> recordedPoints = e.RecordedPoints;
Point currentPoint = new Point(0,0);
Point previousPoint = new Point(0, 0); ;
if(recordedPoints.Count > 0)
{
currentPoint = recordedPoints[recordedPoints.Count - 1];
if(recordedPoints.Count == 1)
{
previousPoint = recordedPoints[0];
}
else
{
previousPoint = recordedPoints[recordedPoints.Count - 2];
}
}
if (e.PaintEventType == PSF_PaintEvent.Painting)
{
List<Point> points = Global.GetPointsOnLine(previousPoint.X, previousPoint.Y, currentPoint.X, currentPoint.Y);
for (int i = 0; i < points.Count ; i++)
{
g.FillEllipse(blackBrush, new Rectangle(points[i].X, points[i].Y, (int)blackPen.Width, (int)blackPen.Width));
}
}
Global.drawToBuffer(canvasBuffer, layerBuffer);//Replaced with redraw the full picture from the List of layer to the canvasBuffer
g.Dispose();
this.Invalidate();
}
And here's my onPaint Code
protected override void OnPaint(PaintEventArgs e)
{
if (canvasBuffer != null)
{
Graphics g = e.Graphics;
g.DrawImage(canvasBuffer, e.ClipRectangle, e.ClipRectangle, GraphicsUnit.Pixel);
g.Dispose();
}
}
Here is the drawing of a picture to the buffer
public static void drawToBuffer(Bitmap buffer, Bitmap image)
{
if (image != null && buffer != null)
{
Graphics g = Graphics.FromImage(buffer);
g.DrawImage(image, new Rectangle(0, 0, buffer.Width, buffer.Height));
g.Dispose();
}
}
Please tell me how do I stop the paint from lagging.
I have tried making several canvases each with a layer image. But since it is not double buffered, it causes flickering.
The main thing that jumps out at me is that you're copying the entire layer on every update. Try limiting the copying to just the affected areas.
Unrelated to performance, you're calling Dispose directly on Graphics objects but then not disposing of the Brush and Pen objects you create. What's wrong with using blocks?

Categories

Resources