欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c# WinForm制作圖片編輯工具(圖像拖動、縮放、旋轉、摳圖)

 更新時間:2021年03月09日 08:27:49   作者:源之緣  
這篇文章主要介紹了c# WinForm制作圖片編輯工具(可實現(xiàn)圖像拖動、縮放、旋轉、摳圖),幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下

閑暇之余,開發(fā)一個圖片編輯小程序。程序主要特點就是可方便的對多個圖像編輯,實現(xiàn)了一些基本的操作。本文主要介紹一下程序的功能、設計思路。

執(zhí)行程序 下載地址:

https://pan.baidu.com/s/1cszsgjKN9ecWZ9sm1hDAdQ

1 功能介紹

程序主界面

點擊打開圖片,可選擇多個圖片文件。圖片縮略圖左側顯示,雙擊左側圖片,添加到編輯區(qū)。

圖片編輯區(qū)分為:紙張區(qū)域和打印區(qū)域。圖片只能在打印區(qū)編輯。當選中這兩個區(qū),可調整各個區(qū)的大小。

 主要功能點:

1 拖動:選中圖片后,可以任意拖動圖片。

2 縮放:可對圖片左右上下實現(xiàn)縮放??梢枣i定顯示比例縮放。

3 旋轉,可以選擇旋轉基點再旋轉。如果不選擇旋轉基點,以對角為基點旋轉。

4 摳圖

5 其他一些操作

當有多個圖片相互覆蓋時,可以調整圖層。

選中一個圖片后,可以對圖片的位置、大小、旋轉角度調整。

選擇保存,會將編輯的圖片保存為文件。

2 處理思路

  圖片編輯信息 每個圖像都有對應的變量記錄該圖像的詳細,比如位置、尺寸、旋轉角度、剪切區(qū)域。見下面代碼:

public class ImageProperty
 {
 public string Name { get; set; }
 public Image EditImage { get; set; } //原始圖片

 public int ActualWidth => EditImage.Width; //實際尺寸
 public int ActualHeight => EditImage.Height;

 public bool ShowImageTip { get; set; } = true;

 public bool LockSizeRate { get; set; } //比例是否鎖定
 public Size DrawSize { get; set; } //顯示尺寸
 public object Tag { get; set; }
 }

 public class ImageEditInfo
 {
 public ImageProperty ImageProperty { get; set; }

 public Point Location { get; set; } = new Point(0, 0); //相對于打印區(qū)的位置
 public Point LocationTopRight => new Point(Location.X + Width, Location.Y);
 public Point LocationBottomRight => new Point(Location.X + Width, Location.Y + Height);
 public Point LocationBottomLeft => new Point(Location.X, Location.Y + Height);

 public int RightX => Location.X + Width;
 public int ButtomY => Location.Y + Height;

 public Size DrawSize
 {
 get { return ImageProperty.DrawSize; }
 set { ImageProperty.DrawSize = value; }
 }

 public Image Image => ImageProperty.EditImage;

 public float RotateAngle { get; set; } = 0; //旋轉角度

 public bool IsSelect { get; set; }

 public bool LockSizeRate //顯示比例是否鎖定
 {
 get
 {
 return ImageProperty.LockSizeRate;
 }
 set
 {
 ImageProperty.LockSizeRate = value;
 }
 }

 public int Width
 {
 get
 {
 return DrawSize.Width;
 }
 set
 {
 ImageProperty.DrawSize = new Size(value, DrawSize.Height);
 }
 }

 public int Height
 {
 get
 {
 return DrawSize.Height;
 }
 set
 {
 ImageProperty.DrawSize = new Size(DrawSize.Width, value);
 }
 }

 public bool ShowImageTip
 {
 get { return ImageProperty.ShowImageTip; }
 set { ImageProperty.ShowImageTip = value; }
 } 

 public Point? RotatioBasePoint { get; set; } //旋轉基點

 public Point RotatioBasePointValue => RotatioBasePoint.Value;

 public bool HasRotatioBasePoint => (RotatioBasePoint != null && RotatioBasePoint.HasValue);
}

圖片旋轉

對正常的圖片移動、縮放并不難。只要調整圖像的長寬、位置就行,基本就是加法減法計算。如果圖片有旋轉,計算起來就麻煩。比如判斷鼠標是否點擊了圖片、鼠標縮放等,實現(xiàn)這些操作都麻煩。

