6

私の意見では、一般的な問題は、ビットマップフォントと組み合わせた文字エンコードです。ほとんどの多言語エンコーディングには、さまざまな文字タイプの間に大きなスペースがあり、そこには未使用のコードポイントがたくさんあります。したがって、それらを使用したい場合は、多くのメモリを浪費します(マルチバイトテキストを保存するためだけでなく、ビットマップフォントのスペースのために特別に意味します)。VRAMはほとんどの場合非常に価値があります...したがって、唯一の合理的なことはつまり、UTF-8文字のテクスチャでカスタムマッピングを使用します(スペースが無駄にならないようにするため)。しかし、この取り組みは、独自の文字エンコードを使用する場合と同じように見えます(したがって、テクスチャ内の文字の順序も独自のものです)。私の特別なケースでは、4096の異なる文字のテクスチャスペースがあり、日本語だけでなくラテン語も表示するための文字が必要です(一般的なcjkコードページのみをサポートするutf-8の混乱)。誰かが同じような問題を抱えたことはありますか(そうでない場合は本当に疑問に思います)?すでにアプローチがある場合は?

編集:同じ問題がここhttp://www.tonypottier.info/Unicode_And_Japanese_Kanji/で説明されていますが、これらのビットマップフォントマッピングをutf-8スペース効率で保存する方法を実際に解決することはできません。だから、さらなる助けは大歓迎です!

Edit2:

ご回答どうもありがとうございました。申し訳ありませんが、私の問題は十分に明確に説明されていませんでした。

私が本当に解決したいのは、CJKUnicodeの範囲が20000文字を超えていることです。ただし、日本語のテキストを正しく表示するには、約2000文字のサブセットのみが必要です。これらのキャラクターは、U+4E00からU+9FA5の範囲に広がっています。したがって、これらのUnicodeコードポイント(日本語の場合は2000のみ)を、作成したテクスチャの座標に変換する必要があります(文字を好きなように並べ替えることができます)。

つまり、U + 4E03は日本語の文字ですが、U + 4E04、U + 4E05、U+4E06はそうではありません。そして、U+4E07も日本語のキャラクターです。したがって、最も簡単な解決策は次のとおりです。文字U + 4E03の後に、テクスチャに3つのスペースを残し(または不要な文字U + 4E04、U + 4E05、U + 4E06をそこに書き込み)、次にU+4E07と書き込みます。しかし、これは非常に多くのテクスチャスペースを浪費します(2000文字だけが必要な場合でも20000文字)。だから私は自分のテクスチャだけを入れられるようにしたい:「... U + 4E03、U +4E07...」。しかし、displayText関数の記述方法がわかりません。表示したいグリフのテクスチャ座標がどこにあるかわからないためです。ハッシュマップなどが必要になりますが、これらのデータを保存する方法がわかりません(... {U + 4E03、128}、{U + 4E07、 129} ... hasmapを埋めるため)。

質問へ:1)特定の形式はありません-したがって、displayText関数を自分で作成します。2)ユニコードに反対する理由はありません-私のビットマップフォントのCJK範囲の問題だけです。3)それは一般的にプラットフォームと言語に依存しないと思いますが、私の場合、Mac OS X/iOSでOpenGLでC++を使用しています。

ご助力ありがとうございます!これについてさらにアイデアがあれば、それは本当に私を大いに助けてくれるでしょう!

4

6 に答える 6

3

あなたが解決したい本当の問題は何ですか?

UTF-8でエンコードされた文字列が1文字あたり3バイトを占めるということですか?はいの場合は、UTF-16に切り替えます。それ以外の場合は、UTF-8のせいにしないでください。(説明:UTF-8は、整数のシーケンスをバイトのシーケンスに変換するための単なるアルゴリズムです。コードページ内の文字のグループ化とは関係ありません。これが、Unicodeコードポイントの目的です。)

