[Gdiplus]_[初级]_[拉伸缩放图片时使用适当的插值模式和像素偏移模式绘制完整图片]

场景

  1. 在开发WTL/Win32程序时,有时候需要绘制短信里的气泡背景。气泡的高度不是固定的,那么需要原图进行Y轴方向的拉伸。默认模式的Gdiplus::Graphics绘制拉伸的图片,气泡底部出现模糊或者空白,并没有完整的绘制指定的目标区域,怎么回事?

说明

  1. Gdiplus默认算法在拉伸图像时,会自动柔化边缘,使得图像看起来更平滑,但这也造成了边缘(尤其是底部)模糊。

  2. 对于拉伸放大的图片,需要设置插值模式为InterpolationModeNearestNeighbor(最近邻插值)和像素采样偏移模式PixelOffsetModeHalf才会对原图做比较精确的拉伸而不丢失颜色。

  • 最近邻插值的特点是简单快速,并且不会引入新的颜色值,因此在放大图像时能保留清晰的边缘,但可能会出现明显的锯齿。当把一张小图放大时,新图像的每一个像素点,都直接取原图中距离它最近的那个像素的值,不进行任何加权平均或融合。 它会采用一种源像素和目标像素关系的算法 x = f(x1) 和 y = f(y1)算法来获取目标像素的颜色值。

  • 像素采样偏移半像素模式(PixelOffsetModeHalf)是为了回避像素采样在像素边界[0,0]导致颜色混合和边缘模糊的情况。它会在源图的像素居中位置[0.5,0.5]开始采样,采样更准确,而不是在边缘的无颜色或混合颜色的采样不确定的颜色。默认的采样还受到Gdiplus的绘图长宽是浮点值的影响造成采样结果偏移和颜色抗锯齿造成模糊情况。

cpp 复制代码
graphics.SetInterpolationMode(Gdiplus::InterpolationModeNearestNeighbor);
graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);

例子

复制代码
LRESULT CView::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	CPaintDC dc(m_hWnd);

	auto imageWidth = imageCenter_->GetWidth();
	auto imageHeight = imageCenter_->GetHeight();

	// 方式1: 不缩放;不需要设置选项;
	Gdiplus::Graphics graphics(dc);
	Gdiplus::Rect rectBorder(100,100, imageWidth, imageHeight);
	rectBorder.Inflate(1, 1);
	graphics.DrawImage(imageCenter_, Gdiplus::Rect(100, 100,imageWidth,imageHeight));
	
	Gdiplus::Pen pen(Gdiplus::Color::Red,1);
	graphics.DrawRectangle(&pen, rectBorder);

	// 方法2:缩放,默认的插入模式和PixelOffsetModeNone模式;
	Gdiplus::Rect rect_2(100, 200, 300, 200);
	graphics.DrawImage(imageCenter_, rect_2,
		0, 0, imageWidth, imageHeight, Gdiplus::UnitPixel);
	rectBorder = rect_2;
	rectBorder.Inflate(1, 1);
	graphics.DrawRectangle(&pen, rectBorder);

	// 方法3:放大,设置近邻插入模式和采样原点在像素里居中模式
	graphics.SetInterpolationMode(Gdiplus::InterpolationModeNearestNeighbor);
	graphics.SetPixelOffsetMode(Gdiplus::PixelOffsetModeHalf);

	Gdiplus::Rect rect_3 = rect_2;
	rect_3.X = rect_2.GetRight() + 20;
	graphics.DrawImage(imageCenter_, rect_3,
		0, 0, imageWidth, imageHeight, Gdiplus::UnitPixel);
	rectBorder = rect_3;
	rectBorder.Inflate(1, 1);
	graphics.DrawRectangle(&pen, rectBorder);

	Gdiplus::Rect rect_4;
	rect_4.X = rect_3.X;
	rect_4.Y = rect_3.GetBottom() + 20;
	rect_4.Width = imageWidth / 2;
	rect_4.Height = imageHeight / 2;
	graphics.DrawImage(imageCenter_, rect_4,
		0, 0, imageWidth, imageHeight, Gdiplus::UnitPixel);
	rectBorder = rect_4;
	rectBorder.Inflate(1, 1);
	graphics.DrawRectangle(&pen, rectBorder);
	

	return 0;
}

图示

参考

  1. PixelOffsetMode

  2. Graphics::SetInterpolationMode

  3. InterpolationMode

  4. Graphics::SetPixelOffsetMode

  5. 在缩放期间使用内插模式控制图像质量

相关推荐
Martina_03213 天前
AI生成3D场景从白模换成精模后镜头全偏了?用6步检查单位、枢轴与层级替换
图像处理·人工智能·3d·ai·自然语言处理·材质·1024程序员节
陈嘿萌4 天前
TIP 2026 | 不再混成一张! RealFusion从模态不变性重想图像融合
图像处理·人工智能·深度学习·计算机视觉·学术研究与理论基础
严肃小白兔5 天前
MATLAB 优秀开源项目与工具箱推荐:涵盖通信、图像处理、脑机接口等九大领域
图像处理·matlab·信息与通信·开源项目
陈嘿萌7 天前
ECCV 2026 | CausalDrive:澳门大学×小米汽车,面向自动驾驶的实时因果世界模型
图像处理·人工智能·深度学习·计算机视觉·自动驾驶·学术研究与理论基础
楚山之石7 天前
【MRM】CAPLEX 对比剂灌注 MRI 开源术语库:ISMRM OSIPI 共识报告
图像处理·人工智能·学习·mri
原子延迟8 天前
批量压缩视频会变大?HandBrake等3款(2026)
图像处理·人工智能·计算机视觉·音视频
闭包不眠8 天前
批量压缩视频先分组,HandBrake等3种方法(2026)
图像处理·人工智能·计算机视觉·音视频
Martina_03218 天前
AI生成3D模型一合并网格,材质就串色?用6步检查材质槽、UV与图集重映射
图像处理·人工智能·3d·材质·uv·游戏策划·1024程序员节
指针向南8 天前
批量压缩视频有文件没变小?HandBrake等3款对比
图像处理·人工智能·计算机视觉·音视频
美狐美颜SDK开放平台9 天前
开发直播APP、电商短视频与视频社交平台时,能否共用一套美颜SDK?
android·图像处理·人工智能·音视频·直播美颜sdk