Similar to Photoshop, where you can type in a ratio or in my case a certain dimention such as 800x600, I want to be able to force a Rectangle
to be a fixed ratio/size when dragging the mouse..
类似于Photoshop,您可以输入一个比例,或者在我的情况下输入一定的尺寸,例如800x600,我希望能够在拖动鼠标时强制Rectangle为固定比率/大小。
At the moment I have this:
目前我有这个:
Which will crop an image using the Rectangle
created from clicking and dragging on the PictureBox
. The bounding box selects the area without any constraints. I want to be able to force the rectangle to be a certain ratio (prefereably from a set resolution) similar to the way Photoshop's cropping tool works.
这将使用通过在PictureBox上单击并拖动创建的矩形来裁剪图像。边界框选择没有任何约束的区域。我希望能够将矩形强制为一定的比例(优选来自设定的分辨率),类似于Photoshop的裁剪工具的工作方式。
My source if anyone needs more detail:
我的来源,如果有人需要更多细节:
Form1.cs
Form1.cs的
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
public partial class Form1 : Form
{
private static string path;
public Form1(string filePath)
{
InitializeComponent();
path = filePath;
}
private Image _originalImage;
private Image _newImage;
private bool _selecting;
private Rectangle _selection;
private void Form1_Load(object sender, System.EventArgs e)
{
pictureBox1.Image = Image.FromFile(path);
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50 || pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
if (pictureBox1.Image.Height > Screen.PrimaryScreen.Bounds.Height - 50)
{
Height = Screen.PrimaryScreen.Bounds.Height - 50;
panel1.Height = Size.Height - statusStrip1.Height - buttonSave.Height - 60;
}
if (pictureBox1.Image.Width > Screen.PrimaryScreen.Bounds.Width - 50)
{
Size = new Size(Screen.PrimaryScreen.Bounds.Width - 50, Screen.PrimaryScreen.Bounds.Height - 50);
panel1.Width = Size.Width - statusStrip1.Height - buttonSave.Height - 60;
}
pictureBox1.Image = pictureBox1.Image.Fit2PictureBox(pictureBox1);
panel1.Size = new Size(pictureBox1.Image.Width, pictureBox1.Image.Height);
}
Size = new Size(panel1.Size.Width + 50, panel1.Size.Height + buttonSave.Height + statusStrip1.Height + 80);
// Create a copy of the original image for later use
_originalImage = pictureBox1.Image.Clone() as Image;
_newImage = pictureBox1.Image.Clone() as Image;
}
private void buttonOrig_Click(object sender, System.EventArgs e)
{
pictureBox1.Image = _originalImage.Clone() as Image;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Starting point of the selection:
if (e.Button == MouseButtons.Left)
{
pictureBox1.Image.Dispose();
pictureBox1.Image = _originalImage.Clone() as Image;
_selecting = true;
_selection = new Rectangle(new Point(e.X, e.Y), new Size());
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
// Update the actual size of the selection:
if (_selecting)
{
_selection.Width = (e.X - _selection.X);
_selection.Height = (e.Y - _selection.Y);
//int nGCD = GetGreatestCommonDivisor(1920, 1080);
//_selection.Width = _selection.Width / nGCD;
//_selection.Height = _selection.Height / nGCD;
int widthRatio = 16;
int heightRatio = 9;
if (_selection.Height * widthRatio <= _selection.Width)
{
_selection.Width = _selection.Height * widthRatio;
}
else if (_selection.Width * heightRatio <= _selection.Width)
{
_selection.Height = _selection.Width * heightRatio;
}
// Redraw the picturebox:
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_selecting && _selection.Height != 0)
{
// Draw a rectangle displaying the current selection
e.Graphics.DrawRectangle(Pens.WhiteSmoke, _selection);
//e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(50, Color.Gray)), 0, pictureBox1.Height - pictureBox1.Image.Height, pictureBox1.Image.Width, pictureBox1.Image.Height);
e.Graphics.SetClip(_selection, CombineMode.Exclude);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Black)), 0, 0, pictureBox1.Width, pictureBox1.Height);
int nGCD = GetGreatestCommonDivisor(_selection.Width, _selection.Height);
string str = string.Format("{0}:{1}", _selection.Width / nGCD, _selection.Height / nGCD);
toolStripStatusLabel1.Text = "Image Size: " + _selection.Width + "x" + _selection.Height + "px. Aspect Ratio: " + str;
}
}
public static int GetGreatestCommonDivisor(int height, int width)
{
return width == 0 ? height : GetGreatestCommonDivisor(width, height % width);
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left &&
_selecting &&
_selection.Size != new Size())
{
// Create cropped image:
_newImage = pictureBox1.Image.Crop(_selection);
_selecting = false;
try
{
// Set new image to the picturebox:
//pictureBox1.Image = _newImage.Fit2PictureBox(pictureBox1);
pictureBox1.Image = _newImage;
//toolStripStatusLabel1.Text = "Image Cropped.";
}
catch (Exception)
{ }
}
else
{
_selecting = false;
}
}
private void buttonResize_Click(object sender, EventArgs e)
{
pictureBox1.Image = ResizeImage(pictureBox1.Image, new Size(800, 600));
int nGCD = GetGreatestCommonDivisor(pictureBox1.Image.Width, pictureBox1.Image.Height);
string str = string.Format("{0}:{1}", pictureBox1.Image.Width / nGCD, pictureBox1.Image.Height / nGCD);
toolStripStatusLabel1.Text = "Image Resized to " + pictureBox1.Image.Width + "x" + pictureBox1.Image.Height + "px. Aspect Ratio: " + str;
}
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 = size.Width / originalWidth;
float percentHeight = size.Height / 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;
}
private void buttonSave_Click(object sender, EventArgs e)
{
string filename = path.Substring(path.LastIndexOf("\\") + 1);
string newPath = path.Substring(0, path.LastIndexOf(".") - 1) + "NEW.png";
toolStripStatusLabel1.Text = "Saving " + filename + " to " + newPath;
pictureBox1.Image.Save(newPath, ImageFormat.Png);
toolStripStatusLabel1.Text = filename + " saved to " + newPath;
}
}
}
Program.cs
Program.cs中
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CropResize
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(args[0]));
}
public static Image SetImageWithinResolution(this Image image, PictureBox pictureBox)
{
//Bitmap bitmap = null;
if (image.Height > Screen.PrimaryScreen.Bounds.Height)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap(image, );
}
if (image.Width > Screen.PrimaryScreen.Bounds.Width)
{
//ActiveForm.Size = new Size(100, 100);
Form.ActiveForm.Size = new Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
image = image.Fit2PictureBox(pictureBox);
//Bitmap bitmap = new Bitmap();
}
return image;
}
public static Image Crop(this Image image, Rectangle selection)
{
Bitmap bmp = image as Bitmap;
try
{
// Check if it is a bitmap:
if (bmp == null)
throw new ArgumentException("No valid bitmap");
// Crop the image:
Bitmap cropBmp = bmp.Clone(selection, bmp.PixelFormat);
// Release the resources:
image.Dispose();
return cropBmp;
}
catch (Exception)
{
return bmp;
}
}
public static Image Fit2PictureBox(this Image image, PictureBox picBox)
{
Bitmap bmp = null;
Graphics g;
// Scale:
double scaleY = (double)image.Width / picBox.Width;
double scaleX = (double)image.Height / picBox.Height;
double scale = scaleY < scaleX ? scaleX : scaleY;
// Create new bitmap:
bmp = new Bitmap(
(int)((double)image.Width / scale),
(int)((double)image.Height / scale));
// Set resolution of the new image:
bmp.SetResolution(
image.HorizontalResolution,
image.VerticalResolution);
// Create graphics:
g = Graphics.FromImage(bmp);
// Set interpolation mode:
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
// Draw the new image:
g.DrawImage(
image,
new Rectangle( // Destination
0, 0,
bmp.Width, bmp.Height),
new Rectangle( // Source
0, 0,
image.Width, image.Height),
GraphicsUnit.Pixel);
// Release the resources of the graphics:
g.Dispose();
// Release the resources of the origin image:
image.Dispose();
return bmp;
}
}
1 个解决方案
#1
1
Maybe this example will help; is shows how to restrict a drawn rectangle to a given ratio:
也许这个例子会有所帮助;显示如何将绘制的矩形限制为给定的比率:
float ratio = 0.33f;
Rectangle setRect()
{
int x = Math.Min(mDown.X, currPt.X);
int y = Math.Min(mDown.Y, currPt.Y);
int w = Math.Max(mDown.X, currPt.X) - x;
int h = Math.Max(mDown.Y, currPt.Y) - y;
if (ratio > 1) h = (int)(1f * w / ratio);
else w = (int)(1f * h * ratio);
return new Rectangle(x, y, w, h);
}
It uses two Points
, one set in the MouseDown
and one updated in the MouseMove
.
它使用两个Point,一个在MouseDown中设置,另一个在MouseMove中更新。
It is up to you to integrate it with you programm; instead of painting all those pixels during MouseMove
I would simply draw a rubberband rectangle on the surface of the control using the Paint
event..
您可以将它与您的程序集成;而不是在MouseMove期间绘制所有这些像素我只是使用Paint事件在控件的表面上绘制一个橡皮带矩形。
If you are scaling things you may want to switch to using all floats
.
如果要缩放内容,可能需要切换到使用所有浮动内容。
#1
1
Maybe this example will help; is shows how to restrict a drawn rectangle to a given ratio:
也许这个例子会有所帮助;显示如何将绘制的矩形限制为给定的比率:
float ratio = 0.33f;
Rectangle setRect()
{
int x = Math.Min(mDown.X, currPt.X);
int y = Math.Min(mDown.Y, currPt.Y);
int w = Math.Max(mDown.X, currPt.X) - x;
int h = Math.Max(mDown.Y, currPt.Y) - y;
if (ratio > 1) h = (int)(1f * w / ratio);
else w = (int)(1f * h * ratio);
return new Rectangle(x, y, w, h);
}
It uses two Points
, one set in the MouseDown
and one updated in the MouseMove
.
它使用两个Point,一个在MouseDown中设置,另一个在MouseMove中更新。
It is up to you to integrate it with you programm; instead of painting all those pixels during MouseMove
I would simply draw a rubberband rectangle on the surface of the control using the Paint
event..
您可以将它与您的程序集成;而不是在MouseMove期间绘制所有这些像素我只是使用Paint事件在控件的表面上绘制一个橡皮带矩形。
If you are scaling things you may want to switch to using all floats
.
如果要缩放内容,可能需要切换到使用所有浮动内容。