比如判斷鼠標是否點擊了圖片,如果一個圖片是斜的(旋轉后的),如何處理?我的思路是旋轉:將圖片和鼠標所在的點都反向旋轉;此后,判斷邏輯就和常規(guī)方法一樣了。旋轉函數(shù)如下:

/// <summary>
 /// pointMove相對于removeAt,以一定角度旋轉
 /// </summary>
 /// <param name="pointMove"></param>
 /// <param name="removeAt"></param>
 /// <param name="rotateAngle"></param>
 /// <param name="clockwise"></param>
 /// <returns></returns>
 public static Point RotationAt(Point pointMove, Point removeAt, double rotateAngle, bool clockwise)
 {
 if (rotateAngle == 0)
 return pointMove;

 lock (matrix)
 {
 matrix.Reset();
 matrix.Rotate((float)(clockwise ? rotateAngle : -rotateAngle));

 Point pt2 = new Point(pointMove.X - removeAt.X, pointMove.Y - removeAt.Y);
 Point[] pts = new Point[] { new Point(pt2.X, pt2.Y) };
 matrix.TransformPoints(pts);

 Point result = new Point(pts[0].X + removeAt.X, pts[0].Y + removeAt.Y);
 return result;
 }
 }

 internal EN_LinePart MouseMove_HitTest(Point pt)
 {
 //鼠標位置 反向旋轉,
 pt = DrawHelper.RotationAt(pt, Location, RotateAngle, false);

 //下面就是 和正常判斷邏輯一樣
 EN_LinePart result = MouseMove_HitTest_Corner(pt);
 if (result != EN_LinePart.無)
 return result;
}

畫圖:

對圖片相關參數(shù)修改后,需要調用refresh,強制重畫。調用GDI+。根據(jù)圖片在列表的順序調用(也就是根據(jù)圖層)。調用時,根據(jù)設定顯示區(qū)域,旋轉角度等,做變換后再畫。

void DrawWithRotation(Graphics g, bool saveToFile)
 {
 //設置質量
 ImageHelper.SetHighQuality(g);

 //置背景色
 if (!saveToFile)
 g.Clear(BackgroundColor);

 ImageEditInfo selectImage = null;
 foreach (ImageEditInfo imageInfo in ImageGroup.ListImageToDraw)
 {
 //畫圖片
 if (imageInfo.IsSelect)
 {
  Debug.Assert(selectImage == null);
  selectImage = imageInfo;
 }

 g.TranslateTransform(imageInfo.Location.X, imageInfo.Location.Y);
 g.RotateTransform(imageInfo.RotateAngle);

 //是否需要畫 摳圖
 Image imageToDraw = imageInfo.Image;
 if (imageInfo.CutStat == ImageCutStat.have_cut
  && imageInfo.CutPoints.Count > 2)
 {
  Bitmap bitmap = imageToDraw as Bitmap;
  System.Windows.Point[] points = imageInfo.CutPoints.Select(o => new System.Windows.Point(o.X,o.Y)).ToArray();
  Bitmap cutBitmap = ImageCutout.GetImage(bitmap, points);
  imageToDraw = cutBitmap;
 }

 g.DrawImage(imageToDraw,
  new Rectangle(0, 0, imageInfo.DrawSize.Width, imageInfo.DrawSize.Height),
  new Rectangle(0, 0, imageInfo.Image.Width, imageInfo.Image.Height),
  GraphicsUnit.Pixel);

 //畫旋轉基點
 if (!saveToFile && imageInfo.HasRotatioBasePoint)
 {
  Point pt = imageInfo.RotatioBasePointValue;
  g.FillEllipse(RotatioBaseBrush, pt.X - RotatioBaseRadius, pt.Y - RotatioBaseRadius, RotatioBaseRadius * 2, RotatioBaseRadius * 2);
 }

 //顯示信息
 if (!saveToFile && imageInfo.ShowImageTip)
 { 
  ImageProperty ImageProperty = imageInfo.ImageProperty;
  string info = string.Format($"({imageInfo.Location.X},{imageInfo.Location.Y}) ({ImageProperty.ActualWidth}X{ImageProperty.ActualHeight}--{imageInfo.DrawSize.Width}X{imageInfo.DrawSize.Height}) (∠{imageInfo.RotateAngle.ToString("0.00")})");

  SizeF sizeF = g.MeasureString(info, _drawProperty.TxtFont);
  g.FillRectangle(_drawProperty.TxtBackgroundBrush,
  new RectangleF(new Point(), sizeF));

  g.DrawString(info, _drawProperty.TxtFont, _drawProperty.TxtBrush, new Point());
 }

 //畫摳圖線
 if(!saveToFile
  && imageInfo.CutStat == ImageCutStat.in_cuting
  && imageInfo.CutPoints.Count>1)
 {
  for(int i=1;i< imageInfo.CutPoints.Count;i++ )
  {
  g.DrawLine(SelectBorderPen, imageInfo.ToDestImage(imageInfo.CutPoints[i-1]),
  imageInfo.ToDestImage(imageInfo.CutPoints[i]));
  }

  if(imageInfo.CutPoints.Count > 2)
  {
  g.DrawLine(SelectBorderPen, imageInfo.ToDestImage(imageInfo.CutPoints.First()),
  imageInfo.ToDestImage(imageInfo.CutPoints.Last()));
  }
 }

 g.ResetTransform();
 }

 //畫選中狀態(tài) 
 if (!saveToFile && selectImage != null)
 {
 DrawSelectImageWithRotation(g, selectImage);
 }
 }

