这是一个之前遗留的问题。wpf里面有很多很多的东西,我以前用的真的只是其中很小的一个角落都不到。

需求背景:图片来源于相机拍摄,由于对像素要求,拍出来的图像素比较高,原图尺寸为3072*2048,以目前的电脑屏幕,很多都是显示不了这么大的,比如1440 * 900啊,1280 * 1024啊这种的,

在全屏情况下图像的显示都是很小的,图片细节看不清。

为了满足看清图片细节的需求,我们想要做一个放大镜。windows系统下有自带的放大镜功能,在一定程度上可以满足需求,但是实际情况是,将宽度为三千多的图放到一千多的屏幕上,图像被压缩了,

损失了很多点,这种情况下,即使使用了放大镜,也只能实现将1个像素放大到2个像素那么大,而那些损失的点找不回来了。

当时做的时候,受放大镜这个名词的束缚,在网络上搜索wpf放大镜的实现,这种情况下,找到了一个类似于实现windows放大镜功能的方法,勉(ying)为(fu)其(jiao)难(chai),就拿来用了。

有一定的效果,但是我心里知道,这个是不行的。

以后说不定还会有用,所以代码还是贴在这里,代码来源已经不记得了(以后找到补上地址),反正是别人那边搬运来的,我记得当时是直接下载了一份代码,那份代码里面太多修饰性的东西了,我不需要就全都去掉了。

主要是使用VisualBrush来实现的。

这是我调整过之后的源码,这份代码勉为其难也算是我部分原创吧。

页面部分:

        <Canvas Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Left">
<Canvas Name="magnifierCanvas" IsHitTestVisible="False" Visibility="{Binding ElementName=checkEnableMagnifier,Path=IsChecked,Converter={StaticResource BoolToVis}}">
<Rectangle Width="149" Height="149" Name="magnifierEllipse" StrokeThickness="1">
<Rectangle.Fill>
<VisualBrush ViewboxUnits="Absolute" Viewbox="0,0,149,149" ViewportUnits="RelativeToBoundingBox" Viewport="0,0,1,1"/>
</Rectangle.Fill>
<Rectangle.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#AAA" />
<GradientStop Offset="1" Color="#111" />
</LinearGradientBrush>
</Rectangle.Stroke>
</Rectangle>
<Line X1="73" X2="77" Y1="75" Y2="75" StrokeThickness="1" Stroke="Cyan" Visibility="Visible"/>
<Line X1="75" X2="75" Y1="73" Y2="77" StrokeThickness="1" Stroke="Cyan" Visibility="Visible"/>
</Canvas>
</Canvas>

后台代码:

private double _delta = 0;

        private void Image_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (_delta <= 0 && e.Delta < 0) return;
if (_delta >= 80 && e.Delta > 0) return;
_delta += (double)e.Delta / 10;
if (_delta > 130) _delta = 130; Point pos = e.MouseDevice.GetPosition(image); if (magnifierEllipse != null)
{
Rect viewBox = vb.Viewbox;
double val = (double)magnifierEllipse.Width - _delta;
viewBox.Width = val;
viewBox.Height = val; double xoffset = viewBox.Width / 2.0;
double yoffset = viewBox.Height / 2.0;
viewBox.X = pos.X - xoffset;
viewBox.Y = pos.Y - yoffset;
vb.Viewbox = viewBox; Canvas.SetLeft(magnifierCanvas, pos.X - magnifierEllipse.Width / 2);
Canvas.SetTop(magnifierCanvas, pos.Y - magnifierEllipse.Height / 2);
}
}

当时遇到了一个小小的坑,Image控件必须放在一个和这个Canvas一样大的容器里面,不然显示的时候总是会错位。

完整代码就不贴了,这是一个大程序的一小部分。

昨天在看一份图像处理的资料的时候,一开始就提到了压缩图片尺寸导致细节丢失的问题,我突然意识到我之前的那种做法特别的坑,今天重新想了一下,我为什么要抓住放大镜这一点不放呢。

