SS blog

C/C++/javaについての話題

知られざるフォント技術の話 -変数フォント-

はじめに

「変数フォント」または「バリアブルフォント variable font」とは外部からパラメーターを指定して文字の形を変更して表示する仕様、または技術です。
例えば、フォントを開くときに「ボールド(太字)」を指定することがありますが、もう少し太くとか、逆に細くできないのかと思ったことはないでしょうか。
通常のフォントではできませんが、変数フォントなら太字を数値で指定して調整できるという訳です。

変数フォント

そんなフォントなんか見たことが無い、そもそもExcel等のアプリでボールドの指定はONかOFFしかないのに、太字を数値で指定するなんてできないでしょう、、、
と、思った人がほとんどでしょう。

そう、その通りなのです。
変数フォントは余り使われてませんし、積極的に使えるようにもなっていないというのが実情です。だから「知られざるフォント技術」なのですが、その一方で、Webの世界では変数フォントもそれを使う方法も出揃ってきています。

その辺りも含めて、
今回は変数フォントの話をしたいと思います。

尚、「variable font」は「変数フォント」より「可変フォント」とするのが適切な訳だと思いますが、Windowsの表示に合わせて「変数フォント」に統一します。

変数フォントでない通常のフォント

そもそも、変数フォントでない通常のフォントですが、どうやって文字をボールド(太字)にしているかご存じでしょうか。
まず標準のフォントがあって、ボールドが指定された時はそれを横方向に縮尺を変えている、あるいは画像や図形の加工技術で文字を太らせている、というイメージだったのではないでしょうか。

それは全く違います。ボールドのフォントと標準のフォントは全く別のフォントデータとして作成されているのです。
例えば、「MS ゴシック」であれば、「MS ゴシック 標準」、「MS ゴシック ボールド」、「MS ゴシック イタリック」、「MS ゴシック ボールド イタリック」の4種が全く別のフォントとして作られています。要するに力業をしているだけです。

この4つのフォントを同じグループとして関連付けているのは、フォントの名前だけ、つまりExcel等は、「MS ゴシック」という名前と、ボールド、イタリックの指定から、4つのフォントの中から適切なものを選択しているということです。

ちなみにフォントのグループの名前に相当する「MS ゴシック」をフォントファミリー名と言い、「ボールド」等の事をフォントフェイス名と言います。
そして本当の個々のフォントの名前である「MS ゴシック ボールド」を完全フォント名と言います。

我々が漠然と「フォント」と呼んだ時、意味しているのはフォントファミリーの事だと気が付いたでしょうか。
フォントファミリーは物理的には複数のフォントフェースの集合体ですが、「複数」だという事を意識する事は無いのは、Windowsのフォントの仕組みが非常によくできているのだと考えるべきでしょう。

そしてこれを発展させ。1つのファントにおいて、わざわざ4つのフォントフェースを作らず、標準フォントに変形処理を施すことで、ボールドやイタリックを実現できる、しかもON/OFFで無く、度合いを数値で指定できるようにしたのが、変数フォントという訳です。

変数フォント

ここまで良いこと尽くしのような変数フォントの話をしましたが、それなら何故、変数フォントは余り普及しないのでしょうか。

要因は幾つかあるのでしょうけど、一番の理由、それはおそらく、仕様も概念も複雑すぎるからです。以下は可変フォントの概念を説明するマイクロソフトのホームページです。

learn.microsoft.com

理解しがたいほど複雑だとはいいませんが、フォント設計者がこの概念に沿って、指定されたボールド、イタリック、その他の「軸」の度合いを複合して、一つ一つのグリフのアウトライン制御点の位置を移動させなければならないのです。
フォント設計者にしてみればそんな事をするくらいなら、むしろ4つフォントを作った方が遥かに楽だと思うに違いないのです。

とは言え、文字の微妙な太さや傾きの度合いに強くこだわる人、拘らなければならない職業などあるでしょう。
変数フォントにも一定の需要があるに違いないのです。

変数フォントか通常フォントかの判別方法

今日では、様々フォントファイルがネットからダウンロードできるのでが、ダウンロードサイトに変数フォントだと書いてあるとは限りません。どうすればそれが変数フォントだと判別できるでしょうか?

フォントファイルが変数フォントかそうでないか、拡張子は通常フォントと同様に、.ttfまたは.otfですので、外形では直ぐに判別できません。ただ変数フォントのフォントファイルはファイル名の中に"Variable"という単語が含まれている場合も多いので、その場合は可変フォントかなと推測することはできますが、ファイル名が必ずそうなっている訳ではないのです。

フォントファイルのデータを直接確認する

確実に判別するにはフォントビューワー的なツールでフォントファイルの中を見るしかありませんが、フォントデータに含まれるテーブルのディレクトリーはファイルの先頭付近にありますので、専用のビューワーでなくてもバイナリエディターでも確認できます。

拡張子が.otfのフォントファイルの場合、タグ名"CFF2"のテーブルがあれば変数フォントで、"CFF "であれば通常のフォントです。
なので、変数フォント非対応のアプリケーションはあるはずの"CFF "データが無いのですから、フォントファイルは不正であると認識される事になります。

可変フォント(CFF2)

拡張子が.ttfのフォントファイルの場合、タグ名"gvar"のテーブルがあれば変数フォントです。
ちなみにタグ名"glyf"がTrueTypeグリフの図形データでこれは必ずあるはずです。タグ名"gvar"のデータはそれに対する変位のデータが格納されており、変数フォントを認識しないアプリケーションは、"gvar"データの存在を認識せず、"glyf"データだけでグリフを描画する事になります。平たく言えば、必ず「標準」のフォントフェースが描画されるという事です。

可変フォント(gvar)

Windowsにインストールする

フォントデータの中身を見なくてもWindowsにフォントを導入すれば、それが変数フォントかどうかは分かります。

確認するには、フォントを導入して、設定画面から、フォントを選択、さらに導入したフォントを選択してください。

Windowsの設定→フォント

変数フォントであれば、上記のように「変数フォント」の表示があります。
さらに「変数フォントのプロパティ」をクリックすると、より詳細な変数フォントの情報を確認することができます。

この画面に記載されている「フォントのインスタンス」とか「バリエーション軸」という言葉を覚えておいてください。

変数フォントのプロパティ

「バリエーション軸」と「インスタンス」

用語を説明しておきます。

バリエーション軸

これまで変更可能なパラメータとして、「重さ」とか「傾き」を上げてきましたが、これを「バリエーション軸(Axis Tag)」と言います。
バリエーション軸はこれら以外にも、フォント設計者が任意に設定できます。
なんなら「可愛さ」とか「丸さ」とかの軸タグを設ける事も出来ますが、代表的なバリエーション軸として、以下の5つが登録されています。

  軸タグ名 意味
