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

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

问题描述

在我的 Windows 窗体程序中,我有一个 PictureBox,其中包含一个小图像,5 x 5 像素.
当将此位图分配给 PictureBox.Image 属性时,它会变得非常模糊.

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

 这就是我想要的 这不是我想要的

解决方案

问题:
位图的大小比用于显示它的容器小得多,被模糊,并且明确定义的颜色区域的其他锐边被毫不客气地混合在一起.
这只是在放大时将双线性过滤器应用于非常小的图像(几个像素)的结果.

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

要达到这个效果,设置Graphics对象的

 默认过滤器 InterpolationMode InterpolationModeInterpolationMode NearestNeighbor NearestNeighbor双线性 PixelOffsetMode.None PixelOffsetMode.Half

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

PixelOffsetMode.DefaultPixelOffsetMode.HighSpeedPixelOffsetMode.None 相同.
PixelOffsetMode.HighQualityPixelOffsetMode.Half 相同.
阅读 .Net 文档,在选择其中一个时似乎有速度影响.差异实际上可以忽略不计.

导入 System.Drawing导入 System.Drawing.Drawing2DPrivate pixelBitmap As Bitmap = NothingPrivate Sub Form1_Load(sender As Object, e As EventArgs) 处理 MyBase.LoadpixelBitmap = DirectCast(New Bitmap("File Path").Clone(), Bitmap)结束子Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) 处理PictureBox1.Painte.Graphics.InterpolationMode = InterpolationMode.NearestNeighbore.Graphics.PixelOffsetMode = PixelOffsetMode.Halfe.Graphics.DrawImage(pixelBitmap, GetScaledImageRect(pixelBitmap, DirectCast(sender, Control)))结束子Private Sub PictureBox1_Resize(sender As Object, e As EventArgs) 处理PictureBox1.ResizePictureBox1.Invalidate()结束子

GetScaledImageRect 是一个辅助方法,用于在容器内缩放图像:

公共函数GetScaledImageRect(image As Image, canvas As Control) As RectangleF返回 GetScaledImageRect(image, canvas.ClientSize)结束函数公共函数 GetScaledImageRect(image As Image, containerSize As SizeF) As RectangleF将 imgRect 调暗为 RectangleF = RectangleF.EmptyDim scaleFactor As Single = CSng(image.Width/image.Height)Dim containerRatio As Single = containerSize.Width/containerSize.Height如果 containerRatio >= scaleFactor 那么imgRect.Size = New SizeF(containerSize.Height * scaleFactor, containerSize.Height)imgRect.Location = New PointF((containerSize.Width - imgRect.Width)/2, 0)别的imgRect.Size = New SizeF(containerSize.Width, containerSize.Width/scaleFactor)imgRect.Location = New PointF(0, (containerSize.Height - imgRect.Height)/2)万一返回 imgRect结束函数

In my Windows Forms program, I have a PictureBox that contains a small image, 5 x 5 pixels.
When this Bitmap is assigned to the PictureBox.Image property, it becomes very blurry.

I tried to find 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.

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

e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor

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

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).

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
                                     

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.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.

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.

How to proceed:

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

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 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

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

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