如何放大面板内绘制的图片框矩形?
How zoom into a drawn rectangle of picturebox which is inside a panel?
我在 Panel 中有一个 PictureBox,以便缩放和平移。我创建了 select 4 个点的可能性,单击鼠标并在 PictureBox 上绘制一个矩形。一旦矩形在我的图片上,我将矩形的坐标传递给方法 "cropRectangle"。此方法裁剪矩形并用裁剪后的图像替换旧图像。 这个效果很好:
(OriginalImage为pictureBox中实际图片的位图)
private void cropRectangle(Rectangle rect){
double left = (rect.X) * originalImage.Width / pictureBox.Width,
top = (rect.Y) * originalImage.Width / pictureBox.Height,
right = (rect.Width) * originalImage.Width / pictureBox.Width,
bottom = (rect.Height) * originalImage.Height / pictureBox.Height;
rect = new Rectangle (Convert.ToInt32(left), Convert.ToInt32(top), Convert.ToInt32(right), Convert.ToInt32(bottom));
Bitmap bitmap = orignalImage.Clone(rect, originalImage.PixelFormat);
pictureBox.Image = (Image)bitmap;
centerPictureBox();
// fit image into pictureBox with respect to the ratio
float ratio = orignalImage.Width / orignalImage.Height;
pictureBox.Width = panel.Width;
pictureBox.Height = Convert.ToInt32(pictureBox.Width * ratio);
centerPictureBox();
}
我现在要做的是缩放 selected 区域而不是裁剪它。图片框的矩形必须与面板匹配。
如何通过面板只显示图片框的 selected 区域(矩形)而不裁剪图像?
您应该坚持使用 Graphics
对象修改现有的 Bitmap
,而不是更改 PictureBox 的大小。当所需的功能在其他地方已经可用时,您不希望被绑定到 UI 控件。
以下是实现该目标的粗略步骤:
- 创建一个临时
Bitmap
对象来存储缩放后的图像。 Bitmap tBitmap = new Bitmap(zoomX, zoomY, PixelFormat.Format24bppRgb);
- 当你想缩放时,像你已经做的那样计算缩放因子和东西(我没有检查代码是否正确但我假设它是正确的)。
- 从临时位图中创建一个新的 Graphics 对象。
Graphics graphics = Graphics.FromImage(tBitmap);
- 设置 InterpolationMode 以便以良好的质量缩放图像。
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- 使用DrawImage方法绘制缩放后的图像(使用PictureBox中的原始图像)。
graphics.DrawImage(pictureBox.Image, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height), new Rectangle(/*The crop rectangle you draw already*/), GraphicsUnit.Pixel);
- 将新绘制的位图设置为PictureBox 中的Image。
pictureBox.Image = tBitmap;
- 记得处理我们用来绘图的图形对象。
graphics.Dispose();
- 您可能需要刷新 PictureBox 以强制其重新绘制自身。
pictureBox.Refresh();
这些是要遵循的基本步骤。我没有时间深入研究您现有的代码,因此您可能需要更改一些其他内容才能使其正常工作。
这里还有一篇涵盖相同内容的 MSDN 文章:Cropping and Scaling Images in GDI+
我找到了解决问题的优雅方法:
private void zoomInsideRectangle(Rectangle rect){
float zoomFactor = ((float)panel.Width / rect.Width) - 1;
pictureBox.Width = pictureBox.Width + convertToIntPerfect(pictureBox.Width * zoomFactor);
pictureBox.Height = pictureBox.Height + convertToIntPerfect(pictureBox.Height * zoomFactor);
rect.X = rect.X + convertToIntPerfect(rect.X * zoomFactor);
rect.Y = rect.Y + convertToIntPerfect(rect.Y * zoomFactor);
pictureBox.Left = convertToIntPerfect(-rect.X);
pictureBox.Top = convertToIntPerfect(-rect.Y);
}
因为我知道可以看到图片框的面板的长度。我采用面板的比例和我想要放大的矩形的宽度。这个比例就是我的 zoomratio。
我将图片框的大小乘以我计算出的比率。
我用矩形的坐标将图片框固定在左侧和顶部。但是在这样做之前,我必须将矩形的坐标乘以缩放比例,因为我更改了图片框的大小。
我没有做Y变换,因为图像的原始比例会被破坏。
您可能对这个允许缩放和平移图片框的控件 (ZoomPicBox) 感兴趣。
此代码的所有功劳均归功于 Bob Powell,它取自他的网站(该网站现在似乎已关闭并且已经关闭很长时间了。)。
我在 link:
复制了 archive.org 的代码
https://web.archive.org/web/20080313161349/http://www.bobpowell.net/zoompicbox.htm
link 提供了更多信息,值得一读。该代码也可以在 VB.Net 中找到。
我不知道 Bob Powell 的网站为何关闭,但它是一个提供 Windows 图形信息的好网站。
我觉得这段代码值得重复。可以将此控件拖到窗体上。
namespace bobpowell.net
{
/// <summary>
/// ZoomPicBox does what it says on the wrapper.
/// </summary>
/// <remarks>
/// PictureBox doesn't lend itself well to overriding. Why not start with something basic and do the job properly?
/// </remarks>
public class ZoomPicBox : ScrollableControl
{
Image _image;
[
Category("Appearance"),
Description("The image to be displayed")
]
public Image Image
{
get{return _image;}
set
{
_image=value;
UpdateScaleFactor();
Invalidate();
}
}
float _zoom=1.0f;
[
Category("Appearance"),
Description("The zoom factor. Less than 1 to reduce. More than 1 to magnify.")
]
public float Zoom
{
get{return _zoom;}
set
{
if(value<0 || value<0.00001)
value=0.00001f;
_zoom=value;
UpdateScaleFactor();
Invalidate();
}
}
/// <summary>
/// Calculates the effective size of the image
///after zooming and updates the AutoScrollSize accordingly
/// </summary>
private void UpdateScaleFactor()
{
if(_image==null)
this.AutoScrollMinSize=this.Size;
else
{
this.AutoScrollMinSize=new Size(
(int)(this._image.Width*_zoom+0.5f),
(int)(this._image.Height*_zoom+0.5f)
);
}
}
InterpolationMode _interpolationMode=InterpolationMode.High;
[
Category("Appearance"),
Description("The interpolation mode used to smooth the drawing")
]
public InterpolationMode InterpolationMode
{
get{return _interpolationMode;}
set{_interpolationMode=value;}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing.
}
protected override void OnPaint(PaintEventArgs e)
{
//if no image, don't bother
if(_image==null)
{
base.OnPaintBackground(e);
return;
}
//Set up a zoom matrix
Matrix mx=new Matrix(_zoom,0,0,_zoom,0,0);
//now translate the matrix into position for the scrollbars
mx.Translate(this.AutoScrollPosition.X / _zoom, this.AutoScrollPosition.Y / _zoom);
//use the transform
e.Graphics.Transform=mx;
//and the desired interpolation mode
e.Graphics.InterpolationMode=_interpolationMode;
//Draw the image ignoring the images resolution settings.
e.Graphics.DrawImage(_image,new Rectangle(0,0,this._image.Width,this._image.Height),0,0,_image.Width, _image.Height,GraphicsUnit.Pixel);
base.OnPaint (e);
}
public ZoomPicBox()
{
//Double buffer the control
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true);
this.AutoScroll=true;
}
}
}
我在 Panel 中有一个 PictureBox,以便缩放和平移。我创建了 select 4 个点的可能性,单击鼠标并在 PictureBox 上绘制一个矩形。一旦矩形在我的图片上,我将矩形的坐标传递给方法 "cropRectangle"。此方法裁剪矩形并用裁剪后的图像替换旧图像。 这个效果很好:
(OriginalImage为pictureBox中实际图片的位图)
private void cropRectangle(Rectangle rect){
double left = (rect.X) * originalImage.Width / pictureBox.Width,
top = (rect.Y) * originalImage.Width / pictureBox.Height,
right = (rect.Width) * originalImage.Width / pictureBox.Width,
bottom = (rect.Height) * originalImage.Height / pictureBox.Height;
rect = new Rectangle (Convert.ToInt32(left), Convert.ToInt32(top), Convert.ToInt32(right), Convert.ToInt32(bottom));
Bitmap bitmap = orignalImage.Clone(rect, originalImage.PixelFormat);
pictureBox.Image = (Image)bitmap;
centerPictureBox();
// fit image into pictureBox with respect to the ratio
float ratio = orignalImage.Width / orignalImage.Height;
pictureBox.Width = panel.Width;
pictureBox.Height = Convert.ToInt32(pictureBox.Width * ratio);
centerPictureBox();
}
我现在要做的是缩放 selected 区域而不是裁剪它。图片框的矩形必须与面板匹配。
如何通过面板只显示图片框的 selected 区域(矩形)而不裁剪图像?
您应该坚持使用 Graphics
对象修改现有的 Bitmap
,而不是更改 PictureBox 的大小。当所需的功能在其他地方已经可用时,您不希望被绑定到 UI 控件。
以下是实现该目标的粗略步骤:
- 创建一个临时
Bitmap
对象来存储缩放后的图像。Bitmap tBitmap = new Bitmap(zoomX, zoomY, PixelFormat.Format24bppRgb);
- 当你想缩放时,像你已经做的那样计算缩放因子和东西(我没有检查代码是否正确但我假设它是正确的)。
- 从临时位图中创建一个新的 Graphics 对象。
Graphics graphics = Graphics.FromImage(tBitmap);
- 设置 InterpolationMode 以便以良好的质量缩放图像。
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
- 使用DrawImage方法绘制缩放后的图像(使用PictureBox中的原始图像)。
graphics.DrawImage(pictureBox.Image, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height), new Rectangle(/*The crop rectangle you draw already*/), GraphicsUnit.Pixel);
- 将新绘制的位图设置为PictureBox 中的Image。
pictureBox.Image = tBitmap;
- 记得处理我们用来绘图的图形对象。
graphics.Dispose();
- 您可能需要刷新 PictureBox 以强制其重新绘制自身。
pictureBox.Refresh();
这些是要遵循的基本步骤。我没有时间深入研究您现有的代码,因此您可能需要更改一些其他内容才能使其正常工作。
这里还有一篇涵盖相同内容的 MSDN 文章:Cropping and Scaling Images in GDI+
我找到了解决问题的优雅方法:
private void zoomInsideRectangle(Rectangle rect){
float zoomFactor = ((float)panel.Width / rect.Width) - 1;
pictureBox.Width = pictureBox.Width + convertToIntPerfect(pictureBox.Width * zoomFactor);
pictureBox.Height = pictureBox.Height + convertToIntPerfect(pictureBox.Height * zoomFactor);
rect.X = rect.X + convertToIntPerfect(rect.X * zoomFactor);
rect.Y = rect.Y + convertToIntPerfect(rect.Y * zoomFactor);
pictureBox.Left = convertToIntPerfect(-rect.X);
pictureBox.Top = convertToIntPerfect(-rect.Y);
}
因为我知道可以看到图片框的面板的长度。我采用面板的比例和我想要放大的矩形的宽度。这个比例就是我的 zoomratio。
我将图片框的大小乘以我计算出的比率。
我用矩形的坐标将图片框固定在左侧和顶部。但是在这样做之前,我必须将矩形的坐标乘以缩放比例,因为我更改了图片框的大小。
我没有做Y变换,因为图像的原始比例会被破坏。
您可能对这个允许缩放和平移图片框的控件 (ZoomPicBox) 感兴趣。
此代码的所有功劳均归功于 Bob Powell,它取自他的网站(该网站现在似乎已关闭并且已经关闭很长时间了。)。
我在 link:
复制了 archive.org 的代码https://web.archive.org/web/20080313161349/http://www.bobpowell.net/zoompicbox.htm
link 提供了更多信息,值得一读。该代码也可以在 VB.Net 中找到。
我不知道 Bob Powell 的网站为何关闭,但它是一个提供 Windows 图形信息的好网站。
我觉得这段代码值得重复。可以将此控件拖到窗体上。
namespace bobpowell.net
{
/// <summary>
/// ZoomPicBox does what it says on the wrapper.
/// </summary>
/// <remarks>
/// PictureBox doesn't lend itself well to overriding. Why not start with something basic and do the job properly?
/// </remarks>
public class ZoomPicBox : ScrollableControl
{
Image _image;
[
Category("Appearance"),
Description("The image to be displayed")
]
public Image Image
{
get{return _image;}
set
{
_image=value;
UpdateScaleFactor();
Invalidate();
}
}
float _zoom=1.0f;
[
Category("Appearance"),
Description("The zoom factor. Less than 1 to reduce. More than 1 to magnify.")
]
public float Zoom
{
get{return _zoom;}
set
{
if(value<0 || value<0.00001)
value=0.00001f;
_zoom=value;
UpdateScaleFactor();
Invalidate();
}
}
/// <summary>
/// Calculates the effective size of the image
///after zooming and updates the AutoScrollSize accordingly
/// </summary>
private void UpdateScaleFactor()
{
if(_image==null)
this.AutoScrollMinSize=this.Size;
else
{
this.AutoScrollMinSize=new Size(
(int)(this._image.Width*_zoom+0.5f),
(int)(this._image.Height*_zoom+0.5f)
);
}
}
InterpolationMode _interpolationMode=InterpolationMode.High;
[
Category("Appearance"),
Description("The interpolation mode used to smooth the drawing")
]
public InterpolationMode InterpolationMode
{
get{return _interpolationMode;}
set{_interpolationMode=value;}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// do nothing.
}
protected override void OnPaint(PaintEventArgs e)
{
//if no image, don't bother
if(_image==null)
{
base.OnPaintBackground(e);
return;
}
//Set up a zoom matrix
Matrix mx=new Matrix(_zoom,0,0,_zoom,0,0);
//now translate the matrix into position for the scrollbars
mx.Translate(this.AutoScrollPosition.X / _zoom, this.AutoScrollPosition.Y / _zoom);
//use the transform
e.Graphics.Transform=mx;
//and the desired interpolation mode
e.Graphics.InterpolationMode=_interpolationMode;
//Draw the image ignoring the images resolution settings.
e.Graphics.DrawImage(_image,new Rectangle(0,0,this._image.Width,this._image.Height),0,0,_image.Width, _image.Height,GraphicsUnit.Pixel);
base.OnPaint (e);
}
public ZoomPicBox()
{
//Double buffer the control
this.SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true);
this.AutoScroll=true;
}
}
}