Web2.0風の背景を簡単に描画する方法を紹介します。
Web2.0風の背景と言うのは、こういう感じ の、グラデーションになっていて上半分がテカっているものです。
Windows Vista や Windows Media Player でもおなじみですね。
わざわざ画像を用意することなく、これをプログラムで描画してみます。
こういった背景を見ると、上半分が下半分より明るいグラデーションで描画されていますね。
なので、そのような描画を行うコードを書けばいいわけです。
まず、単純な2色のグラデーションを描画する関数を書きます。
あまり知られていませんが、Windows には GradientFill というグラデーションを描画するための API 関数が用意されていますので、ここではそれを利用します。
ただ、この関数は引数が分かりにくかったり、色の指定が16ビットだったりと、ちょっと癖があります。
GradientFill 関数は Windows98 以降に用意されている msimg32.dll という DLL に入っていますので、利用する場合は msimg32.lib をリンクする必要があります。
#include <windows.h> // いつものヘッダ
#pragma comment(lib, "msimg32.lib") // msimg32.lib をリンクする指定です
// 2色のグラデーションを描画する関数です
BOOL TwoColorsGradient(
HDC hdc, // 描画先のデバイスコンテキスト・ハンドルです
const RECT *pRect, // 描画する範囲の矩形です
COLORREF Color1, // 描画する一つ目の色です
COLORREF Color2, // 描画する二つ目の色です
BOOL fHorizontal // 水平のグラデーションを描画する場合は TRUE にします
)
{
TRIVERTEX vert[2];
GRADIENT_RECT rect = {0, 1};
// 描画範囲と色を設定します
vert[0].x = pRect->left;
vert[0].y = pRect->top;
vert[0].Red = GetRValue(Color1) << 8;
vert[0].Green = GetGValue(Color1) << 8;
vert[0].Blue = GetBValue(Color1) << 8;
vert[0].Alpha = 0;
vert[1].x = pRect->right;
vert[1].y = pRect->bottom;
vert[1].Red = GetRValue(Color2) << 8;
vert[1].Green = GetGValue(Color2) << 8;
vert[1].Blue = GetBValue(Color2) << 8;
vert[1].Alpha = 0;
return GradientFill(hdc, vert, 2, &rect, 1,
fHorizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V);
}
一見 Alpha で透明度を指定できそうですが、実際には Alpha は無視されます。
また、GetRValue(Color1) << 8 は GetRValue(Color1) * 257 の間違いと思われるかも知れませんが、色の指定は最大が 0xFF00 という変な仕様になっています。
なお、Windows 2000 以降では GdiGradientFill という、GradientFill と同様の関数が gdi32.dll にありますので、こちらを使うようにすれば msimg32.lib をリンク指定する必要が無くなります。
GradientFill (GdiGradientFill) を使用せずに、GDI 関数でペンを使ってグラデーションを描くこともできますので、そちらに挑戦してみてもいいでしょう。
さて、次は本題のテカった背景を描画するコードです。 このコードでは、縦方向と横方向のどちらでもグラデーションを描画できるようにしています。
// 二つの色を混ぜ合わせる関数です
COLORREF MixColor(COLORREF Color1, COLORREF Color2, BYTE Ratio = 128)
{
int Alpha = 255 - Ratio;
return RGB((GetRValue(Color1) * Ratio + GetRValue(Color2) * Alpha) / 255,
(GetGValue(Color1) * Ratio + GetGValue(Color2) * Alpha) / 255,
(GetBValue(Color1) * Ratio + GetBValue(Color2) * Alpha) / 255);
}
// テカったグラデーションを描画する関数です
void GlossyGradient(
HDC hdc, // 描画先のデバイスコンテキスト・ハンドルです
const RECT *pRect, // 描画する範囲の矩形です
COLORREF Color1, // 描画する一つ目の色です
COLORREF Color2, // 描画する二つ目の色です
BOOL fHorizontal = FALSE, // 水平のグラデーションを描画する場合は TRUE にします
BYTE GlossRatio1 = 96, // 端のテカりの強さです
BYTE GlossRatio2 = 48, // 中央のテカりの強さです
)
{
// 中央の色を求めます
COLORREF CenterColor = MixColor(Color1, Color2);
RECT rc;
// テカり部分の範囲を計算します(描画領域の半分です)
rc.left = pRect->left;
rc.top = pRect->top;
if (fHorizontal) {
rc.right = (rc.left + pRect->right) / 2;
rc.bottom = pRect->bottom;
} else {
rc.right = pRect->right;
rc.bottom = (rc.top + pRect->bottom) / 2;
}
// テカり部分を描画します
TwoColorsGradient(hdc, &rc,
MixColor(RGB(255, 255, 255), Color1, GlossRatio1),
MixColor(RGB(255, 255, 255), CenterColor, GlossRatio2),
fHorizontal);
// テカり以外の部分を描画します
if (fHorizontal) {
rc.left = rc.right;
rc.right = pRect->right;
} else {
rc.top = rc.bottom;
rc.bottom = pRect->bottom;
}
TwoColorsGradient(hdc, &rc, CenterColor, Color2, fHorizontal);
}
要するに、描画する範囲を半分ずつに二分割して、片方を明るい色で描画している訳です。
引数の GlossRatio1 と GlossRatio2 でテカりの強さを指定できます。
デフォルト値は見た目から適当に設定したものです。
この関数は以下のように呼び出せます。
GlossyGradient(hdc, &rect, RGB(80, 80, 80), RGB(0, 0, 0));
GlossyGradient(hdc, &rect, RGB(0, 80, 255), RGB(48, 255, 255));
実行するとこのように描画されます。
どうでしょうか? なかなかそれらしい見栄えになっていると思います。
また、応用として両端から中心に向かってグラデーションを描画するようにすると、以下のようなちょっと違うパターンのものを描画できます。