WPF之图片处理系列
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 英寸)为单位)。
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几何图形
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); }