我在面板中有一个 PictureBox,以便缩放和平移。我创建了用鼠标单击选择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();
}
我现在要做的是缩放所选区域而不是裁剪它。图片框的矩形必须与面板匹配。
如何通过面板仅显示图片框的选定区域(矩形)而不裁剪图像?
答案 0 :(得分:1)
您应该坚持使用Bitmap
对象修改现有的Graphics
,而不是更改PictureBox的大小。当所需功能已在其他地方可用时,您不希望与UI控件绑定。
以下是实现这一目标的粗略步骤:
Bitmap
对象,用于存储缩放的图像。 Bitmap tBitmap = new Bitmap(zoomX, zoomY, PixelFormat.Format24bppRgb);
Graphics graphics = Graphics.FromImage(tBitmap);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(pictureBox.Image, new Rectangle(0, 0, pictureBox.Width, pictureBox.Height), new Rectangle(/*The crop rectangle you draw already*/), GraphicsUnit.Pixel);
pictureBox.Image = tBitmap;
graphics.Dispose();
pictureBox.Refresh();
这些是要遵循的基本步骤。我没有时间深入了解您现有的代码,因此您可能需要更改一些其他内容才能使其正常工作。
这里还有一篇MSDN文章,其中涵盖了相同的内容:Cropping and Scaling Images in GDI+
答案 1 :(得分:1)
您可能对此控件(ZoomPicBox)感兴趣,它允许缩放和平移图片框。
此代码的所有功劳都归功于鲍勃鲍威尔,它来自他的网站(现在似乎已经停止了很长一段时间。)
我通过以下链接复制了archive.org中的代码:
https://web.archive.org/web/20080313161349/http://www.bobpowell.net/zoompicbox.htm
该链接有其他信息,值得一读。该代码也可以在VB.Net中找到。
我不知道为什么鲍勃鲍威尔的网站已关闭,但它是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;
}
}
}
答案 2 :(得分:0)
我找到了解决问题的优雅方法:
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转换,因为图像的原始比例将被损坏。