Unicodeコードポイントが多くの「コードページ」(「コードページ」は256個の隣接するUnicodeコードポイントのブロックを意味します)に分散しているということですか?はいの場合、Unicodeコードポイント(0x000000-0x10FFFF)からより小さな整数のセットへのマッピングを考案します。メモリに関しては、これは実際に必要な文字数の4バイト倍以下のコストで済みます。ルックアップ時間は、約24のメモリアクセス、24の整数比較、および24の分岐命令になります。(実際、これはツリーマップでのバイナリ検索になります。)そして、それが高すぎる場合は、ハッシュテーブルに基づくマッピングを使用できます。

それは何か他のものですか?次に、問題をよりよく理解するために、いくつかの例を教えてください。

私が理解している限りでは、アプリケーションで使用するUnicodeコードポイントのセットを入力として受け取り、テキストを表示するためのコードとデータを生成する小さなユーティリティプログラムを作成する必要があります。これは疑問を投げかけます:

  1. 特定のビットマップフォント形式を使用する必要がありますか、displayTextそれとも関数を自分で作成しますか?
  2. すべての文字列にUnicodeを使用し、テキストをレンダリングするときだけそれらをビットマップに最適化されたエンコーディングに変換することに反対する理由はありますか?もちろん、エンコーディング変換はメソッドの内部でdisplayText行われ、通常のアプリケーションコードには表示されません。
  3. ただ興味がない:問題は特定のプログラミング言語または環境に固有のものですか?

更新

私はあなたの主な問題がこのようないくつかの機能であると仮定しています:

Rectangle position(int codepoint)

これを行う必要がある場合は、文字ごとに1つのビットマップを用意することから始めます。ビットマップのファイル名はコードポイントになるため、必要な文字がさらに見つかった場合に備えて、「全体像」を簡単に再生成できます。準備は次の手順で構成されます。

  1. すべてのビットマップをロードし、それらの寸法を決定します。このステップの結果は、整数から(幅、高さ)のペアへのマップです。
  2. 全体像のキャラクター画像の適切なレイアウトを計算し、各キャラクターが配置された場所を覚えておいてください。全体像を保存します。コードポイントから(x、y、幅、高さ)へのマッピングを別のファイルに保存します。これはテキストファイルの場合もあれば、ディスク容量がない場合はバイナリファイルの場合もあります。詳細は関係ありません。

この場合、displayText関数は次のように機能します。

void displayText(int x, int y, String s) {
  for (char c : s.toCharArray()) { // TODO: handle code points correctly
    int codepoint = c;
    Rectangle position = positions.get(codepoint);
    if (position != null) {
      // draw bitmap
      x += position.width;
    }
  }
}

Map<Integer, Rectangle> positions = loadPositionsFromFile();

現在残っている唯一の問題は、このマップを可能な限り少ないメモリを使用してメモリ内で表現し、それでも十分に高速である方法です。もちろん、それはプログラミング言語によって異なります。

インメモリ表現は、x、y、幅、高さを含むいくつかの配列である可能性があります。各要素には、16ビット整数で十分です。そしておそらくあなたはとにかく幅と高さのために8ビットだけを必要とします。次に、別の配列がコードポイントをインデックスにマップしますpositionData(またはコードポイントが使用できない場合は特別な値)。これは20000の16ビット整数の配列になるため、要約すると次のようになります。

  • 2000 *(2 + 2 + 1 + 1)= 、、、およびの場合は12000positionXバイトpositionYpositionWidthpositionHeight
  • codepointToIndexInPositionArraysマップの代わりに配列を使用する場合、20000 * 2=40000バイト。

ビットマップ自体のサイズと比較すると、これは十分に小さいはずです。また、配列は変更されないため、読み取り専用メモリに配置できます。

于 2010-12-27T00:48:03.303 に答える
2

このデータをエンコードするための最も効率的な(ロスレス)方法は、ハフマンエンコードを使用してドキュメント情報を保存することだと思います。これは古典的な情報理論の問題です。圧縮されたスペースから文字スペースに移動するには、マッピングを実行する必要があります。

