在我的 Windows 窗体程序中,我有一个 PictureBox
包含一个小图像,5 x 5
像素。
当这个 Bitmap 被分配给 PictureBox.Image
属性,它变得非常模糊。
我试图找到诸如混合模式、模糊模式或抗锯齿模式之类的东西,但我没有运气。
This is what I want This is not what I want
最佳答案
问题 :
位图的大小比用于显示它的容器小得多,它变得模糊,并且明确定义的颜色区域的其他锐利边缘被毫不客气地混合在一起。
这只是放大时将双线性过滤器应用于非常小的图像(几个像素)的结果。
期望的结果是在放大图像时保持单个像素的原始颜色。
为了达到这个效果,设置 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 文档没有描述
PixelOffsetMode
参数很好。您可以找到 6 个明显不同的选择。 Pixel Offset 模式实际上只有两种:PixelOffsetMode.None
(默认)和 PixelOffsetMode.Half
.PixelOffsetMode.Default
和 PixelOffsetMode.HighSpeed
与 PixelOffsetMode.None
相同.PixelOffsetMode.HighQuality
与 PixelOffsetMode.Half
相同.阅读 .Net 文档,在选择一个而不是另一个时似乎会影响速度。差异实际上可以忽略不计。
C++ documentation about this matter (以及一般的 GDI+),它更加明确和精确,应该使用它而不是 .Net 。
如何进行 :
我们可以将小的源 Bitmap 绘制到一个新的更大的 Bitmap 并将其分配给
PictureBox.Image
属性(property)。但是,假设 PictureBox 的大小在某个时候发生了变化(因为布局发生了变化和/或因为 DPI Awareness 的妥协),我们(几乎)回到了原点。
一个简单的解决方案是直接在控件的表面上绘制新位图,并在必要时将其保存到磁盘。
这也将允许在需要时缩放位图而不会降低质量:
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
关于vb.net - 禁用图片框上的图像混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54720916/