1 ital イタリック
2 opsz 高額サイズ
3 slnt 傾き
4 wdth 幅
5 wght 重さ

「タグ名」とはフォント全般で使われる言葉ですが、フォントのデータやパラメータの名前となる4文字の英数字の事です。

登録済みの軸タグについて、詳しくは以下のリンク先を参照してください

learn.microsoft.com

インスタンス

インスタンスとは、各軸を特定の値を決めた設定値軍につけた名前です。
例えば、「軸タグの重さ(wght) 700」を「Bold」という名前のインスタンスとします。
インスタンスも設計者が任意の名前、任意の個数を決める事ができます。

変数フォント非対応のアプリケーションを使って変数フォントを使う

Windowsにおいて、変数フォント非対応のアプリケーションは軸タグの値を指定する事はできません。指定できるのはインスタンスのみです

インスタンス名はフォントファイス名として機能しますので、フォント名指定で「フォントファミリー名+フォントフェイス名」の完全名を指定すれば、今までON/OFFしかなかった「太さ」もインスタンスの数だけ段階的な指定ができるという訳です。

例えば、Excel であれば数では表示しきれていませんが、フォントファミリー名「Source Serif Variable」、インスタンス名はwght 100に相当する「ExtraLight」を組み合わせて「Source Serif Variable ExtraLigh」を指定します。

「t」が抜けてる「Source Serif Variable ExtraLight」ではないか、と思った人が居るかもしれませんが、間違いではありません。

Windowsのフォント名は最大31文字と決まっていて、超過分は切られてしまうのです。

インスタンスをフォント名として指定する

変数フォントを使えるアプリケーション

では、逆に変数フォントを使えるアプリケーションはどのようなものがあるかと言えば、それはずばりWebです。より正確に言えばMS Edge等のブラウザーです。

HTMLやSVG等で変数フォントを使えるのですが、変数フォントのパラメーター指定はスタイルシートでは「font-variation-settings」という属性を使用し、以下のように設定します。

font-variation-settings: 'wght' 100

フォントの太さの場合は’wght'というキーワードを指定しますが、フォント仕様の世界ではこのような機能や特性を表す4文字の名前の事を「タグ名」と呼びますが、変数フォントのパラメーターの場合は「軸タグ Aixis Tag」と呼びます。

冒頭の9つの「S」は同じフォントで’wght'の値を100~900で表示しています。

これを表示するHTMLは以下の通りです。
SourceSerifVariable-Roman.otf はローカルフォルダーに置いたフォントファイルです。

<html>
  <head>
    <style type="text/css">
      @font-face {
        font-family: "SourceSerifVariable-Roman"; 
        src: url("fonts vf/SourceSerifVariable-Roman.otf") format("opentype")
      }

      .vfont {
        font-family: "SourceSerifVariable-Roman";
        font-size: 120px;
      }
    </style>
  </head>

  <body>
    <span class="vfont" style="font-variation-settings: 'wght' 100;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 200;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 300;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 400;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 500;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 600;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 700;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 800;">S</span>
    <span class="vfont" style="font-variation-settings: 'wght' 900;">S</span>
  </body>
</html>

プログラムにおける変数フォント

Win32 APIのプログラム開発者は、フォント指定は昔からフォントの太さを数値で指定していたことはご存じでしょう。通常なら400、ボールドなら700で、長らく意味のある値はこの2種類だけでした。(だと思っていましたが…)
やっと変数フォントを使えば、それ以外の値も機能するようになるのかと期待する人もいると思いますが、残念ながらそれはならずなのでが、ここは実際に試してみましょう。

Win32 GDIプログラムによる重さの指定

上記のプログラムは以下の通りです。

void CChildView::OnPaint()
{
  CPaintDC dc(this);

  LOGFONT logFont = {0};
  wcscpy_s(logFont.lfFaceName, _countof(logFont.lfFaceName), L"Source Serif Variable");
  logFont.lfHeight = 200;

  dc.SetTextAlign(TA_UPDATECP);
  dc.MoveTo(10, 10);

  CFont font;
  for (int weight = 100; weight <= 900; weight += 100)
  {
    logFont.lfWeight = weight;
    font.CreateFontIndirect(&logFont);
    CFont* pOldFont = dc.SelectObject(&font);
    dc.TextOut(0, 0, L"S");
    dc.SelectObject(pOldFont);
    font.DeleteObject();
  }
}

上で少し触れましたが、実行結果をよく見ると、フォントの太さは通常とボールドの二種類だけでなく、左から6番目(600 FW_SEMIBOLD)が通常とボールドの中間の太さになっています。いつの間にかこういう機能があったようです、それはさておき。

変数フォントで軸タグの値を指定するには、GDIもGDI+も不可で、DirectWrite APIを使う必要があります。ちょっと面倒です。

軸タグではなく、上記のExcelの例と同様にフォント名にインスタンスを含んだ完全名を指定するのは有効に機能します。

Win32 GDIプログラムによるインスタンス指定
void CChildView::OnPaint() 
{
  CPaintDC dc(this);
  
  LOGFONT logFont = {0};
  logFont.lfHeight = 200;
  logFont.lfWeight = FW_NORMAL;
  dc.SetTextAlign(TA_UPDATECP);
  dc.MoveTo(10, 10);

  LPCWSTR fontfaces[] = {
    L"Source Serif Variable ExtraLigh",
    L"Source Serif Variable Light",
    L"Source Serif Variable Regular",
    L"Source Serif Variable SemiBold",
    L"Source Serif Variable Bold",
    L"Source Serif Variable Black",
  };

  CFont font;
  for (int i = 0; i < _countof(fontfaces); i++)
  {
    wcscpy_s(logFont.lfFaceName, _countof(logFont.lfFaceName), fontfaces[i]);
    font.CreateFontIndirect(&logFont);
    CFont* pOldFont = dc.SelectObject(&font);
    dc.TextOut(0, 0, L"S");
    dc.SelectObject(pOldFont);
    font.DeleteObject();
  }
}

変数フォント通常フォントのアウトラインの違い

変数フォントのアウトラインには、通常フォントとは微妙な違いがあります。下の図を見比べてください。

通常フォントのアウトラインは重なりがありませんが、変数フォントはストロークの重なりがあります。

全てのフォントが項ではないのですが、一般に通常フォントはストロークの重なりは無いのですが、変数フォントには重なりができます。これはグリフをデザインする時、変数フォントは個々のストローク毎に変形させる方法で無ければデザインが困難だからです。

通常のフォントのアウトライン

変数フォントのアウトライン

過去の記事

こちらもご覧ください

