在PictureBox上禁用图像混合 [英] Disable Image blending on a PictureBox

查看:109
本文介绍了在PictureBox上禁用图像混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Windows窗体程序中,我有一个PictureBox.其中的位图图像很小,5 x 5个像素.
分配给PictureBox时,它会变得非常模糊.

In my Windows Forms program, I have a PictureBox. The bitmap image inside it is small, 5 x 5 pixels.
When assigned to a PictureBox, it becomes very blurry.

我尝试查找诸如混合模式,模糊模式或抗锯齿模式之类的东西,但是我没有运气.

I tried finding something like blending mode, blurring mode, or anti-aliasing mode, but I had no luck.

   This is what I want     This is not what I want

推荐答案

问题:
模糊化大小比用于显示它的容器小得多的位图,并随意地混合了定义良好的颜色区域的尖锐边缘.
这只是在放大时将双线性滤镜应用于很小的图像(几个像素)的结果.

The problem:
A Bitmap, with a size that is much smaller than the container used to show it, is blurred and the otherwise sharp edges of the well-defined areas of color are unceremoniously blended.
This is just the result of a Bilinear filter applied to a really small image (a few pixels) when zoomed in.

所需的结果是在放大图像时保持单个像素的原始颜色.

The desired result is to instead maintain the original color of the single pixels while the Image is enlarged.

要获得此结果,只需设置Graphics对象的

To achieve this result, it's enough to set the Graphics object's InterpolationMode to:

e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor

此滤镜也称为 Point Filter ,它只是选择一种与正在评估的像素颜色最接近的颜色.评估均匀颜色区域时,结果是所有像素的像素颜色相同.
只有一个问题,即Graphics对象的

This filter, also known as Point Filter, simply selects a color which is the nearest to the pixel color that is being evaluated. When evaluating homogeneous areas of color, the result is the same pixel color for all the pixels.
There's just one problem, the default value of the Graphics object's PixelOffsetMode, which is:

e.Graphics.PixelOffsetMode = PixelOffsetMode.None

在启用此模式的情况下,与图像的顶部和左侧边界相对应的外部像素(在 normal 图像采样中)绘制在由所定义的矩形区域的边缘的中间容器(目标位图或设备上下文).

With this mode active, the outer pixels, corresponding to the top and left borders of an Image (in the normal image sampling) are drawn in the middle of the edges of the rectangular area defined by the container (the destination Bitmap or device context).

因此,由于源图像较小,并且其像素被放大了很多,因此第一条水平线和垂直线的像素被明显地切成两半.
可以使用另一个 PixelOffsetMode来解决:

Because of this, since the source Image is small and its pixels are enlarged quite a lot, the pixels of the first horizontal and vertical lines are visibly cut in half.
This can be resolved using the other PixelOffsetMode:

e.Graphics.PixelOffsetMode = PixelOffsetMode.Half

此模式后退图像的渲染位置半个像素.
结果的样本图像可以更好地说明这一点:

This mode moves back the image's rendering position by half a pixel.
A sample image of the results can explain this better:

      Default Filter         InterpolationMode        InterpolationMode
    InterpolationMode         NearestNeighbor          NearestNeighbor
         Bilinear           PixelOffsetMode.None     PixelOffsetMode.Half

注意:
.Net的MSDN文档不能很好地描述PixelOffsetMode参数.您可以找到6个明显不同的选择.像素偏移模式实际上只有两种:
PixelOffsetMode.None (默认)和 PixelOffsetMode.Half .

Note:
The .Net's MSDN Docs do not describe the PixelOffsetMode parameter very well. You can find 6, apparently different, choices. The Pixel Offset modes are actually only two:
PixelOffsetMode.None (the default) and PixelOffsetMode.Half.

PixelOffsetMode.DefaultPixelOffsetMode.HighSpeedPixelOffsetMode.None相同.
PixelOffsetMode.HighQualityPixelOffsetMode.Half相同.
阅读.Net Docs时,选择其中一项似乎有 speed 含义.差异实际上可以忽略不计.

PixelOffsetMode.Default and PixelOffsetMode.HighSpeed are the same as PixelOffsetMode.None.
PixelOffsetMode.HighQuality is the same as PixelOffsetMode.Half.
Reading the .Net Docs, there seems to be speed implications when choosing one over the other. The difference is actually negligible.

有关此问题的 C ++文档(通常是GDI +)更加明确和精确,应该使用它代替.Net.

The C++ documentation about this matter (and GDI+ in general), is much more explicit and precise, it should be used instead of the .Net one.

如何进行:

我们可以将较小的源位图绘制到新的较大的位图上,并将其分配给 PictureBox.Image 属性.

We could draw the small source Bitmap to a new, larger Bitmap and assign it to a PictureBox.Image property.

但是,假设PictureBox的大小在某个时候发生了变化(因为布局更改和/或由于DPI意识的折衷),我们(几乎)回到了平方.

But, assume that the PictureBox size changes at some point (because the layout changes and/or because of DPI Awareness compromises), we're (almost) back at square one.

一个简单的解决方案是将新的位图直接绘制在控件的表面上,并在必要时将其保存到光盘中.

A simple solution is to draw the new Bitmap directly on the surface of a control and save it to disc when/if necessary.

这也将允许在需要时缩放位图,而不会损失质量:

This will also allow to scale the Bitmap when needed without losing quality:

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 是用于缩放容器内图像的辅助方法:

GetScaledImageRect is a helper method used to scale an Image inside a container:

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

这篇关于在PictureBox上禁用图像混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