作者:DarkBaron_ | 来源:互联网 | 2022-11-16 09:18
1> Jimi..:
问题所在:
位图的尺寸远小于用于显示它的容器,它很模糊,并且明确定义的颜色区域的锐利边缘被毫不客气地混合.
这只是在放大时应用于非常小的图像(几个像素)的双线性滤波器的结果.
期望的结果是在图像被放大时保持单个像素的原始颜色.
要实现此结果,将Graphics对象的InterpolationMode设置为:
e.Graphics.InterpolatiOnMode= InterpolationMode.NearestNeighbor
此过滤器也称为Point Filter
,仅选择与正在评估的像素颜色最接近的颜色.在评估均匀的颜色区域时,结果是所有像素的像素颜色相同.
只有一个问题,即Graphics对象的PixelOffsetMode的默认值,它是:
e.Graphics.PixelOffsetMode = PixelOffsetMode.None
在此模式激活的情况下,对应于图像的顶部和左侧边框的外部像素(在正常图像采样中)绘制在由容器定义的矩形区域的边缘的中间(目标位图或设备上下文) .
因此,由于源图像很小并且其像素被放大很多,所以第一水平线和垂直线的像素被明显地切成两半.
这可以使用另一个 来解决PixelOffsetMode
:
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half
此模式将图像的渲染位置移回半个像素.
结果的示例图像可以更好地解释这一点:
Default Filter InterpolationMode InterpolationMode
InterpolationMode NearestNeighbor NearestNeighbor
Bilinear PixelOffsetMode.None PixelOffsetMode.Half
注意:
.Net的MSDN Docs不能PixelOffsetMode
很好地描述参数.你可以找到6种,显然不同的选择.Pixel Offset模式实际上只有两个:(
PixelOffsetMode.None
默认值)和PixelOffsetMode.Half
.
PixelOffsetMode.Default
和PixelOffsetMode.HighSpeed
是一样的PixelOffsetMode.None
.
PixelOffsetMode.HighQuality
是一样的PixelOffsetMode.Half
.
阅读.Net Docs,当选择一个而不是另一个时,似乎会有速度影响.差异实际上可以忽略不计.
关于这个问题的C++文档(以及一般的GDI +)更加明确和精确,应该使用它而不是.Net文件.
如何进行:
我们可以将小源Bitmap绘制到一个新的更大的Bitmap并将其分配给一个PictureBox.Image
属性.
但是,假设PictureBox大小在某些时候发生变化(因为布局发生变化和/或因为DPI意识受到影响),我们(几乎)回到了第一个方向.
一个简单的解决方案是直接在控件的表面上绘制新的Bitmap,并在必要时将其保存到光盘.
这也可以在需要时缩放Bitmap而不会降低质量:
Imports System.Drawing
Imports System.Drawing.Drawing2D
Private pixelBitmap As Bitmap = Nothing
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
pixelBitmap = DirectCast(New Bitmap("File Path").Clone(), Bitmap)
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.InterpolatiOnMode= InterpolationMode.NearestNeighbor
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half
e.Graphics.DrawImage(pixelBitmap, GetScaledImageRect(pixelBitmap, DirectCast(sender, Control)))
End Sub
Private Sub PictureBox1_Resize(sender As Object, e As EventArgs) Handles PictureBox1.Resize
PictureBox1.Invalidate()
End Sub
GetScaledImageRect
是一个帮助方法,用于在容器内缩放图像:
Public Function GetScaledImageRect(image As Image, canvas As Control) As RectangleF
Return GetScaledImageRect(image, canvas.ClientSize)
End Function
Public Function GetScaledImageRect(image As Image, containerSize As SizeF) As RectangleF
Dim imgRect As RectangleF = RectangleF.Empty
Dim scaleFactor As Single = CSng(image.Width / image.Height)
Dim containerRatio As Single = containerSize.Width / containerSize.Height
If containerRatio >= scaleFactor Then
imgRect.Size = New SizeF(containerSize.Height * scaleFactor, containerSize.Height)
imgRect.Location = New PointF((containerSize.Width - imgRect.Width) / 2, 0)
Else
imgRect.Size = New SizeF(containerSize.Width, containerSize.Width / scaleFactor)
imgRect.Location = New PointF(0, (containerSize.Height - imgRect.Height) / 2)
End If
Return imgRect
End Function