占星術の十二星座と実際の星座がずれてること、それとその理由

はじめに

前回、日食の話の中で2030年6月1日に北海道の広域で金環日食が起こるという話をしました。

seiichis.hatenablog.com

日食によって空が暗くなり普段の昼間には見えない星が見えてきます。となると、6月1日が誕生日の方は自分は「ふたご座生まれ」なので、暗くなった太陽の位置にはふたご座が現れるはずだと、そう期待するかもしれません。

本当にそうなるか、その時の空の予測画像を作りましたのでご覧ください。

2030年6月1日 金環日食

期待とは違い、太陽の位置にあるのはふたご座ではなくおうし座です。

これは何故か、今回はテーマはこの話です。

黄道十二星座とは

女性は何故だか星座と血液型を気にするものですが、「星座」と言っているのは黄道十二星座の事です。「黄道十二宮」とも言います。
太陽が出ている間、つまり昼間は星が見えないので気が付かないかもしれませんが、日食の時に思い知ります。昼間でも見えないだけで空には星があります。
まあ考えてみれば当たり前の事ですが。

もし、一年中、昼も夜も星が見えれば、太陽は星々の間を移動して一年かけて一周している事に気付くはずです。
この空の太陽の通り道の事を「黄道」といい、黄道の上にある12の星座の事を「黄道十二星座」と言います。

人が誕生した瞬間に太陽がどの星座の上にあったか、これが一生の運・不運に作用するのだと占いが好きな人は考えるという訳です。
少なくてもこれが最初の考え方だったと思います。

もう一度冒頭の画像を見てください。

太陽を通り抜けて上下に伸びる黄色の線が黄道です。空を一巡りし、さらに地球の裏側を通りぬけて反対側と繋がる円の形になっています。

※

この黄道の円環を途中で切って直線状に広げたのが下の図です。

見やすいように背景を黒にしていますが地球を一周する円環なので昼も夜もありません。
左端と右端は繋がっていて、このつなぎ目の真上にあるうお座は左右に二分されての表示となってしまいます。

黄道は円ですので位置は角度で表しますが、ここでは一周360度として図の下に目盛りを表示しています。原点は右端で、ここは春分点、すなわちここに太陽が来ると「春分の日」になる場所です。北半球では太陽は黄道を右から左に移動するので、ちょっと面倒に感じるかもしれません。

黄道上にあるのが黄道十二星座で、良く見ると、黄道上に星座が存在しない部分があります。さそり座の左上の方です。正確には星座が存在しないのではなく、黄道十二星座には含まれない「へびつかい座」がこの場所にあるのですが、図の中では省いているだけです。
黄道十二星座を含めて星座は88個あり、88星座が地球から見える全ての空を隙間なく埋め尽くしているのです。

上の図は2030年6月1日の図ですが、1か月後の7月1日に空を見ると(日食ではないので昼に星は見えないのですが、頭の中で太陽の光を消してください)、太陽は黄道上を左に移動して下のように、ふたご座の上にやってきます。

この日に生まれた人は、「ふたご座生まれ」ではなく、「かに座生まれ」となります。

太陽がおうし座の上にあるのに「ふたご座生まれ」、太陽がふたご座の上にあるのに「かに座生まれ」と、つまり星座一つ分ずれているのです。

黄道十二星座がずれている理由

この件は Wikipedia に解説がありました。

要するに、誕生日と十二星座の関係の定義はひとつではなく、一般に我々が自分の「星座」と思っているのは「トロピカル方式」と呼ばれるもので、星座の範囲を日付で固定するこの方式では長年の歳差による変動で星座一つ分ズレてしまっている。日付を固定せず変動を補正するのが「サイデリアル方式」で、ただしこれには諸派があるというわけです。
なるほど。
「トロピカル Tropical 方式」とはもう少し訳せば「黄道方式」あるいは「太陽方式」、「サイデリアル Siderial 方式」は「恒星方式」ってところでしょうか。
諸派があるというのは、十二星座の天球上の範囲をどこからどこまでと考えるかの違いで諸派があるのでしょう。

「歳差」とは

地球の自転軸が傾いているのはご存じかと思いますが、この傾いている方向が徐々に変わり、25,800年かけて一回りするのが「歳差」です。25,800年とは非常にゆっくりした変化のようですが、12星座の一個分のずれですから歳差運動の1/12が起きたという事で、25,800年÷12を計算すると、今から2,150年、紀元前1、2世紀です。案の定、十分それっぽい年代が出てきます。

この時代の6月1日には太陽はふたご座の上にあって、誕生日と黄道十二星座を結び付けた占いも定義されたのでしょう。
しかし、それから2000年以上経ち、歳差運動により黄道十二星と太陽の位置関係が少しずつ変わっているのですが、占い上の誕生日と星座の関係はそれに併せてアップデートしてないので、両者に不一致が生じてしまっている。

古代の黄道十二星座

紀元前200年の黄道の様子を見てみましょう。

紀元前200年6月1日の黄道と黄道十二星座

2030年と比べると歳差によって星座の配置全体が左に移動し、黄道の春分点付近にはおひつじ座があり、6月1日の位置(図には書いてません)にはおうし座ではなく、ちゃんとふたご座があります。期待通りです。

正確に何月何日何時何分からふたご座という事も計算できるのですが、それをすると諸派があるという「サイデリアル方式」に新しい派を増やす結果になりそうなので、やめておきましょう。

関連リンク

関連ありませんが興味ある方ご覧ください

2026年8月12日のスペイン皆既日食の話(それと今後の日食予報)

はじめに

先日(2026年8月12日)、スペインで皆既日食というニュースがありました。

皆既日食はひと際神秘的な天体現象といてよいでしょう。滅多に起こらず、しかもそれが起こるのは地球上のごく限られた場所です。一生のうちに一度でもそれを見ようと思えば、普通は大金払って海外に出向かなければなりません。

国内で皆既日食を見られたスペインの人は幸運です。

皆既日食のあらまし

Wikipediaに日食チャートが載っていましたので、これを見てください。

知らずに見るとアメリカ軍のミサイル防空網か何かかと勘違いしてしまいそうですが、見方を説明します。青い線で示された場所が月の影が投影された本影の通過経路、すなわち皆既日食が観測できる地域です。この線上にぽつぽつと描かれた楕円形は、ある時点にできる本影の形で10分おきに描かれています。月は丸いのに影の形が円にならないのは、影ができる地球が球形だからです。

水色の罫線が描かれていますが、これは月の半影、すなわち部分日食が観測できる場所です、赤いリボンのような形で示された場所は、日の出または日没の瞬間に部分日食が起こっていた場所です。

 見方は理解できたでしょうか。

