WPF中一些圖片處理方案整理,可以大致實現類似PS的一些基本功能:移動,裁剪,摳圖,背景橡皮擦等等 ...
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);
}