WPF 中的一些图片处理方法

一,视觉处理(控件展示)

1,显示图片

  • Image控件展示

Xaml代码:

<Image source="/Resources/Images/1.png"/>
  • 缩放位图渲染算法

Xaml代码:

<Image Source="/Resources/Images/1.jpg" RenderOptions.BitmapScalingMode="Fant"/>

枚举值 描述
Fant 使用超高质量 Fant 位图缩放,虽然速度比所有其他位图缩放模式都慢,但输出质量更高。
HighQuality 使用高质量位图缩放,虽然速度比 LowQuality 模式慢,但输出质量更高。 HighQuality 模式与 Fant 模式相同。
Linear 使用线性位图缩放,虽然速度比 HighQuality 模式快,但输出质量较低。
LowQuality 使用双线性位图缩放,虽然速度比 HighQuality 快,但输出质量较低。 LowQuality 模式与 Linear 模式相同。
NearesNeighbor 使用最近邻域位图缩放,当使用软件光栅器时,该缩放提供优于 LowQuality 模式的性能。 该模式常用于放大位图。
Unspecified 使用默认位图缩放模式,即 Linear。

2,Image遮罩

  • OpacityMask

来自微软官方的说明:

获取或设置一个作为 Brush 实现的不透明蒙板,该蒙板可应用到此元素所呈现内容的任何 Alpha 通道蒙板。 这是依赖项属性。

来自个人的经验解释:

OpacityMask也是一张图片,它用来改变被它遮住的内容的显示区域,

OpacityMasK本身:有内容的区域被镂空,没有内容的区域被填充

被它遮住的控件或者画布:镂空的区域就展示,填充的区域变透明



3,图片DPI

  • 图片DPI是每英寸显示的点的个数(点/英寸)
  • 图片的宽像素=宽dpi*尺寸
  • 图片的高像素=高dpi*尺寸
  • WPF 中,所有图片在Xaml中都会被强制拉成96dpi。

4,控件的Transform

来自微软官方的说明:

Transform 定义如何将点从一个坐标空间映射或转换到另一个坐标空间。 此映射由转换 Matrix描述,该转换是包含三列 Double 值的三行的集合。

枚举值 描述
RotateTransform 按指定角度旋转元素。
ScaleTranform 按指定的 ScaleX 和 ScaleY 量来缩放元素。
SkewTransform 按指定的 AngleX 和 AngleY 量倾斜元素。
TranslateTransform 按指定的 X 和 Y 量移动(平移)元素。

Xaml代码:

<Image Width="450" Source="/Images/3.jpg">
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform X="10" Y="10" />
<RotateTransform Angle="20" CenterX="200" CenterY="121"/>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" CenterX="200" CenterY="121"/>
<SkewTransform AngleX="10" AngleY="10" CenterX="200" CenterY="121"/>
</TransformGroup>
</Image.RenderTransform>
</Image>


二,输出文件

1,显示图片

①,BitmapImage的保存

与Bitmap.Save()不同,需要对BitmapImage的数据转为Stream,通过文件流保存

C#代码

BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frame.Add(BitmapFrame.Create(bitmapImage));
using(var straem=new FileStream(path,FileMode.Create)){
encoder.Save(stream);
}

②,BitmapImage的Width,Height和PixelWidth,PixelHeight

Width和Height:获取位图的宽/高度(以与设备无关的单位(每个单位 1/96 英寸)为单位)。(会根据电脑DPI的更改获取到不同的值)

PixelWidth和PixelHeight:获取位图的宽/高度(以像素为单位)

③,BitmapImage与Bitmap的互相转换

同样是转为流数据,向Bitmap的构造函数传参

