旋轉
(1)按角度旋轉
/// <summary> /// 根據角度旋轉圖標 /// </summary> /// <param name="img"></param> public Image RotateImg(Image img, float angle) { //通過Png圖片設置圖片透明,修改旋轉圖片變黑問題。 int width = img.Width; int height = img.Height; //角度 Matrix mtrx = new Matrix(); mtrx.RotateAt(angle, new PointF((width / 2), (height / 2)), MatrixOrder.Append); //得到旋轉后的矩形 GraphicsPath path = new GraphicsPath(); path.AddRectangle(new RectangleF(0f, 0f, width, height)); RectangleF rct = path.GetBounds(mtrx); //生成目標位圖 Bitmap devImage = new Bitmap((int)(rct.Width), (int)(rct.Height)); Graphics g = Graphics.FromImage(devImage); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //計算偏移量 Point Offset = new Point((int)(rct.Width - width) / 2, (int)(rct.Height - height) / 2); //構造圖像顯示區域:讓圖像的中心與窗口的中心點一致 Rectangle rect = new Rectangle(Offset.X, Offset.Y, (int)width, (int)height); Point center = new Point((int)(rect.X + rect.Width / 2), (int)(rect.Y + rect.Height / 2)); g.TranslateTransform(center.X, center.Y); g.RotateTransform(angle); //恢復圖像在水平和垂直方向的平移 g.TranslateTransform(-center.X, -center.Y); g.DrawImage(img, rect); //重至繪圖的所有變換 g.ResetTransform(); g.Save(); g.Dispose(); path.Dispose(); return devImage; }
(2)按弧度旋轉
/// <summary> /// 第二種方法 /// </summary> /// <param name="b"></param> /// <param name="angle"></param> /// <returns></returns> public Image RotateImg2(Image b, float angle) { angle = angle % 360; //弧度轉換 double radian = angle * Math.PI / 180.0; double cos = Math.Cos(radian); double sin = Math.Sin(radian); //原圖的寬和高 int w = b.Width; int h = b.Height; int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin))); int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos))); //目標位圖 Image dsImage = new Bitmap(W, H); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(dsImage); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //計算偏移量 Point Offset = new Point((W - w) / 2, (H - h) / 2); //構造圖像顯示區域:讓圖像的中心與窗口的中心點一致 Rectangle rect = new Rectangle(Offset.X, Offset.Y, w, h); Point center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); g.TranslateTransform(center.X, center.Y); g.RotateTransform(360-angle); //恢復圖像在水平和垂直方向的平移 g.TranslateTransform(-center.X, -center.Y); g.DrawImage(b, rect); //重至繪圖的所有變換 g.ResetTransform(); g.Save(); g.Dispose(); //dsImage.Save("yuancd.jpg", System.Drawing.Imaging.ImageFormat.Jpeg); return dsImage; }
以上參考:基於C#的兩種圖片旋轉方法
此外,可以直接使用已封裝的方法:
/// <summary> /// 旋轉(利用已封裝的方法) /// </summary> /// <param name="path">圖片路徑</param> /// <param name="rotateFlipType">旋轉方式</param> /// <returns></returns> public bool KiRotate(string path, RotateFlipType rotateFlipType) { try { using (Bitmap bitmap = new Bitmap(path)) { // 順時針旋轉90度 RotateFlipType.Rotate90FlipNone // 逆時針旋轉90度 RotateFlipType.Rotate270FlipNone // 水平翻轉 RotateFlipType.Rotate180FlipY // 垂直翻轉 RotateFlipType.Rotate180FlipX bitmap.RotateFlip(rotateFlipType); bitmap.Save(path); } return true; } catch(Exception ex) { return false; } }
轉換
(1)Bitmap & BitmapImage
// 程序集 System.Xaml.dll System.Drawing.dll WindowsBase.dll PresentationCore.dll // 命名空間 using System.Drawing; using System.IO; using System.Windows.Media.Imaging; using System.Windows.Interop; using System.Windows; /// <summary> /// 創建一個Bitmap對象 /// </summary> /// <param name="_uri">"../Images/test.png"</param> public Bitmap CreatBitmapObject(string _uri) { Bitmap bitmap = new Bitmap(_uri); return bitmap; } /// <summary> /// 創建一個BitmapImage對象 /// </summary> /// <param name="_uri">"../Images/test.png"</param> public BitmapImage CreatBitmapImageObject(string _uri) { BitmapImage bitmapImage = new BitmapImage( new Uri(_uri, UriKind.Relative)); return bitmapImage; } /// <summary> /// BitmapImage to Bitmap /// </summary> public Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage) { using (MemoryStream outStream = new MemoryStream()) { BitmapEncoder enc = new BmpBitmapEncoder(); enc.Frames.Add(BitmapFrame.Create(bitmapImage)); enc.Save(outStream); Bitmap bitmap = new Bitmap(outStream); return new Bitmap(bitmap); } } /// <summary> /// Bitmap to BitmapImage /// </summary> [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); public BitmapImage Bitmap2BitmapImage(Bitmap bitmap) { IntPtr hBitmap = bitmap.GetHbitmap(); BitmapImage retval; try { retval = (BitmapImage)Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); } finally { DeleteObject(hBitmap); } return retval; }
若是將Bitmap轉換成BitmapSource,只需將返回值類型更改為BitmapSource即可。
具體參考:Converting BitmapImage to Bitmap and vice versa;
(2)Bitmap/BitmapImage & byte[]
/// <summary> /// Bitmap to 字節數組 /// </summary> public byte[] Bitmap2Bytes(Bitmap bitmap) { ImageFormat format = bitmap.RawFormat; using (MemoryStream ms = new MemoryStream()) { bitmap.Save(ms, format); byte[] data = new byte[ms.Length]; //Save()會改變MemoryStream的Position,需要重新Seek到Begin也就是開始的0位置 ms.Seek(0, SeekOrigin.Begin); ms.Read(data, 0, Convert.ToInt32(ms.Length)); return data; } } /// <summary> /// 字節數組 to Bitmap /// </summary> public Bitmap Bytes2Bitmap(byte[] data) { MemoryStream ms = null; try { ms = new MemoryStream(data); return new Bitmap((Image)new Bitmap(ms)); } catch (Exception ex) { throw ex; } finally { ms.Close(); } } /// <summary> /// BitmapImage to 字節數組 /// </summary> public byte[] BitmapImage2Bytes(BitmapImage bitmapImage) { byte[] bytes = null; try { Stream ms = bitmapImage.StreamSource; if (ms != null && ms.Length > 0) { //很重要,因為Position經常位於stream的末尾,導致下面讀取到的長度為0 ms.Position = 0; using (BinaryReader br = new BinaryReader(ms)) { bytes = br.ReadBytes((int)ms.Length); } } } catch(Exception ex) { bytes = null; throw ex; } return bytes; } /// <summary> /// 字節數組 to BitmapImage /// </summary> public BitmapImage Bytes2BitmapImage(byte[] data) { BitmapImage bitmapImage = null; try { bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.StreamSource = new MemoryStream(data); bitmapImage.EndInit(); } catch(Exception ex) { bitmapImage = null; throw ex; } return bitmapImage; }
此時,可以總結下Bitmap、BitmapImage、Image和BitmapSource、ImageSource之間的關系
// Image抽象類,Bitmap密封類 public abstract class Image: xxx public sealed class Bitmap : Image // ImageSource和BitmapSource抽象類,BitmapImage密封類 public abstract class ImageSource: xxx public abstract class BitmapSource : ImageSource public sealed class BitmapImage : BitmapSource
壓縮
圖片大小 > 1M 時,可以對圖片進行壓縮,有效減小圖片大小、占用內存空間等。
/// <summary> /// 生成縮略圖 /// </summary> /// <param name="sourceFile">原始圖片文件</param> /// <param name="quality">質量壓縮比:0-100,越大質量越好</param> /// <param name="multiple">壓縮倍數</param> /// <param name="outputFile">輸出文件名</param> /// <returns>成功返回true,失敗返回false</returns> /// 調用格式:GetThumImage("", 85L, 3, ""); public static bool GetThumImage(string sourceFile, long quality, int multiple, string outputFile) { try { // 獲取圖片信息 Bitmap sourceImage = new Bitmap(sourceFile); ImageCodecInfo myImageCodecInfo = GetEncoderInfo(sourceImage.RawFormat); if (null == myImageCodecInfo) { return false; } // 壓縮質量 System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, quality); myEncoderParameters.Param[0] = myEncoderParameter; // 按比例壓縮 float _xWidth = sourceImage.Width; float _yWidth = sourceImage.Height; Bitmap newImage = new Bitmap((int)(_xWidth / multiple), (int)(_yWidth / multiple)); Graphics g = Graphics.FromImage(newImage); /// 可按需配置屬性 //g.CompositingQuality = CompositingQuality.HighQuality; //g.CompositingMode = CompositingMode.SourceCopy; //g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(sourceImage, 0, 0, (_xWidth / multiple), (_yWidth / multiple)); g.Dispose(); // 保存圖片 newImage.Save(outputFile, myImageCodecInfo, myEncoderParameters); return true; } catch { return false; } } /// <summary> /// 獲取圖片編碼信息 /// </summary> private static ImageCodecInfo GetEncoderInfo(ImageFormat format) { ImageCodecInfo[] encoders; encoders = ImageCodecInfo.GetImageEncoders(); for (int j = 0; j < encoders.Length; ++j) { if (encoders[j].FormatID == format.Guid) { return encoders[j]; } } return null; }
提供一個在工作中壓縮圖片的方法
public string CompressImageString(string str) { string convertedImageString = string.Empty; byte[] b = Convert.FromBase64String(str); MemoryStream ms = new MemoryStream(b); Bitmap bitMap = new Bitmap(ms); bitMap = CompressImage(bitMap); byte[] byteArray = null; using (MemoryStream stream = new MemoryStream()) { bitMap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); byteArray = new byte[stream.Length]; stream.Seek(0, SeekOrigin.Begin); if (stream.Read(byteArray, 0, Convert.ToInt32(stream.Length)) <= 0) { return ""; } } convertedImageString = Convert.ToBase64String(byteArray); return convertedImageString; } private Bitmap CompressImage(Bitmap bitmap, double compressRatio) { int width = (int)(bitmap.Width * compressRatio); int height = (int)(bitmap.Height * compressRatio); System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback); System.Drawing.Image myThumbnail = bitmap.GetThumbnailImage(width, height, myCallback, IntPtr.Zero); Bitmap compressBitmap = new Bitmap(myThumbnail); return compressBitmap; } public bool ThumbnailCallback() { return false; }
Base64處理
最常見的用於傳輸8Bit字節碼的編碼方式之一,可以將任意一組字節轉換為較長的常見文本字符序列,從而可以合法地作為首部字段值
- Base64:一種基於64個可打印字符以及用作后綴的等號來表示二進制數據的方法
- Base64編碼:從二進制到字符的過程,可用於在HTTP環境下傳遞較長的標識信息
- 編碼規則:每三個8Bit的字節轉換為四個6Bit的字節(3*8 = 4*6 = 24),然后把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換后的字符串理論上將要比原來的長1/3個字符變成4個字符,每76個字符加一個換行符,最后的結束符也要處理
其中,64個可打印字符包括:大小寫字母、數字、 + 和 / 。相關特點:
- 把含有不可見字符串的信息用可見字符串表示出來、降低出錯率,但具有不可讀性、需解碼
- 二進制序列的長度必須是24的倍數(6和8的最小公倍數)
- 等號一定用作后綴,且數目一定是0個、1個或2個
- 因為將3個字節轉化成4個字節,因此編碼后的文本,會比原文本大出三分之一左右
['A', 'B', 'C', 'D', ... 'a', 'b', 'c', 'd', ... '0', '1', '2', ... '+', '/']
注意,標准的Base64編碼存在 '+'和 '/',針對URL,通過"url safe"的base64編碼,將 '+'和 '/' 分別變成 '-'和 '_',同時會刪除結果最后的 '='
>>> base64.b64encode('i\xb7\x1d\xfb\xef\xff') 'abcd++//' >>> base64.urlsafe_b64encode('i\xb7\x1d\xfb\xef\xff') 'abcd--__'
對於二進制序列長度必須是24倍數的解釋:正常情況下,只要長度是6的倍數即可。但是,當連接兩段Base64編碼過的字符串后再解碼,這個時候就需要6和8的公倍數,即長度必須是24的倍數。
現在瀏覽器已有內置的自動生成base64的方法 atob()
和 btoa()
// 編碼 window.btoa() // 解碼 window.atob()
具體參見:window.btoa()
;window.atob()
;
注意,待編碼字符串若包含中文,直接編碼會出現問題,應采用如下方式
function utf8_to_b64( str ) { return window.btoa( unescape( encodeURIComponent( str ))); } function b64_to_utf8( str ) { return decodeURIComponent( escape( window.atob( str ))); }
參考: