支持 Alpha 信息图片最近邻内插
我发现 EasyX 图形库上用图像缩放后是模糊的。本文使用了最近邻内插方法,实现放大像素图像。
NearestNeighborImage 函数实现了最近邻内插方法,可以使图像缩放保持清晰的像素效果。
执行效果如下:
半透明贴图的png文件下载:
完整的源代码如下:
///////////////////////////////////////////////
// 程序名称:支持 Alpha 信息图片最近邻内插
// 编译环境:Visual C++ 2019,EasyX_20200902
// 作者:豆焰(beanflame)
// QQ:2962672241
// 邮箱:beanflame@163.com
// 最后修改:2020-10-18
//
#include <graphics.h> // 引用图形库头文件
#include <conio.h>
#include <cmath>
#include <iostream>
using namespace std;
// transparentimage 函数:
// 请参考 https://codebus.cn/yangw/transparent-putimage 中的第五项:
// 根据 png 的 alpha 信息实现半透明贴图(基于直接操作显示缓冲区)
void transparentimage(IMAGE* dstimg, int x, int y, IMAGE* srcimg)
{
DWORD* dst = GetImageBuffer(dstimg);
DWORD* src = GetImageBuffer(srcimg);
int src_width = srcimg->getwidth();
int src_height = srcimg->getheight();
int dst_width = (dstimg == NULL ? getwidth() : dstimg->getwidth());
int dst_height = (dstimg == NULL ? getheight() : dstimg->getheight());
int iwidth = (x + src_width > dst_width) ? dst_width - x : src_width;
int iheight = (y + src_height > dst_height) ? dst_height - y : src_height;
if (x < 0) { src += -x; iwidth -= -x; x = 0; }
if (y < 0) { src += src_width * -y; iheight -= -y; y = 0; }
dst += dst_width * y + x;
for (int iy = 0; iy < iheight; iy++)
{
for (int ix = 0; ix < iwidth; ix++)
{
int sa = ((src[ix] & 0xff000000) >> 24);
int sr = ((src[ix] & 0xff0000) >> 16);
int sg = ((src[ix] & 0xff00) >> 8);
int sb = src[ix] & 0xff;
int dr = ((dst[ix] & 0xff0000) >> 16);
int dg = ((dst[ix] & 0xff00) >> 8);
int db = dst[ix] & 0xff;
dst[ix] = ((sr + dr * (255 - sa) / 255) << 16)
| ((sg + dg * (255 - sa) / 255) << 8)
| (sb + db * (255 - sa) / 255);
}
dst += dst_width;
src += src_width;
}
}
void NearestNeighborImage(IMAGE* dstimg, IMAGE* srcimg, int width, int height)
{
// 初始化新图
dstimg->Resize(width, height);
DWORD* dst = GetImageBuffer(dstimg);
DWORD* src = GetImageBuffer(srcimg);
int src_width = srcimg->getwidth();
int src_height = srcimg->getheight();
int dst_width = (dstimg == NULL ? getwidth() : dstimg->getwidth());
int dst_height = (dstimg == NULL ? getheight() : dstimg->getheight());
// 比例
float h_scale_rate = (float)src_height / height;
float w_scale_rate = (float)src_width / width;
for (int iy = 0; iy < height; iy++)
{
for (int ix = 0; ix < width; ix++)
{
// 比例计算原图相应坐标中
int i_scale = h_scale_rate * iy;
int j_scale = w_scale_rate * ix;
DWORD* p = GetImageBuffer(srcimg);
int psc_width = srcimg->getwidth();
int psc_height = srcimg->getheight();
for (int iy = 0; iy < i_scale; iy++)
{
p += psc_width;
}
dst[ix] = p[j_scale];
}
dst += dst_width;
src += src_width;
}
}
int main()
{
int width = 800;
int height = 600;
// 初始化图形窗口
initgraph(width, height);
BeginBatchDraw();
IMAGE RedSweetPepper, src, yyy;
loadimage(&RedSweetPepper, _T("red_sweet_pepper.png")); // 加载图片
loadimage(&src, _T("red_sweet_pepper.png"), 64 * 2, 64 * 2); // 加载放大图片
while (true)
{
// 清屏
FlushBatchDraw();
// 绘制背景
setfillcolor(RGB(255, 255, 255));
fillrectangle(0, 0, width, height);
// 最近邻内插
NearestNeighborImage(&yyy, &RedSweetPepper, 64 * 2, 64 * 2);
// 贴图
putimage(0, 0, &src);
transparentimage(NULL, 300, 0, &src);
putimage(0, 200, &yyy);
transparentimage(NULL, 300, 200, &yyy);
}
EndBatchDraw();
closegraph();
return 0;
}
添加评论
取消回复