C# giving a PictureBox the shape of a Image [duplicate] - c#

This question already has answers here:
Irregular shaped Windows Form (C#)
(2 answers)
Closed 8 years ago.
I want to give a pictureBox the shape of an image I have. The image off course is rectangular, but there is the backgroundcolor that should be ignored, which leads to the desired form. So if there is a picture of a banana on a white background, I should have a pictureBox in shape of a banana at the end.. This is needed so that I can move shaped PictureBox in front of a AxWMPLib Mediaplayer without having the rectangle surrounding the banana covering all of the video.
My approach is to create a new class that extends PictureBox and then setting the region to the shape. Problem is, I don't know how to get the shape.
class ShapedPBox : PictureBox
{
public ShapedPBox()
{
this.Paint += this.shapedPaint;
}
void shapedPaint(object sender, paintEventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath gP = new System.Drawing.Drawing2D.GraphicsPath();
//do something to give gP.addPicture? perhaps something with transparency key?
this.Region = new Region(graphicsPath);
}
public Image image;
}

You can set the SizeMode property of PictureBox to StretchImage and that would remove default background colour. Of course, the image will shrink or grow based on image and control size.
If you cannot resize the image and you know where the background is, following code could be used. All it does is that it gets colour from edge of image and sets that as background color of picture box.
Image image = Image.FromFile(#"c:\Image.png");
Bitmap bitmap = new Bitmap(image);
pictureBox1.BackColor = bitmap.GetPixel(0, 1);
pictureBox1.Image = image;

Related

Panel to Image (DrawToBtimap doesn't work) [duplicate]

This question already has an answer here:
DrawToBitmap returning blank image
(1 answer)
Closed 3 years ago.
I'm trying to make an application similar to Paint.
Everything works well, but I have a problem with saving the image to a file.
The function for saving works okay, the file saves in the selected location, but it is empty when something is drawn.
It works only when I change the background color, then the image saves with this color.
When I 'draw' something like that
the saved image looks like this
Code:
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
int width = pnl_Draw.Width;
int height = pnl_Draw.Height;
Bitmap bm = new Bitmap(width, height);
SaveFileDialog sf = new SaveFileDialog();
sf.Filter = "Bitmap Image (.bmp)|*.bmp|Gif Image (.gif)|*.gif|JPEG Image (.jpeg)|*.jpeg|Png Image (.png)|*.png|Tiff Image (.tiff)|*.tiff|Wmf Image (.wmf)|*.wmf";
sf.ShowDialog();
var path = sf.FileName;
pnl_Draw.DrawToBitmap(bm, new Rectangle(0, 0, width, height));
bm.Save(path, ImageFormat.Jpeg);
}
Drawing:
private void pnl_Draw_MouseMove(object sender, MouseEventArgs e)
{
if(startPaint)
{
//Setting the Pen BackColor and line Width
Pen p = new Pen(btn_PenColor.BackColor,float.Parse(cmb_PenSize.Text));
//Drawing the line.
g.DrawLine(p, new Point(initX ?? e.X, initY ?? e.Y), new Point(e.X, e.Y));
initX = e.X;
initY = e.Y;
}
}
Where is your "g" (System.Drawing.Graphics?) object come from when you DrawLine on it? I also can't see where you fill the background color, but I have the suspiction that your drawing gets discarded/overwritten - but given the little code visible here, it's hard to tell.
I'd just suggest what worked for me in the past:
Use a Bitmap object to draw your lines etc into, not the panel directly. And when you want to save it, just save the bitmap.
To make the drawing visible on your panel, call Invalidate(...) on your panel after a new line stroke was made, with the bounding rectangle around the line stroke as the update-rectangle passed to Invalidate.
In the OnPaint handler of your panel, then make sure to only draw that portion that's new, e.g. that rectangle I mentioned. This will be passed as the clip bounds of the OnPaint call. If only the changed portion of the whole image is drawn in the OnPaint handler, it will be much faster than always drawing the whole bitmap onto the panel.
For that, you need to creage a graphics object from the drawn-to bitmap, and keep both the bitmap and the graphics object alive throughout your drawing session (i.e. don't let it get garbage collected by not having references to them somewhere)
Something roughly like this:
// assuming you're all doing this directly in your main form, as a simple experimental app:
// Somewhere in your form class:
Bitmap drawingBitmap;
Graphics gfx;
// in your form class' constructor, AFTER the InitializeComponent() call, so the sizes are known:
// using a pixelformat which usually yields good speed vs. non-premultiplied ones
drawingBitmap = new Bitmap( pnl.Width, pnl.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb );
gfx = Graphics.FromImage( drawingBitmap );
private void pnl_Draw_MouseMove(object sender, MouseEventArgs e)
{
if(startPaint)
{
//Setting the Pen BackColor and line Width
Pen p = new Pen(btn_PenColor.BackColor,float.Parse(cmb_PenSize.Text));
//Drawing the line.
var p1 = new Point(initX ?? e.X, initY ?? e.Y);
var p2 = new Point(e.X, e.Y);
gfx.DrawLine( p, p1, p2 ); // !!! NOTE: gfx instance variable is used
initX = e.X;
initY = e.Y;
// makes the panel's Paint handler being called soon - with a clip rectangle just covering your new little drawing stroke, not more.
pnl.Invalidate( new Rectangle( p1.X, p1.Y, 1+p2.X-p1.X, 1+p2.Y-p1.Y ));
}
}
private void pnl_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
// use the clip bounds of the Graphics object to draw only the relevant area, not always everything.
var sourceBounds = new RectangleF( g.ClipRectangle.X, g.ClipRectangle.Y, g.ClipRectangle.Width, g.ClipRectangle.Height );
// The bitmap and drawing panel are assumed to have the same size, to make things easier for this example.
// Actually you might want have a drawing bitmap of a totally unrelated size, and need to apply scaling to a setting changeable by the user.
g.DrawImage( drawingBitmap, g.ClipRectangle.X, g.ClipRectangle.Y, sourceBounds );
}
Here is a little bit about that, although pretty old article. But GDI+ hasn't change that much since then, as it's a wrapper around the Win32 drawing stuff.
https://www.codeproject.com/Articles/1355/Professional-C-Graphics-with-GDI
NOTE: What I don't have time right now to check and do not remember is whether you are allowed to, at the same time:
have an "open" graphics object of a bitmap and draw into the bitmap
paint that same bitmap onto something else (like the panel)
save the bitmap to file
You'd have to check that, and manage the existence of the graphics object with its claws on your drawing bitmap accordingly.

Saving off picturebox composed of image and drawings

Here is what I am trying to do. I have an Image that is 1920X1080. I am showing that image in a PictureBox and allowing a user to draw an ellipse on the screen. Once they finish that I will need to save that image off with the image and ellipse in 1 photo.
So I have tried several ways:
1. Just trying to save the image and ellipse from the PictureBox. No success doing that.
2. To store the location of the ellipse on the picture box and then redraw that ellipse on a new copy of the image using a graphics object. The problem with this one is that when it saves off the ellipse is not in the right place due to the size of the PictureBox and the original image difference.
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
pictureBox1.Cursor = Cursors.Default;
if (isMoving)
{
Circles.Add(mouseDownPosition, mouseMovePosition);
}
isMoving = false;
}
Bitmap newImage = new Bitmap(new Bitmap(#"C:\Personal\test\Sample.jpg"));
Graphics g = Graphics.FromImage(newImage);
foreach (var circle in Circles)
{
g.DrawEllipse(new Pen(Color.Red, 3), new Rectangle(circle.Key, new Size(circle.Value.X - circle.Key.X, circle.Value.Y - circle.Key.Y)));
}
newImage.Save(#"C:\Projects\Projects\SampleCombine.jpg");
I am really just looking for a way to take exactly what I see on the PictureBox and save it as its own jpg.
My take is that I need to figure out how to reposition the "Circle" based on where it was drawn and where it should be drawn on a larger file.
Any ideas?

how to extend draw area in Graphics.DrawImage c#

I have a Rectangle (rec) that contains the area in which a smaller image is contained within a larger image. I want to display this smaller image on a Picturebox. However, what I really am doing is using the smaller image as a picture detector for a larger image that is 333x324. So what I want to do is use the coordinates of the smaller image rectangle, and then draw to the Picturebox, starting from lefthand side of the rectangle, going outwards by 333 width and 324 height.
Currently my code works but it only displays the small image that was being used for detection purposes. I want it to display the smaller image + 300 width and + 300 height.
I fiddled with this code for hours and I must be doing something extremely basic wrong. If anyone can help me I would appreciate it so much!
My code for the class:
public static class Worker
{
public static void doWork(object myForm)
{
//infinitely search for maps
for (;;)
{
//match type signature for Threading
var myForm1 = (Form1)myForm;
//capture screen
Bitmap currentBitmap = new Bitmap(CaptureScreen.capture());
//detect map
Detector detector = new Detector();
Rectangle rec = detector.searchBitmap(currentBitmap, 0.1);
//if it actually found something
if(rec.Width != 0)
{
// Create the new bitmap and associated graphics object
Bitmap bmp = new Bitmap(rec.X, rec.Y);
Graphics g = Graphics.FromImage(bmp);
// Draw the specified section of the source bitmap to the new one
g.DrawImage(currentBitmap, 0,0, rec, GraphicsUnit.Pixel);
// send to the picture box &refresh;
myForm1.Invoke(new Action(() =>
{
myForm1.getPicturebox().Image = bmp;
myForm1.getPicturebox().Refresh();
myForm1.Update();
}));
// Clean up
g.Dispose();
bmp.Dispose();
}
//kill
currentBitmap.Dispose();
//do 10 times per second
System.Threading.Thread.Sleep(100);
}
}
}
If I understand correctly, the rec variable contains a rectangle with correct X and Y which identifies a rectangle with Width=333 and Height=324.
So inside the if statement, start by setting the desired size:
rec.Width = 333;
rec.Height = 324;
Then, note that the Bitmap constructor expects the width and height, so change
Bitmap bmp = new Bitmap(rec.X, rec.Y);
to
Bitmap bmp = new Bitmap(rec.Width, rec.Height);
and that's it - the rest of the code can stay the way it is now.

I need to render an image on top of a drawn Object

I need to make a program that'll enable the user to customize his own car.
My problem is I have to draw the customizables by code and I have to add a PNG image of details on top of the drawn car.
The user has to select the colors, rim designs, and decals from the right
The car will be drawn when the PIMP button is pressed.
I have to add the PNG image, the second image, on top of the drawn image(first image), to make it look like the third image.
My current code looks like:
private void button1_Click(object sender, EventArgs e)
{
Graphics g;
g = this.CreateGraphics();
if (color == 1)
{
g.FillPolygon(blue, body);
}
else if (color ==2)
{
g.FIllPolygon(red, body);
}
g.FillPolygon(blackBrush, window);
pCard.Visible = True;
//pCard is an existing PictureBox where the Image is the cardetails.PNG
backcolor = transparent
}
When I press the PIMP button it draws the first image, but when it draws the PictureBox of cardetails.png, the transparent color displays the color gray and covers the first image.
I am very new to C# and Visual Basic. The only thing i know how to do here is to draw that blue car.
Load the image that contains the details you want to add:
Image decalImage = Image.FromFile("cardetails.png");
It would probably be best if you do not load it in your button1_Click method.
Then draw the image upon your graphics object using
g.DrawImage(decalImage, x, y);
Where x and y would be the position to draw it to.

PictureBox performing unwanted scaling C#

I currently have a windows form app with a pictureBox in the middle of it which i am drawing various images too. The images are drawing fine except for the fact that they are all being scaled up by exactly 25%. I should also add that i am drawing everything inside a Paint method, using the PaintEventArgs to get the graphics device.
Ive made sure the SizeMode is set to Normal, ive checked over and over that the scale factor of the graphics object is 1 and all the image objects that i pass to the paint method are of the size they should be, but when they get drawn they are a different size.
I have until now just been calling g.drawImage(image, Rectangle) and passing the width and height of the image as the width and height of the Rectangle so that they are forced to be drawn at the correct size but i feel that this should be a short term fix and i am overlooking something simple.
Any help would be great, thanks in advance.
Code is as follows (only the important bits):
public class Level : PictureBox
{
...
private Image image;
...
public Level(TabPage parent, Panel propertiesPanel, ItemManager items, string levelName)
{
...
image = Image.FromFile(#"Levels/" + levelName);
Size = image.Size;
SizeMode = PictureBoxSizeMode.Normal;
MouseClick += new MouseEventHandler(level_MouseClick);
MouseMove += new MouseEventHandler(level_MouseMove);
Paint += new PaintEventHandler(level_Paint);
Invalidate();
}
private void level_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
//With the rectangle fix (drawing to correct size)
g.DrawImage(image, new Rectangle(0, 0, image.Size.Width, image.Size.Height));
////Without the fix (as i thought it should be be this is where it scales it)
//g.DrawImage(image, new Point(0, 0));
drawPlacedItems(g);
drawItemPreview(g);
}
This sounds like the HorizontalResolution and VerticalResolution properties of your image are being applied when you don't want them to, modify your code as per Jeremy's link to Image sizing issue in bitmap that ensures that HorizontalResolution and VerticalResolution are reset or ignored before calling DrawImage.

Categories

Resources