Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Collections.Generic
Imports JiuSpdfvUtl
Imports JiuSpdfGeometry
Imports System.IO
' GDI画布类 - 封装GDI+图形操作
Public Class GDICanvas
Implements IDisposable
Private _graphics As Graphics
Private _bitmap As Bitmap
Private _width As Integer
Private _height As Integer
Private _dpiX As Single
Private _dpiY As Single
Private _transformStack As New Stack(Of Matrix)()
Private _stateStack As New Stack(Of GraphicsState)()
Private _disposedValue As Boolean = False
' 构造函数
Public Sub New(width As Integer, height As Integer)
_width = Math.Max(1, width)
_height = Math.Max(1, height)
Try
' 创建内存位图
_bitmap = New Bitmap(_width, _height)
_graphics = Graphics.FromImage(_bitmap)
InitializeGraphics()
Catch ex As Exception
LogHelper.LogError($"创建GDICanvas失败: {ex.Message}", "GDICanvas", ex)
Throw New InvalidOperationException("无法创建图形画布", ex)
End Try
End Sub
Public Sub New(graphics As Graphics, width As Integer, height As Integer)
If graphics Is Nothing Then
Throw New ArgumentNullException("graphics")
End If
_graphics = graphics
_width = Math.Max(1, width)
_height = Math.Max(1, height)
_bitmap = Nothing ' 外部Graphics不管理位图
InitializeGraphics()
End Sub
Public Sub New(image As Image)
If image Is Nothing Then
Throw New ArgumentNullException("image")
End If
_bitmap = If(TypeOf image Is Bitmap, DirectCast(image, Bitmap), New Bitmap(image))
_width = _bitmap.Width
_height = _bitmap.Height
_graphics = Graphics.FromImage(_bitmap)
InitializeGraphics()
End Sub
' 初始化图形设置
Private Sub InitializeGraphics()
Try
' 设置高质量渲染
_graphics.SmoothingMode = SmoothingMode.AntiAlias
_graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
_graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
_graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
_graphics.CompositingQuality = CompositingQuality.HighQuality
' 获取DPI
_dpiX = _graphics.DpiX
_dpiY = _graphics.DpiY
' 保存原始状态
SaveState()
Catch ex As Exception
LogHelper.LogError($"初始化GDICanvas失败: {ex.Message}", "GDICanvas", ex)
End Try
End Sub
' 属性访问器
Public ReadOnly Property Graphics As Graphics
Get
Return _graphics
End Get
End Property
Public ReadOnly Property Bitmap As Bitmap
Get
Return _bitmap
End Get
End Property
Public ReadOnly Property Width As Integer
Get
Return _width
End Get
End Property
Public ReadOnly Property Height As Integer
Get
Return _height
End Get
End Property
Public ReadOnly Property DpiX As Single
Get
Return _dpiX
End Get
End Property
Public ReadOnly Property DpiY As Single
Get
Return _dpiY
End Get
End Property
Public ReadOnly Property Size As Size
Get
Return New Size(_width, _height)
End Get
End Property
Public ReadOnly Property Bounds As Rectangle
Get
Return New Rectangle(0, 0, _width, _height)
End Get
End Property
Public ReadOnly Property IsDisposed As Boolean
Get
Return _disposedValue OrElse _graphics Is Nothing
End Get
End Property
Public ReadOnly Property HasBitmap As Boolean
Get
Return _bitmap IsNot Nothing
End Get
End Property
' 状态管理
Public Sub SaveState()
If IsDisposed Then Return
Try
_stateStack.Push(_graphics.Save())
Catch ex As Exception
LogHelper.LogError($"保存图形状态失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub RestoreState()
If IsDisposed OrElse _stateStack.Count = 0 Then Return
Try
_graphics.Restore(_stateStack.Pop())
Catch ex As Exception
LogHelper.LogError($"恢复图形状态失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 变换管理
Public Sub PushTransform()
If IsDisposed Then Return
Try
_transformStack.Push(_graphics.Transform.Clone())
Catch ex As Exception
LogHelper.LogError($"保存变换失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub PopTransform()
If IsDisposed OrElse _transformStack.Count = 0 Then Return
Try
_graphics.Transform = _transformStack.Pop()
Catch ex As Exception
LogHelper.LogError($"恢复变换失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 应用PDF矩阵变换
Public Sub ApplyMatrix(matrix As PDFMatrix)
If IsDisposed OrElse matrix Is Nothing Then Return
Try
Dim gdiMatrix = matrix.ToMatrix()
_graphics.MultiplyTransform(gdiMatrix)
Catch ex As Exception
LogHelper.LogError($"应用矩阵变换失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub ApplyMatrix(a As Single, b As Single, c As Single, d As Single, e As Single, f As Single)
ApplyMatrix(New PDFMatrix(New Single() {a, b, c, d, e, f}))
End Sub
' 重置变换
Public Sub ResetTransform()
If IsDisposed Then Return
Try
_graphics.ResetTransform()
Catch ex As Exception
LogHelper.LogError($"重置变换失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 坐标系转换
Public Function ToCanvasPoint(pdfPoint As PDFPoint) As PointF
If IsDisposed OrElse pdfPoint Is Nothing Then Return PointF.Empty
Try
Dim matrix = _graphics.Transform
Dim points As PointF() = {pdfPoint.ToPointF()}
matrix.TransformPoints(points)
Return points(0)
Catch ex As Exception
LogHelper.LogError($"坐标转换失败: {ex.Message}", "GDICanvas")
Return pdfPoint.ToPointF()
End Try
End Function
Public Function ToCanvasRectangle(pdfRect As PDFRectangle) As RectangleF
If IsDisposed OrElse pdfRect Is Nothing Then Return RectangleF.Empty
Try
Dim points As PointF() = {
New PointF(pdfRect.Left, pdfRect.Top),
New PointF(pdfRect.Right, pdfRect.Bottom)
}
Dim matrix = _graphics.Transform
matrix.TransformPoints(points)
Dim x = Math.Min(points(0).X, points(1).X)
Dim y = Math.Min(points(0).Y, points(1).Y)
Dim width = Math.Abs(points(1).X - points(0).X)
Dim height = Math.Abs(points(1).Y - points(0).Y)
Return New RectangleF(x, y, width, height)
Catch ex As Exception
LogHelper.LogError($"矩形转换失败: {ex.Message}", "GDICanvas")
Return pdfRect.ToRectangleF()
End Try
End Function
Public Function ToPDFPoint(canvasPoint As PointF) As PDFPoint
If IsDisposed Then Return PDFPoint.Empty
Try
Dim matrix = _graphics.Transform
Dim inverseMatrix = matrix.Clone()
inverseMatrix.Invert()
Dim points As PointF() = {canvasPoint}
inverseMatrix.TransformPoints(points)
Return New PDFPoint(points(0))
Catch ex As Exception
LogHelper.LogError($"逆向坐标转换失败: {ex.Message}", "GDICanvas")
Return New PDFPoint(canvasPoint.X, canvasPoint.Y)
End Try
End Function
' 清除画布
Public Sub Clear(color As Color)
If IsDisposed Then Return
Try
' 保存当前状态
SaveState()
' 重置变换以清除整个区域
Dim savedTransform = _graphics.Transform
_graphics.ResetTransform()
_graphics.Clear(color)
_graphics.Transform = savedTransform
' 恢复状态
RestoreState()
Catch ex As Exception
LogHelper.LogError($"清除画布失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub Clear()
Clear(Color.White)
End Sub
' 裁剪区域
Public Sub SetClip(rect As PDFRectangle)
If IsDisposed OrElse rect Is Nothing Then Return
Try
Dim canvasRect = ToCanvasRectangle(rect)
_graphics.SetClip(canvasRect)
Catch ex As Exception
LogHelper.LogError($"设置裁剪区域失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub SetClip(path As PDFPath)
If IsDisposed OrElse path Is Nothing Then Return
Try
Dim graphicsPath = path.ToGraphicsPath()
_graphics.SetClip(graphicsPath)
Catch ex As Exception
LogHelper.LogError($"设置路径裁剪失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub SetClip(region As Region)
If IsDisposed OrElse region Is Nothing Then Return
Try
_graphics.SetClip(region)
Catch ex As Exception
LogHelper.LogError($"设置区域裁剪失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub ResetClip()
If IsDisposed Then Return
Try
_graphics.ResetClip()
Catch ex As Exception
LogHelper.LogError($"重置裁剪失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 获取可见区域边界
Public ReadOnly Property VisibleClipBounds As RectangleF
Get
If IsDisposed Then Return RectangleF.Empty
Return _graphics.VisibleClipBounds
End Get
End Property
' 检查可见性
Public Function IsPointVisible(point As PDFPoint) As Boolean
If IsDisposed OrElse point Is Nothing Then Return False
Try
Dim canvasPoint = ToCanvasPoint(point)
Return VisibleClipBounds.Contains(canvasPoint)
Catch ex As Exception
Return False
End Try
End Function
Public Function IsRectangleVisible(rect As PDFRectangle) As Boolean
If IsDisposed OrElse rect Is Nothing Then Return False
Try
Dim canvasRect = ToCanvasRectangle(rect)
Return VisibleClipBounds.IntersectsWith(canvasRect)
Catch ex As Exception
Return False
End Try
End Function
' 渲染到另一个Graphics
Public Sub RenderTo(targetGraphics As Graphics, destRect As Rectangle)
If IsDisposed OrElse targetGraphics Is Nothing Then Return
Try
If _bitmap IsNot Nothing Then
targetGraphics.DrawImage(_bitmap, destRect)
End If
Catch ex As Exception
LogHelper.LogError($"渲染到Graphics失败: {ex.Message}", "GDICanvas")
End Try
End Sub
Public Sub RenderTo(targetGraphics As Graphics, destPoint As Point)
If IsDisposed OrElse targetGraphics Is Nothing Then Return
Try
If _bitmap IsNot Nothing Then
targetGraphics.DrawImageUnscaled(_bitmap, destPoint)
End If
Catch ex As Exception
LogHelper.LogError($"渲染到Graphics失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 保存到文件
Public Sub SaveToFile(filePath As String, Optional format As Imaging.ImageFormat = Nothing)
If IsDisposed OrElse _bitmap Is Nothing Then Return
Try
If format Is Nothing Then
format = Imaging.ImageFormat.Png
End If
_bitmap.Save(filePath, format)
Catch ex As Exception
LogHelper.LogError($"保存到文件失败: {ex.Message}", "GDICanvas", ex)
Throw New IOException($"无法保存图像到文件: {filePath}", ex)
End Try
End Sub
' 获取图像数据
Public Function GetImageBytes(Optional format As Imaging.ImageFormat = Nothing) As Byte()
If IsDisposed OrElse _bitmap Is Nothing Then Return New Byte() {}
Try
Using stream As New IO.MemoryStream()
If format Is Nothing Then
format = Imaging.ImageFormat.Png
End If
_bitmap.Save(stream, format)
Return stream.ToArray()
End Using
Catch ex As Exception
LogHelper.LogError($"获取图像数据失败: {ex.Message}", "GDICanvas", ex)
Return New Byte() {}
End Try
End Function
' 调整大小
Public Function Resize(newWidth As Integer, newHeight As Integer) As GDICanvas
If IsDisposed Then Return Nothing
Try
Dim resizedCanvas As New GDICanvas(newWidth, newHeight)
resizedCanvas.Graphics.DrawImage(_bitmap, 0, 0, newWidth, newHeight)
Return resizedCanvas
Catch ex As Exception
LogHelper.LogError($"调整画布大小失败: {ex.Message}", "GDICanvas", ex)
Return Nothing
End Try
End Function
' 创建副本
Public Function Clone() As GDICanvas
If IsDisposed Then Return Nothing
Try
If _bitmap IsNot Nothing Then
Return New GDICanvas(_bitmap.Clone())
Else
Return New GDICanvas(_width, _height)
End If
Catch ex As Exception
LogHelper.LogError($"克隆画布失败: {ex.Message}", "GDICanvas", ex)
Return Nothing
End Try
End Function
' 测量文本
Public Function MeasureText(text As String, font As Font) As SizeF
If IsDisposed OrElse text Is Nothing OrElse font Is Nothing Then
Return SizeF.Empty
End If
Try
Return _graphics.MeasureString(text, font)
Catch ex As Exception
LogHelper.LogError($"测量文本失败: {ex.Message}", "GDICanvas")
Return SizeF.Empty
End Try
End Function
Public Function MeasureText(text As String, font As Font, maxWidth As Single) As SizeF
If IsDisposed OrElse text Is Nothing OrElse font Is Nothing Then
Return SizeF.Empty
End If
Try
Return _graphics.MeasureString(text, font, CInt(maxWidth))
Catch ex As Exception
LogHelper.LogError($"测量文本失败: {ex.Message}", "GDICanvas")
Return SizeF.Empty
End Try
End Function
' 检查是否支持透明
Public ReadOnly Property SupportsTransparency As Boolean
Get
If _bitmap Is Nothing Then Return False
Return _bitmap.PixelFormat = Imaging.PixelFormat.Format32bppArgb
End Get
End Property
' 设置透明度支持
Public Sub EnableTransparency()
If IsDisposed OrElse _bitmap Is Nothing Then Return
Try
If Not SupportsTransparency Then
Dim newBitmap As New Bitmap(_width, _height, Imaging.PixelFormat.Format32bppArgb)
Using g = Graphics.FromImage(newBitmap)
g.DrawImage(_bitmap, Point.Empty)
End Using
_bitmap.Dispose()
_bitmap = newBitmap
_graphics.Dispose()
_graphics = Graphics.FromImage(_bitmap)
InitializeGraphics()
End If
Catch ex As Exception
LogHelper.LogError($"启用透明度失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 获取像素颜色
Public Function GetPixel(x As Integer, y As Integer) As Color
If IsDisposed OrElse _bitmap Is Nothing Then Return Color.Empty
Try
If x >= 0 AndAlso x < _width AndAlso y >= 0 AndAlso y < _height Then
Return _bitmap.GetPixel(x, y)
End If
Return Color.Empty
Catch ex As Exception
LogHelper.LogError($"获取像素颜色失败: {ex.Message}", "GDICanvas")
Return Color.Empty
End Try
End Function
' 设置像素颜色
Public Sub SetPixel(x As Integer, y As Integer, color As Color)
If IsDisposed OrElse _bitmap Is Nothing Then Return
Try
If x >= 0 AndAlso x < _width AndAlso y >= 0 AndAlso y < _height Then
_bitmap.SetPixel(x, y, color)
End If
Catch ex As Exception
LogHelper.LogError($"设置像素颜色失败: {ex.Message}", "GDICanvas")
End Try
End Sub
' 释放资源
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _disposedValue Then
If disposing Then
If _graphics IsNot Nothing Then
_graphics.Dispose()
_graphics = Nothing
End If
If _bitmap IsNot Nothing Then
_bitmap.Dispose()
_bitmap = Nothing
End If
While _stateStack.Count > 0
_stateStack.Pop()
End While
While _transformStack.Count > 0
_transformStack.Pop().Dispose()
End While
End If
_disposedValue = True
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(disposing:=True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Dispose(disposing:=False)
End Sub
End Class
最新发布