Using Graphics to load an image and rotate it into a panel - c#

I am trying to use the graphics object to load an image in and then rotate it (either portrait or landscape) and then display it in a panel (not a picture box).
How would I load the graphics in the panel? Also what would be the simplest way to do a landscape or portrait rotation on the graphics object?
GDI must be used to rotate and work with the image, I need a way to get the Graphics object into the panel.

Use the Paint event of the Panel:
private void panel1_Paint(object sender, PaintEventArgs e)
{
int angle = 90;
Graphics g = e.Graphics;
Image i = new Bitmap(#"C:\Jellyfish.jpg");
g.TranslateTransform((float)i.Width / 2, (float)i.Height / 2);
g.RotateTransform(angle);
g.TranslateTransform(-(float)i.Width / 2, -(float)i.Height / 2);
g.DrawImage(i, new Point(0,0));
}

Since you are talking about a panel and it's C#, I will guess you are referring to WinForms.
You can rotate any Image instance using the RotateFlip method, and you can use an Image as the BackgroundImage of your panel. A working example:
Bitmap bitmap = new Bitmap(#"D:\word.png");
bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
Form form = new Form() { Height = 400, Width = 600 };
Panel p = new Panel() { Height = 400, Width = 600, Left = 0, Top = 0};
form.Controls.Add(p);
p.BackgroundImage = bitmap;
form.Show();

Related

Drawing over image

I'm trying to draw a rectangle over an image, the rectangle is drawn but the image disappears.
My code:
private void button12_Click(object sender, EventArgs e)
{
currentBitmap = (Bitmap)pictureBox1.Image;
Bitmap temp1 = new Bitmap(currentBitmap.Height, currentBitmap.Width);
Bitmap bmap = (Bitmap)temp1.Clone();
Graphics gr = Graphics.FromImage(bmap);
Pen pen = new Pen(Color.Red);
gr.DrawRectangle(pen, 120, 120, 100, 100);
currentBitmap = (Bitmap)bmap.Clone();
pictureBox1.Image = currentBitmap;
}
Put your drawing methods inside the pictureBox1 onPaint Method. Then you call that using
pictureBox1.Paint += picturebox1_OnPaint;
I fixed this.
It was an error on my code which I didnt realize, i was just taking the width and height of the picturebox instead of the image data.
I changed
Bitmap temp1 = new Bitmap(currentBitmap.Height, currentBitmap.Width);
To
Bitmap temp1 = new Bitmap(pictureBox1.Image);
This is likely due to the fact that your image is set in pictureBox1. Try making a new pictureBox to overlay the old one:
pictureBox1 = image itself
pictureBox2 = bitmap
Good luck!

Image doesn't cover the whole PictureBox

I'm creating an image viewer using C# and having a small issue with scaling (zooming) PictureBox.
I have a PictureBox inside a Panel, and I can zoom (scale) an image using the controls at the top left and using mouse wheel just fine. However, at some specific zoom scales, the image doesn't cover the whole PictureBox.
For example, SO logo (100x116 pixels) at 100% and at 200%:
Image at the right is 199x131 pixels, while the PictureBox is 200x132.
I've set the BackColor of the PictureBox to Red to make the issue noticeable.
This doesn't always happen, just at specific zoom levels. Why is that? Am I doing something wrong?
I can set the BackColor of PictureBox to the BackColor of the Panel to give the illusion that the image covers the whole PictureBox, but I rather fix the problem. If I can't, I'll apply the tricky solution.
Relevant code:
float zoom = 1;
Image image = null;
public MainForm(string[] args)
{
InitializeComponent();
image = ImageBox.Image;
this.ImageBox.MouseWheel += ImageBox_MouseWheel;
if (args.Length > 0)
{
LoadImage(args[0]);
}
}
private void ImageBox_Paint(object sender, PaintEventArgs e)
{
// disable interpolation (sharper pixels)
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
// https://msdn.microsoft.com/en-us/library/ms142046(v=vs.110).aspx
e.Graphics.DrawImage(image,
new Rectangle(0, 0, ImageBox.Width, ImageBox.Height),
0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
}
private void LoadImage(string path)
{
image = Image.FromFile(path);
ImageBox.Width = (int)(image.Width * zoom);
ImageBox.Height = (int)(image.Height * zoom);
ImageBox.Image = image;
CenterImage();
}
private void ScaleImage()
{
ImageBox.Image = null;
ImageBox.Width = (int)(image.Width * zoom);
ImageBox.Height = (int)(image.Height * zoom);
ImageBox.Image = image;
CenterImage();
}
I've also created a repository, in case anyone wants to examine the app live.
You need to adjust the rectangle in ImageBox_Paint. Try this:
private void ImageBox_Paint(object sender, PaintEventArgs e)
{
int add = ImageBox.Width / 200;
// disable interpolation (sharper pixels)
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
// https://msdn.microsoft.com/en-us/library/ms142046(v=vs.110).aspx
e.Graphics.DrawImage(image,
new Rectangle(0, 0, ImageBox.Width + add, ImageBox.Height + add),
0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
}
Simply set the SizeMode property of the PictureBox to Zoom. Then adapting the size of the picturebox will automatically make the image stretch to its full size.
You don't even need that Paint event listener; it's inbuilt functionality. Just change the dimensions of the PictureBox to the calculated zoomed dimensions of the image and you're done.

Is it possible to rotate a drawing half-way its definition?

I'm doing some draws that are repetitive, and each of them gives lot of work.
What i need to do is rotate the drawing half-way its definition, something like this:
using (Graphics g = Graphics.FromImage(bmp))
{
//define area do pictureBox e preenche a branco
Brush brush = new SolidBrush(Color.White);
Rectangle area = new Rectangle(0, 0, 520, 520);
g.FillRectangle(brush, area);
//rotate
g.RotateTransform(some angle, some reference point)
//draw some more lines on the top of the rotated previous ones.
}
I tried using g.RotateTransform(90) as there is that function in Winforms, but it didn't change anything. Why??
Any tip?
Edit: if it helps, i only need to rotate fixed angles, 180ยบ
RotateTransform certainly does change the subsequent drawing.
Note that you usually need a TranslateTransform before to set the rotation point. But it 'it didn't change anything' is certainly wrong. Try again! And yes you can rotate (or scale or move) at any point and move/turn it back or completely reset the Graphics object.
And yes, learning about Matrix and MultiplyTransform is also very helpful..
But: You need to understand the Graphics object does not contain any graphic, a common misconception! It is the tool which does the drawing on a Bitmap, most often the surface of a Control. So the rotation will happen but only for the things you draw after:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Rectangle rect = new Rectangle(25, 25, 25, 25);
e.Graphics.TranslateTransform(25, 25);
e.Graphics.FillRectangle(Brushes.Red, rect);
for (int i = 0; i < 15; i++)
{
rect.Inflate(2, 2);
e.Graphics.TranslateTransform(5, 2);
e.Graphics.RotateTransform(2.5f);
e.Graphics.DrawRectangle(Pens.Blue, rect);
}
}
Try this:
use these references:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
I made windows application and put on form1 picturebox then this is the code in form_load:
//Load an image in from a file
Bitmap pImage = new Bitmap(Environment.CurrentDirectory + #"\Image.bmp", true);
//Set our picture box to that image
pictureBox1.Image = (Bitmap)pImage.Clone();
//Store our old image so we can delete it
Image oldImage = pictureBox1.Image;
//Pass in our original image and return a new image rotated 35 degrees right
pictureBox1.Image = RotateImage(pImage, 270);
if (oldImage != null)
{
oldImage.Dispose();
}
Then make static function with parameters of image and rotation angle return the rotated image and call it from form_load as mentioned before :
if (image == null)
{
throw new ArgumentNullException("image");
}
else
{
//create a new empty bitmap to hold rotated image
Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(rotatedBmp);
//move rotation point to center of image
g.TranslateTransform((float)image.Width / 2, (float)image.Height / 2);
//rotate
g.RotateTransform(angle);
//move image back
g.TranslateTransform(-(float)image.Width / 2, -(float)image.Height / 2);
//draw passed in image onto graphics object
g.DrawImage(image, new PointF(0, 0));
return rotatedBmp;
}
You can also use directly the code in form_load by using ready RotateFlipType (Enumeration type) but this with fixed angles like 90,270,.... but the previous method you can use any integer values to rotate the image :
private void Form1_Load(object sender, EventArgs e)
{
//Load an image in from a file
Bitmap pImage = new Bitmap(Environment.CurrentDirectory + #"\Image.bmp", true);
pImage.RotateFlip(RotateFlipType.Rotate90FlipXY);
pictureBox1.Image = pImage;
}

Reveal portions of an image behind another image

I have a PictureBox where I display an image (Let's call it Image1). There's a second image (Image2) which needs to be revealed as the user hovers the Image1 with the mouse. I only need to reveal part of Image2 (a 10X10 pixel size box), not the whole image as the mouse moves.
Both images are BMP.
How can I accomplish this task? I would think using overlays?
I display the Image1 in the picturebox and then I load the Image2 in memory, now I just need to display the portions of the Image2 over Image1 as the mouse moves.
Thank you,
Here is an example:
public Form1()
{
InitializeComponent();
pictureBox1.Image = Bitmap.FromFile(your1stImage);
bmp = (Bitmap)Bitmap.FromFile(your2ndImage);
pb2.Parent = pictureBox1;
pb2.Size = new Size(10,10);
/* this is for fun only: It restricts the overlay to a circle:
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(pb2.ClientRectangle);
pb2.Region = new Region(gp);
*/
}
Bitmap bmp;
PictureBox pb2 = new PictureBox();
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Rectangle rDest= pb2.ClientRectangle;
Point tLocation = new Point(e.Location.X - rDest.Width - 5,
e.Location.Y - rDest.Height - 5);
Rectangle rSrc= new Rectangle(tLocation, pb2.ClientSize);
using (Graphics G = pb2.CreateGraphics() )
{
G.DrawImage(bmp, rDest, rSrc, GraphicsUnit.Pixel);
}
pb2.Location = tLocation;
}
It uses offsets the overly to the top left of the Cursor adding a little for smooth movement..

C# : GDI+ Image cropping

I have an image .I want to crop 10 px from left and 10px from right of the image.I used the below code to do so
string oldImagePath="D:\\RD\\dotnet\\Images\\photo1.jpg";
Bitmap myOriginalImage = (Bitmap)Bitmap.FromFile(oldImagePath);
int newWidth = myOriginalImage.Width;
int newHeight = myOriginalImage.Height;
Rectangle cropArea = new Rectangle(10,0, newWidth-10, newHeight);
Bitmap target = new Bitmap(cropArea.Width, cropArea.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(myOriginalImage,cropArea);
}
target.Save("D:\\RD\\dotnet\\Images\\test.jpg");
But this is not giving me the results which i expect. This outputs an image which has 10 px cropped from the right and a resized image.Instead of cropiing it is resizing the width i think.So the image is shrinked(by width). Can any one correct me ? Thanks in advance
Your new width should be reduced by twice the crop margin, since you'll be chopping off that amount from both sides.
Next, when drawing the image into the new one, draw it at a negative offset. This causes the area that you aren't interested in to be clipped off.
int cropX = 10;
Bitmap target = new Bitmap(myOriginalImage.Width - 2*cropX, myOriginalImage.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(myOriginalImage, -cropX, 0);
}
My guess is this line
Rectangle cropArea = new Rectangle(10,0, newWidth-10, newHeight);
should be
Rectangle cropArea = new Rectangle(10,0, newWidth-20, newHeight);
Set the width of the new rectangle to be 20 less than the original - 10 for each side.
Some indication what result it is giving you would be helpful in confirming this.
Corey Ross is correct. Alternately, you can translate along the negative x axis and render at 0.0, 0.0. Should produce identical results.
using (Graphics g = Graphics.FromImage(target))
{
g.TranslateTransform(-cropX, 0.0f);
g.DrawImage(myOriginalImage, 0.0f, 0.0f);
}
You need to use the overload that has you specify both Destination Rectangle, and Source Rectangle.
Below is an interactive form of this using a picture box on a form. It allows you to drag the image around. I suggest making the picture box 100 x 100 and have a much larger image such as a full screen window you've captured with alt-prtscr.
class Form1 : Form
{
// ...
Image i = new Bitmap(#"C:\Users\jasond\Pictures\foo.bmp");
Point lastLocation = Point.Empty;
Size delta = Size.Empty;
Point drawLocation = Point.Empty;
bool dragging = false;
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!dragging)
{
lastLocation = e.Location;
dragging = true;
}
delta = new Size(lastLocation.X - e.Location.X, lastLocation.Y - e.Location.Y);
lastLocation = e.Location;
if (!delta.IsEmpty)
{
drawLocation.X += delta.Width;
drawLocation.Y += delta.Height;
pictureBox1.Invalidate();
}
}
else
{
dragging = false;
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Rectangle source = new Rectangle(drawLocation,pictureBox1.ClientRectangle.Size);
e.Graphics.DrawImage(i,pictureBox1.ClientRectangle,source, GraphicsUnit.Pixel);
}
//...
Okay, I totally fail at explaining this, but hang on:
The DrawImage function requires the location of the image, as well as it's position. You need a second position for cropping as how the old relates to the new, not vice versa.
That was entirely incomprehensible, but here is the code.
g.DrawImage(myOriginalImage, -cropArea.X, -cropArea.Y);
I hope that explains it more then I did.

Categories

Resources