今回、皆既日食を観測できた場所がスペインだけという事になったのは、本影の通り道が主に北極の周囲だったためで、日食の終了間際の夕方にやっとスペインに本影が到達したためです。

何故、日食はこのようなルートになったか?

それにしても今回の日食チャートは格別に奇妙な形と言って良いでしょう。日食が北極を一巡りするなんて事がどうやって起こり得るのか感覚的には違和感ありありの事でしょう。

今回の日食は北半球が夏の時期に起こったため、北極点が太陽が輪に傾いており、たまたま月の影が北極付近を通過し、それに地球の自転が加わったため、日食チャートがミサイル防衛網と見紛うような奇妙な形となりました。

それが分かるように動画を作りましたので、それを見てください。
NASAの暦表データで計算した一応は精密な動画です。

太陽からの視点です。本当は月が地球の前を通過するのですが、月は無しで月の影だけを描画しています。月の直径は地球の4分の1ほどですので、地球の前を通過する月を創造で付け足してください。

この動画を見ての通り、起こている事は自転する地球に月の影が円形の影を作って一直線に通過しているだけで、なんら不思議に思いません。

上記を視点を変えて見ると、円のはずの月の影は地球の球面で大きく歪み地球の自転と月の移動の組合わせにより一見不思議なルートを通るという訳です。

下の動画で半円型に暗くなっている場所は言うまでも無く、夜の場所です。この夜の場所からは日食を観測する事はできません。意外に思ったでしょうか?
でもそれが何故なのかは結構当たり前なので考えてみてください、

今後の日食

2028年2月6日 南アメリカ南部 金環日食

次の地球上の日食は2028年2月6日で、南アメリカで金環日食が観測できます。金環日食は月の距離が地球から離れているため太陽を隠し切れずリング状に太陽がはみ出る日食です。
皆既日食と金環日食を併せて「中心食」と言いますが、月の距離が地球から遠い時に日食が起こるとその分見た目の月が小さくなるため太陽を隠し切れず金環日食となるのです。
ところで、英語では「Annular Eclipse」なのですが、日本語でなぜ「金」が付くのかは謎です。それを言うなら「皆既」も謎ですが。ちょっと詩的な日本人科学者が命名したのかもしれません。

2028年2月6日 南アメリカ南部 金環日食

2028年8月2日 アフリカ北部 皆既日食

次の皆既日食という事であれば2028年8月2日です。

アフリカ大陸の北側の海岸線に沿うように日食が起こります。

2028年8月2日 アフリカ北部 皆既日食

2030年6月1日 北海道 金環日食

日本での次の中心食は2030年6月1日で、金環日食です。北海道の広い地域で16時:55分前後で金環日食を観測できます。6月1日なら気候も良さそうで北海道は盛り上がる事でしょう。

2030年6月1日 北海道 金環日食

2030年6月1日 北海道 金環日食

関連リンク

関連ありませんが興味ある方ご覧ください

 

知られざるフォント技術の話 -「双方向性」あるいは「Bidi」-

はじめに

「双方向性」あるいは「Bidi」とはテキスト表示に関する言葉です。

「Bidi」は「Bidirection」の略で、それを日本語で「双方向性」と訳すのがどれほど一般的になのか分かりません。なので以後は「Bidi」と書きますが、ここで言う「方向 direction」とは、単語なり文を英語等のように「左→右」に書くか、アラビア語のように「右→左」に書くかという事です。

それだけなら大して難しい事は無さそうですが、「左→右」の言語と「右→左」の言語が混在した時面倒なことになります。そしてそれを扱う仕様、あるいは技術が「Bidi」という訳です。

説明の前に決めごと

詳しく説明したいのですが、私も含めて殆どの日本人は「右→左」の言語であるアラビア語もヘブライ語が分からないでしょうから、それで例を挙げてもピンとこないと思います。それで便宜的に日本語を「右→左」の言語である事にします。
実際昔は日本語を横書きにする時は「右→左」で書いていたのですから、比較的馴染みやすいはずです。

例えば「明日は晴れます」は、

すまれ晴は日明

となります。ご理解できたでしょうか?

Bidiのいくつかの例

ではいきます。

例1

「私はWindowsにExcelを導入しました」

これはどうなるかというと、

たしまし入導をExcelにWindowsは私

となります。文全体は日本語ですから「右→左」ですが、「Windows」や「Excel」と言う単語は英語ですから「左→右」に書かなければなりません。

このように左右方向の文字の向きが混在するのが「Bidi」です。別にそのためにユーザーに何か「やってください」という話ではなく、Windowsが勝手にやっている事ですのでご安心ください。

例2

次です。

「I like 和牛 of Japan」

これはどうなるかというと、

I like 牛和 of Japan

です。文全体は英語ですので「左→右」ですが、日本語の単語の部分だけ「右→左」です。

例3

もう一つ行きます。

「彼は『I like 和牛 of Japan』と言いました」

これは

たしまい言と「I like 牛和 of Japan」は彼

となります。文全体は日本語ですので「右→左」、その中の英語文は「左→右」で、英語文の中の日本語単語は「右→左」です。言語が入れ子になって、方向もネストされる事に気が付いたでしょうか。

例4

最後に2つの文を示します。違いに注意してください。

ではいきます。

「私はMicrosoft Excelを導入しました」

これは、

たしまし入導をMicrosoft Excelは私

となります。「Microsoft Excel」が一連の英語と見做されています。次はどうでしょう。

「私はMicrosoftのExcelを導入しました」

これは、

たしまし入導をExcelのMicrosoftは私

となります。「Microsoft」と「Excel」が別の英文の部分と見做されの順番が変わります。両者を空白文字で繋いだか、「の」で繋いだかでこのように語順の違いになります。

つまりBidiは面倒くさい

Bidiを突き詰めていくと思いの外面倒臭く、ここまで日本語が「右→左」であると便宜的に仮定して説明したので、本当にWindowsはこんなことやっているのかと、怪しんでいる方もいるかと思いますが、本当です。

アラビア語で示します。
「メモ帳」を開いて、以下の日本語とアラビア語の混在テキストをコピペして、テキスト上でカーソルを左右に動かして文字の並びを追いかけてみてください。

私は「لماذا لا يتكلمون اللّغة العربية فحسب؟」と思いました。

ご納得して頂けたことでしょう。

何故「左→右」に統一できないか

いやいやいや、こんな七面倒くさい事しないで、かつて日本人がそうしたように、世界の全ての言語が横書きでは「左→右」にすると決めれば、全ての問題は解決でしょう、と思ったかもしれませんが、それはできないのです。特にアラビア語では無理なのです。

アラビア語は手書きだろうが活字だろうがコンピューターだろうが、必ず「右→左」への方向をもった「続け字」で書くからです。

