锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C#开源 / C#界面控件 / WPF交互式图像裁剪控件
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发

锐英源精品原创,禁止全文或局部转载,禁止任何形式的非法使用,侵权必究。点名“简易百科”和闲暇巴盗用锐英源原创内容。

WPF交互式图像裁剪控件


背景

最近写大屏界面,在地图(图形局部)交互方面需要提高,看到本文和图像及交互有关,就翻译学习下。请记住,codeproject看不懂,请找锐英源软件。本文里的交互也是codeproject上的大牛提出的,本文作者也是借用了方法。

 

介绍

最近,我的一位刚创办公司的朋友向我介绍了这个网站,该网站做了很多精美的图像编辑。尽管他不知道 XAML 或 Sliverlight,但他认为他们所做的一些事情非常出色,并要求我考虑在 WPF 中做类似的事情。虽然本文仅代表该网站的一小部分可以做(即图像裁剪)我觉得它为你们中可能最终尝试在 WPF/Silverlight 中进行图像编辑应用程序的人概述了一些有用的技术和学习笔记。尽管我不能断然说本文的 100% 都适用于 Silverlight,因为它确实是用 WPF 编写的,但我正在等待使用 Silverlight v1.1 的托管版本。JavaScript 让我很冷(讨厌的东西)。因此,在我玩过它之后,我应该能够编写我知道可以与 Silverlight 一起使用的 WPF 文章。到那时,恐怕如果你想要一个 Silverlight 版本,你只需要自己尝试一个代码端口。

那么这篇文章到底是什么?就像我说的,我的朋友让我在 WPF 中创建一个漂亮的图像裁剪器。所以这就是事实。它是一个图像裁剪控件,可以放置在任何其他 XAML 中并用于裁剪图像。图像的裁剪是通过首先绘制一个形状,然后将形状移动到所需的位置,然后完成并接受裁剪的图像来实现的。

简而言之,就是这样。这是一个简单的图像裁剪器,基本上是用 WPF 编写的。

设计步骤

我实际上非常喜欢这里的图像裁剪,所以我想创建一个尽可能相似的图像。为此,我对自己的核心职能简介如下:

  • 核心功能1:支持所有者绘制的半透明裁剪区域
  • 核心功能2:裁剪区域应该可以移动
  • 核心功能3:用户应该能够调整裁剪区域的大小
  • 核心功能 4:用户应该能够接受或拒绝特定的裁剪操作

这些是我想要介绍的基本步骤。然而,我对自己施加了一些更多的扩展功能,如下所示:

  • 扩展功能 1:裁剪功能应包含在一个可重复使用的 WPF 用户控件中
  • 扩展功能2:用户应该能够调整图像大小,以便在处理非常大的图像时能够看到整个图像

这些是我为这篇文章设定的任务。在下一节中,我将解释我是如何完成或未能完成这些任务的。

这个怎么运作

所以我现在要做的是解释前面提到的每个核心/扩展功能。

核心功能一:支持自绘裁剪区域

这很容易做到,我只是对鼠标事件进行了子类化System.Windows.Controls.Canvas并覆盖了鼠标事件,这样当鼠标移动时,一个新的子UIElement类被添加到新的子类Canvas中。基本上每次用户移动鼠标时System.Windows.Shapes.Rectangle,都会使用鼠标坐标添加或调整新鼠标的大小。这与久经考验的旧 .NET 2.0ControlPaint.DrawReversibleFrame()方法的概念类似。通过子类化System.Windows.Controls.Canvas意味着这System.Windows.Controls.Canvas可以在任何代码或 XAML 文件中使用。

注:面向对象的具体实践。

这个子类Canvas的实际演示如下所示:

执行此功能的代码非常简单,如下所示。

C#

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ImageCropper
{
/// <span class="code-SummaryComment"><summary></span>
/// Provides a Canvas where a rectangle will be drawn
/// that matches the selection area that the user drew
/// on the canvas using the mouse
/// <span class="code-SummaryComment"></summary></span>
public partial class SelectionCanvas : Canvas
{
#region Instance fields
private Point mouseLeftDownPoint;
private Style cropperStyle;
public Shape rubberBand = null;
public readonly RoutedEvent CropImageEvent;
#endregion

#region Events
/// <span class="code-SummaryComment"><summary></span>
/// Raised when the user has drawn a selection area
/// <span class="code-SummaryComment"></summary></span>
public event RoutedEventHandler CropImage
{
add { AddHandler(this.CropImageEvent, value); }
remove { RemoveHandler(this.CropImageEvent, value); }
}
#endregion

#region Ctor
/// <span class="code-SummaryComment"><summary></span>
/// Constructs a new SelectionCanvas, and registers the
/// CropImage event
/// <span class="code-SummaryComment"></summary></span>
public SelectionCanvas()
{
this.CropImageEvent = EventManager.RegisterRoutedEvent
("CropImage", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(SelectionCanvas));
}
#endregion

#region Public Properties
public Style CropperStyle
{
get { return cropperStyle; }
set { cropperStyle = value; }
}
#endregion

#region Overrides

/// <span class="code-SummaryComment"><summary></span>
/// Captures the mouse
/// <span class="code-SummaryComment"></summary></span>
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (!this.IsMouseCaptured)
{
mouseLeftDownPoint = e.GetPosition(this);
this.CaptureMouse();
}
}

/// <span class="code-SummaryComment"><summary></span>
/// Releases the mouse, and raises the CropImage Event
/// <span class="code-SummaryComment"></summary></span>
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);

if (this.IsMouseCaptured && rubberBand != null)
{
this.ReleaseMouseCapture();

RaiseEvent(new RoutedEventArgs(this.CropImageEvent, this));
}
}

/// <span class="code-SummaryComment"><summary></span>
/// Creates a child control
/// <span class="code-SummaryComment"><see cref="System.Windows.Shapes.Rectangle">Rectangle</see></span>
/// and adds it to this controls children collection
/// at the co-ordinates the user
/// drew with the mouse
/// <span class="code-SummaryComment"></summary></span>
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);

if (this.IsMouseCaptured)
{
Point currentPoint = e.GetPosition(this);

if (rubberBand == null)
{
rubberBand = new Rectangle();
if (cropperStyle != null)
rubberBand.Style = cropperStyle;
this.Children.Add(rubberBand);
}

double width = Math.Abs(mouseLeftDownPoint.X - currentPoint.X);
double height =
Math.Abs(mouseLeftDownPoint.Y - currentPoint.Y);
double left = Math.Min(mouseLeftDownPoint.X, currentPoint.X);
double top = Math.Min(mouseLeftDownPoint.Y, currentPoint.Y);

rubberBand.Width = width;
rubberBand.Height = height;
Canvas.SetLeft(rubberBand, left);
Canvas.SetTop(rubberBand, top);
}
}
#endregion
}
}

可以看出,crop 区域实际上是一个Rectangle. 我最初有这是一个固定的颜色。但 Josh Smith 建议我将其更改为包含用户允许的样式依赖属性。因此,我在主UcImageCropper上创建了一个CropperStyle依赖属性,UcImageCropper包含此画布和下图所示DragCanvas的。

核心功能2:裁剪区域应该可以移动

好吧,这很容易(真的很容易),因为我所做的只是换掉当前selectionCanvas的DragCanvas,小心地从当前的子集合中删除当前的裁​​剪区域 ( Rectangle) selectionCanvas,并将其添加到DragCanvas.

之所以这么简单,是因为所有的工作都已经由别人完成了,我只是看到了如何使用它的机会。原始文章由Josh Smith撰写,我使用的特定文章在 CodeProject 上托管。它称为在画布中拖动元素。所以感谢乔希。我希望你喜欢在这段代码中使用它。

一旦DragCanvas就位,用户就可以将裁剪区域拖动到他们喜欢的任何地方。高兴时,他们可以使用上下文菜单(右键单击)来保存图像或重新开始。

核心功能3:裁剪区域应该可以调整大小

我的直接想法是使用System.Windows.Documents.Adorner. 对于那些不知道我到底在说什么的人,简单地说,装饰器允许您将额外的功能应用于UIElement旋转、调整大小等。关于此有许多很好的来源,例如:

  • 装饰器样本 MSDN
  • WPF 中的装饰器,简单介绍一下

不幸的是,由于JoSmithDragCanvas使用了鼠标事件,而且漂亮的 MSDNResizeAdorner示例也使用了鼠标事件,所以要让它们正常工作有点困难。为此,我不得不放弃调整裁剪区域的大小。但是,如果有人想试一试,System.Windows.Documents.Adorners 将是要走的路。我的想法是简单地使用ResizeAdorner(MSDN)来装饰当前的裁剪矩形,这样用户不仅可以拖动(感谢DragCanvas)而且可以调整大小。反正就是这个想法。