后記:

一般來講,圖像的處理屬于比較難的操作。需要有空間想象能力,相應的幾何數(shù)學基礎。不過,如果掌握好了圖像操作,對了解控件原理很有幫助。當遇到難以實現(xiàn)的界面,gdi+就是最后的手段;winform也是微軟過時的技術了,使用winform作圖效率很難提高;為了響應的事件,不停重畫,效率很低。WPF對圖像的操作又進了一步,wpf屬于“保持模型”,就是你告訴操作系統(tǒng)你要畫什么就行了,只需要告訴一次。而對于winform,操作系統(tǒng)不停的告訴你,你需要重畫了。這就導致winform畫圖效率比較低,但是省了內存。

以上就是c# WinForm制作圖片編輯工具(圖像拖動、縮放、旋轉、摳圖)的詳細內容,更多關于c# WinForm圖片編輯的資料請關注腳本之家其它相關文章!

相關文章

  • c#源碼的執(zhí)行過程詳解

    c#源碼的執(zhí)行過程詳解

    在本篇文章中給大家詳細講述了c#源碼的執(zhí)行過程,對此有需要的朋友們可以學習下。
    2018-07-07
  • C#拼圖游戲編寫代碼

    C#拼圖游戲編寫代碼

    這篇文章主要為大家詳細介紹了C#拼圖游戲的編寫代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • C# Dictionary的使用實例代碼

    C# Dictionary的使用實例代碼

    C# Dictionary的使用實例代碼,需要的朋友可以參考一下
    2013-04-04
  • C#中fixed關鍵字的作用總結

    C#中fixed關鍵字的作用總結

    以下是對C#中fixed關鍵字的作用進行了詳細的總結介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-09-09
  • C#使用NPOI庫讀寫Excel文件

    C#使用NPOI庫讀寫Excel文件

    這篇文章主要為大家詳細介紹了C#使用NPOI庫讀寫Excel文件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#生成漂亮驗證碼完整代碼類

    C#生成漂亮驗證碼完整代碼類

    本文主要介紹了C#生成漂亮驗證碼的完整代碼類。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • WCF實現(xiàn)的計算器功能實例

    WCF實現(xiàn)的計算器功能實例

    這篇文章主要介紹了WCF實現(xiàn)的計算器功能,結合具體實例形式較為詳細的分析了WCF實現(xiàn)計算器功能的具體步驟與相關操作技巧,需要的朋友可以參考下
    2017-06-06
  • C#實現(xiàn)鐘表程序設計

    C#實現(xiàn)鐘表程序設計

    這篇文章主要為大家詳細介紹了C#實現(xiàn)鐘表程序設計,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C#?md5?算法實現(xiàn)代碼

    C#?md5?算法實現(xiàn)代碼

    相對C#來說,md5算法就相對簡單很多,因為?System.Security.Cryptography;?已經包含了md5算法。所以我們只需創(chuàng)建MD5類對象即可實現(xiàn)md5算法,今天通過本文給大家介紹C#?md5?算法實現(xiàn),感興趣的朋友一起看看吧
    2022-11-11
  • 使用Barrier來控制線程同步示例

    使用Barrier來控制線程同步示例

    這篇文章主要介紹了使用Barrier來控制線程同步示例,需要的朋友可以參考下
    2014-04-04

最新評論