例えば以下のアラビア語の文字、UNICODEのU+064Eの文字ですが、

خ

この文字を4つ書きます。最初の1文字の後には空白を一文字置くので、空白も入れて5文字です。「右→左」に書かれている事にもご注意ください。

خ خخخ

同じUNICODEの文字を4つ書いたのですが4つの文字が微妙に異なる形をしています。このように「続け字」にするために4つの字体を使い分けるのがアラビア語なのです。

同じ文字でも続け字の都合で字形も変わるので、もしアラビア語も「左→右」に書くと決めるには「左→右」用の新字体を発明する必要があるのです。

が、それは正しい事とは思いません。
テクノロジーがすべきことはコンピューターの都合で新字体を発明させる事ではなく、現にある言語にコンピューターが合わせるべきです、それはそうでしょう。

Bidiの仕様と技術、

冒頭で「フォント技術」と謳いましたが、上記のようなBidiの仕様を定めているのはCSSとUnicodeです。

 

関連リンク

関連ありませんが興味ある方ご覧ください

"EBCDIC"を何と読むか?と、それにまつわる話

はじめに

"EBCDIC"という言葉をご存じでしょうか?
プロのシステム技術者で無ければ聞いたこともない言葉かもしれません。
"EBCDIC"とは主にIBMのメインフレームで最初期から欽日に至るまで使われ続けている文字コードの事で、パソコン等で使用される"ASCII"と同列の言葉です。
今回は"EBCDIC"を何と読むか?と、それにそれにまつわる話をしたいと思います。

"EBCDIC"を何と読むか?

さて、"EBCDIC"と"ASCII"ですが、"ASCII"の読み方は「アスキー」で誰も迷いは無いと思いますが、"EBCDIC"ははてさて、「エビクディック」?、「エブクディック」?、「エビスディック」?、「エビシディック」?と色んな読まれ方がされ、迷いまくりです。
ただ、その昔、"EBCDIC"は「エビシディック」で迷いは無かったと私は記憶しています。昨今は技術者にとってメインフレームが縁遠くなってきたため、読みが継承されず忘れられているだけだと思います。
ちなみにwikipediaにもEBCDICの読みに関する言及はありません。

"EBCDIC"は"ABCDic"

昔は「エビシディック」で迷いは無かったのは、ある裏話が伝わっていたからです。
「"EBCDIC"とは"Extended Binary Coded Decimal Interchange Code"の略と言うのは後付けの説明で、命名者の意図は"ABCDic"であり、だから『エビシディック』と読むのだ」という話を何かで読んだか、聞かされたか、記憶は定かではありません。
今となってはソースも何もない話ではあります。

"ABCDic"はラテン語のウィット

"EBCDIC"は"ABCDic"なので「エビシディック」だ、という話ももう一つこじ付けっぽくて腹落ちしないかもしれません。私もそう思っていました。
しかし昨今私も齢を重ねてラテン語の知恵がついてきたこともあり、今頃になって"ABCDic"はラテン語のウィットである事に気が付きました。

昔の技術者・科学者はこのラテン語のウィットが好きで、コンピューターの分野でも、"nil" (ラテン語"nihil"が約まった形、現在の"null")とか、"data" (ラテン語「do」の完了分詞で、中性、複数、主格の変化形)とか、コンピューター用語にさりげなくラテン語が散りばめられています。

"ABCDic"についてですが、英語ではアルファベット全体を「ABC エー・ビー・シー」と3文字で呼ぶところをラテン語の流儀では「ABCD アー・ベー・ケー・デー」と4文字を挙げるのです。実際にはこれにラテン語の語尾「~arius」を取り付けて、母音を全て短音で発音して、「ABCDarius アベケダリウス」と言います。(発音通りに「abecedarius」と綴る事が多いかもしれません)

このラテン語の流儀を英語で真似すると、つまり「ABCD」に英語の語尾「~ic」を取り付けて母音を短音で発音すると、「ABCDic エビシディック」になる、という訳です。

残念ながらこのラテン語の話はIBMのマネジメント層には響かなかったのか、面倒くさかったのか分かりませんが、とにかく封印され、「"EBCDIC"とは"Extended Binary Coded Decimal Interchange Code"の略です」、という事になったのでしょう。

むすび

いかがでしょう、"EBCDIC"は「エビシディック」でしっかり腹落ちしたでしょうか。
これからは職場で"EBCDIC"を読み上げる時には、「えび※▲でぃっく…(ごにょごにょ)」ではなく、しっかりと「エビシディック」と言いましょう。

関連リンク

関連ありませんが興味ある方ご覧ください

拡張メタファイルの話、EMFとEMF+

はじめに

今回はWindowsの「メタファイル」の形式について整理します。

Windowsには複数のメタファイルの形式があり、それはGDIのモードと密接に関係しています。以前にGDIのモードの比較の記事を掲載しましたが、今回の記事はその続編ということになります。

Windows API GDIのモードの比較とGDI+の特徴 - SS blog

何のためにそういう事を調べているのかと、一言で言えばプログラムで作成した図形をExcel文書にコピペするためです。
そういう場合、プログラムの画面をキャプチャーしてその画像をExcel文書にコピペするという人が多いかもしれませんが、それだと当然ながら、Excelに貼り付けた画像は一切編集できません。画像の中の日本語文言を英語に置き換えたり、図形の配置を変えたりといった画像編集をExcelの中でするには、キャプチャー画像ではなくメタファイルで貼り付ける必要があるのです。
メタファイルでそれができるのはベクターデータだからですが、ただしメタファイルなら何でもそれができるのではなく、メタファイルの形式の違いを理解して、貼り付け元のプログラムを作ってやる必要があるのです。

メタファイルの種類

メタファイルは古くからWindowsに備えられた機能で、Windows GDIの拡張に従ってメタファイルの仕様も拡張されたため、今では三種類のメタファイルの形式ができています。

  • WMF形式 (メタファイル)
  • EMF形式 (拡張メタファイル)
  • EMF+形式 (拡張メタファイル+)

GDIの拡張モードができると、それをカバーするようにEMFも仕様が拡張されるという図式なのですが、表に整理すると以下のようになります。

GDIモードの拡張とメタファイル形式の拡張の関係

Windowsに最初にあったメタファイルの形式は「WMF」という形式でしたが、GDIに拡張モード(GM_ADVANCED)を追加したとき、マイクロソフトは全く新しい独立した命令セットとメタファイルのデータ形式として拡張メタファイル「EMF」を定義しました。しかし、WindowsにGDI+が追加された時は完全に独立したものとせず。拡張メタファイル(EMF)の中のメタファイルタイプという仕様になりました。これは一定の相互互換性を持たせることで、過去の資産を作り直したり、捨てたりしなくても良いようにと考えたのでしょう。