この手法は、ドキュメントごとの文字頻度(またはドキュメントを適用するために選択したドメイン/ドキュメント)に基づいて、ドキュメントを可能な限り効率的に圧縮します。使用する文字のみが保存され、使用頻度に正比例して効率的に保存されます。

この問題を解決する最善の方法は、既存の実装(UTF16、UTF8 ...)を使用することだと思います。これは、少しスペースを節約するために、独自のハフマンコーディングを実装するよりもエラーが発生しにくいでしょう。ディスク容量と帯域幅は安価ですが、顧客や管理者を怒らせるエラーはありません。ハフマン符号化は理論的には可能な限り最も効率的な(ロスレス)符号化であると私は信じていますが、このアプリケーションにとって最も実用的ではありません。リンクをチェックしてください、これはこれらの概念のいくつかに役立つかもしれません。

-ブライアンJ.スティナー-

于 2010-12-28T19:45:06.847 に答える
1

UTF-8は通常、非常に効率的なエンコーディングです。アプリケーションが主にアジアやマルチバイト文字セットを持つ他の地域に焦点を当てている場合は、UTF-16を使用することでより多くのメリットが得られる可能性があります。もちろん、独自のエンコーディングを作成することもできますが、それほど多くのデータを節約することはできず、多くの作業を提供します。

本当にデータを圧縮する必要がある場合(そして、なぜかどうか疑問に思う)、UTFデータを圧縮するために何らかのアルゴリズムを使用するのが最善です。ほとんどのアルゴリズムは、データの大きなブロックでより効率的に機能しますが、テキストの小さなチャンクを圧縮するためのアルゴリズムもあります。独自のエンコーディングを定義するのではなく、これらを検討すれば、時間を大幅に節約できると思います。

于 2010-12-22T08:35:42.980 に答える
1

この論文はほとんど時代遅れであり、1980年ではなく、ビットを探すことはほとんどすべてのディスプレイアプリケーションの要件ではありません。アプリケーションを開発する場合、たとえばiPhoneの場合、複数の言語でl10nを計画する必要があるため、日本語だけで数ビット節約するのは少し無意味です。

日本はまだShift-JISを使用しています。これは、GB18030を使用する中国、BIG5を使用する香港などのように、ロケールエンコーディングにロックされた、大きくて安定した効率的なリソースプールがあるためです。Unicodeに移行するには、大量のフレームワークツールを書き直し、それに続く追加のテストを行う必要があります。

iPodを見ると、ラテン語、中国語、日本語、韓国語のみをサポートし、タイ語やその他のスクリプトをスキップすることで、ビットを節約できます。iPhoneでメモリの価格が下がり、ストレージが増えたため、Appleはより多くのスクリプトのサポートを追加できるようになりました。

UTF-8は、スペースを節約し、ストレージにUTF-8を使用し、より便利な操作と表示のためにUCS-2以降に変換する方法です。Shift-JISとUnicodeの違いはごくわずかです。

于 2010-12-30T13:23:48.700 に答える
0

中国語だけでも4096文字以上あり、句読点ではなく、単語を形成するために使用される文字を話します。ウィキペディアから:

康熙字辞典に含まれる漢字の数は約47,035ですが、これらの多くは歴史を通して蓄積されためったに使用されない変種です。

それらの多くはめったに使用されませんが、90%が必要でなかったとしても、クォータを使い果たしてしまいます。(現代のテキストで使用されている実際の数は、約10〜20kだと思います。)

どの文字を使用する必要があるかを事前に知っている場合は、テクスチャにインデックスを付けるためのUnicodeコードポイントの間接テーブルを作成することをお勧めします。そうすれば、実際に使用するのと同じ数の文字をテクスチャに配置するだけで済みます。Flash(および一部のPDF)は内部でこのようなことをしていると思います。

于 2010-12-22T08:14:49.310 に答える
0

可能なすべての文字を包含しようとする単一のビットマップの代わりに、複数のビットマップを使用してオンデマンドでロードすることができます。

于 2010-12-26T10:08:07.707 に答える