也不是,其实我之前的问题在于我要怎么在Image控件上显示某张图片上的指定偏移量指定宽高的图片区域,一直没有找到这个方法。

今天突然醒悟了,我傻了吧唧的,其实可以使用图片裁切的方法,把原图在指定位置指定大小的内容裁切下来显示不就好了么。。。。

代码大部分也是来源网络,这个方法感觉还可以,我之前用了另一种方法,内存没管理好,竟然爆表了。。。。。

源代码来源:https://blog.csdn.net/qq_18995513/article/details/67637521

下面贴的代码是我根据实际情况微调之后的,更符合我现阶段的情况。

找找和源代码哪里不一样?

// 图像工具类
public static class SystemUtils
{
/// <summary>
/// 切图
/// </summary>
/// <param name="bitmapSource">图源</param>
/// <param name="cut">切割区域</param>
/// <returns></returns>
public static BitmapSource CutImage(BitmapSource bitmapSource, Int32Rect cut)
{
//计算Stride
int max = cut.Width > cut.Height ? cut.Width : cut.Height;
//var stride = bitmapSource.Format.BitsPerPixel * cut.Width / 8;
var stride = bitmapSource.Format.BitsPerPixel * max / 8;
//声明字节数组
byte[] data = new byte[stride * max];
//调用CopyPixels
bitmapSource.CopyPixels(cut, data, stride, 0); return BitmapSource.Create(cut.Width, cut.Height, 0, 0, PixelFormats.Bgr32, null, data, stride);
} // ImageSource --> Bitmap
public static System.Drawing.Bitmap ImageSourceToBitmap(ImageSource imageSource)
{
BitmapSource m = (BitmapSource)imageSource; System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); System.Drawing.Imaging.BitmapData data = bmp.LockBits(
new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bmp.UnlockBits(data); return bmp;
} // Bitmap --> BitmapImage
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Bmp); stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
// Force the bitmap to load right now so we can dispose the stream.
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze(); return result;
}
}
}

不一样的地方就是我遇到的坑,真的好坑啊,没有人和我遇到一样的问题吗?我就看到我有这个问题。。。。。

在切割宽度小于高度的时候,就是会有一个异常,改掉之后就好啦。

其他关于放大缩小后坐标的计算的代码就不贴了。其实也算了好久,终于算对了。为了省事,我把鼠标所在的位置作为放大后的局部图片的左上角坐标了,比中心坐标稍微少算点东西。


本来呢,事情到这边就应该告一段落了,放大功能已经实现了,但是问题是,其实我的需求不仅仅是把图片放大,图片上可能会有一些新画上去的东西,这个东西有可能会需要擦掉,

上面这种操作只将图片显示在了放大框内,而我后期添加的那些线条啊文字啊,全都没有显示,怎么办呢?第一种方法的好处就是它直接把这个控件里面的所有东西都放大了,而第二种放大仅仅把控件里的图片放大了。唉,还是没有解决问题呀。

WPF实现放大镜的更多相关文章

  1. WPF设置VistualBrush的Visual属性制作图片放大镜效果

    原文:WPF设置VistualBrush的Visual属性制作图片放大镜效果 效果图片:原理:设置VistualBrush的Visual属性,利用它的Viewbox属性进行缩放. XAML代码:// ...

  2. WPF放大镜效果

    在做WPF项目中,不止两个项目需要有放大镜功能. 第一个项目是一个手术室的远程示教系统,主要是为了方便专家演示病症时,可以放大图片上的某些部位. 第二个项目是一个工厂的MES项目,其中有个功能是质量预 ...

  3. WPF中利用RadialGradient模拟放大镜效果

    原文:WPF中利用RadialGradient模拟放大镜效果 --------------------------------------------------------------------- ...

  4. 《深入浅出WPF》笔记——绘画与动画

    <深入浅出WPF>笔记——绘画与动画   本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...

  5. WPF 学习笔记 路由事件

    1. 可传递的消息: WPF的UI是由布局组建和控件构成的树形结构,当这棵树上的某个节点激发出某个事件时,程序员可以选择以传统的直接事件模式让响应者来响应之,也可以让这个事件在UI组件树沿着一定的方向 ...

  6. WPF 如何画出1像素的线

    如何有人告诉你,请你画出1像素的线,是不是觉得很简单,实际上在 WPF 上还是比较难的. 本文告诉大家,如何让画出的线不模糊 画出线的第一个方法,创建一个 Canvas ,添加一个线 界面代码 < ...

  7. WPF自学入门(三)WPF路由事件之内置路由事件

    有没有想过在.NET中已经有了事件机制,为什么在WPF中不直接使用.NET事件要加入路由事件来取代事件呢?最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,是否还记得在WPF自学入门(一 ...

  8. Silverlight/WPF 系列汇总

    Silverlight 解谜游戏系列 -- Silverlight 3 · Silverlight 解谜游戏 之一 新建项目 · Silverlight 解谜游戏 之二 创建题板 · Silverli ...

  9. WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)

    WPF 自定义窗口样式有多种方式,不过基本核心实现都是在修改 Win32 窗口样式.然而,Windows 上的应用就应该有 Windows 应用的样子嘛,在保证自定义的同时也能与其他窗口样式保持一致当 ...

