使用 Winforms 和 GDI+ 创建漂亮的阴影是一项艰巨的任务。
它既没有多边形缩放也没有模糊;让我们甚至不考虑3D ..! - 但是我们至少可以在不做太多工作的情况下做一些事情,并为许多图像获得不错的结果..
假设您已经有一张从背景中剪下的图片。
下一步是将所有颜色变为黑色。
那么我们很可能想要添加某种程度的透明度,以便阴影落在背景上,仍然可以透过。
通过使用合适的ColorMatrix,这两项任务都非常有效地完成。
使用非常透明的版本,我们还可以通过绘制带有偏移的图像来创建简单的模糊。为了获得最佳效果,我会用 3 个不同的权重/alpha 值绘制九次。
高质量的模糊是一门艺术,您只需查看专业软件(如 Adobe Photoshop 或 Affinity Photo)中的滤镜和调整即可。这是nice 一组有趣的链接..
但由于我们只处理黑白位图,因此简单的方法就足够了。我使用 3 个 5%、10% 和 20% 的 alpha 值用于 4 个角、4 个边缘和 1 个中心绘图。
最后一步是绘制带有一些倾斜的阴影。
这是解释here;但是,虽然这看起来很简单,但也有些不切实际。需要计算DrawImage 叠加层期望的三个点。
所以这里有一个方法可以做到这一点;请注意,这是一种高度简化的方法:
叠加层需要三个点,即 6 个浮点数。我们只使用 3 个数字:
- 一个为倾斜量;
0.5 表示顶部向右移动位图宽度的一半。
- 另外两个是生成的边界框的缩放比例。
1 和0.5 表示宽度不变,高度降低为50%。
函数如下:
public Bitmap SkewBitmap(Bitmap inMap, float skewX, float ratioX, float ratioY )
{
int nWidth = (int)(inMap.Width * (skewX + ratioX));
int nHeight = (int)(Math.Max(inMap.Height, inMap.Height * ratioY));
int yOffset = inMap.Height - nHeight;
Bitmap outMap = new Bitmap(nWidth, nHeight);
Point[] destinationPoints = {
new Point((int)(inMap.Width * skewX), (int)(inMap.Height * ratioY) + yOffset),
new Point((int)(inMap.Width * skewX + inMap.Width * ratioX),
(int)(inMap.Height * ratioY) + yOffset),
new Point(0, inMap.Height + yOffset ) };
using (Graphics g = Graphics.FromImage(outMap))
g.DrawImage(inMap, destinationPoints);
return outMap;
}
注意一些简化:
如果您想将阴影放在左边,您不仅需要将前两个点向左移动,还需要调整宽度的计算以及将对象覆盖在阴影上的方式.
如果您研究 MSDN 示例,您会发现 DrawImage 覆盖还允许进行旋转。我没有将它添加到我们的函数中,因为计算起来要复杂得多,甚至只是写一个签名。
-
如果你想知道这六个数字的信息在哪里,这里是完整的布局:
- 3 进入我们的参数
- 1 是我们不做的旋转角度
- 2 可以是旋转中心点,也可以是转换结果的点 (deltaX&Y)
如果您仔细观察,您会发现左脚的阴影略低于脚。这是因为脚不在同一水平线上,并且随着垂直压缩,基线会分开。为了纠正这一点,我们要么修改图像,要么添加一个微小的旋转。
看看你的例子,很明显你需要把它拆开,分别处理“房子”和“树”!
签名保持简单;这始终是易用性和编码工作量之间的平衡。 On 可能需要一个参数来控制倾斜。随意进行必要的计算..
请注意,在其他按钮后面添加功能将超出问题的范围。可以这么说,大多数只需要一条线来绘制,十几条线来设置颜色矩阵..
这是“倾斜”按钮中的代码:
Bitmap bmp = SkewBitmap((Bitmap)pictureBox4.Image, 0.5f, 1f, 0.5f);
pictureBox5.Image = pictureBox1.Image;
pictureBox5.BackgroundImage = bmp;
pictureBox5.ClientSize = new Size(bmp.Width, bmp.Height);
我没有在阴影上绘制对象,而是使用了PictureBox 的额外层。你当然会结合这两个Bitmaps..