メタファイルタイプ

拡張メタファイルおける、メタファイルタイプは以下の3つです。

  • MetafileTypeEmf
  • MetafileTypeEmfPlusOnly
  • MetafileTypeEmfPlusDual

一番目の MetafileTypeEmf は従来型の拡張メタファイ(EMF)の事です。GDIの命令セットで拡張メタファイルを作成するか、あるいはGDI+の命令セットで MetafileTypeEmf を指定して拡張メタファイルを作成すれば、このメタファイルとなります。

MetafileTypeEmf のメタファイルの中身は、GDI命令の単純な羅列です。GDI+の命令でMetafileTypeEmf のメタファイルを作成するとGDIの命令に置き換えられて保管されます。ただし。GDI+はGDIより機能が多いのですから、MetafileTypeEmf を選んだ場合は、例えばグラデーションの塗りつぶしがハッチ塗りつぶしで代用されるなどの一部機能の「劣化」が起こります。

劣化を避けたいなら、残り2つの何れを選ぶしかありませんが、MetafileTypeEmfPlusOnlyを選んだ場合、できたメタファイルを利用する側がEMF+に対応している必要があります。より具体的に言えばメタファイルの表示にGDI命令ではなく、GDI+命令を使っている必要があります。

EMF+に対応しているのか分からないという場合の選択肢が、最後のMetafileTypeEmfPlusDualで、これはEMFとEMF+の両方のレコードを持っている拡張メタファイルです。表示するプログラムがEMF+に対応していればEMF+を表示し、そうでなければEMFを表示します。便利ですが拡張メタファイルのデータ量はざっくり2倍となります。

ところでEmfPlusOnlyの拡張メタファイルをEMF+に対応していないプログラム(非GDI+プログラム)が表示しようとすると何が起こるでしょう。EMF+に対応していないのだからデータ内のEMF+レコードはゴミデータにしか認識できないはずで、そのために実行時エラーになってしまうでしょうか。実はその場合、エラーなどにはならず表示域は透明で塗りつぶされます。そうなるのはEMF+のレコードはEMFのコメントレコードとして格納されているからです。EMFの描画レコードは表示域を透明で塗りつぶすBitBlt 命令があるだけです。それでエラーが起こらず白い表示になるという訳です。

ここまで説明してきたことを表にまとめます。

メタファイルの形式と描画命令の関係

ExcelはEMF+に対応しているか

冒頭に述べた通り、私のやりたいことはExcelにメタファイルを貼り付けて、図形データを編集したいという事です。

論より証拠、実験してみましょう。

EmfTypeEmfメタファイルの貼り付け

メタファイルを作成するのは自作のSVGデータをメタファイル化してクリップボードにコピーするプログラムです。オプション操作により。Emf/Emf+/Emf+Dualを切り替えられるように作ってあります。

SVGをメタファイルに変換するプログラム

まずはEmfTypeEmfPlusでコピペします・

ExcelにEmfで貼り付け

EmfTypeEmfPlusのメタファイルを貼り付けると、一般の「画像データ」という扱いで表示されますし、拡大・縮小も問題なく表示されます。

さらに、この画像データに対して「グループ解除」するとメタファイルが分解されExcelの図形データとなります。

文字列の編集

普通の図形データとして文字列の変更も普通にできます。

EmfTypeEmfであればExcelで表示と編集の両方ができる事が分かりました。

MetafileTypeEmfPlusOnlyメタファイルの貼り付け

次はMetafileTypeEmfPlusOnlyです。
MetafileTypeEmfPlusOnlyのメタファイルを貼り付けると、ひとまずは一般の「図形データ」という扱いで表示されますし、拡大・縮小も問題なく表示されます。

EmfPlusOnlyの表示

編集のためにグループ解除します。

EmfPlusOnlyのグループ解除結果

「グループ解除」すると表示されていた図形は消えて透明表示となります。上で説明したEMFのBitBltによる透明表示です。
グループ解除するまえに表示されていたEMF+のデータはゴミデータ扱いで消えてしまいます。

つまりEmfTypeEmfPlusOnlyでは、Excelは表示はできても編集はできないという事になります。

EmfTypeEmfPlusDualメタファイルの貼り付け

上記の結果からEmfTypeEmfPlusDualの結果は予想できます。

表示はEMF+のメタファイル画像で編集はEMFのメタファイルの表示となるはずです。

まずは貼り付けです。

表示

表示は問題ありません。次にグループ解除します。

EmfPlusDualのグループ解除後

こちらも編集可能となりました。
Dualの場合、貼り付け後に表示されたメタファイルはEMF+で、グループ解除後に表示されるのはEMFのメタファイルである事は覚えておきましょう。

結論

上記のExcel実験を纏めると下記の通りです。

メタファイルタイプによるExcel貼り付け後の違い

関連リンク

関連ありませんが興味ある方ご覧ください

Win32apiのリージョンの中身はどうなっているか、パスと何が違うか

はじめに

今更ながら、Win32apiの「リージョン」とは何か、パスとの違いを調べてみました。

私は、WIndows 3.0の頃からWin32のプログラムを作ってきましたが、漠然とパスは「線」、リージョンは「面」を示すデータくらいの認識を持っていました。
ただ、パスには開いたパスと閉じたパスがあり前者はパスに囲まれた領域を示し、実際に塗りつぶしたり「面」としての処理もできるのですから、上記の区別ではパスとリージョンの違いを言い表せていないことになります。
ネットで検索しても特にリージョンの説明は何故だか少ないのです。

という事で、今更ながらちゃんと調べてようと一念発起したというわけですが、結果は今まで思い込んでいたのとは些か違っていました。
私と同様に漠然とリージョンを使っていたという方、是非最後まで読んでください。

リージョンの基本(GDI編)

まずはリージョンの使い方などをおさらいします。実はGDIとGDI+で違うのですが、しばらくはGDIの場合で説明します。

リージョンの作り方

GDIで新規にリージョンを作成するAPI関数には以下のようなものがあります。
作成されるとHRGN ハンドルが返されます。
MFCで作成する場合は CRgn クラスのメソッドの実行という形になります。

リージョン用の描画命令が一式用意されているのが、パスと違います。パスはBeginPathとEndPathの間で一般の描画命令を実行するという方式です。

  • CreateEllipticRgn 楕円
  • CreateEllipticRgnIndirect 楕円
  • CreatePolygonRgn 多角形
  • CreatePolyPolygonRgn 多角形
  • CreateRectRgn 矩形
  • CreateRectRgnIndirect 矩形
  • SetRectRgn 矩形
  • CreateRoundRectRgn 角の丸い矩形
  • CreateFromPath パスから作る
  • CreateFromData GetRegionDataで取得したデータから作る

