WPF之圖片處理系列

WPF 中的一些圖片處理方法

一,視覺處理(控件展現)

1,顯示圖片

  • Image控件展現算法

    Xaml代碼:canvas

<Image source="/Resources/Images/1.png"/>
  • 縮放位圖渲染算法c#

    Xaml代碼:api

<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 通道蒙板。 這是依賴項屬性。ide

來自我的的經驗解釋:
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,經過文件流保存this

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);
}

相關文章
相關標籤/搜索