1
0

MyBitmap.vb 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. '一个万能的自动图片类型转换工具类
  2. Imports System.Drawing.Imaging
  3. Public Class MyBitmap
  4. ''' <summary>
  5. ''' 存储的图片
  6. ''' </summary>
  7. Public Pic As System.Drawing.Bitmap
  8. '自动类型转换
  9. '支持的类:Image,ImageSource,Bitmap,ImageBrush,BitmapSource
  10. Public Shared Widening Operator CType(Image As System.Drawing.Image) As MyBitmap
  11. If Image Is Nothing Then Return Nothing
  12. Return New MyBitmap(Image)
  13. End Operator
  14. Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Image
  15. If Image Is Nothing Then Return Nothing
  16. Return Image.Pic
  17. End Operator
  18. Public Shared Widening Operator CType(Image As ImageSource) As MyBitmap
  19. If Image Is Nothing Then Return Nothing
  20. Return New MyBitmap(Image)
  21. End Operator
  22. Public Shared Widening Operator CType(Image As MyBitmap) As ImageSource
  23. If Image Is Nothing Then Return Nothing
  24. Dim BitmapPic As System.Drawing.Bitmap = Image.Pic
  25. Dim rect = New System.Drawing.Rectangle(0, 0, BitmapPic.Width, BitmapPic.Height)
  26. Dim bitmapData = BitmapPic.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
  27. Try
  28. Dim Result = BitmapSource.Create(BitmapPic.Width, BitmapPic.Height, BitmapPic.HorizontalResolution, BitmapPic.VerticalResolution,
  29. PixelFormats.Bgra32, Nothing, bitmapData.Scan0,
  30. rect.Width * rect.Height * 4, bitmapData.Stride)
  31. Result.Freeze()
  32. Return Result
  33. Finally
  34. BitmapPic.UnlockBits(bitmapData)
  35. End Try
  36. End Operator
  37. Public Shared Widening Operator CType(Image As System.Drawing.Bitmap) As MyBitmap
  38. If Image Is Nothing Then Return Nothing
  39. Return New MyBitmap(Image)
  40. End Operator
  41. Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Bitmap
  42. If Image Is Nothing Then Return Nothing
  43. Return Image.Pic
  44. End Operator
  45. Public Shared Widening Operator CType(Image As ImageBrush) As MyBitmap
  46. If Image Is Nothing Then Return Nothing
  47. Return New MyBitmap(Image)
  48. End Operator
  49. Public Shared Widening Operator CType(Image As MyBitmap) As ImageBrush
  50. If Image Is Nothing Then Return Nothing
  51. Return New ImageBrush(New MyBitmap(Image.Pic))
  52. End Operator
  53. '构造函数
  54. Public Sub New()
  55. End Sub
  56. Public Sub New(FilePathOrResourceName As String)
  57. Try
  58. FilePathOrResourceName = FilePathOrResourceName.Replace("pack://application:,,,/images/", PathImage)
  59. If FilePathOrResourceName.StartsWithF(PathImage) Then
  60. '使用缓存
  61. Static Cache As New Concurrent.ConcurrentDictionary(Of String, MyBitmap)
  62. If Cache.ContainsKey(FilePathOrResourceName) Then
  63. Pic = Cache(FilePathOrResourceName).Pic
  64. Else
  65. Pic = New MyBitmap(CType((New ImageSourceConverter).ConvertFromString(FilePathOrResourceName), ImageSource))
  66. Cache.TryAdd(FilePathOrResourceName, Pic)
  67. End If
  68. Else
  69. '使用这种自己接管 FileStream 的方法加载才能解除文件占用
  70. Using InputStream As New FileStream(FilePathOrResourceName, FileMode.Open, FileAccess.Read, FileShare.Read)
  71. '判断是否为 WebP 文件头
  72. Dim Header(1) As Byte
  73. InputStream.Read(Header, 0, 2)
  74. InputStream.Seek(0, SeekOrigin.Begin)
  75. If Header(0) = 82 AndAlso Header(1) = 73 Then
  76. '读取 WebP
  77. Dim FileBytes(InputStream.Length - 1) As Byte
  78. InputStream.Read(FileBytes, 0, FileBytes.Length)
  79. Pic = WebPDecoder.DecodeFromBytes(FileBytes) '将代码隔离在另外一个类中,这样只要不走进这个分支就不会加载 Imazen.WebP.dll
  80. Else
  81. Pic = New System.Drawing.Bitmap(InputStream)
  82. End If
  83. End Using
  84. End If
  85. Catch ex As Exception
  86. Pic = My.Application.TryFindResource(FilePathOrResourceName)
  87. If Pic Is Nothing Then
  88. Pic = New System.Drawing.Bitmap(1, 1)
  89. If TypeOf ex Is ArgumentException Then
  90. Throw New Exception($"图片格式不支持,或图片文件损坏({FilePathOrResourceName})", ex)
  91. Else
  92. Throw New Exception($"加载 MyBitmap 意外失败({FilePathOrResourceName})", ex)
  93. End If
  94. Else
  95. Log(ex, $"指定类型有误的 MyBitmap 加载({FilePathOrResourceName})", LogLevel.Developer)
  96. Exit Try
  97. End If
  98. End Try
  99. End Sub
  100. Public Sub New(Image As ImageSource)
  101. Using MS = New MemoryStream()
  102. Dim Encoder = New PngBitmapEncoder()
  103. Encoder.Frames.Add(BitmapFrame.Create(Image))
  104. Encoder.Save(MS)
  105. Pic = New System.Drawing.Bitmap(MS)
  106. End Using
  107. End Sub
  108. Public Sub New(Image As System.Drawing.Image)
  109. Pic = Image
  110. End Sub
  111. Public Sub New(Image As System.Drawing.Bitmap)
  112. Pic = Image
  113. End Sub
  114. Public Sub New(Image As ImageBrush)
  115. Using MS = New MemoryStream()
  116. Dim Encoder = New BmpBitmapEncoder()
  117. Encoder.Frames.Add(BitmapFrame.Create(Image.ImageSource))
  118. Encoder.Save(MS)
  119. Pic = New System.Drawing.Bitmap(MS)
  120. End Using
  121. End Sub
  122. Private Class WebPDecoder '将代码隔离在另外一个类中,这样只要不调用这个方法就不会加载 Imazen.WebP.dll
  123. Public Shared Function DecodeFromBytes(Bytes As Byte()) As System.Drawing.Bitmap
  124. If Is32BitSystem Then Throw New Exception("不支持在 32 位系统下加载 WebP 图片。")
  125. Dim Decoder As New Imazen.WebP.SimpleDecoder()
  126. Return Decoder.DecodeFromBytes(Bytes, Bytes.Length)
  127. End Function
  128. End Class
  129. ''' <summary>
  130. ''' 获取裁切的图片,这个方法不会导致原对象改变且会返回一个新的对象。
  131. ''' </summary>
  132. Public Function Clip(X As Integer, Y As Integer, Width As Integer, Height As Integer) As MyBitmap
  133. Dim bmp As New System.Drawing.Bitmap(Width, Height, Pic.PixelFormat)
  134. bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
  135. Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
  136. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
  137. g.TranslateTransform(-X, -Y)
  138. g.DrawImage(Pic, New System.Drawing.Rectangle(0, 0, Pic.Width, Pic.Height))
  139. End Using
  140. Return bmp
  141. End Function
  142. ''' <summary>
  143. ''' 获取旋转或翻转后的图片,这个方法不会导致原对象改变且会返回一个新的对象。
  144. ''' </summary>
  145. Public Function RotateFlip(Type As System.Drawing.RotateFlipType) As MyBitmap
  146. Dim bmp As New System.Drawing.Bitmap(Pic)
  147. bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
  148. bmp.RotateFlip(Type)
  149. Return bmp
  150. End Function
  151. ''' <summary>
  152. ''' 将图像保存到文件。
  153. ''' </summary>
  154. Public Sub Save(FilePath As String)
  155. Dim encoder As BitmapEncoder = New PngBitmapEncoder()
  156. encoder.Frames.Add(BitmapFrame.Create(Me))
  157. Using fileStream As New FileStream(FilePath, FileMode.Create)
  158. encoder.Save(fileStream)
  159. End Using
  160. End Sub
  161. End Class