WPF头像裁剪
来源:互联网 发布:中国地名数据库下载 编辑:程序博客网 时间:2024/05/16 15:09
需求很常见,就是用户上传头像前进行固定大小的裁剪。
百度一番,找到几个差不多的,
其一 http://download.csdn.net/detail/tianhaosen/7159901,这个的实现方式是截图框大小固定不变,背景图可以通过鼠标拖动和鼠标滚轮缩放,经过测试,这个对图片的裁剪不是很准确,尤其是大图或者靠近图片边缘裁剪的时候会出现较大误差,然后我尝试调整了下截图位置的算法,但多少还是有偏差,无奈只好放弃,有兴趣的同学可以下下来研究研究。
其二 http://blog.csdn.net/jtl309/article/details/50651911,这个的实现方式是背景图片保持大小不变,裁剪框可以通过鼠标拖动进行缩放。于是尝试在这个的基础上进行调整:)
首先,裁剪框的拖动以及缩放作者已经做的很完善了,主要是利用了Thumb控件进行自定义。我的需求是裁剪框要是一个固定大小的正方形,所以我对作者的源码进行了修改。源码中作者是在DragHelperBase.cs中对矩形框的大小进行实时计算,其中有4个ResizeFrom**方法,我在这4个方法的入参中均加入了宽高(out double HeightNew,out double WidthNew),并且在方法的最后一行赋值高和宽相等,这样就保证了裁剪框始终是正方形,另外,作者的这个框框拖动的时候能把框拖到大边框以外,是个小bug,我这边在每次拖动之后都跟Parent.ActualWidth比较一下。ok,算法代码修改完毕,下面就是对样式代码进行了一些调整,这个各位同学根据自己需求改动即可。
主要修改了DragHelperBase.cs代码:
#region ResizeElement private Rect ResizeElement(CustomThumb HitedThumb, double HorizontalChange, double VerticalChange) { #region Get Old Value if (HitedThumb == null) return Rect.Empty; Rect TargetActualBound = GetTargetActualBound(); double TopOld = CorrectDoubleValue(TargetActualBound.Y); double LeftOld = CorrectDoubleValue(TargetActualBound.X); double WidthOld = CorrectDoubleValue(TargetActualBound.Width); double HeightOld = CorrectDoubleValue(TargetActualBound.Height); double TopNew = TopOld; double LeftNew = LeftOld; double WidthNew = WidthOld; double HeightNew = HeightOld; #endregion if (HitedThumb.DragDirection == DragDirection.TopLeft || HitedThumb.DragDirection == DragDirection.MiddleLeft || HitedThumb.DragDirection == DragDirection.BottomLeft) { ResizeFromLeft(DragHelperParent, LeftOld, WidthOld, TopOld, HeightOld, HorizontalChange, out LeftNew, out WidthNew, out HeightNew); } if (HitedThumb.DragDirection == DragDirection.TopLeft || HitedThumb.DragDirection == DragDirection.TopCenter || HitedThumb.DragDirection == DragDirection.TopRight) { ResizeFromTop(DragHelperParent, LeftOld, WidthOld, TopOld, HeightOld, VerticalChange, out TopNew, out HeightNew, out WidthNew); } if (HitedThumb.DragDirection == DragDirection.TopRight || HitedThumb.DragDirection == DragDirection.MiddleRight || HitedThumb.DragDirection == DragDirection.BottomRight) { ResizeFromRight(DragHelperParent, LeftOld, WidthOld,TopOld,HeightOld, HorizontalChange, out WidthNew, out HeightNew); } if (HitedThumb.DragDirection == DragDirection.BottomLeft || HitedThumb.DragDirection == DragDirection.BottomCenter || HitedThumb.DragDirection == DragDirection.BottomRight) { ResizeFromBottom(DragHelperParent, LeftOld, WidthOld, TopOld, HeightOld, VerticalChange, out HeightNew, out WidthNew); } WidthNew = WidthNew < 0 ? 0 : WidthNew; HeightNew = HeightNew < 0 ? 0 : HeightNew; this.Width = WidthNew; this.Height = HeightNew; Canvas.SetTop(this, TopNew); Canvas.SetLeft(this, LeftNew); return new Rect { X = LeftNew, Y = TopNew, Width = WidthNew, Height = HeightNew }; } #endregion #region Resize Base Methods private static void CalcSize(double h,double w) { } #region ResizeFromTop private static void ResizeFromTop(FrameworkElement Parent, double LeftOld, double WidthOld, double TopOld, double HeightOld, double VerticalChange, out double TopNew, out double HeightNew, out double WidthNew) { double MiniHeight = 10; double top = TopOld + VerticalChange; TopNew = ((top + MiniHeight) > (HeightOld + TopOld)) ? HeightOld + TopOld - MiniHeight : top; TopNew = TopNew < 0 ? 0 : TopNew; HeightNew = HeightOld + TopOld - TopNew; HeightNew = CorrectNewHeight(Parent, TopNew, HeightNew); double tmpWidth = WidthOld; if (LeftOld+HeightNew>Parent.ActualWidth) { HeightNew = tmpWidth; WidthNew = tmpWidth; } else { WidthNew = HeightNew; tmpWidth = HeightNew; } } #endregion #region ResizeFromLeft private static void ResizeFromLeft(FrameworkElement Parent, double LeftOld, double WidthOld, double TopOld, double HeightOld, double HorizontalChange, out double LeftNew, out double WidthNew, out double HeightNew) { double MiniWidth = 10; double left = LeftOld + HorizontalChange; LeftNew = ((left + MiniWidth) > (WidthOld + LeftOld)) ? WidthOld + LeftOld - MiniWidth : left; LeftNew = LeftNew < 0 ? 0 : LeftNew; WidthNew = WidthOld + LeftOld - LeftNew; WidthNew = CorrectNewWidth(Parent, LeftNew, WidthNew); double tmpHeight = HeightOld; if (TopOld + WidthNew > Parent.ActualHeight) { WidthNew = tmpHeight; HeightNew = tmpHeight; } else { HeightNew = WidthNew; tmpHeight = WidthNew; } } #endregion #region ResizeFromRight private static void ResizeFromRight(FrameworkElement Parent, double LeftOld, double WidthOld, double TopOld, double HeightOld, double HorizontalChange, out double WidthNew, out double HeightNew) { if (LeftOld + WidthOld + HorizontalChange < Parent.ActualWidth) { WidthNew = WidthOld + HorizontalChange; } else { WidthNew = Parent.ActualWidth - LeftOld; } if (TopOld + HeightOld + HorizontalChange < Parent.ActualHeight) { HeightNew = HeightOld + HorizontalChange; } else { HeightNew = Parent.ActualWidth - TopOld; } WidthNew = WidthNew < 0 ? 0 : WidthNew; if (WidthNew<HeightNew) { HeightNew = WidthNew; } else { WidthNew = HeightNew; } } #endregion #region ResizeFromBottom private static void ResizeFromBottom(FrameworkElement Parent, double LeftOld, double WidthOld, double TopOld, double HeightOld, double VerticalChange, out double HeightNew, out double WidthNew) { if (TopOld + HeightOld + VerticalChange < Parent.ActualWidth) { HeightNew = HeightOld + VerticalChange; } else { HeightNew = Parent.ActualWidth - TopOld; } if (LeftOld + WidthOld + VerticalChange < Parent.ActualWidth) { WidthNew = WidthOld + VerticalChange; } else { WidthNew = Parent.ActualWidth - LeftOld; } HeightNew = HeightNew < 0 ? 0 : HeightNew; if (WidthNew < HeightNew) { HeightNew = WidthNew; } else { WidthNew = HeightNew; } } #endregion
现在回到我们自己的项目,把上面修改过的工程生成的dll引用进来,
<Canvas x:Name="canvas" Grid.Row="1" Width="500" Height="500"> <Rectangle Stroke="{StaticResource ButtonBackgroundBrush}" Fill="Transparent" StrokeThickness="2" Width="300" Height="300" Canvas.Left="100" Canvas.Top="100" UICommon:DragControlHelper.IsEditable="True" UICommon:DragControlHelper.IsSelectable="True"/> <UICommon:DragControlHelper CornerWidth="6" Background="{StaticResource CancleButtonBackgroudBrush}" BorderBrush="{StaticResource ButtonBackgroundBrush}" DragChanging="DragControlHelper_DragChanging" DragCompleted="DragControlHelper_DragCompleted"/> </Canvas><StackPanel Grid.Row="2" HorizontalAlignment="Center" Orientation="Horizontal"> <Button Content="取消" Name="btnCancel" Width="62" Height="32" Foreground="#FFFFFF" Style="{StaticResource CustomButtonStyle}" Margin="10" Click="btnCancel_Click" Background="{StaticResource CancleButtonBackgroudBrush}"></Button> <Button Content="确定" Name="btnConfirm" Width="62" Height="32" Foreground="#FFFFFF" Style="{StaticResource CustomButtonStyle}" Margin="10" Click="btnConfirm_Click" Background="{StaticResource ButtonBackgroundBrush}"></Button></StackPanel>
private void DragControlHelper_DragCompleted(object Sender, UICommon.Controls.DragChangedEventArgs e){ newBound = e.NewBound;//拖动完成后的新位置}private void btnConfirm_Click(object sender, RoutedEventArgs e){ Bitmap map = new Bitmap(choosedImagePath); int mapHeight = map.Height; int mapWidth = map.Width;//图片宽高 int actualHeight = 0; int actualWidth = 0;//Canvas宽高 int offset = 1; int left = 0; int top = 0; int x = (int)newBound.X; int y = (int)newBound.Y; if (mapHeight>mapWidth)//此时高度撑满500 { actualHeight = 500; actualWidth = 500 * mapWidth / mapHeight; left = (500 - actualWidth) / 2; x -= left; offset = mapHeight / 500d;//需要小数 } else//此时宽度撑满500 { actualWidth = 500; actualHeight = 500 * mapHeight / mapWidth; top = (500 - actualHeight) / 2; y -= top; offset = mapWidth / 500d; } //计算截图位置和大小 int w= (int)Math.Round(newBound.Width * offset, MidpointRounding.AwayFromZero); int h = (int)Math.Round(newBound.Height * offset, MidpointRounding.AwayFromZero); int startX=(int)Math.Round( x * offset,MidpointRounding.AwayFromZero); int startY=(int)Math.Round( y * offset,MidpointRounding.AwayFromZero); var resultMap = KiCut(map,startX,startY, w, h); if (resultMap==null) { Alert alert = new Alert("图片裁剪失败,请重新选择图片。"); alert.Owner = this; alert.ShowDialog(); return; } string savePath = NIM.ToolsAPI.GetLocalAppDataDir() + ConfigHelper.GetSettingStr("appDataDir") + "\\CutImageTemp\\"; if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); } string name = "UserHead_" + DateTimeHelper.DatetimeConvertUnix() + ".jpg"; string path=savePath + name; if (resultMap.Width!=300)//用户调整了裁剪框大小 { Bitmap newImage = new Bitmap(300, 300, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(newImage); g.DrawImage(resultMap, 0, 0, 300, 300); g.Dispose(); newImage.Save(path, ImageFormat.Jpeg); } else//直接保存 { resultMap.Save(path, ImageFormat.Jpeg); }}private static Bitmap KiCut(Bitmap b, int StartX, int StartY, int iWidth, int iHeight){ if (b == null) { return null; } try { Bitmap bmpOut = new Bitmap(iWidth, iHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(bmpOut); g.DrawImage(b, new System.Drawing.Rectangle(0, 0, iWidth, iHeight), new System.Drawing.Rectangle(StartX, StartY, iWidth, iHeight), GraphicsUnit.Pixel); g.Dispose(); return bmpOut; } catch(Exception ex) { return null; }}private void Window_Loaded(object sender, RoutedEventArgs e){ BinaryReader binReader = new BinaryReader(File.Open(choosedImagePath, FileMode.Open)); FileInfo fileInfo = new FileInfo(choosedImagePath); byte[] bytes = binReader.ReadBytes((int)fileInfo.Length); binReader.Close(); bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.StreamSource = new MemoryStream(bytes); bitmap.EndInit(); ImageBrush brush = new ImageBrush(bitmap); brush.Stretch = Stretch.Uniform; this.canvas.Background = brush;}
稍微解释下代码,以上代码只是核心部分,另外newBound在构造函数中需要初始化new Rect(100, 100, 300, 300),因为我这边需要裁剪成300X300的图片,并且我在窗口的Load事件里给Canvas设置了背景图片,也就是用户选择的图片(路径存放在choosedImagePath变量中),并且设置其Stretch属性为Uniform,这样能保证图片在框中自适应正常显示。
虽然我这边默认框大小是300X300,但是一旦用户缩放了裁剪框,我们就需要对裁剪下来的图片进行放大或压缩,然后再做进一步操作(如转码base64、上传至服务器)。
- WPF头像裁剪
- Quartz2D裁剪圆形头像
- phonegap头像裁剪上传
- iOS 上传头像 裁剪
- Android高仿微信头像裁剪
- java头像裁剪上传
- iOS ---上传头像 裁剪
- 裁剪头像为圆形
- android裁剪圆型头像
- android裁剪头像上传
- Quartz2D裁剪圆形头像
- iOS 头像裁剪上传
- 头像裁剪源码
- Vue头像上传,裁剪
- iOS 图片裁剪(用户头像裁剪)
- WPF圆形头像显示
- WPF圆形头像设置
- 裁剪 图片 图像 头像 iOS
- mybatis之mapper的配置
- gulp-Gulp资料大全:入门、插件、脚手架、包清单
- vue从入门到放弃---Vuex vueBus
- window 安装thrift
- jxbrowser-6.14 jxbrowser破解版
- WPF头像裁剪
- 【脚本语言系列】关于PythonWeb客户端标准库requests,你需要知道的事情
- 79-Word Search
- EM算法通用形式(ESL 8.5.2)
- 51Nod 1046 A^B Mod C
- MongoDB--架构搭建 分片+副本集
- Codeforces Maximum in Table
- python脚本实现git commit hooks钩子
- 高性能 DOM & 重排重绘