核心功能4:接受/拒绝结果

为了允许用户预览图像被裁剪后的样子,有一个小的弹出窗口允许用户接受或拒绝裁剪。如果用户接受,裁剪后的图像将用作当前图像的新来源。如果用户拒绝裁剪,将使用现有图像而不执行任何裁剪。

扩展功能 1:包装为控件

重复使用是好的。为此,我已将所有这些功能封装到一个名为的可重用控件中,该控件ucImageCropper可在其他 XAML 文件中使用。

的源代码ucImageCropper如下所示:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;

#region Explanation of why this .NET3.0 app is using .NET2.0 Dlls
//For some very simple .NET niceties like being able to save a bitmap
//to a filename I have had to use the System.Drawing .NET 2.0 DLL
//
//While this looks possible using something like the following :
//
//RenderTargetBitmap rtb = new RenderTargetBitmap((int)img.width,
//(int)img, 0, 0, PixelFormats.Default);
//rtb.Render(this.inkCanv);
//BmpBitmapEncoder encoder = new BmpBitmapEncoder();
//encoder.Frames.Add(BitmapFrame.Create(rtb));
//encoder.Save(file);
//file.Close();
//
//For this to work I would have needed to used a .NET 3.0 CroppedBitmap
//within the RenderTargetBitmap.Render() method. And as CroppedBitmap
//doesn't inherit from Visual this is not possible.
//
//So if anyone knows how to do this better in .NET 3.0 I am all ears
#endregion
using System.Drawing;
using System.Drawing.Drawing2D;

//Josh Smith excellent DragCanvas
using WPF.JoshSmith.Controls;