例えば、楕円のリージョンを作るには以下のようにします。

HRGN hRgn = ::CreateEllipticRgn(10, 10, 600, 400)

MFCであれば同じことを以下のように書きます。

CRgn rgn;
rgn.CreateEllipticRgn(10, 10, 600, 400)

ところで、MFCとは「Microsoft Foundation Class」の事でWin32apiをC++のクラス群に置き換えたラッパークラスです。以後プログラムはMFCで記載しますが、MFCでも「素」のwin32apiでも機能は同じですので、頭の中で変換して頂ければと思います。
こんな感じです。

(MFC)

dc.LineTo(10, 10, 100, 200);

↓

(Win32api)

LineTo(hdc, 10, 10, 100, 200);

リージョンの描画

リージョンは「面」ですので描画と言えばまず塗りつぶしですが、それ以外の命令もあります。。

  • FillRgn 塗りつぶし
  • PaintRgn 塗りつぶし
  • FrameRgn 周囲に罫線を描画
  • InvertRgn 領域内の色を反転

FrameRgnは「線 line」と言わず「罫線 border」と説明するのが意味深です。ここにリージョンとパスの違いの一端が現れていると言えるでしょう。説明は後にとっておきます。

リージョンを塗りつぶすプログラムを示します。MFCのOnPrintメソッドです。

void CChildView::OnPaint() 
{
  CPaintDC dc(this);

  CRgn rgn;
  rgn.CreateEllipticRgn(10, 10, 400, 300);

  CBrush brRed(RGB(255, 0, 0));
  dc.FillRgn(&rgn, &brRed);
}

実行結果は下記の通りです。

リージョンの塗りつぶし

念のため、同じ処理を「素」のWin32apiで書けば以下のようになります。こちらはWM_PRINTメッセージの処理となります。

やっている事はMFCと完全にイコールです。

case WM_PAINT:
{
  PAINTSTRUCT ps;
  HDC hdc = BeginPaint(NULL, &ps);

  HRGN hrgn = CreateEllipticRgn(10, 10, 400, 300);
  HBRUSH hbrRed = CreateSolidBrush(RGB(255, 0, 0));

  FillRgn(hdc, hrgn, hbrRed);
  DeleteObject(hbrRed);
  DeleteObject(hrgn);
  EndPaint(hwnd, &ps);
  return 0;
}

クリップ領域

塗りつぶしは一般の描画命令やパスを使ってする事が多いので、リージョンの実際的な用途はそれ自体を描画するより、後から描画を制限する、すなわちクリップ領域を設定するのに使われる事が多いのではないでしょうか。

クリップ領域の設定は下記のようなAPI関数を使います。

  • SelectClipRgn
  • ExtSelectClipRgn 
  • SetMetaRgn
    等

プログラム例を示します。変数の text には長い文章の文字列が格納されています。
まず楕円のリージョン(rgn)を作成し、デバイスコンテキスト(dc)にクリップ領域として設定します。
それに続いて画面いっぱいに表示したテキストの表示が楕円のクリップ領域内に抜き取られるという訳です。

void CChildView::OnPaint()
{
  CPaintDC dc(this);

  CRgn rgn;
  rgn.CreateEllipticRgn(10, 10, 400, 300);
  dc.SelectClipRgn(&rgn);

  CRect rc;
  GetClientRect(&rc);
  dc.DrawText(text, -1, &rc, DT_WORDBREAK);
}

実行すると以下のようになります。

リージョンによるクリップ

ここまでのリージョンを使用した例でやった事は、実はリージョンを使わずパスを使ってもなんなくできます。上に示した楕円のテキスト表示であれば、以下のパスを使ったプログラムでも全く同じ結果になります。

void CChildView::OnPaint()
{
  CPaintDC dc(this);

  dc.BeginPath();
  dc.Ellipse(10, 10, 400, 300);
  dc.EndPath();
  dc.SelectClipPath(RGN_COPY);

  CRect rc;
  GetClientRect(&rc);
  dc.DrawText(text, -1, &rc, DT_WORDBREAK);
}

パスの作成はBeginPathとEndPathの間で描画命令を実行するとデバイスコンテキストにパスが保管されるという方式で、領域の作成よりも癖があります。GDI+ではパスもオブジェクトとして整理されて、実用性が格段に増しています。それはさておき。

上のプログエラムを実行すると下図のようになりますが、要するに領域でなくパスを使っても結果は同じです。

パスによるクリップ

リージョンの結合

複数のリージョンをAND/OR/XOR/COPY/DIFFの演算で結合する事です。
APIは下記となります。

  • CombineRgn

以下のプログラムは複数の楕円をXORで結合したクリップ領域を作る例です。

void CChildView::OnPaint()
{
  CPaintDC dc(this);

  CRgn rgn1;
  rgn1.CreateEllipticRgn(10, 10, 400, 300);
  CRgn rgn2;
  rgn2.CreateEllipticRgn(210, 10, 600, 300);

  CRgn rgn;
  rgn.CreateRectRgn(0, 0, 0, 0);
  rgn.CombineRgn(&rgn1, &rgn2, RGN_XOR);
  dc.SelectClipRgn(&rgn);

  CRect rc;
  GetClientRect(&rc);
  dc.DrawText(text, -1, &rc, DT_WORDBREAK);
}

リージョンによるクリップの結合

パスでもやってみましょう。パスはデバイスコンテキストの中で結合させるというやり方になりますが、やはりリージョンと同じ結果になります。

void CChildView::OnPaint()
{
  CPaintDC dc(this);

  dc.BeginPath();
  dc.Ellipse(10, 10, 400, 300);
  dc.EndPath();
  dc.SelectClipPath(RGN_COPY);

  dc.BeginPath();
  dc.Ellipse(210, 10, 600, 300);
  dc.EndPath();
  dc.SelectClipPath(RGN_XOR);

  CRect rc;
  GetClientRect(&rc);
  dc.DrawText(text, -1, &rc, DT_WORDBREAK);
}

パスによるクリップの結合

ひとまずの纏め

ここまで示した通り、プログラムの外形としてはパスでもリージョンでも同じ。これだけ見ると2つは要らない。リージョンは「面」だけで、パスは「線」も「面」も可能ですから、パスだけあれば良いように思えてしまいます。

しかしリージョンにちゃんと役割があります。パスでもクリップ領域は作れると書きましたが、内部的にはパスで設定したクリップ領域は内部的にはリージョンに置き換えられています。要するに描画は兎も角、クリップはリージョンでなければ駄目なのです。

という事を踏まえて、以降が本題、リージョンの中身の話をします。

リージョンの中身

