ぬの部屋(仮)
nu-no-he-ya
  •      12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
    1234567
    891011121314
    15161718192021
    22232425262728
           
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
         12
    3456789
    10111213141516
    17181920212223
    242526272829 
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
        123
    45678910
    11121314151617
    18192021222324
    25262728   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    15161718192021
    293031    
           
         12
    3456789
    10111213141516
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30      
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    2627282930  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728     
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
     123456
    78910111213
    14151617181920
    21222324252627
    28293031   
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
     123456
    78910111213
    14151617181920
    21222324252627
    282930    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31      
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
      12345
    6789101112
    13141516171819
    20212223242526
    27282930   
           
          1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031     
          1
    2345678
    9101112131415
    16171819202122
    232425262728 
           
       1234
    567891011
    12131415161718
    19202122232425
    262728293031 
           
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
           
         12
    3456789
    10111213141516
    17181920212223
    24252627282930
           
      12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
           
    1234567
    891011121314
    15161718192021
    22232425262728
    2930     
           
        123
    45678910
    11121314151617
    18192021222324
    25262728293031
           
  • libwebpを使ってみる(Encode , Lossless)

    libwebpを使って.webpファイルを出力してみる。

    公式からダウンロード・展開

    https://developers.google.com/speed/webp/download?hl=ja

    展開する。

    マニュアルは以下:

    https://developers.google.com/speed/webp/docs/api

    LosslessでRGB画像出力

    #pragma warning(disable:4996)
    
    #include <vector>
    
    #include <webp/encode.h>
    
    #pragma comment(lib,"libwebp.lib")
    
    int main()
    {
      // 作成したwebp形式のデータのアドレスを受け取るポインタ
      uint8_t* output = 0;
    
      // 2×3のRGB画像を作成
      std::vector<uint8_t> rgbdata = {
        255,  0,  0 /**/,   0,255,  0,
          0,  0,255 /**/, 255,255,  0,
        255,  0,255 /**/,   0,255,255
      };
      int width = 2;
      int height = 3;
    
      size_t size = WebPEncodeLosslessRGB(
        rgbdata.data(), // 変換したい画像へのポインタ
        width,          // 画像幅  ピクセル数
        height,         // 画像高さ ピクセル数
        width * 3,      // stride 一行のメモリサイズ
        &output         // データを受け取るポインタのアドレス
      );
    
      // 戻り値はoutputのバイト数
      printf("%zu", size);
    
      // ファイル出力
      FILE* fp = fopen("C:\\dev\\test-lossless-rgb.webp", "wb");
      fwrite(output, 1, size, fp);
      fclose(fp);
    
      // libwebpが確保したメモリの解放
      WebPFree(output);
    
    }
    

    LosslessでRGBA画像出力

    RGBAも可。

    #pragma warning(disable:4996)
    
    #include <vector>
    
    #include <webp/encode.h>
    
    #pragma comment(lib,"libwebp.lib")
    
    
    int main()
    {
      uint8_t* output = 0;
    
      std::vector<uint8_t> rgbdata = {
        255,  0,  0, 255 /**/,   0,255,  0, 212,
          0,  0,255, 170 /**/, 255,255,  0, 127,
        255,  0,255,  85 /**/,   0,255,255,  42
      };
      int width = 2;
      int height = 3;
    
      size_t size = WebPEncodeLosslessRGBA(
        rgbdata.data(),
        width,
        height,
        width * 4, // stride 一行のメモリサイズ
        &output
      );
      printf("%zu", size);
    
    
      FILE* fp = fopen("C:\\dev\\test-lossless-rgba.webp", "wb");
      fwrite(output, 1, size, fp);
      fclose(fp);
    
    
      WebPFree(output);
    
    }
    

    塗りつぶし Flood fill(3)再帰なし版を真面目に実装

    以前作ったFloodFill。無理やり再帰なしにしたが、今度はちゃんとスタックを使ってまともに再帰なし版を書いた。

    #pragma once
    
    
    #pragma once
    
    #include "NByteData.hpp"
    #include <stack>
    
    using uc3T = NByteData<3>;
    
    //! @brief 座標計算などを行う補助クラス
    class accessor {
      int width;
      int height;
    public:
      void set(int Width, int Height) {
        width = Width;
        height = Height;
      }
      bool is_in(const int x, const int y) {
        if (x < 0 || y < 0 || x >= width || y >= height)
          return false;
    
        return true;
    
      }
      size_t get_pos(const int x, const int y) {
        return (size_t)y * width + (size_t)x;
      }
    
    };
    
    
    //! @brief floodfill本体
    //! @param [in] x 対象の画素のX座標
    //! @param [in] y 対象の画素のY座標
    //! @param [in] targetcolor 塗りつぶし対象の色
    //! @param [in] replacementcolor 塗りつぶし結果の色
    //! @param [in,out] img 対象の画像データ
    //! @param [in] acc 画素の座標等を求めたりする補助クラスのインスタンス
    void ff_fill(
      int x,
      int y,
      uc3T targetcolor,
      uc3T replacementcolor,
      uc3T* img,
      accessor* acc) {
    
      using xyT = std::pair<int, int>;
    
      std::stack<xyT> stack;
    
      stack.push({ x,y });
    
      while (stack.empty() != true) {
    
        xyT xy = stack.top();
        stack.pop();
        x = xy.first;
        y = xy.second;
    
        if (acc->is_in(x, y) == false)
          continue;
    
        uc3T* node = &img[acc->get_pos(x,y)];
    
        if (*node != targetcolor) {
          continue;
        }
    
        *node = replacementcolor;
    
        stack.push({ x + 1, y });
        stack.push({ x - 1, y });
        stack.push({ x, y - 1 });
        stack.push({ x, y + 1 });
      }
    
      return;
    
    }
    //! @brief floodfillエントリポイント
    //! @param [in] seedx 塗りつぶし開始点
    //! @param [in] seedy 塗りつぶし開始点
    //! @param [in] replacementcolor 塗りつぶし結果の色
    //! @param [in,out] img 対象の画像データ
    //! @param [in] Width 画像幅(画素数)
    //! @param [in] Height 画像高さ(画素数)
    void f_fill(
      int seedx, int seedy,
      uc3T replacementcolor,
      uc3T* img,
      int Width, int Height) {
    
      accessor acc;
      acc.set(Width, Height);
      if (acc.is_in(seedx, seedy) == false)
        return;
    
      uc3T targetcolor = img[acc.get_pos(seedx, seedy)];
    
      ff_fill(seedx, seedy, targetcolor, replacementcolor, img, &acc);
    
    }
    

    関連

    塗りつぶし Flood fill(1)

    塗りつぶし Flood fill(2)再帰関数を無理やり不使用にする

    塗りつぶし Flood fill(3)再帰なし版を真面目に実装

    WordPress + Gantry 5 ページごとのスタイルを設定

    前回Gantry 5を有効にするまでやったので、各ページごとにスタイル等を設定していく方法を調べた。

    WordPressでGantry 5 を使う

    まず、設定の変更をわかりやすくするために、メニューを作成する。

    カテゴリーアーカイブのページで表示されるメニュー、シングルページで表示されるメニュー、…と言った具合で作成しておく。

    次に、アウトラインを作成する。

    カテゴリーアーカイブのページ用のアウトライン、シングルページ 用のアウトライン 、…と言った具合で作成しておく。

    ここで、一例としてカテゴリアーカイブのアウトラインを、カテゴリアーカイブのページに適用する事を考える。

    まず、カテゴリアーカイブページのアウトラインがちゃんとカテゴリアーカイブのページで表示される設定になっている事をわかりやすくするためにメニューを設定しておく。

    次に、Categoryarchiveアウトラインを選択した状態で、Assignmentsへ行き、Pate Contextの「Category Archive Page」のスイッチをONにする。

    この設定で、Category Archive Pageに対しては、Categoryarchiveアウトラインを使用する、事になる。

    この状態で設定を保存しカテゴリアーカイブを見てみると、ちゃんとアウトラインが反映されている。

    ここで、例えばカテゴリアーカイブページでは本文を表示させないでタイトル一覧だけにしたいというような変更を加えてみる。

    今度はContentへ行き、Archiveの項目の「Content」のスイッチをOFFにする。これでコンテンツ、つまり本文が表示されなくなる。ついでに、「Comments Meta」もOFFにし、No comments という部分も非表示にしてみる。

    設定を保存して更新すると、本文が消えているのがわかる。

    WordPressでGantry 5 を使う

    Gantry 5 はテーマフレームワーク。Wordpress版もあるらしい。

    プラグインから検索してインストールもできる(Gantry 5 Framework)のだが、テーマもインストールしなければならず、テーマと本体のバージョンの違いによってはうまく動かないので公式からダウンロードしたほうがいい。

    公式からプラグイン本体とテーマを一つ以上ダウンロードする

    https://gantry.org/downloads

    プラグインとテーマをインストールする

    テーマを有効化するとテーマの設定項目が表示される。

    Local by flywheel + All-in-One WP Migration + FTP clientでWordPressサイトのコピーをローカルに作る話

    概要

    ・Local by flywheelで環境を作るときに、 PreferではなくCustomで作る。こうしないとphp.iniの設定などが難しい

    ・Local by flywheelで環境を作るときに、元のサイトとPHPのバージョンを合わせておく必要がある。少なくともPHP5系列とPHP7系列には互換性がないらしいのでここが違うと動かない

    ・Local by flywheelで作られた環境ではファイルアップロード容量がphp.iniの初期設定により小さくなっているので、php.ini.hbsのupload_max_filesize等々を編集し、All-in-One WP Migrationでエクスポートした.wpressファイルをインポートできるサイズに拡張しておく必要がある

    ・ Local by flywheel側で、All-in-One WP Migrationはデフォルトでは2021/11の時点で300Mしかインポートできないので、プラグインを編集して制約を撤廃する。

    ・元サイト側で、 All-in-One WP Migration でエクスポートをする際に、ドメイン名をローカルのドメイン名に文字列置換しておく

    ・元サイト側のサイズが極めて大きい場合、ローカル側のAll-in-One WP Migrationのインポート処理が終わらなくなってしまうので、メディアファイルを省いてエクスポートする。(私の場合全体で1GB近くあり、上記設定を行ってもインポート処理が進まなくなってしまったので、メディアファイル抜きで約300Mまで落とした)

    ・ローカル側にAll-in-One WP Migrationをインストールし、インポートする。結構時間がかかる

    ・元サイトにFTP接続し、wp-content/uploads/ ディレクトリを別途ダウンロードし、Local by flywheel側のwordpressのディレクトリに上書きする

    Local by Flywheelで環境構築

    ローカル環境を作るときはCustomで。あとPHPのバージョンを合わせる。

    php.ini.hbs でアップロード上限をwpressファイル以上にあげておく。ただしwpressファイルが大きすぎるとそれでも無理かもしれない。

    Local by Flywheel側のファイルアップロード上限撤廃

    私は一応全部を2048Mに設定している

     

    memory_limit = 2048M

    post_max_size = 2048M

    upload_max_filesize = 2048M

     

    Local by Flywheel側のAll-in-One WP Migrationのファイルインポート上限撤廃

    ローカル側のWordpressにログインし、All-in-One WP Migration をインストール。同プラグインのインポート上限を上げるためにプラグインエディタでAll-in-One WP Migrationを編集する

    408行目あたりにある「Max File Size」の項目を 536870912*10 に変更

    // =================
    // = Max File Size =
    // =================
    define( ‘AI1WM_MAX_FILE_SIZE’, 536870912*10 );

    元サイトのデータをエクスポート

    元サイト側のAll-in-One WP Migrationで、エクスポート時、ドメインの置換を設定し、大きくなることが懸念される場合はメディアファイルをエクスポートしない設定をする。

    Local by Flywheel側のwordpressにてインポート

    ローカル側で普通にインポート→待つ。

    ファイルが大きすぎる場合、あるいはローカルと元サイトでPHPバージョンが違う場合、100%から動かない。

    なおファイルのサイズは360MBまで減らしても数分は待ったので安易に見切りをつけてはいけない。HDDかSSDかなど環境に持っても違うと思う。

    メディアファイルを別途FTPでダウンロード・上書

    最後にwp-content/uploads/ をサーバーからコピーして上書。完成。

    icu::UnicodeStringで正規表現 icu::RegexMatcher

    icu::RegexMatcher

    #include <fstream>
    #include <iostream>
    #include <vector>
    
    #include <unicode/ucnv.h>
    #include <unicode/regex.h>
    
    
    // 要リンク
    #pragma comment(lib, "icuuc.lib")
    
    //regex.hに必要
    #pragma comment(lib, "icuin.lib")
    
    
    // 以下のdllを要求される
    // icudt69.dll
    // icuuc69.dll
    
    // icuin69.dll regexに必要
    
    
    int main()
    {
      std::fstream w(
        "C:\\dev\\icu-test\\converted.txt",
        std::ios::out | std::ios::binary | std::ios::trunc);
    
    
      std::u16string u16s = u"aい山うkえ👨‍👧經お经";
    
      icu::UnicodeString ustr(u16s.c_str());
    
      UErrorCode status = U_ZERO_ERROR;
      icu::RegexMatcher matcher(u"[う-お].+[あ-お]", 0, status);
    
      matcher.reset(ustr);
    
    if (matcher.find()) { icu::UnicodeString ret; int start = matcher.start(status); // string index of start of match. int end = matcher.end(status); ustr.extract( start, end - start, ret ); w.write((char*)ret.getBuffer(), ret.length()*2); } ///////////////////////////////// }

    いくつかの例

    ICUライブラリで一文字replace

    // char16のindexとその文字を構成するchar16の個数のリスト作成
    std::vector<std::pair<int32_t, int32_t>> getIndexList(const icu::UnicodeString& s) {
    
      std::vector<std::pair<int32_t, int32_t>> c_c;
    
      UErrorCode err;
      icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
        icu::Locale::getDefault(), err);
      bi->setText(s);
    
      int32_t current = bi->first();
      while (current != icu::BreakIterator::DONE) {
    
        int32_t prev = current;
        current = bi->next();
    
        if (current == UBRK_DONE) break;
    
        c_c.emplace_back(prev, current - prev );
    
      }
    
      return c_c;
    }
    void WinPaint(HWND hWnd) {
    
      // 元の文字列の定義
      std::u16string u16s = u"aあغ山👨‍👧經经";
    
      ////////////////////////////////////////
      ////////////////////////////////////////
    
      icu::UnicodeString usr(u16s.c_str());
    
      // char16のindexとその文字を構成するchar16の個数のリスト作成
      std::vector<std::pair<int32_t, int32_t>> ilis = getIndexList(usr);
    
      // 文字の置き換え
      icu::UnicodeString B("B");
      // 4文字目を「B」に書き換える
      // UnicodeString::replace(先頭index,置換前の要素数,置換後の文字)
      usr.replace(ilis[4].first, ilis[4].second, B);
    
    
      ////////////////////////////////////////
      ////////////////////////////////////////
    
    
      ////////////////////////////
      //フォトの設定
      HDC hdc;
      PAINTSTRUCT ps;
      hdc = BeginPaint(hWnd, &ps);
      SetTextColor(hdc, RGB(0, 0, 0));  //文字の色を設定
      SetBkColor(hdc, RGB(230, 230, 230));  //文字の背景色を設定
      HFONT backup = (HFONT)SelectObject(hdc, hFont1);  //Step2  フォントを適応
      TEXTMETRIC tm;
      GetTextMetrics(hdc, &tm);
      int TH = 10;
    
      ////////////////////////////
      //文字を一文字(書記素)ずつ表示
    
      UErrorCode err;
      icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
        icu::Locale::getDefault(), err);
      bi->setText(usr);
    
      int32_t current = bi->first();
      while (current != icu::BreakIterator::DONE) {
    
        int32_t prev = current;
        current = bi->next();
    
        if (current == UBRK_DONE) break;
    
        int32_t count = current - prev;//文字の長さ
    
        icu::UnicodeString e;
        usr.extract(prev, count, e);
        // win32api のWCHARはutf16なのでただキャストするだけで変換できる
        TextOutW(hdc, 10, TH, (WCHAR*)e.getBuffer(), e.length());//文字を書く
    
        //改行
        TH += tm.tmHeight+5;
      }
    
    
    
      SelectObject(hdc, backup);
    
      EndPaint(hWnd, &ps);
    }
    

    ICUライブラリBreakIteratorでutf16を一文字ずつ表示する方法いくつか

    void WinPaint(HWND hWnd) {
    
      // 元の文字列の定義
      std::u16string u16s = u"aあغ山👨‍👧經经";
    
      /////////////////////////////
      // ICUの設定
    
      icu::UnicodeString usr(u16s.c_str());
    
      UErrorCode err;
      icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
        icu::Locale::getDefault(),err);
      bi->setText(usr);
    
      ////////////////////////////
      //フォトの設定
      HDC hdc;
      PAINTSTRUCT ps;
      hdc = BeginPaint(hWnd, &ps);
      SetTextColor(hdc, RGB(0, 0, 0));  //文字の色を設定
      SetBkColor(hdc, RGB(230, 230, 230));  //文字の背景色を設定
      HFONT backup = (HFONT)SelectObject(hdc, hFont1);  //Step2  フォントを適応
      TEXTMETRIC tm;
      GetTextMetrics(hdc, &tm);
      int TH = 10;
      ////////////////////////////
      //文字を一文字(書記素)ずつ表示
    
    
      int32_t current = bi->first();
      while (current != icu::BreakIterator::DONE) {
    
        // 文字の長さを知る必要があるので、
        // 「現在の文字の位置」と「前の文字の位置」が必要
        int32_t prev = current;
        current = bi->next();
    
        if (current == UBRK_DONE) {
          break;
        }
    
        int32_t count = current - prev;//文字の長さ
    
    
        TextOutW(hdc, 10, TH, (WCHAR*)& usr.getBuffer()[prev], count);//文字を書く
    
        //改行
        TH += tm.tmHeight+5;
      }
    
      SelectObject(hdc, backup);
    
      EndPaint(hWnd, &ps);
    }
    

    一文字表示する部分の記述方法

        TextOutW(hdc, 10, TH, (WCHAR*)& usr.getBuffer()[prev], count);//文字を書く
    
        icu::UnicodeString e;
        usr.extract(prev, count, e);
        // win32api のWCHARはutf16なのでただキャストするだけで変換できる
        TextOutW(hdc, 10, TH, (WCHAR*)e.getBuffer(), e.length());//文字を書く
    
        // substr(現在位置,切り取る長さ)
        std::u16string sub = u16s.substr(prev, count);
        TextOutW(hdc, 10, TH, (WCHAR*)sub.data(), count);//文字を書く
    

    なおなぜかWordpressのせいでサロゲートペアが入力できないのでサンプルから抜いている。

    prev,currentの変化

    first(),next()で操作するのはchar16_tとしての配列の要素番号。なので+1移動で2Byte移動だが、サロゲートペアや結合文字があった場合はその限りではない。

    ICUライブラリ+win32apiでutf16を一文字ずつ表示

    ICUライブラリで文字を一文字ずつ切り出したい。しかし切り出した結果をコンソール出力するのはもろもろの事情で難しく、ファイル出力は確認がめんどくさいのでウィンドウに描画する。

    #include <windows.h>
    
    #include <unicode/ucnv.h>
    #include <unicode/brkiter.h>
    
    // 要リンク
    #pragma comment(lib, "icuuc.lib")
    
    // 以下のdllを要求される
    // icudt69.dll
    // icuuc69.dll
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    WCHAR szClassName[] = L"MY_ICU_TEST";  //ウィンドウクラス
    
    LPCWSTR fontname = L"MS P ゴシック";
    
    HFONT hFont1;
    
    void WinPaint(HWND hWnd) {
    
      // 元の文字列の定義
      std::u16string u16s = u"aあغ山👨‍👧經经";
    
      /////////////////////////////
      // ICUの設定
    
      icu::UnicodeString usr(u16s.c_str());
    
      UErrorCode err;
      icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
        icu::Locale::getDefault(),err);
      bi->setText(usr);
    
      ////////////////////////////
      //フォトの設定
      HDC hdc;
      PAINTSTRUCT ps;
      hdc = BeginPaint(hWnd, &ps);
      SetTextColor(hdc, RGB(0, 0, 0));  //文字の色を設定
      SetBkColor(hdc, RGB(230, 230, 230));  //文字の背景色を設定
      HFONT backup = (HFONT)SelectObject(hdc, hFont1);  //フォントを適応
      TEXTMETRIC tm;
      GetTextMetrics(hdc, &tm);
      int TH = 10;
    
    //////////////////////////// //文字を一文字(書記素)ずつ表示
    int32_t current = bi->first(); while (current != icu::BreakIterator::DONE) { // 文字の長さを知る必要があるので、 // 「現在の文字の位置」と「前の文字の位置」が必要 int32_t prev = current; current = bi->next(); if (current == UBRK_DONE) { break; } int32_t count = current - prev;//文字の長さ //win32api のWCHARはutf16なのでただキャストするだけで変換できる TextOutW(hdc, 10, TH, (WCHAR*)(&u16s.data()[prev]), count);//文字を書く // こっちでもいい substr(現在位置,切り取る長さ) // std::u16string sub = u16s.substr(prev, count); // TextOutW(hdc, 10, TH, (WCHAR*)sub.data(), count);//文字を書く //改行 TH += tm.tmHeight+5; } SelectObject(hdc, backup); EndPaint(hWnd, &ps); }
    ////////////////////////////////////
    ////////////////////////////////////
    // 表示用
    ////////////////////////////////////
    ////////////////////////////////////
    
    
    int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) {
      MSG msg;
      BOOL bRet;
      WNDCLASSEX wc;
      HWND hWnd;
      ATOM atom;
    
      wc.cbSize = sizeof(WNDCLASSEX);
      wc.style = CS_HREDRAW | CS_VREDRAW;
      wc.lpfnWndProc = WndProc;
      wc.cbClsExtra = 0;
      wc.cbWndExtra = 0;
      wc.hInstance = hCurInst;
      wc.hIcon = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
      wc.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
      wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wc.lpszMenuName = NULL;
      wc.lpszClassName = (LPCWSTR)szClassName;
      wc.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
    
      if ((atom = RegisterClassEx(&wc)) == 0)return FALSE;
    
      hWnd = CreateWindow(
        MAKEINTATOM(atom), 
        L"icu test", 
        WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, 
        200, 500, // ウィンドウのサイズ
        NULL, NULL, hCurInst, NULL);
    
      if (!hWnd)return FALSE;
    
      ShowWindow(hWnd, nCmdShow);
      UpdateWindow(hWnd);
      while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (bRet == -1) {
          break;
        }
        else {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        }
      }
      return (int)msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
      switch (msg) {
      case WM_CREATE:
        //Step1  フォント作成
        hFont1 = CreateFont(
          50, 0, //高さ, 幅
          0, 0, FW_BOLD,
          FALSE, FALSE, FALSE,
          SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
          CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
          VARIABLE_PITCH | FF_ROMAN, fontname);
        break;
      case WM_PAINT:
        WinPaint(hWnd);
        break;
      case WM_DESTROY:
        DeleteObject(hFont1);   //Step4. HFONTオブジェクトを破棄
        PostQuitMessage(0);
        break;
      default:
        return (DefWindowProc(hWnd, msg, wp, lp));
      }
      return 0;
    }
    

    ICUライブラリのicu::UnicodeString::extractに指定するコードページにはどんなものがあるか

    ICUライブラリを使って文字コードの変換を行うとき、例えば日本固有の文字コードに変換したいなら「Shift_JIS」や「EUC-JP」、中国固有の文字コードなら「GBK」「EUC-CN」など、変換先の文字コードを指定しなければならない。この文字コード名を「コードページ」というらしいが、Shift_JISやEUC-JPの他にどんな物があるか。

    void test() {
    
      icu::UnicodeString us(u"いろはにほへと");
    
      const char* code_page = "Shift_JIS"; // コードページ。他にどんな物があるか。
    
      char dst_data[100];
      int32_t len = us.extract(0, us.length(), dst_data, code_page);
    
      printf("%s (%d) \n",dst_data,len);
    
    }
    

    コンバータ名一覧を取得する関数

    マニュアルを読むと、どうやらConverter Namesという呼称でコードページを与えるらしい。そして使える名前一覧を取得する関数がいくつか用意されているらしい。

    https://unicode-org.github.io/icu/userguide/conversion/converters.html#converter-names

    ucnv_openAllNames

    例えば、ucnv_openAllNames は

    Get a list of all known converter names.

    と、「全ての知られているコンバータ名を取得する」と書かれている。使い方はこんな感じ。

      auto name_enum = ucnv_openAllNames(&err);
    
      int32_t len;
      const char* name;
    
      while (name = uenum_next(name_enum, &len, &err)) {
        printf("%s\n", name);
      }
      uenum_close(name_enum);
    

    ucnv_openAllNamesでイテレータを取得して、uenum_nextでイテレータを前に進めるような使い方をする。

    ただこれで得られる内容は膨大すぎてよくわからない。

    ucnv_countAvailable

    次に、ucnv_countAvailable は

    Get a list of available converter names that can be opened.

    と、「使えるコンバータのリストを取得する」と書かれている。使い方はこんな感じ。

      int32_t convcount = ucnv_countAvailable();
      for (int32_t i = 0; i < convcount; i++) {
        printf("[%03d] %s\n",i, ucnv_getAvailableName(i));
      }
    

    これでも200個以上出てくる上に、Shift_JISなどわかりやすい物がない。

    ucnv_getAliases コードページの別名一覧を取得

    そもそも同じコードページにも複数の表記法があるらしい。例えばShift_JIS,CP932,Windows-31J,MS932は(ほぼ)同じ意味になる。 ucnv_getAliases はそんな、あるコードページの仲間のコードページを探す。

    int main()
    {
      UErrorCode err;
    
      const char* ALIAS = "Shift_JIS";   // 日本語のコードページ
    
    
      // ALIAS で表されるコードページの別名一覧を表示
      uint16_t acount = ucnv_countAliases(ALIAS, &err);
      for (auto i = 0; i < acount; i++) {
        const char* code_page_arias = ucnv_getAlias(ALIAS, i, &err);
    
        printf("-- %s\n", code_page_arias);
    
      }
      
      getchar();
    }
    

    出力:

    — ibm-943_P15A-2003
    — ibm-943
    — Shift_JIS
    — MS_Kanji
    — csShiftJIS
    — windows-31j
    — csWindows31J
    — x-sjis
    — x-ms-cp932
    — cp932
    — windows-932
    — cp943c
    — IBM-943C
    — ms932
    — pck
    — sjis
    — ibm-943_VSUB_VPUA
    — x-MS932_0213
    — x-JISAutoDetect

    CP932 vs Shift_JIS

    Shift_JIS を ucnv_getAliases にかけるとエイリアスが大量に出てくるのだが違いがあるのかよくわからない。拡張文字の有無など微細な違いがあるらしいCP932とShift_JISにそれぞれ変換してみた。

    #include <fstream>
    #include <iostream>
    
    #include <unicode/ucnv.h>
    #include <unicode/unistr.h>
    #pragma comment(lib, "icuuc.lib")
    
    // 以下のdllを要求される
    // icudt69.dll
    // icuuc69.dll
    
    
    void Converter(const icu::UnicodeString& us,const char* dstCode) {
    
    
      //内部形式の文字コードを目的の文字コードへ変換
      char dst_data[100];
      int32_t len = us.extract(0, us.length(), dst_data, dstCode);
    
      printf("length: %d\n", len);
    
      std::string textname = "C:\\dev\\icu-test\\converted-";
      textname += dstCode;
      textname += ".txt";
      ///////////////////////////////
    // 文字コード変換した内容をファイル出力 std::fstream w( textname, std::ios::out | std::ios::binary | std::ios::trunc); w << dst_data; }
    int main()
    {
      UErrorCode err;
    
      const char* ALIAS = "Shift_JIS";   // 日本語のコードページ
    
      //std::u16string src_data = u"いろはにほへと";       // 日本語
    
      // NEC拡張文字
      // ①②㌍
      // IBM拡張文字
      // 髙ⅱⅲ㈱
      std::u16string jps = u"①②㌍髙ⅱⅲ㈱";
    
      // ICUの内部表現へ変更
      icu::UnicodeString ustr(jps.c_str());
    
      Converter(ustr, "Shift_JIS");// コードページを指定して変換
      Converter(ustr, "CP932");
    
    
      
      getchar();
    }
    

    実行結果。特に変換できない文字は出てこなかった。

    指定できそうなコードページを調べる

    https://www.ibm.com/docs/ja/integration-bus/10.0?topic=ssmkhh-10-0-0-com-ibm-etools-mft-doc-ac00408–htm

    ICUライブラリのページではないようだがIBMのページなので、ここの一覧から選ぶことができそうである。いくつか拾い上げて ucnv_getAliases に与えると表のとおりの結果が返ってきている。

    おまけ

    中国語やギリシャ語への変換例。確認方法が面倒。Converterは前述のものを使用。

    ギリシャ語はWordでフォントをTimes New Romanにすると確認できる。

    int main()
    {
      UErrorCode err;
    
      const char* ALIAS = "EUC-CN";      // 中国語のコードページ
      std::u16string src_data = u"什么";  // 中国語
    
      icu::UnicodeString ustr(src_data.c_str());
    
      Converter(ustr, ALIAS);
      
      getchar();
    }
    
    int main()
    {
      UErrorCode err;
    
      const char* ALIAS = "ibm737";     // ギリシャ語のコードページ
      std::u16string src_data = u"πανσέληνος"; // ギリシャ語
    
      icu::UnicodeString ustr(src_data.c_str());
    
      Converter(ustr, ALIAS);
    
      getchar();
    }
    

    参考:

     

     

    本当は怖くないCP932
    https://qiita.com/kasei-san/items/cfb993786153231e5413