free-form crop selection doesn't work properly - c#

I made a program that lets you do a random selection then the selected area to save into a new image, but I got a problem it doesn't work how it's supposed to... I will post my code here so you can have a look:
private List<Point> Points = null;
private bool Selecting = false;
private Bitmap SelectedArea = null;
private void pictureBox5_MouseDown(object sender, MouseEventArgs e)
{
Points = new List<Point>();
Selecting = true;
}
private void pictureBox5_MouseMove(object sender, MouseEventArgs e)
{
if (!Selecting) return;
Points.Add(new Point(e.X, e.Y));
pictureBox5.Invalidate();
}
private void pictureBox5_MouseUp(object sender, MouseEventArgs e)
{
Selecting = false;
// Copy the selected area.
SelectedArea = GetSelectedArea(pictureBox5.Image, Color.Transparent, Points);
SelectedArea.Save(#"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg", ImageFormat.Jpeg);
string filename = #"C:\Users\User\Desktop\Gallery\image" + NumberOfClick.ToString() + "cropped.jpeg";
if(File.Exists(filename))
{
button1.Visible = true;
pictureBox5.Visible = false;
}
}
private void pictureBox5_Paint(object sender, PaintEventArgs e)
{
if ((Points != null) && (Points.Count > 1))
{
using (Pen dashed_pen = new Pen(Color.Black))
{
dashed_pen.DashPattern = new float[] { 5, 5 };
e.Graphics.DrawLines(Pens.White, Points.ToArray());
e.Graphics.DrawLines(dashed_pen, Points.ToArray());
}
}
}
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
// Make a new bitmap that has the background
// color except in the selected area.
Bitmap big_bm = new Bitmap(source);
using (Graphics gr = Graphics.FromImage(big_bm))
{
// Set the background color.
gr.Clear(bg_color);
// Make a brush out of the original image.
using (Brush br = new TextureBrush(source))
{
// Fill the selected area with the brush.
gr.FillPolygon(br, points.ToArray());
// Find the bounds of the selected area.
Rectangle source_rect = GetPointListBounds(points);
// Make a bitmap that only holds the selected area.
Bitmap result = new Bitmap(
source_rect.Width, source_rect.Height);
// Copy the selected area to the result bitmap.
using (Graphics result_gr = Graphics.FromImage(result))
{
Rectangle dest_rect = new Rectangle(0, 0,
source_rect.Width, source_rect.Height);
result_gr.DrawImage(big_bm, dest_rect,
source_rect, GraphicsUnit.Pixel);
}
// Return the result.
return result;
}
}
}
private Rectangle GetPointListBounds(List<Point> points)
{
int xmin = points[0].X;
int xmax = xmin;
int ymin = points[0].Y;
int ymax = ymin;
for (int i = 1; i < points.Count; i++)
{
if (xmin > points[i].X) xmin = points[i].X;
if (xmax < points[i].X) xmax = points[i].X;
if (ymin > points[i].Y) ymin = points[i].Y;
if (ymax < points[i].Y) ymax = points[i].Y;
}
return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin);
}
This is how I am doing and saving the cropped images.
And also this is how I am uploading the pictures:
OpenFileDialog f = new OpenFileDialog();
f.Filter = "Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png) | *.jpg; *.jpeg; *.jpe; *.jfif; *.png";
if (f.ShowDialog() == DialogResult.OK)
{
currentImage = Image.FromFile(f.FileName);
pictureBox1.Image = currentImage;
}
pictureBox1.Image.Save(#"C:\Users\User\Desktop\Gallery\image1.jpeg", ImageFormat.Jpeg);
DialogResult result = MessageBox.Show("Crop your image", "Information", MessageBoxButtons.OK);
if(result == DialogResult.OK)
{
pictureBox5.Visible = true;
button1.Visible = false;
pictureBox5.Image = pictureBox1.Image;
}
In pictureBox5 I am selecting and cropping the picture.
mySelection
croppedImage

You need to calculate the zoom and the offset of the image when it is zoomed.
Here is how to do that; this assumes the PictureBox is indeed in Zoom mode, not in Stretch mode. If you stretch it you need to calculate the zooms for x and y separately..
SizeF sp = pictureBox5.ClientSize;
SizeF si = pictureBox5.Image.Size;
float rp = sp.Width / sp.Height; // calculate the ratios of
float ri = si.Width / si.Height; // pbox and image
float zoom = (rp > ri) ? sp.Height / si.Height : sp.Width / si.Width;
float offx = (rp > ri) ? (sp.Width - si.Width * zoom) / 2 : 0;
float offy = (rp <= ri)? (sp.Height - si.Height * zoom) / 2 : 0;
Point offset = Point.Round(new PointF(offx, offy));
You calculate this after setting the Image and after resizing the PictureBox..
Now you can transform each drawn point into a zoomed or an unzoomed coordinate:
PointF zoomed(Point p1, float zoom, Point offset)
{
return (new PointF(p1.X * zoom + offset.X, p1.Y * zoom + offset.Y));
}
PointF unZoomed(Point p1, float zoom, Point offset)
{
return (new PointF((p1.X - offset.X) / zoom, (p1.Y - offset.Y) / zoom));
}
Here is a demo the draws on to either a normal (left) or a zoomed in (middle) image. To the right is the result of placing your GetSelectedArea bitmap onto a PictureBox with a checkerbox background:
Case 1: If you store the points as they come in: In your GetSelectedArea method use this point list instead:
private Bitmap GetSelectedArea(Image source, Color bg_color, List<Point> points)
{
var unzoomedPoints =
points.Select(x => Point.Round((unZoomed(Point.Round(x), zoom, offset))))
.ToList();
// Make a new bitmap that has the background
After this replace each reference to points in the method by one to unzoomedPoints. Actually there are just two of them..
Case 2: If you store the points already 'unZoomed' :
Points.Add(unZoomed(e.Location, zoom, offset));
you can use the list directly..

Related

zoom an image in a second picturebox following cursor

i have a picturebox that contain an image (1280 X 720), i want to create a second picturebox that contain a zoomed version of the image centered around the cursor (for example a 40 X 40 square around the cursor zomed to be in a 120 X 120 square picturebox) that follow the cursor in real time in real time (if it's possible also to have a cross in the middle of the picturebox that show the precise placing of the cursor is even better).
private void Button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "All jpg files (*.jpg)|*.jpg";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
Bitmap img = new Bitmap(openFileDialog1.FileName);
double imageHeight = img.Height;
double imageWidth = img.Width;
pictureBox1.Image = img;
}
}
private void PictureBox1_MouseMove(object sender, MouseEventArgs e)
{
int xupleft = e.X - 20;
int yupleft = e.Y - 20;
Rectangle myrectangle = new Rectangle(xupleft, yupleft, 40, 40);
pictureBox2.Image = pictureBox1.Image;
}
Here is a simple example with the layout I described in the comment:
Both PictureBoxes are nested in Panels.
The first one is in Zoom mode and upon loading a file its size is adapted to avoid blank stripes to the sides. Its parent panel is used to reset to the maximum allowed size.
The 2nd one is in AutoSize mode and its parent panel is used to 1) hide the outer portions and 2) to calculate the offset to center the image.
Here is the simple Paint event for pbox1:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Size sz = pictureBox1.ClientSize;
Point pt = pictureBox1.PointToClient(Control.MousePosition);
e.Graphics.DrawLine(Pens.OrangeRed, pt.X, 0, pt.X, sz.Height);
e.Graphics.DrawLine(Pens.OrangeRed, 0, pt.Y, sz.Width, pt.Y);
}
Here is the MouseMove the triggers the Paint and moves pbox2:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
pictureBox1.Invalidate();
float f = 1f * pictureBox2.ClientSize.Width / pictureBox1.ClientSize.Width;
Size s2 = pictureBox2.Parent.ClientSize;
Point p2 = Point.Round(new PointF(s2.Width/2 - e.X * f , s2.Height/2 - e.Y * f ));
pictureBox2.Location = p2;
}
The file loading is a bit tricky, as it needs to analyze the aspect ratios of image and pbox:
void loadFile(string fileName)
{
if (File.Exists(fileName))
{
pictureBox1.Size = panel1.ClientSize;
pictureBox1.Location = Point.Empty;
pictureBox1.Image = Image.FromFile(fileName);
pictureBox2.Image = Image.FromFile(fileName);
pictureBox2.Location = Point.Empty;
}
Size csz = pictureBox1.ClientSize;
Size isz = pictureBox1.Image.Size;
float iar = 1f * isz.Width / isz.Height; // aspect..
float car = 1f * csz.Width / csz.Height; //..ratios
if (iar < car)
{
pictureBox1.ClientSize = new Size((int)(pictureBox1.ClientSize.Height * iar),
pictureBox1.ClientSize.Height);
}
else if (iar > car)
{
pictureBox1.ClientSize = new Size((pictureBox1.ClientSize.Width,
(int)(pictureBox1.ClientSize.Width / iar));
}
}
Note that before loading the new images one should Dispose of the previous images! Also that after setting the pbox2.SizeMode to Autosize one could set it to Zoom and scale its Size up or down to zoom in or out, if one keeps the aspect ratio the same.
Result:

pictureBox zoom onpaint only applying to rectangle

I am trying to understand the complex GDI module.
Below, I have some code that allows the user to zoom in and out on pictureBox but it is only doing it to the rectangle. It only works if the mouse is over the small rectangle drawn by GDI. How you please show me how to apply this effect to the actual image loaded in the pictureBox? These images have resolutions upwards of 7200 x 4800.
Here's the code.
private Matrix transform = new Matrix();
private float m_dZoomscale = 1.0f;
public const float s_dScrollValue = 0.1f;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Image image;
// open file dialog
OpenFileDialog open = new OpenFileDialog();
// image filters
open.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp; *.tiff)|*.jpg; *.jpeg; *.gif; *.bmp; *.tiff";
if (open.ShowDialog() == DialogResult.OK)
{
image = Image.FromFile(open.FileName);
pictureBox1.Height = image.Height;
pictureBox1.Width = image.Width;
pictureBox1.Image = image;
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Transform = transform;
Pen mypen = new Pen(Color.Red, 5);
Rectangle rect = new Rectangle(10, 10, 30, 30);
e.Graphics.DrawRectangle(mypen, rect);
}
protected override void OnMouseWheel(MouseEventArgs mea)
{
pictureBox1.Focus();
if (pictureBox1.Focused == true && mea.Delta != 0)
{
// Map the Form-centric mouse location to the PictureBox client coordinate system
Point pictureBoxPoint = pictureBox1.PointToClient(this.PointToScreen(mea.Location));
ZoomScroll(pictureBoxPoint, mea.Delta > 0);
}
}
private void ZoomScroll(Point location, bool zoomIn)
{
// Figure out what the new scale will be. Ensure the scale factor remains between
// 1% and 1000%
float newScale = Math.Min(Math.Max(m_dZoomscale + (zoomIn ? s_dScrollValue : -s_dScrollValue), 0.1f), 10);
if (newScale != m_dZoomscale)
{
float adjust = newScale / m_dZoomscale;
m_dZoomscale = newScale;
// Translate mouse point to origin
transform.Translate(-location.X, -location.Y, MatrixOrder.Append);
// Scale view
transform.Scale(adjust, adjust, MatrixOrder.Append);
// Translate origin back to original mouse point.
transform.Translate(location.X, location.Y, MatrixOrder.Append);
pictureBox1.Invalidate();
}
}

