PictureBox右边缘模糊渐变:SizeMode.StretchImage异常原因及修复方案(附示例)
Hey there, let's tackle this PictureBox edge blur issue you're seeing when using SizeMode.StretchImage—it's a common gotcha with GDI+ rendering, so I'll break down why it happens and how to fix it, plus throw in a gradient example as requested.
Why does SizeMode.StretchImage create that blurry gradient edge?
The core issue boils down to interpolation (smoothing) that GDI+ uses when scaling images. When you set SizeMode.StretchImage, the control stretches your image to fit its exact dimensions. If the original image's width/height isn't an integer multiple of the PictureBox's size, GDI+ uses bilinear or bicubic interpolation to fill in the gaps between pixels.
This interpolation blends edge pixels with the PictureBox's background (or empty space) to create a smooth transition, which results in that faint, blurry gradient along the right (and sometimes bottom) edge. Think of it as the renderer trying to "guess" what the pixels should look like when scaling doesn't line up perfectly—unfortunately, that guess creates unwanted edge blur.
How to fix the blurry edge issue?
Here are three reliable fixes depending on your use case:
1. Match image and PictureBox dimensions (integer scaling)
If possible, resize your image to a size that's an exact multiple of the PictureBox's dimensions before assigning it. For example, if your PictureBox is 400px wide, use an image that's 200px, 100px, etc.—this way, each image pixel maps directly to 2, 4, etc., control pixels, and no interpolation is needed. No blur, no gradient.
2. Disable interpolation via custom PictureBox
If you need dynamic scaling and can't pre-resize the image, override the PictureBox's painting logic to use nearest-neighbor interpolation, which skips smoothing and uses hard pixel mapping. Here's a custom control to do that:
public class SharpScalingPictureBox : PictureBox { protected override void OnPaint(PaintEventArgs e) { if (Image == null) { base.OnPaint(e); return; } // Disable smoothing/interpolation for sharp edges e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; // Draw the image to fit the control exactly var destRect = new Rectangle(0, 0, Width, Height); e.Graphics.DrawImage(Image, destRect, 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel); } }
Just replace your regular PictureBox with this custom one, and the edge blur should disappear.
3. Adjust control padding and image bounds
Another quick fix: add 1px of padding to the PictureBox, then adjust the image's drawing bounds to fit inside the padding. This pushes the interpolated edge outside the visible area of the control. You can do this in the OnPaint method similar to the example above, but shift the destRect by 1px on all sides.
Example code for intentional gradient effects
If you want to add a controlled gradient effect (like a fade-out on the right edge) instead of fixing an accidental one, here's a method to apply a gradient mask to an image:
public Image AddControlledRightGradient(Image originalImage, int gradientWidth = 50) { // Create a bitmap to hold the gradient-enhanced image var resultBitmap = new Bitmap(originalImage.Width, originalImage.Height); using (var g = Graphics.FromImage(resultBitmap)) { // Draw the original image first g.DrawImage(originalImage, new Rectangle(0, 0, originalImage.Width, originalImage.Height)); // Create a linear gradient brush: fades from transparent to semi-transparent black using (var gradientBrush = new LinearGradientBrush( new Rectangle(originalImage.Width - gradientWidth, 0, gradientWidth, originalImage.Height), Color.Transparent, Color.FromArgb(180, Color.Black), LinearGradientMode.Horizontal)) { // Customize the gradient blend for a smoother transition var colorBlend = new ColorBlend(); colorBlend.Colors = new[] { Color.Transparent, Color.FromArgb(120, Color.Black), Color.FromArgb(180, Color.Black) }; colorBlend.Positions = new[] { 0f, 0.6f, 1f }; gradientBrush.InterpolationColors = colorBlend; // Apply the gradient mask g.FillRectangle(gradientBrush, originalImage.Width - gradientWidth, 0, gradientWidth, originalImage.Height); } } return resultBitmap; }
You can use this method to generate a gradient version of your image, then assign it to the PictureBox (you can use SizeMode.Normal or StretchImage here—since this is an intentional gradient, interpolation won't ruin it).
内容的提问来源于stack exchange,提问作者Sergey J.

