2017年7月14日金曜日

VB GIMP Unicode 特殊文字で悩む

GIMP Unicode 特殊文字で悩む で お約束した VB プログラム の件です。
少し、書いて見ました。
そう、 システムに登録していないフォントを使って、
PUA に登録された 字体のバリエーション を呼び出すものです。


フォントをシステムでなく GIMP 特有のフォルダに格納して使う件は、前回 にも触れた便利な機能です。
しかし、そのお陰で、ある一部のフォントでの特殊機能が弊害を受ける事になっています。
Unicode の 私的領域 PUA Private Use Area に格納された 異字体 字体のバリエーション の操作です。
特に、日本語環境の場合、IME とバッティングするのか、
マニュアル(ヘルプ)に記載の方法 で入力出来ないのは 前回 書きました。

そこで、苦労して書いたのが、 これ。  
WPF です。  扱うフォントファイルの制限事項が多い Form で ではなく、 WPF で です。



GIMP の Default で用意される ユーザー用の フォント フォルダ から、
Font Family 名 を取得して、
それを選ぶ事で、
PUA の文字を表示させようと言う訳です。

    あっ、フォント名は GIMP で示される それ とは異なり、 また、 先頭に "./#" が附きます。
    これは Visual Studio (Windows) での フォントの仕組みに因るもので そのままで表示させています。
    名称表示も微妙な差異があります。
    一部の バリエーションを持つ FontFamily では 同一グループに纏められるため、
    文字のスタイル ( Bold / Italic ) を選択出来る様にしました。  これも GIMP と違う箇所です。

    この部分を、WPF と GIMP とで同期させる仕組みは、 以前の GIMP Fonts Tool で実装済みですが、
    これは、かなり重いので(自分のスパゲッティコードのせい ... )、 今回は、簡便さを重視し、違いに目を瞑りました。


未だ、最低限の実装ですので、
フォルダ名は、ハード コーディングですし、 GIMP version も 2.8 前提。
きっと、 もうすぐ、 2.10 が歩み出すでしょうし、 2.9 の存在もあります。
その辺りは、考えないと、 ね。  ハイ。  直さないとね。  です。


序なので、
絵文字や、Unicode の拡張領域( U+10000 以降 の 5桁部分 )に対応する事に。

一般的なフォントは、
PUA に 絵文字に類するものが入っています。
これは、 Windows が標準で用意する UI (UserInterface) を補う目的で事前に用意されたアイコン類等です。
Windows を弄っていて、其処彼処で目にする アレやそれ と ご対面 です。  前々投稿 参照。
大昔ならば、リソースとして画像で組み込まれていたのだろうと想像しています。
フォントに組み込んでしまえば便利ですから。
その部分が画面表示される 自分のプログラム を眺めていれば、 自ずと、 他の 記号や 文様や 絵文字に 目が移ります。
自然な流れです。
そして、 サロゲート や U+FFFF 以降の拡張領域 にも 目移り します。
いいえ、正確には、面倒そうなのを承知の上で、手を出す事になるのです。

やはり、 この、サロゲートや 5桁部分 には てこずり ました。
例えば、
文字を削除する Button を作れば、 途端に 可笑しくなるのです。
1文字を2文字分で表現しているものが混ざるので、 そこを超えないといけません。
16進数の Unicode は易しいのですが、 32になると敷居が高くなります。
そして、困った時の検索でも、数はグッと減ります。
  下手に、幾つか該当しそうな語句を入れて検索するより、
  検索で、目安や辺りを付け、 そこにある Code には目を瞑って、
  IDE の Debug 機能と IntelliSense に頼って自力で書いた方が早かったです。
  或いは、 Microsoft さま の Help に出て来る Sample も有用です。
  最近、ようやく、その有難さが分かる様になりました。
    分かり難いですが ... 。  以前からそう思っていましたが、それは、こちらの知識が足らないから です、きっと。

また、コピーする文字列 (テキスト) の収まる TextBox は  ToolTip を附け、
上段に 16進、 下段に 32(所謂、Unicode Code Point 1文字1コード)、です。
Unicode のコードポイント(例えば、U+ 1F0A1) から 文字を入れられる様にしたので、確認も出来る様に です。 
上段で、サロゲートペアの場合は U+ ではなく、 u+ 表示( 小文字の u )にしました。
当然、 文字によって、 文字数と 上段のコード数が異なるケースが出て来ます。

これで、特殊な文字の入力は 少しは 楽が出来る ... 筈 です。
実際に、 文字列をコピーして、 GIMP に張り付けた処が 以下の図 です。  ちゃんと、PUA の文字 (e) も出ています。  :) 。


これらの、特殊な文字は、前や後続の文字と重なるものも多いので、スペース挿入による文字間調節が必要になるかもです。
勿論、 重なっても分かるのなら、 GIMP に文字を張り付けてから、GIMP のテキスト機能で文字間調整しても結構です。

尚、 自分のケースでは、
日本語の PUA を利用する Font は使っていませんので、 欧米圏 の言語用 Font が対象です。



折角ですから、 Code 絡みを少し。
書いたプログラムの中から 抜粋または考え方 を示しましょう。

