I'm creating a control that inherits from a Windows.Forms.Panel and has a specific region onto which I want to draw an image.
This code draws the image over the region I want, but doesn't stretch it.
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.FillRegion(new TextureBrush(ContentImage), ContentRegion);
regionNeedsRefresh = false;
}
This code draws the image over the rectangle I want, and stretches it to fit the rectangle, but it doesn't draw over the exact region I want:
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.DrawImage(ContentImage, ContentRegion.GetBounds(_g));
regionNeedsRefresh = false;
}
So what I need is a bit of both solutions I'm guessing...
Any help would be much appreciated!
You can use Graphics.DrawImage, and simply set the Clip property of the Graphics object to the Region you want to draw in before and after the operation.
Related
I have two pictureBoxes "source" and "dest". Now I would like to resize the "source" image and display it in my "dest"-picturebox.
Question:
How can I resize my "source" image and display it in my "dest"-picturebox?
Here is my code which only display the same image again:
private void pictureBoxZoom_Paint(object sender, PaintEventArgs e)
{
var settings = new Settings();
// Create a local version of the graphics object for the PictureBox.
Graphics Draw = e.Graphics;
Draw.ScaleTransform(2, 2); // rescale by factor 2
IntPtr hDC = Draw.GetHdc(); // Get a handle to pictureBoxZoom.
Draw.ReleaseHdc(hDC); // Release pictureBoxZoom handle.
}
In each case, you have to handle the PictureBox.SizeMode-Property. It determines what the PictureBox does to the image when painting.
If you want to apply a customized Zoom-factor, you can use the Graphics.ScaleTransform-Property. It allows you to scale the complete graphics. The Scaling can be done on the image itself by creating a bitmap (which has a Graphics-object you can use) or by overriding the PictureBox.OnPaint-Method, which requires you to create a class deriving from PictureBox. That's the most flexible attempt because you can control everything by yourself - if you like to.ยด
EDIT:
Sorry for not being clear enough, the way using the Paint-event does not work. You need to make your own PictureBox-class (derive from PictureBox) and override the OnPaint-method. Then you can call ScaleTransform on the Graphics-object the PictureBox uses. I got a tested sample for you:
public class PictureBoxScaleable : PictureBox
{
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.ScaleTransform(.2f, .2f);
base.OnPaint(pe);
}
}
I'm experiencing a discrepancy between a GraphicsPath drawn in World coordinates on a UserControl and the results of GraphicsPath.IsVisible() to Hit Test the shape with the mouse.
I performed a little test that made a map of where IsVisible() returned true, relative to the GraphicsPath shape that was drawn. The results show a very "low resolution" version of the shape I'm drawing.
Link to shared Google Drive image showing the results:
http://goo.gl/zd6xiM
Is there something I'm doing or not doing correctly that's causing this?
Thanks!
Here's the majority of my OnMouseMove() event handler:
protected override void OnMouseMove(MouseEventArgs e)
{
//base.OnMouseMove(e);
debugPixel = Point.Empty;
PointF worldPosition = ScreenToWorld(PointToClient(Cursor.Position));
if (_mouseStart == Point.Empty) // Just moving mouse around, no buttons pressed
{
_objectUnderMouse = null;
// Hit test mouse position against each canvas object to see if we're overtop of anything
for (int index = 0; index < _canvasObjects.Count; index++) // Uses front to back order
{
NPCanvasObject canvasObject = _canvasObjects[index];
if (canvasObject is NPCanvasPart)
{
NPCanvasPart canvasPart = (canvasObject as NPCanvasPart);
NPPart part = canvasPart.Part;
GraphicsPath gp = canvasPart.GraphicsPath;
// Set the object under the mouse cursor, and move it to the "front" so it draws on top of everythign else
if (gp.IsVisible(worldPosition))
{
// DEBUG
debugPixel.X = e.X;
debugPixel.Y = e.Y;
_objectUnderMouse = canvasObject;
_canvasObjects.MoveItemAtIndexToFront(_canvasObjects.IndexOf(canvasObject));
break; // Since we're modifying the collection we're iterating through, we can't reliably continue past this point
}
}
}
}
else
{
...
}
}
Later in my drawing code I draw a pixel whenever debugPixel != Point.Empty . I temporarily suppressed clearing before drawing so I could see them all.
Some other info that may be asked, or could be helpful to troubleshoot:
I've tried different Graphics.InterpolationMode settings but that doesn't seem to have any effect
I've applied a TranslateTransform and ScaleTransform to the main drawing Graphics but the underlying HitTest map seems to scale and translate equal to the GraphicsPath
For my main drawing canvas, Graphics.PageUnit = GraphicsUnit.Inch, except when I'm doing pixel-based overlay stuff
I thought I had researched this thoroughly enough, but apparently not. Shortly after posting this question I did another search with slightly different terms and found this:
http://vbcity.com/forums/t/72877.aspx
...which was enough to clue me in that the GraphicsPath and my main drawing Graphics were not the same. Using the overloaded GraphicsPath.IsVisible(PointF, Graphics) solved this problem very nicely.
Essentially it was trying to check against a very aliased (pixelated) version of my shape that had been scaled to the same size but not smoothed.
I created the logic that crops an image that is contained inside a border that is inside a grid. The grid has many borders, so this grid will have many pictures. The problem is that when I zoom the picture the logic zoomed the picture (which is okay) but when I use the crop logic the AdornerLayer goes outside the border like the picture:
On this image the pic doesn't have zoom, so the AdornerLayer is correct:
The code that I'm using to add the crop to the image:
private void AddCropToElement(FrameworkElement fel, System.Drawing.Image img)
{
if (!cropElements.ContainsKey(Convert.ToString(((Image)fel).Source)))
{
if (_felCur != null)
{
RemoveCropFromCur();
}
rcInterior = new Rect(
fel.ActualWidth * 0.2,
fel.ActualHeight * 0.2,
fel.ActualWidth * 0.6,
fel.ActualHeight * 0.6);
rectMoving = false;
Rect newRect = scaleRect(rcInterior, img);
imgCropMove = img;
AdornerLayer aly = AdornerLayer.GetAdornerLayer(fel);
_clp = new CroppingAdorner(fel, rcInterior);
aly.Add(_clp);
cropElements.Add(Convert.ToString(((Image)fel).Source), fel);
imageCropped = _clp.Crop(new System.Drawing.Bitmap(img), newRect);
_clp.CropChanged += HandleCropChanged;
_felCur = fel;
}
}
In this case the object named fel is the picture that I want to crop and the Border is his parent.
How I can fix the problem of the AdornerLayout that goes outside if the image is zoomed?
Are you using the default Window Adorner or have you created a custom AdornerDecorator around your Border in your XAML?
<AdornerDecorator>
<Border>...</Border>
</AdornerDecorator>
Additionally, if you are applying a zoom factor on your Border, you can add a Binding on your cropping display rectangle to match the Scale on your Border object.
I was nicely supplied a code from Alex M, for painting the background image to a panel but realized that if a PictureBox's BackgroundImage has its Center image property set, the drawn image becomes stretched but not centered. I so far have this code:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(pictureBox1.BackgroundImage,
new Rectangle(pictureBox1.Location, pictureBox1.Size));
}
This draws the background image to the panel but if pictureBox1's background image property is set to CENTER, it does not paint the image in the Center of the Rectangle, but instead stretches the image to fit the rectangle.
The only possible solution I've found is here but I can't make any sense of it.
The reason the image is being stretched is because the second parameter to DrawImage specifies the location and size of where you're drawing the image, and you're specifying the entire area of the picture box, not the area of the image itself.
If you want to center it, try something like this:
private void panel1_Paint(object sender, PaintEventArgs e)
{
var hPadding = (pictureBox1.Width - pictureBox1.BackgroundImage.Width) / 2;
var vPadding = (pictureBox1.Height - pictureBox1.BackgroundImage.Height) / 2;
var imgRect = new Rectangle(pictureBox1.Left + hPadding, pictureBox1.Top + vPadding, pictureBox1.BackgroundImage.Width, pictureBox1.BackgroundImage.Height);
e.Graphics.DrawImage(pictureBox1.BackgroundImage, imgRect);
}
I have a picturebox with a png in it. Yet even when I set the BackColor to Transparent, it is not transparent. Any ideas what might be wrong? :)
Thanks!
I have also faced the problem regarding transparent pictures.
you have to Draw it through code.
See my question A PictureBox Problem
EDIT:
In paint event (Control containing Background Image)
write this
//If added your image in project's resources get from there OR your Image location
Image img = yourNamespace.Properties.Resources.yourPicture;
e.Graphics.DrawImage(img,50,50,100,100);
Your PNG file should also have the transparent background. This is can be done while creating the image(png) files.
You really have to draw it through code. Place a pictureBox on your form, set sizeMode and docking as you like. Then you may fire the following function on the pictureBox's PAINT event:
public void LogoDrawTransparent(PaintEventArgs e)
{
// Create a Bitmap object from an image file.
Image myImg;
Bitmap myBitmap;
try
{
myImg = cls_convertImagesByte.GetImageFromByte(newImg);
myBitmap = new Bitmap(myImg); // #"C:\Temp\imgSwacaa.jpg");
// Get the color of a background pixel.
Color backColor = myBitmap.GetPixel(0, 0); // GetPixel(1, 1);
Color backColorGray = Color.Gray;
Color backColorGrayLight = Color.LightGray;
Color backColorWhiteSmoke = Color.WhiteSmoke;
Color backColorWhite = Color.White;
Color backColorWheat = Color.Wheat;
// Make backColor transparent for myBitmap.
myBitmap.MakeTransparent(backColor);
// OPTIONALLY, you may make any other "suspicious" back color transparent (usually gray, light gray or whitesmoke)
myBitmap.MakeTransparent(backColorGray);
myBitmap.MakeTransparent(backColorGrayLight);
myBitmap.MakeTransparent(backColorWhiteSmoke);
// Draw myBitmap to the screen.
e.Graphics.DrawImage(myBitmap, 0, 0, pictureBox1.Width, pictureBox1.Height); //myBitmap.Width, myBitmap.Height);
}
catch
{
try { pictureBox1.Image = cls_convertImagesByte.GetImageFromByte(newImg); }
catch { } //must do something
}
}
This is my class that is referenced in the above function:
class cls_convertImagesByte
{
public static Image GetImageFromByte(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
public static byte[] GetByteArrayFromImage(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
}
Thanks. chagbert.
From what I learned I can't do it within a windows form, as it doesn't have layers for the images. So guess will have to make it as WPF. :)
How did you create the background? Is that set by setting the Form.BackgroundImage?
If that background (the paper like image) is a container control, the transparency should just work.
However, If you are placing two PictureBox objects on top of eachother this doesn't work. The transparent area takes on the color of its parent object. If you have two PictureBox objects they both will have the Form as their parent. If this is your situation, it can be solved by setting the transparent image's Parent property to be the background image.
private void Form1_Load(object sender, EventArgs e)
{
transparentPictureBox.Parent = backgroundPictureBox;
}
When changing the Parent property, the Location of the tranparentPictureBox will become relative to its new parent. You'd have to subtract the x and y coordinates of the background image from the transparent image. See my answer on A PictureBox Question for an example with a screen shot.
AFAIK, you can not set the Parent in the Designer, only in code. Therefore, the Designer will still not show a transparent image, but at runtime it should.
The same problem occurs if you place a transparent Label on top of a PictureBox object.