绘制主题元素的技巧(即如何不拉伸绘制)?

Technique for drawing theme element (i.e. how to not stretch draw)?

我正在考虑将自定义主题元素绘制到设备内容上。

例如,我将使用 Windows XP 中的 HeaderItem header/listview:

(18×18 px)

哪个大家可以炸开看看容易一点:

Note: I am not using the Theme API, nor am i asking about using the Theme API.

如果我有像上面那样的位图,我该如何实际绘制它?

拉伸画破坏了风格

需要解决的重要问题是如何维护重要的细节。你可以看到实际的 Windows XP Header 将右边缘的垂直线绘制得漂亮而清晰:

但如果我盲目StretchBlt图像,细节变得模糊:

当图像垂直拉伸时,具有清晰水平特征的主题元素也会出现此问题。在这种情况下,它还会弄乱垂直渐变。但其他一些元素更明显。

那么可以使用什么技术来解决这个问题?

我应该把 6 px 的顶部、左侧、底部和右侧剪掉吗?:

然后我画了九张而不是一张图片?:

并根据位置使用各种水平或垂直拉伸规则绘制它们?:

Unstretched
Horizontally stretched
Unstretched
Vertically stretched
Horizontally and vertically stretched
Vertically stretched
Unstretched Horizontally stretched
Unstretched

这一定是一个已经解决的问题;因为Windows已经解决了,谁知道还有多少支持主题的Widget库。

Microsoft 对此问题的解决方案可以通过查看 NormalBlue.ini 文件在 Luna.msstyles 中进行逆向工程.查看 Header.HeaderItem 的条目:

NormalBlue.ini:

[Header.HeaderItem]
bgtype = imagefile
SizingMargins = 8, 8, 3, 4
ContentMargins = 3, 0, 0, 0
ImageFile = Blue\ListViewHeader.bmp
imageCount=5
imageLayout=vertical
sizingType = tile
transparent=true
transparentcolor=255 0 0
FillColorHint = 250 248 243; Average fill color (light beige)
AccentColorHint = 252 194 71; Rollover hilite color (orange)

首先我们看到它引用了 \Blue\ListViewHeader.bmp:

ImageFile = Blue\ListViewHeader.bmp

即:

然后是魔法片:

SizingMargins = 8, 8, 3, 4

这对应于TMT_SIZINGMARGINS:

TMT_SIZINGMARGINS: The margins used for sizing a non-true-size image.

您可以在 TmSchema.h 中看到更多提示:

//---- rendering MARGIN properties ----
TM_PROP(3601, TMT, SIZINGMARGINS,     MARGINS)    // margins used for 9-grid sizing

“用于 9 格大小调整的边距”。这是对将图像拆分为 3x3 网格并根据需要独立调整块大小的想法的参考。

最后一块是 MARGINS 类型的文档 UxTheme.h:

typedef struct _MARGINS
{
    int cxLeftWidth;      // width of left border that retains its size
    int cxRightWidth;     // width of right border that retains its size
    int cyTopHeight;      // height of top border that retains its size
    int cyBottomHeight;   // height of bottom border that retains its size
} MARGINS, *PMARGINS;

及其 documentation:

  • cxLeftWidth: int - 保持其大小的左边框宽度。
  • cxRightWidth: int - 保持其大小的右边框宽度。
  • cyTopHeight: int - 保持其大小的上边框高度。
  • cyBottomHeight: int - 保持其大小的底部边框的高度。

砍和油漆

Luna 主题告诉我们,当我们绘制 ListViewHeader.bmp 时,我们需要使用大小边距:

SizingMargins = 8, 8, 3, 4

并将图像切割成 9 块 (3x3)。但是我们需要使用图像设计者想要的尺寸,而不是到处使用 6px(就像我在我的问题中所说的那样):

  • 左: 8
  • 右:8
  • 顶:3
  • 底部:4

所以给定设计师在 Photoshop 中创建的 18×18 主题元素图像:

创建图像的人说我的绘图代码需要截断:

  • 左 8 像素
  • 右8像素
  • 前 3 个像素
  • 底部 4 个像素

这意味着我必须绘制九张图片中的每一张:

然后向特定方向拉伸绘制一些部分:

  • Top-left:绘制未拉伸
  • 左:垂直​​拉伸
  • Bottom-left:绘制未拉伸
  • 顶部:水平拉伸
  • 中间:绘制水平和垂直拉伸
  • 底部:水平拉伸绘制
  • Top-right:绘制未拉伸
  • 右:绘制垂直拉伸
  • Bottom-right:绘制未拉伸