namespace ImageCropper
{

/// <span class="code-SummaryComment"><summary></span>
/// Provides a simple Image cropping facility for a WPF image element,
/// where the cropped area may be picked using a rubber band and moved
/// by dragging the rubber band around the image. There is also a popup
/// window from where the user may accept or reject the crop.
/// <span class="code-SummaryComment"></summary></span>
public partial class UcImageCropper : System.Windows.Controls.UserControl
{

#region CropperStyle Dependancy property

/// <span class="code-SummaryComment"><summary></span>
/// A DP for the Crop Rectangle Style
/// <span class="code-SummaryComment"></summary></span>
public Style CropperStyle
{
get { return (Style)GetValue(CropperStyleProperty); }
set { SetValue(CropperStyleProperty, value); }
}

/// <span class="code-SummaryComment"><summary></span>
/// register the DP
/// <span class="code-SummaryComment"></summary></span>
public static readonly DependencyProperty CropperStyleProperty =
DependencyProperty.Register(
"CropperStyle",
typeof(Style),
typeof(UcImageCropper),
new UIPropertyMetadata(null, new PropertyChangedCallback
(OnCropperStyleChanged)));

/// <span class="code-SummaryComment"><summary></span>
/// The callback that actually changes the Style if one was provided
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="depObj">UcImageCropper</param></span>
/// <span class="code-SummaryComment"><param name="e">The event args</param></span>
static void OnCropperStyleChanged(DependencyObject depObj,

DependencyPropertyChangedEventArgs e)
{
Style s = e.NewValue as Style;
if (s != null)
{
UcImageCropper uc = (UcImageCropper)depObj;
uc.selectCanvForImg.CropperStyle = s;
}
}
#endregion

#region Instance fields
private string ImgUrl = "";
private BitmapImage bmpSource = null;
private SelectionCanvas selectCanvForImg = null;
private DragCanvas dragCanvasForImg = null;
private System.Windows.Controls.Image img = null;
private Shape rubberBand;
private double rubberBandLeft;
private double rubberBandTop;
private string tempFileName;
private ContextMenu cmSelectionCanvas;
private RoutedEventHandler cmSelectionCanvasRoutedEventHandler;
private ContextMenu cmDragCanvas;
private RoutedEventHandler cmDragCanvasRoutedEventHandler;
private string fixedTempName = "temp";
private long fixedTempIdx = 1;
private double zoomFactor=1.0;
#endregion

#region Ctor
public UcImageCropper()
{
InitializeComponent();

//this.Unloaded += new RoutedEventHandler
(UcImageCropper_Unloaded);
selectCanvForImg = new SelectionCanvas();
selectCanvForImg.CropImage +=
new RoutedEventHandler(selectCanvForImg_CropImage);
dragCanvasForImg = new DragCanvas();
}

#endregion

#region Public properties
public string ImageUrl
{
get { return this.ImgUrl; }
set
{
zoomFactor = 1.0;
ImgUrl = value;
grdCroppedImage.Visibility = Visibility.Hidden;
createImageSource();
createSelectionCanvas();
//apply the default style if the user of this control
//didn't supply one
if (CropperStyle == null)
{
Style s = gridMain.TryFindResource("defaultCropperStyle")
as Style;
if (s != null)
{
CropperStyle = s;
}
}

}
}
#endregion

#region Private methods
/// <span class="code-SummaryComment"><summary></span>
/// Deletes all occurrences of previous unused temp files from the
/// current temporary path
/// <span class="code-SummaryComment"></summary></span>
/// <span class="code-SummaryComment"><param name="tempPath">The temporary file path</param></span>
/// <span class="code-SummaryComment"><param name="fixedTempName">The file name part to search for</span>
/// <span class="code-SummaryComment"></param></span>
/// <span class="code-SummaryComment"><param name="CurrentFixedTempIdx">The current temp file suffix</span>
/// <span class="code-SummaryComment"></param></span>
public void CleanUp(string tempPath, string fixedTempName,
long CurrentFixedTempIdx)
{
//clean up the single temporary file created
try
{
string filename = "";
for (int i = 0; i < CurrentFixedTempIdx; i++)
{
filename = tempPath + fixedTempName + i.ToString()+".jpg";
File.Delete(filename);
}
}
catch (Exception)
{
}
}

/// <span class="code-SummaryComment"><summary></span>
/// Popup form Cancel clicked, so created the SelectionCanvas
/// to start again
/// <span class="code-SummaryComment"></summary></span>
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
grdCroppedImage.Visibility = Visibility.Hidden;
createSelectionCanvas();
}

/// <span class="code-SummaryComment"><summary></span>
/// Popup form Confirm clicked, so save the file to their
/// desired location
/// <span class="code-SummaryComment"></summary></span>
private void btnConfirm_Click(object sender, RoutedEventArgs e)
{
ImageUrl = tempFileName;
grdCroppedImage.Visibility = Visibility.Hidden;
}

/// <span class="code-SummaryComment"><summary></span>
/// creates the selection canvas, where user can draw
/// selection rectangle
/// <span class="code-SummaryComment"></summary></span>
private void createSelectionCanvas()
{
createImageSource();
selectCanvForImg.Width = bmpSource.Width * zoomFactor;
selectCanvForImg.Height = bmpSource.Height * zoomFactor;
selectCanvForImg.Children.Clear();
selectCanvForImg.rubberBand = null;
selectCanvForImg.Children.Add(img);
svForImg.Width = selectCanvForImg.Width;
svForImg.Height = selectCanvForImg.Height;
svForImg.Content = selectCanvForImg;
createSelectionCanvasMenu();
}

/// <span class="code-SummaryComment"><summary></span>
/// Creates the selection canvas context menu
/// <span class="code-SummaryComment"></summary></span>
private void createSelectionCanvasMenu()
{
cmSelectionCanvas = new ContextMenu();
MenuItem miZoom25 = new MenuItem();
miZoom25.Header = "Zoom 25%";
miZoom25.Tag = "0.25";
MenuItem miZoom50 = new MenuItem();
miZoom50.Header = "Zoom 50%";
miZoom50.Tag = "0.5";
MenuItem miZoom100 = new MenuItem();
miZoom100.Header = "Zoom 100%";
miZoom100.Tag = "1.0";
cmSelectionCanvas.Items.Add(miZoom25);
cmSelectionCanvas.Items.Add(miZoom50);
cmSelectionCanvas.Items.Add(miZoom100);
cmSelectionCanvasRoutedEventHandler =
new RoutedEventHandler(MenuSelectionCanvasOnClick);
cmSelectionCanvas.AddHandler
(MenuItem.ClickEvent, cmSelectionCanvasRoutedEventHandler);
selectCanvForImg.ContextMenu = cmSelectionCanvas;
}

/// <span class="code-SummaryComment"><summary></span>
/// Handles the selection canvas context menu. Which will zoom the
/// current image to either 25,50 or 100%
/// <span class="code-SummaryComment"></summary></span>
private void MenuSelectionCanvasOnClick(object sender,
RoutedEventArgs args)
{
MenuItem item = args.Source as MenuItem;
zoomFactor = double.Parse(item.Tag.ToString());
img.RenderTransform = new ScaleTransform
(zoomFactor, zoomFactor, 0.5, 0.5);
selectCanvForImg.Width = bmpSource.Width * zoomFactor;
selectCanvForImg.Height = bmpSource.Height * zoomFactor;
svForImg.Width = selectCanvForImg.Width;
svForImg.Height = selectCanvForImg.Height;

}

/// <span class="code-SummaryComment"><summary></span>
/// Creates the Image source for the current canvas
/// <span class="code-SummaryComment"></summary></span>
private void createImageSource()
{
bmpSource = new BitmapImage(new Uri(ImgUrl));
img = new System.Windows.Controls.Image();
img.Source = bmpSource;
//if there was a Zoom Factor applied
img.RenderTransform = new ScaleTransform
(zoomFactor, zoomFactor, 0.5, 0.5);
}

/// <span class="code-SummaryComment"><summary></span>
/// creates the drag canvas, where user can drag the
/// selection rectangle
/// <span class="code-SummaryComment"></summary></span>
private void createDragCanvas()
{
dragCanvasForImg.Width = bmpSource.Width * zoomFactor;
dragCanvasForImg.Height = bmpSource.Height * zoomFactor;
svForImg.Width = dragCanvasForImg.Width;
svForImg.Height = dragCanvasForImg.Height;
createImageSource();
createDragCanvasMenu();
selectCanvForImg.Children.Remove(rubberBand);
dragCanvasForImg.Children.Clear();
dragCanvasForImg.Children.Add(img);
dragCanvasForImg.Children.Add(rubberBand);
svForImg.Content = dragCanvasForImg;
}

/// <span class="code-SummaryComment"><summary></span>
/// Creates the drag canvas context menu
/// <span class="code-SummaryComment"></summary></span>
private void createDragCanvasMenu()
{
cmSelectionCanvas.RemoveHandler
(MenuItem.ClickEvent, cmSelectionCanvasRoutedEventHandler);
selectCanvForImg.ContextMenu = null;
cmSelectionCanvas = null;
cmDragCanvas = new ContextMenu();
MenuItem miCancel = new MenuItem();
miCancel.Header = "Cancel";
MenuItem miSave = new MenuItem();
miSave.Header = "Save";
cmDragCanvas.Items.Add(miCancel);
cmDragCanvas.Items.Add(miSave);
cmDragCanvasRoutedEventHandler =
new RoutedEventHandler(MenuDragCanvasOnClick);
cmDragCanvas.AddHandler
(MenuItem.ClickEvent, cmDragCanvasRoutedEventHandler);
dragCanvasForImg.ContextMenu = cmDragCanvas;
}

/// <span class="code-SummaryComment"><summary></span>
/// Handles the selection drag context menu.
/// Which allows user to cancel or save
/// the current cropped area
/// <span class="code-SummaryComment"></summary></span>
private void MenuDragCanvasOnClick
(object sender, RoutedEventArgs args)
{
MenuItem item = args.Source as MenuItem;
switch (item.Header.ToString())
{
case "Save":
SaveCroppedImage();
break;
case "Cancel":
createSelectionCanvas();
break;
default:
break;
}
}

/// <span class="code-SummaryComment"><summary></span>
/// Raised by the <span class="code-SummaryComment"><see cref="selectionCanvas">selectionCanvas</see></span>
/// when the new crop shape (rectangle) has been drawn. This event
/// then replaces the current selectionCanvas with a
<see cref="DragCanvas">DragCanvas</see>
/// which can then be used to drag the crop area around
/// within a Canvas
/// </summary>
private void selectCanvForImg_CropImage
(object sender, RoutedEventArgs e)
{
rubberBand = (Shape)selectCanvForImg.Children[1];
createDragCanvas();
}

/// <summary>
/// User cancelled out of the popup,
/// so go back to showing original image
/// </summary>
private void lblExit_MouseDown
(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
grdCroppedImage.Visibility = Visibility.Hidden;
createSelectionCanvas();
}

/// <summary>
/// Saves the cropped image area to a temp file,
/// and shows a confirmation
/// popup from where the user may accept or reject the cropped image.
/// If they accept the new cropped image
/// will be used as the new image source
/// for the current canvas, if they reject the crop,
/// the existing image will
/// be used for the current canvas
/// </summary>
private void SaveCroppedImage()
{
if (popUpImage.Source!=null)
popUpImage.Source = null;

try
{
rubberBandLeft = Canvas.GetLeft(rubberBand);
rubberBandTop = Canvas.GetTop(rubberBand);
//create a new .NET 2.0 bitmap (which allowing saving)
//based on the bound bitmap URL
using (System.Drawing.Bitmap source =
new System.Drawing.Bitmap(ImgUrl))
{
//create a new .NET 2.0 bitmap (which allowing saving)
//to store cropped image in, should be
//same size as rubberBand element which is the size
//of the area of the original image we want to keep
using (System.Drawing.Bitmap target =
new System.Drawing.Bitmap((int)rubberBand.Width,
(int)rubberBand.Height))
{
//create a new destination rectangle
System.Drawing.RectangleF recDest =
new System.Drawing.RectangleF
(0.0f, 0.0f, (float)target.Width,
(float)target.Height);
//different resolution fix prior to cropping image
float hd = 1.0f / (target.HorizontalResolution /
source.HorizontalResolution);
float vd = 1.0f / (target.VerticalResolution /
source.VerticalResolution);
float hScale = 1.0f / (float)zoomFactor;
float vScale = 1.0f / (float)zoomFactor;
System.Drawing.RectangleF recSrc =
new System.Drawing.RectangleF
((hd * (float)rubberBandLeft) *
hScale, (vd * (float)rubberBandTop) *
vScale, (hd * (float)rubberBand.Width) *
hScale, (vd * (float)rubberBand.Height) *
vScale);
using (System.Drawing.Graphics gfx =
System.Drawing.Graphics.FromImage(target))
{
gfx.DrawImage(source, recDest, recSrc,
System.Drawing.GraphicsUnit.Pixel);
}
//create a new temporary file, and delete
//all old ones prior to this new temp file
//This is a hack that I had to put in,
//due to GDI+ holding on to previous
//file handles used by the Bitmap.Save()
//method the last time this method was run.
//This is a well known issue see
//http://support.microsoft.com/?id=814675 for example
tempFileName = System.IO.Path.GetTempPath();
if (fixedTempIdx >

扩展功能 2:调整源图像大小

如果您有一个非常大的源图像,您可能想要修改它,因此您可以使用右键单击上下文菜单(仅在非拖动模式下可用),它允许 25、50 和 100% 的大小。在幕后,正在发生的只是 aSystem.Windows.Media.ScaleTransform 被应用。一个例子如下:

C#
img.RenderTransform = new ScaleTransform(zoomFactor, zoomFactor, 0 . 5 , 0 . 5 )

注:缩放通过此方式能够快速实现。

如何使用它

按着这些次序:

  • 使用选择图像(左上)区域选择图像
  • 使用右键单击上下文菜单进行缩放(可选)
  • 使用鼠标(左键)绘制裁剪区域
  • 移动裁剪区域
  • 使用右键单击上下文菜单保存或取消
  • 重新开始

而已

虽然本文中的代码不多,但我做这个很有趣,并希望它对那里的人有用。

所以你怎么看 ?

我想问一下,如果你喜欢这篇文章,请给它投票,并留下一些评论,因为它让我知道这篇文章是否处于正确的水平,以及它是否包含人们需要知道的内容。

结论

这里没有太多要提及的,因为我认为本文的其余部分几乎涵盖了它。我想要说的一件事是,虽然我真的很喜欢 WPF,但我发现自己仍然需要深入研究 .NET 2.0 来做一些像素级的事情。.NET 3.0中当然有一个System.Windows.Media.Imaging.CroppedBitmap,但是这个类没有提供保存图像的能力,所以不是我想要的。在图像过滤方面,WPF 确实通过使用System.Windows.Media.Imaging.FormatConvertedBitmap该类提供了一些像素级功能。但又不是我所追求的,因为我希望将图像的裁剪保留在某个地方。因此,除非 .NET 映像类能够保存到磁盘,否则我必须改用 .NETBitmap 或Image类。

 

 

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内劳动服务器公司办公楼一层