リージョンはラスター

リージョンは、プログラムの外形としてはリージョンは多角形とか楕円とか閉じたパスとか、ベクトル図形を描画しているのだから内部には描画したベクトル図形データが蓄積されているのだろうと思ってしまいそうです。あるいは当然そうであるべきと期待してしまいます。
しかし実はそうではなくリージョンはCreateXxxx関数の指定は「ベクトル図形的」でも、それを内部ではラスター図形のデータとして保管します。

まずはAPI関数の仕様を確認してください。リージョンの内部データを取り出すAPI関数は、GetRegionData ですが、これはリージョンを構成する矩形の配列を取得する仕様となっているのです。

learn.microsoft.com

「矩形であればラスターではなくベクトル図形でしょう」、と言われそうですが、例えばCreateEllipticRgn で作成した円のリージョンデータをGetRegionData で取得すると以下の図のようなデータが返されます。

GDIにおける円のリージョンの保有データ

このギザギザ図形はベクトル図形ではなくラスター図形の特徴である事が分かっていただけるでしょうか。矩形の集合という形式は謂わばビットマップのランレングス圧縮と本質的には同じで、その意味で矩形の配列というのはラスターデータの圧縮形式と考えることができます。

論より証拠

腹落ちしない人もいるかもしれませんが、論より証拠です。
小さな円(半径30)のリージョンを作って10倍に拡大して描画させてみます。拡大のためにGM_ADVANCEDを使用します。

void CChildView::OnPaint()
{
  CPaintDC dc(this);
  dc.SetGraphicsMode(GM_ADVANCED);
  XFORM xf = { 10.0f, 0, 0, 10.0f, 0, 0 };
  dc.SetWorldTransform(&xf);

  CRgn rgn;
  rgn.CreateEllipticRgn(1, 1, 31, 31);

  CBrush brRed(RGB(255, 0, 0));
  dc.FillRgn(&rgn, &brRed);
}

リージョンの拡大描画

リージョンがラスターである事を示すギザギザができました。
パスでも試してみましょう。

void CChildView::OnPaint()
{
  CPaintDC dc(this);
  dc.SetGraphicsMode(GM_ADVANCED);
  XFORM xf = { 10.0f, 0, 0, 10.0f, 0, 0 };
  dc.SetWorldTransform(&xf);

  dc.BeginPath();
  dc.Ellipse(1, 1, 31, 31);
  dc.EndPath();

  CBrush brRed(RGB(255, 0, 0));
  CBrush* pBrOld = (CBrush*)dc.SelectObject(&brRed);
  dc.FillPath();
  dc.SelectObject(pBrOld);
}

パスの拡大描画

リージョンとは違い、パス描画の拡大ではギザギザはできません。内部に格納された図形データがベクトルデータであるためです。

リージョンの存在意義

リージョンは何故このような仕様なのか、というより、何のためにリージョンが存在するのか、パスがあるから要らないでしょう、と言う思いが脳裏をよぎっているかと思う。

リージョンのこうした仕様の狙いは、クリップ領域の判定における「スピード」であるに違いありません。ある点がクリップ領域に含まれているか否か、ベクトル図形データで数学的に判定するより、矩形配列で判定した方が早いに決まっています。
そしてそのスピードは少なくても一昔前のWindowsでは非常に重要な事でした。Windowsのウィンドウの描画は常にクリップ領域に対して行われるからです。
ウィンドウの描画は例えばウィンドウからはみ出す大きな円を描画しても、はみ出た部分は描画されずにクリップされます。ウィンドウの外に描画しても何も起こらないの当然でしょ、とつい思えてしまいますが、ウィンドウもWindowsがスクリーン上に描画している図形に過ぎず、ウィンドウの外に描画されないのはクリップ領域が設定されているからです。
あるいは、ウィンドウの裏に部分的に隠れていた別のウィンドウを前面に表示したとき、再度描画するのはウィンドウに隠されていた部分だけ、つまり「無効領域」だけであるのが、Windowsの描画の大基本です。
無効領域はクリップ領域として設定され、WM_PAINTメッセージが発出されて、ここのプログラムは無効領域を意識せず再描画をする仕組になっています。みなさんが今使っているWindowsに表示されている何十というウィンドウも一番後ろのデスクトップもこの仕組みで表示されています。
つまりクリップはWindowsの「幹」であり、領域内外の判定のスピードはWindowsの全体の表示スピードに直結しているのです。

GDI+のリージョン

GDI+のリージョンはベクトルデータ

これまでのリージョンの説明は全てGDIでの話です。
GDI+のリージョンは内部データがベクトルデータに一新されています。ハードウェアの能力が向上して、当初の「スピード」の目的は優先順位が下がったという事なのでしょう。

プログラムを動かして確認しましょう。また円を拡大した上で塗りつぶしますので、ベクトルでなければギザギザができるはずです。

void CChildView::OnPaint() 
{
  CPaintDC dc(this);
  Graphics g(dc);
  Matrix m;
  m.SetElements(10.0f, 0, 0, 10.0f, 0, 0);
  g.SetTransform(&m);

  GraphicsPath path;
  path.AddEllipse(1, 1, 30, 30);

  Region rgn;
  rgn.Intersect(&path);

  SolidBrush brRed(Color::Red);
  g.FillRegion(&brRed, &rgn);
}

GDI+のリージョンの塗りつぶし

上図の通り、ギザギザはなくGDI+のリージョンはベクトルデータである事は確認できました。データの実体は GetDataメソッドで取得できます。

earn.microsoft.comこのRegion::GetDataメソッド、バイト列を返す仕様となっていますが、どのようなバイト列を返すのかの説明がどこにもありません。ネットを探しいれば見つかるかもしれませんが、取り敢えずバイトデータを解析するとEMF+のリージョンオブジェクトが格納されている事が分かりました。

EMF+の仕様は以下をご確認ください。

learn.microsoft.com

EMF+のリージョンオブジェクトは木構造で演算と共にパスや矩形データを保有する形式であり、これであれば紛れも無くベクトルデータです。

GDI+のリージョンクラスとパスクラス

既にプログラムを示しましたが、GDI+のリージョンクラスはGDIのリージョンのように、直接リージョンオブジェクトに描画するのではなく、あらかじめ作成しておいたパスをリージョンに結合していくという方式です。或いは矩形であれば直接に結合できます。
パスはGDIのBeginPath、EndPathの方式は改められ、GDI+ではGraphicsPathクラスのオブジェクトなり、このGraphicsPathオブジェクトに対する各種描画メソッドが設けられてます。非常にすっきりしたと言えます。

GDI+のリージョンははパスの集合として整理されたという事になります。

関連リンク

関連ありませんが興味ある方ご覧ください