//BitmapImage  to  Bitmap
public static Bitmap GetBitmapByBitmapImage(this BitmapImage bitmapImage,bool isPng=false) {
Bitmap bitmap;
MemoryStream outStream = new MemoryStream();
BitmapEncoder enc = new BmpBitmapEncoder();
if (isPng) {
enc = new PngBitmapEncoder();
}
enc.Frames.Add(BitmapFrame.Create(bitmapImage));
enc.Save(outStream);
bitmap = new Bitmap(outStream);
return bitmap;
}
// Bitmap to BitmapImage
public static BitmapImage GetBitmapImageBybitmap(this Bitmap bitmap) {
BitmapImage bitmapImage = new BitmapImage();
try {
using (MemoryStream ms = new MemoryStream()) {
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
bitmapImage.BeginInit();
bitmapImage.StreamSource = ms;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
}
catch (Exception ex) {
log.ErrorFormat("bitmap to BitmapImage Failed:" + ex.Message);
}
return bitmapImage;
}

2,Visual和DrawingContext

①,Visual

Visual:为 WPF 中的呈现提供支持,其中包括命中测试、坐标转换和边界框计算。

层级关系:

System.Windows.Media.Visual

     System.Windows.Media.ContainerVisual

            System.Windows.UIElement

②,DrawingContext

DrawingContext:使用绘图、推送和弹出命令描述可视内容。

绘制方法:

DrawDrawing: 画Drawing对象

DrawEllipse: 画圆

DrawGeometry: 画几何图形

DrawGlyphRun:画文字

DrawImage: 画图

DrawLine:画线

DrawRectangle/DrawRoundedRectangle:画矩形

DrawText:画带格式的文本

DrawVideo:画视频

PushClip:推送剪切区域

③,RenderTargetBitmap

RenderTargetBitmap:将System.Windows.Media.Visual 对象转换为位图。

④,Image遮罩

和控件方式类似,在后台代码中使用Visual来展示

C#代码

RenderTargetBitmap bmp = new RenderTargetBitmap((int)img.Source.Width, (int)img.Source.Height, 96, 96, PixelFormats.Default);
DrawingVisual visual = new DrawingVisual() { OpacityMask = imgBrush };//遮罩Visual
using (DrawingContext dc = visual.RenderOpen()) {
dc.DrawImage(img.Source, new Rect(0, 0, img.Source.Width, img.Source.Height));
}
bmp.Render(visual);

⑤,图像变化

同样是修改Visual的Transform

这里注意:文件渲染的Transform和前台的Transform不全相同!!!!

因为界面显示的图片大小和实际大小不一样

C#代码

RenderTargetBitmap bmp = new RenderTargetBitmap((int)img.Source.Width, (int)img.Source.Height, 96, 96, PixelFormats.Default);
DrawingVisual visual = new DrawingVisual() { Transform=img.RenderTransform };//修改Transform
using (DrawingContext dc = visual.RenderOpen()) {
dc.DrawImage(img.Source, new Rect(0, 0, img.Source.Width, img.Source.Height));
}
bmp.Render(visual);

⑥,PathGeometry

来自微软官方的解释:表示一个可能由弧、曲线、椭圆、直线和矩形组成的复杂形状

LineGeometry 直线

ps:这个LineGeometry可以实现线头和线尾的圆滑笔触效果

new LineGeometry(start, end).GetWidenedPathGeometry(new Pen(Brushes.Black, 10) { StartLineCap = PenLineCap.Round, EndLineCap = PenLineCap.Round });

EllipseGeometry 圆

RectangleGeometry 矩形

⑦,抠图

通过DrawingContext的PushClip可以将指定的剪辑区域推送到绘图上下文上。

需要利用到上面的Geometry几何图形

配合一些鼠标事件可以手动实现inkcanvas和类似PS的背景橡皮擦

C#代码

RenderTargetBitmap bmp = new RenderTargetBitmap((int)img.Source.Width, (int)img.Source.Height, 96, 96, PixelFormats.Default);
DrawingVisual visual = new DrawingVisual() { OpacityMask = imgBrush };//遮罩Visual
using (DrawingContext dc = visual.RenderOpen()) {
RectangleGeometry full = new RectangleGeometry(new Rect(0,0,777,523));//全图区域
var clip= Geometry.Combine(full, new RectangleGeometry(new Rect(200,200,300,300)), GeometryCombineMode.Exclude, null);//减去一个矩形的区域
dc.PushClip(clip);//推送clip区域结果
dc.DrawImage(img.Source, new Rect(0, 0, img.Source.Width, img.Source.Height));
}
bmp.Render(visual);

正方形抠图



线条抠图

⑧,裁剪

  • BitmapSource中有一个方法叫做CopyPixels,复制像素点集到一个新的BitmapSource里面。可以实现裁剪

stride:位图的跨距(一行的字节数)。

pixels:表示位图图像内容的字节数组。

public static BitmapSource CutImage(BitmapSource bitmapSource, Int32Rect cut) {
//计算Stride
var stride = bitmapSource.Format.BitsPerPixel * cut.Width / 8;
//声明字节数组
byte[] data = new byte[cut.Height * stride];
//调用CopyPixels
bitmapSource.CopyPixels(cut, data, stride, 0);
return BitmapSource.Create(cut.Width, cut.Height, 0, 0, PixelFormats.Bgra32, null, data, stride);
}

WPF之图片处理系列的更多相关文章

  1. WPF之图片处理系列(19/590)

    https://www.cnblogs.com/Big-Head/p/12068230.html

  2. WPF Step By Step 系列 - 开篇 ·

    WPF Step By Step 系列 - 开篇 公司最近要去我去整理出一个完整的WPF培训的教程,我刚好将自己学习WPF的过程和经验总结整理成笔记的方式来讲述,这里就不按照书上面的东西来说了,书本上 ...

  3. C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试(续)

    介绍 本文是接着上文<C# WPF 显示图片和视频显示 EmuguCv.AForge.Net测试>写的,建议先看下上文,因为有些代码还需要了解. 增添 接着上文的代码,我们可以在事件处理方 ...

  4. WPF Step By Step 系列-Prism框架在项目中使用

    WPF Step By Step 系列-Prism框架在项目中使用 回顾 上一篇,我们介绍了关于控件模板的用法,本节我们将继续说明WPF更加实用的内容,在大型的项目中如何使用Prism框架,并给予Pr ...

  5. WPF从我炫系列4---装饰控件的用法

    这一节的讲解中,我将为大家介绍WPF装饰控件的用法,主要为大家讲解一下几个控件的用法. ScrollViewer滚动条控件 Border边框控件 ViewBox自由缩放控件 1. ScrollView ...

  6. WPF显示图片

    1.WPF显示图片内部一部分 <Rectangle Height="> <Rectangle.Fill > <ImageBrush ImageSource=&q ...

  7. Silverlight或WPF动态绑定图片路径问题,不用Converter完美解决

    关于Silverlight或WPF动态绑定图片路径问题,不用Converter完美解决, 可想,一个固定的字符串MS都能找到,按常理动态绑定也应该没问题的,只需在前面标记它是一个Path类型的值它就能 ...

  8. WPF 修改图片颜色

    原文:WPF 修改图片颜色 本文告诉大家如何修改图片的颜色,如去掉图片的蓝色 在 WPF 可以使用很多图片处理的方法,本文告诉大家的是一个图片处理,可以把处理的图片保存在文件. 在阅读本文,我假设大家 ...

  9. 使用WPF将图片转变为灰度并加上水印并保存为文件

    原文:使用WPF将图片转变为灰度并加上水印并保存为文件 运行效果: (上图中左下角为原图的缩小显示,By:Johnson为TextBlock)保存的结果图片:上图的"Test Words.& ...

随机推荐

  1. 防火墙和SELinux复习02

    1.防火墙 防火墙主要起隔离作用,严格的过滤入站,允许出站.又分为硬件防火墙和软件防火墙,硬件防火墙主要保护一群机器,而软件防火墙主要保护本机. 防火墙相关命令:systemctl status fi ...

  2. Deep attention tracking via Reciprocative Learning

    文章:Deep attention tracking via Reciprocative Learning 出自NIPS2018 文章链接:https://arxiv.org/pdf/1810.038 ...

  3. es6 every的使用

    let arr2 =[1,3,5,7,9,10]; //arr2.every() 数组里面所有的元素都有符合条件,才返回true var b =arr2.every(function (val,ind ...

  4. CSP2019,RP+=150。

    csp2019游记 第一题水死了,2分钟过! 第二题被卡住了,才得了30分. 第三题背包DP,可惜了,出了考场才知道... 第四题骗到20分,也算心满意足了.. 150,省二左右,辣鸡... 反正就是 ...

  5. solr数据操作

    本文介绍solr的基本数据操作,基于solr 8.2.solr支持多种数据格式,包括XML,JSON,CSV等,并提供多种脚本和工具来操作数据.本文讲解curl请求和JSON数据格式的处理方式. 本文 ...

  6. Selenium+Java(九)Selenium键盘与鼠标事件

    一.键盘事件 ctrl+a driver.findElement(By.id("kw")).sendKeys(Keys.CONTROL, "a"); ctrl+ ...

  7. IDEA启动tomcat报java.net.SocketExceptionsocket closed

    IDEA启动tomcat报java.net.SocketException:socket closed.如图所示   解决方法:打开任务管理器,检查有没有java.exe进程. 关闭了重新启动就好了 ...

  8. 页面嵌套iframe的时候引发的js交互问题

    今天在做一个新页面的时候,用到了iframe这个东西.结果出现了一个有趣的问题.自己写的页面和iframe里边的页面属性和js有冲突.具体的点说就是层级出现了问题.不能正常显示.不管怎么修改,总是解决 ...

  9. java访问数据库被拒绝,不能连接数据库ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

    错误原因:mysql数据库只允许本地ip访问: 解决方法:修改mysql表设置所有ip都可以访问: 登录数据库 使用以下命令: use mysql; grant all privileges on * ...

  10. Lua的面向对象,封装,继承,多态

    概述 我们总所周知对象是由属性和方法组成的,要用lua要描述一个对象,也必然要有这两个特性,属性和方法.lua的基本结构是table,所以Lua的类,其实都是table,因为它可以存储普通的变量又可以 ...