FontFamily 取得。

       Dim u1 As Uri = New UriBuilder("file", "", -1, "C:\Users\UserName\.gimp-2.8\fonts\").Uri
       Dim listFontsOnDir As ICollection(Of FontFamily) = System.Windows.Media.Fonts.GetFontFamilies(u1)

Unicode 4桁 文字取得 U+FFFF 迄、10進数値を直接。

       Dim i As Integer = 32    'Sample U+0020 " " sp
       Dim u4ch As String = ChrW(i)

Unicode 5桁 文字取得 U+10000 以上 ChrW ではエラー 引数が Integer の範囲を越す為。

       Dim u5code As String = "1F0A0"    'Sample U+1F0A0 Playing Card Back
       Dim u5ch As String = Char.ConvertFromUtf32(Convert.ToInt32(u5code, 16)).ToString

Unicode コード取得 任意文字列から。

        Dim sourceText As String = ""     'Please Set A Text
        Dim valueSB As New Text.StringBuilder

        Dim si As New System.Globalization.StringInfo(sourceText)
        Dim v As UShort = 0
        For Each c As Char In si.String     'Char base = Detail
            If Char.IsHighSurrogate(c) Or Char.IsLowSurrogate(c) Then
                valueSB.Append("u+")
            Else
                valueSB.Append("U+")
            End If
            v = Convert.ToInt32(c)
            valueSB.Append(String.Format("{0:X4}", v))
            valueSB.Append(" ")
        Next
        '> Result : Hex. Each Code 4-Digit. If Need, Surrogate Pair, 2 Codes on 1 Char.

        valueSB.Append(vbCrLf)

        Dim charEnum As System.Globalization.TextElementEnumerator = _
           System.Globalization.StringInfo.GetTextElementEnumerator(sourceText)
        Dim tx As String = ""       'Target Text ( One Char. )
        Dim cp As Integer = 0       'Unicode:CodePoint
        Dim cpHex As String = ""    'Unicode:U+ String
        While (True)                'Each Char.
            If charEnum.MoveNext() = False Then     'End
                Exit While
            End If
            tx = charEnum.Current.ToString
            cp = [Char].ConvertToUtf32(tx, 0)
            If cp < 65536 Then
                cpHex = cp.ToString("X4")
            Else
                cpHex = cp.ToString("X")
            End If

            valueSB.Append("U+")
            valueSB.Append(cpHex)
            valueSB.Append(" ")
        End While
        '> Result : Hex. Each Code 4or5-Digit. 1 Code on 1 Char.

実際には、 Subroutineを組んだり、 Function に書き上げたり、 していますが、
書きながら悩んだのは、ここに示した もの に到達する迄です。
後から、こうして書き出すと、単純な数行のものなのですが ... 。

特に、
最後の、 任意文字列からコード取得 は Tooltip 用に書いた Function の ほぼ そのまま です。  戻り値に変換する部分を除く。.
個々の要素毎に数行にしての記載も考えたのですが、 ブロックのまま、載せる事にします。
サロゲートペアや 5桁の Unicode や 1文字としての認識 等、
色々な要素が詰まっていますので、 細かくは説明を書きませんが、 味わって下さい。
      (不味いかも?  変数名の命名が不統一な辺り、苦労が滲んでいますが、 そのまま載せます。)



さて、このプログラム、公開すべきか否かで迷っています。


   ListBox に bind した文字群ですが、 数が多くなると、ItemSource を切り替えた場合、
  選択したグループ切り替えと 描画完了との間に タイムラグ があって、 それが私の知識では解消出来ないのです。
  ListBox に何千個もの項目を割り当てる事自体が 無理 なのでしょう。
  PUA に関しては、細切れ (500) にする事で逃げていますが、 全数 (6400) を選ぶと、その様な状況になってしまっています。
  描画完了迄、じっと待って下されば問題無いのですが、 焦って、完了前に文字を選ぶと ... 。  あぁ ... 。


  また、フォントを指定すると、不足グリフを補う為に、他のフォントが呼ばれる仕組み (FallBack) が備わっています。
  つまり、 文字を選択すると、それが、指定フォントから なのか、 補完機能から なのか、 が明確では無いのです。
  無論、 解析する事も可能なのでしょうが、 現在は対応出来ていません。


  そして、この補完に当たっては、かなり、複雑なメカニズムが支援していますが、
  OS (Windows System) と GIMP (FreeType) とで、 若干、異なる様なのです。
  そう、 GIMP に於いても、類似の補完機能があります。  類似であって、同じではありません。
  極論すれば、 補完されていない字体のみが正確で、 一部、別のグリフが紛れ込む可能性を排除出来ません。
  Windows の場合、 フォントの表示(レンダリング)自体が OS と GIMP とで異なるので、その差異吸収は 私の手には負えません。.


当初の目的の GIMP で 個人用フォント対象の PUA の異字体 表示選択 は目的が達成出来ていますが、
複合フォントや FallBack の問題、 そして、 App としての UI の不完全さ がありますから。



0 件のコメント:

コメントを投稿