Why when i create the bitmap it's empty all white?

private Bitmap CropImage()
{
Bitmap pic = pictureBoxSnap.Image as Bitmap;
Bitmap cropped = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(cropped))
{
g.DrawImage(pic, new Rectangle(0, 0, rect.Width, rect.Height),
rect, GraphicsUnit.Pixel);
}
pic.Save(#"c:\temp\testingitimage.jpg");
cropped.Save(#"c:\temp\testingitimage1.bmp");
return cropped;
}
I added this two lines of Save to test what i get. The first one pic i see the correct image that is in the pictureBox.
But the second one cropped is all white and empty.
And i call this method from the pictureBox paint event:
private void pictureBoxSnap_Paint(object sender, PaintEventArgs e)
{
if (pictureBoxSnap.Image != null)
{
{
if (ClearGraphics == false)
{
if (cropRect == false)
{
if (rectangles[listBoxSnap.SelectedIndex] != Rectangle.Empty)
{
e.Graphics.DrawRectangle(Pens.Firebrick, rectangles[listBoxSnap.SelectedIndex]);
}
}
else
{
if (rect.Width > 10 && rect.Height > 10)
{
e.Graphics.DrawRectangle(Pens.Gray, rect);
pictureBoxSnap.Image = CropImage();
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");
}
}
}
}
}
}
I used a breakpoint on the: e.Graphics.DrawRectangle(Pens.Gray, rect); and rect is not empty ( rect is Rectangle i draw on the pictureBox then when i click on a button it's making validate for the pictureBox).
I also did a save here too and testimageing i see it black on the hard disk but when i edit it with Paint i see it's white empty.
For exmaple when i draw a rectangle on the pictureBox then i use a breakpoint in the CropImage method i see that the variable rect is for example: X = 136 Y = 149 Width = 131 Height = 106
Also in the paint event this rect variable have the same values.
And the pictureBox size is: 640x480
And the pictureBox property SizeMode is set to: zoom
Wo why i get empty white image ? And not the cropped rectangle with the part of the image inside ?
EDIT:
This is the code im using now:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using DannyGeneral;
using System.Diagnostics;
namespace MinimizeCapture
{
public partial class Form1 : Form
{
Boolean bHaveMouse;
Point ptOriginal = new Point();
Point ptLast = new Point();
bool cropRect;
Bitmap cloneBitmap;
Rectangle recttest;
private Rectangle Rect;
private Rectangle[] rectangles;
private Rectangle RectClone;
private bool btn = false;
private Point RectStartPoint = Point.Empty;
private Point RectEndPoint = Point.Empty;
private Brush selectionBrush = new SolidBrush(Color.Red);
private Pen pen;
private string selectedIndex;
private List<string> drawnItems = new List<string>();
private bool ClearGraphics;
public Form1()
{
InitializeComponent();
cropRect = false;
var windows = OpenWindowGetter.FindWindowsWithText();
ClearGraphics = false;
this.DoubleBuffered = true;
btn = false;
pen = new Pen(selectionBrush);
buttonSnap.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void buttonSnap_Click(object sender, EventArgs e)
{
ClearGraphics = true;
this.listBoxSnap.Items.Clear();
this.pictureBoxSnap.Image = null;
backgroundWorker1.RunWorkerAsync();
}
private void listBoxSnap_SelectedIndexChanged(object sender, EventArgs e)
{
WindowSnap snap = this.listBoxSnap.SelectedItem as WindowSnap;
selectedIndex = this.listBoxSnap.SelectedIndex.ToString();
this.pictureBoxSnap.Image = snap.Image;
for (int i = 0; i < rectangles.Length; i++)
{
if (rectangles[i] != RectClone)
{
ClearGraphics = false;
}
else
{
ClearGraphics = true;
}
}
}
private void checkBoxForceMDI_CheckedChanged(object sender, EventArgs e)
{
WindowSnap.ForceMDICapturing = (sender as CheckBox).Checked;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.Add("Minimized Windows"); }));
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true,true).ToArray()); }));
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
rectangles = new Rectangle[listBoxSnap.Items.Count];
buttonSnap.Enabled = true;
}
private void pictureBoxSnap_Paint(object sender, PaintEventArgs e)
{
if (pictureBoxSnap.Image != null)
{
{
if (ClearGraphics == false)
{
if (rectangles[listBoxSnap.SelectedIndex] != Rectangle.Empty)
{
e.Graphics.DrawRectangle(Pens.Firebrick, rectangles[listBoxSnap.SelectedIndex]);
}
}
if (cropRect == true)
{
if (recttest.Width > 10 && recttest.Height > 10)
{
//e.Graphics.DrawRectangle(Pens.Gray, recttest);
e.Graphics.Clear(Color.White);
/*pictureBoxSnap.Image = CropImage();
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");*/
}
}
}
}
}
private void pictureBoxSnap_MouseMove(object sender, MouseEventArgs e)
{
if (btn == true)
{
ClearGraphics = false;
RectEndPoint = e.Location;
int currentindex = listBoxSnap.SelectedIndex;
rectangles[currentindex] = RectClone;
Rect = getRect(RectStartPoint, RectEndPoint);
RectClone = Rect;
pictureBoxSnap.Invalidate();
}
Point ptCurrent = new Point(e.X, e.Y);
// If we "have the mouse", then we draw our lines.
if (bHaveMouse)
{
// If we have drawn previously, draw again in
// that spot to remove the lines.
if (ptLast.X != -1)
{
MyDrawReversibleRectangle(ptOriginal, ptLast);
}
// Update last point.
ptLast = ptCurrent;
// Draw new lines.
MyDrawReversibleRectangle(ptOriginal, ptCurrent);
}
}
private void pictureBoxSnap_MouseDown(object sender, MouseEventArgs e)
{
RectStartPoint = e.Location;
btn = true;
Rect = Rectangle.Empty;
RectClone = Rectangle.Empty;
bHaveMouse = true;
// Store the "starting point" for this rubber-band rectangle.
ptOriginal.X = e.X;
ptOriginal.Y = e.Y;
// Special value lets us know that no previous
// rectangle needs to be erased.
ptLast.X = -1;
ptLast.Y = -1;
}
private void pictureBoxSnap_MouseUp(object sender, MouseEventArgs e)
{
recttest = rectangles[listBoxSnap.SelectedIndex];
ClearGraphics = false;
btn = false;
RectEndPoint = e.Location;
pictureBoxSnap.Invalidate();
int currentindex = listBoxSnap.SelectedIndex;
rectangles[currentindex] = RectClone;
// Set internal flag to know we no longer "have the mouse".
bHaveMouse = false;
// If we have drawn previously, draw again in that spot
// to remove the lines.
if (ptLast.X != -1)
{
Point ptCurrent = new Point(e.X, e.Y);
MyDrawReversibleRectangle(ptOriginal, ptLast);
}
// Set flags to know that there is no "previous" line to reverse.
ptLast.X = -1;
ptLast.Y = -1;
ptOriginal.X = -1;
ptOriginal.Y = -1;
pictureBoxSnap.Invalidate();
}
Rectangle getRect(Point p1, Point p2)
{
Point p = new Point(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y));
Size s = new Size(Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y));
return new Rectangle(p, s);
}
private void ConfirmRectangle_Click(object sender, EventArgs e)
{
ConfirmRectangle.ForeColor = Color.Red;
ConfirmRectangle.Enabled = false;
StreamWriter w = new StreamWriter(#"c:\temp\Settings.txt", true);
w.WriteLine("Rectangle Location: " + RectClone.Location + " Rectangle Size: " + RectClone.Size + " Selected Index: " + selectedIndex);
textBoxIndex.Text = selectedIndex.ToString();
w.Close();
cropRect = false;
//pictureBoxSnap.Invalidate();
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");
pictureBoxSnap.Image = img;
}
// Convert and normalize the points and draw the reversible frame.
private void MyDrawReversibleRectangle(Point p1, Point p2)
{
Rectangle rc = new Rectangle();
// Convert the points to screen coordinates.
p1 = pictureBoxSnap.PointToScreen(p1);
p2 = pictureBoxSnap.PointToScreen(p2);
// Normalize the rectangle.
if (p1.X < p2.X)
{
rc.X = p1.X;
rc.Width = p2.X - p1.X;
}
else
{
rc.X = p2.X;
rc.Width = p1.X - p2.X;
}
if (p1.Y < p2.Y)
{
rc.Y = p1.Y;
rc.Height = p2.Y - p1.Y;
}
else
{
rc.Y = p2.Y;
rc.Height = p1.Y - p2.Y;
}
// Draw the reversible frame.
rect = new Rectangle(pictureBoxSnap.PointToClient(rc.Location), rc.Size);
ControlPaint.DrawReversibleFrame(rc, Color.Gray, FrameStyle.Dashed);
}
Rectangle rect = Rectangle.Empty;
private Bitmap CropImage()
{
//rect = recttest;
Bitmap pic = pictureBoxSnap.Image as Bitmap;
Bitmap cropped = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(cropped))
{
g.DrawImage(pic, new Rectangle(0, 0, rect.Width, rect.Height),
rect, GraphicsUnit.Pixel);
}
pic.Save(#"c:\temp\testingitimage.jpg");
cropped.Save(#"c:\temp\testingitimage1.bmp");
return cropped;
}
}
}
Moved the CropImage call method from the paint and added it to the button click here:
private void ConfirmRectangle_Click(object sender, EventArgs e)
{
ConfirmRectangle.ForeColor = Color.Red;
ConfirmRectangle.Enabled = false;
StreamWriter w = new StreamWriter(#"c:\temp\Settings.txt", true);
w.WriteLine("Rectangle Location: " + RectClone.Location + " Rectangle Size: " + RectClone.Size + " Selected Index: " + selectedIndex);
textBoxIndex.Text = selectedIndex.ToString();
w.Close();
cropRect = false;
//pictureBoxSnap.Invalidate();
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");
pictureBoxSnap.Image = img;
}
This lines:
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");
pictureBoxSnap.Image = img;
But what i get in the pictureBox is this:
Not sure why. The rectangle is in the position i drawed it's ok but instead showing the part of the original image cut in the rectangle it's doing like zoom in.
You are cropping multiple times.
pictureBoxSnap.Image = CropImage(); // First Time
Image img = CropImage(); // Second Time
img.Save(#"c:\temp\testimageing.jpg");
You just need to crop once. Here you are using same picturebox for source and for cropped image. first time when you crop then image. the cropped image will be set correctly to the picturebox. but, second time application will try to crop that image again.
You should do like this
Image img = CropImage();
img.Save(#"c:\temp\testimageing.jpg");
pictureBoxSnap.Image = img;
private Bitmap CropImage(){
Bitmap pic = pictureBoxSnap.Image as Bitmap;
Bitmap cropped = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(cropped)){
g.DrawImage(pic, new Rectangle(0, 0, rect.Width, rect.Height),
rect, GraphicsUnit.Pixel);
}
using (Graphics g = Graphics.FromImage(pic)){
g.DrawImage(cropped , 136, 149, rect.Width, rect.Height);
//Draw the rectangle
}
//pic.Save(#"c:\temp\testingitimage.jpg");
//cropped.Save(#"c:\temp\testingitimage1.bmp");
return pic;
}
valter

Drag and Drop move PictureBox- size of image when I'm dragging

I have created a method which move the PictureBox when I Drag and Drop. But when I'm dragging the PictureBox, the image has the real size of image and I wanna that the image has the size of PictureBox
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
picBox = (PictureBox)sender;
var dragImage = (Bitmap)picBox.Image;
IntPtr icon = dragImage.GetHicon();
Cursor.Current = new Cursor(icon);
DoDragDrop(pictureBox1.Image, DragDropEffects.Copy);
DestroyIcon(icon);
}
}
protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
{
e.UseDefaultCursors = false;
}
protected override void OnDragEnter(DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(Bitmap))) e.Effect = DragDropEffects.Copy;
}
protected override void OnDragDrop(DragEventArgs e)
{
picBox.Location = this.PointToClient(new Point(e.X - picBox.Width / 2, e.Y - picBox.Height / 2));
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static bool DestroyIcon(IntPtr handle);
Use
var dragImage = new Bitmap((Bitmap)picBox.Image, picBox.Size);
instead of
var dragImage = (Bitmap)picBox.Image;
(and maybe call Dispose on the temporary image later, but the GC will deal with it if you don't)
This is because the image in your picture box is the full size image. The picture box just scales it for display purposes but the Image property has the original-sized image.
So, in your MouseDown event handler you want to resize the image before using it.
Rather than:
var dragImage = (Bitmap)picBox.Image;
Try:
var dragImage = ResizeImage(picBox.Image, new Size(picBox.Width, PicBox.Height));
Use something like this method to resize the image for you:
public static Image ResizeImage(Image image, Size size,
bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
*Image resize code from here: http://www.codeproject.com/Articles/191424/Resizing-an-Image-On-The-Fly-using-NET

Im trying to save now the image inside the pictureBox1 to my hard disk but its saving it without the rectangle inside the pictureBox1 why?

if (ImagesComparion1.ImageComparison(File1, file2, image_scan_text_rect) == true)
{
/* Logger.Write("File1 is >>>> " + combinedTemp);
// Logger.Write("File2 is >>>> " + fi.FullName);
Logger.Write("Last File is >>>> " + last_file);
Logger.Write("image_scan_text_rect values are >>>>> " + image_scan_text_rect.ToString());
Logger.Write("ImagesComparion1.ImageComparison(File1, file2, image_scan_text_rect) is now true");*/
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
pictureBox1.Load(last_file);
File1.Dispose();
Properties.Resources.RadarImageClose.Dispose();
label18.Text = "The Radar Is Not Active Now";
label18.Visible = true;
if (paintDemoMode == true)
{
Bitmap bmp = new Bitmap(combinedTemp);
Bitmap bb = new Bitmap(bmp);
bmp.Dispose();
bmp = null;
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = null;
}
pictureBox1.Image = bb;
image_scan_text_rect = new Rectangle(25, 240, 341, 39);
float x = ((float)image_scan_text_rect.X / bb.Width) * (float)this.pictureBox1.Width;
//float y = ((float)Rect.Y / this.pictureBox1.ClientSize.Height) * (float)FirstImage.Height;
float y = ((float)image_scan_text_rect.Y / bb.Height) * (float)this.pictureBox1.Height;
//float newRight = ((float)Rect.Right / (float)pictureBox1.ClientSize.Width) * ((float)FirstImage.Width);
float newRight = ((float)image_scan_text_rect.Right / bb.Width) * (float)pictureBox1.Width;
//float newBottom = ((float)Rect.Bottom / (float)pictureBox1.ClientSize.Height) * ((float)FirstImage.Height);
float newBottom = ((float)image_scan_text_rect.Bottom / bb.Height) * (float)pictureBox1.Height;
rectToDrawOut = new RectangleF(x, y, newRight - x, newBottom - y);
pictureBox1.Image.Save(#"d:\testit.png", System.Drawing.Imaging.ImageFormat.Png);
}
return;
}
When i click a button and paintDemoMode is true then its showing this rectToDrawOut as rectangle on the pictureBox1
Now i want to save to my hard disk the image show now in the pictureBox1 including the rectangle.
But its aving just the image from the pictureBox1 without the rectangle. I tried also instead pictureBox1.Image.Save i tried bb.Save but again it didnt save the rectangle. whats wrong here ?
In the pictureBox1_Paint event im drawing the rectangle if its needed this is the code:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Red, 2))
{
if (paintDemoButtonSwitch == true)
{
e.Graphics.DrawRectangle(pen, rectToDrawOut.X, rectToDrawOut.Y, rectToDrawOut.Width, rectToDrawOut.Height);
}
}
}
Thanks for helping.
You are drawing the rectangle on the screen where the bitmap just have been drawn by the regular Paint event of the control. That doesn't affect the bitmap.
You can use the DrawToBitmap method to render the control to a bitmap. That will include the rectangle, and it will also include any scaling/cropping that the control does when it renders the image:
using (Bitmap b = new Bitmap(pictureBox1.Width, pictureBox1.Height)) {
pictureBox1.DrawToBitmap(b, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
b.Save(#"d:\testit.png", System.Drawing.Imaging.ImageFormat.Png);
}
It's because you don't change the Image, you change the output to the screen. You need to create a graphics object from the image with
Graphics g = Graphics.FromImage(pictureBox1.Image);
If you add a rectangle with that graphics object it should work.
Edit:
Replace the line where you save the image with this:
Graphics g = Graphics.FromImage(pictureBox1.Image);
using (Pen pen = new Pen(Color.Red, 2))
{
if (paintDemoButtonSwitch == true)
{
g.DrawRectangle(pen, rectToDrawOut.X, rectToDrawOut.Y, rectToDrawOut.Width, rectToDrawOut.Height);
}
}
pictureBox1.Image.Save(#"d:\testit.png", System.Drawing.Imaging.ImageFormat.Png);

Categories

Resources