随机推荐

  1. STM32的RTC中断标志只能手动清除

    背景: 最近在做一个stm32的项目,其中用到RTC的实时时钟功能.时钟源采用外部32.768K晶振,时钟预分频设置为32767,目的是为了产生1秒的中断,然后在中断处理函数中更新实时年月日时分秒. ...

  2. 37 (OC)* 类别的作用

    问题: OC中类别(Category)是什么?Category类别是Objective-C语言中提供的一个灵活的类扩展机制.类别用于在不获悉.不改变原来代码的情况下往一个已经存在的类中添加新的方法,只 ...

  3. Java开发者薪资最低?程序员只能干到30岁?国外真的没有996?Intellij真的比Eclipse受欢迎?

    Stack Overflow作为全球最大的程序设计领域的问答网站,每年都会出据一份开发者调查报告.近日,Stack Overflow公布了其第9次年度开发者调查报告(https://insights. ...

  4. Spring——依赖注入(DI)详解

    声明:本博客仅仅是一个初学者的学习记录.心得总结,其中肯定有许多错误,不具有参考价值,欢迎大佬指正,谢谢!想和我交流.一起学习.一起进步的朋友可以加我微信Liu__66666666 这是简单学习一遍之 ...

  5. hadoop之hdfs命令详解

    本篇主要对hadoop命令和hdfs命令进行阐述,yarn命令会在之后的文章中体现 hadoop fs命令可以用于其他文件系统,不止是hdfs文件系统内,也就是说该命令的使用范围更广可以用于HDFS. ...

  6. [VB.NET Tips]赋值运算千万要注意

    赋值运算符是一个语句,不能在表达式中使用,表达式中的等号表示相等而不是赋值. 上示例: Dim x As Integer Dim y As Object x = 5 y = x = 5 Console ...

  7. Jmeter BeanShell 执行多次问题,每发送一次请求执行一次BeanShell问题

    前言:(此问题耗时半天) 提供解决思路的博主又有新问题了. 如图所示,写了一个BeanShell从文件中去获取值之后给测试计划的变量赋值. 问题来了,当禁用b的情况下,a只执行一次.当启用b请求的情况 ...

  8. 基于Docker搭建大数据集群(五)Mlsql部署

    主要内容 mlsql部署 前提 zookeeper正常使用 spark正常使用 hadoop正常使用 安装包 微云下载 | tar包目录下 mlsql-cluster-2.4_2.11-1.4.0.t ...

  9. APP设计与开发(ui篇)

    这篇文章是我个人在开发与设计APP的所用的一些设计思路,仅用于和大家分享知识并不是什么设计标准之类的.主要说明App的开发中是如何来开发与组织UI部分. UI模块结构 在项目中建立ui包用于存放ui类 ...

  10. mybatis - 通用mapper

    title: 玩转spring-boot-mybatis date: 2019-03-11 19:36:57 type: "mybatis" categories: mybatis ...