・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のディレクトリに上書きする
ローカル環境を作るときはCustomで。あとPHPのバージョンを合わせる。
php.ini.hbs でアップロード上限をwpressファイル以上にあげておく。ただしwpressファイルが大きすぎるとそれでも無理かもしれない。
私は一応全部を2048Mに設定している
memory_limit = 2048M
post_max_size = 2048M
upload_max_filesize = 2048M
ローカル側のWordpressにログインし、All-in-One WP Migration をインストール。同プラグインのインポート上限を上げるためにプラグインエディタでAll-in-One WP Migrationを編集する
408行目あたりにある「Max File Size」の項目を 536870912*10 に変更
元サイト側のAll-in-One WP Migrationで、エクスポート時、ドメインの置換を設定し、大きくなることが懸念される場合はメディアファイルをエクスポートしない設定をする。
ローカル側で普通にインポート→待つ。
ファイルが大きすぎる場合、あるいはローカルと元サイトでPHPバージョンが違う場合、100%から動かない。
なおファイルのサイズは360MBまで減らしても数分は待ったので安易に見切りをつけてはいけない。HDDかSSDかなど環境に持っても違うと思う。
最後にwp-content/uploads/ をサーバーからコピーして上書。完成。
#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); } ///////////////////////////////// }
// 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);
}
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のせいでサロゲートペアが入力できないのでサンプルから抜いている。
first(),next()で操作するのはchar16_tとしての配列の要素番号。なので+1移動で2Byte移動だが、サロゲートペアや結合文字があった場合はその限りではない。
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ライブラリを使って文字コードの変換を行うとき、例えば日本固有の文字コードに変換したいなら「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 は
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 は
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などわかりやすい物がない。
そもそも同じコードページにも複数の表記法があるらしい。例えば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(); }
出力:
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(); }
実行結果。特に変換できない文字は出てこなかった。
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
以前やったのが2014年とかだったので更新する。
古い記事:
https://icu.unicode.org/download
公式サイトからICU4C系をクリックする。
ICU4CはC++。
ICU4JはJava。
その先のページの一番下のDownloadにある、Source and binary downloads are available on the git/GitHub tag pageのリンクへ飛ぶ。
一覧の中から、対応開発環境のものを選ぶ
リンクにicuuc.libが必要。また実行時にicudt69.dll , icuuc69.dllが必要。
#include <fstream> #include <unicode/ucnv.h> // icu::UnicodeString に必要 #include <unicode/unistr.h> // 要リンク #pragma comment(lib, "icuuc.lib") // 以下のdllを要求される // icudt69.dll // icuuc69.dll void Converter() { std::fstream r("C:\\dev\\icu-test\\shiftjis.txt"); std::string src_data; r >> src_data; //エラーを受け取る変数 UErrorCode err = U_ZERO_ERROR; //入力・出力の各文字コード char srcCode[] = "shift-jis"; char dstCode[] = "euc-jp"; //UnicodeStringに渡す文字列の文字コードを指定する UConverter* srccnv = ucnv_open(srcCode, &err); //入力された文字の文字コードを内部形式に変換 icu::UnicodeString srcstr(src_data.c_str(), src_data.length(), srccnv, err); //内部形式の文字コードを目的の文字コードへ変換 char* dst_data = new char[100]; srcstr.extract(0, srcstr.length(), dst_data, dstCode); using namespace std; std::fstream w("C:\\dev\\icu-test\\euc-jp.txt", ios::out | ios::binary | ios::trunc); w << dst_data; } int main() { Converter(); }
file-png-save-defaults関数を使うのだが、画像番号と一緒にdrawableを指定しなければならず、したがってそのdrawableのレイヤーしか保存できない。
全てのレイヤーをマージするにはgimp-image-merge-visible-layers関数を使えばいいが、エクスポートしたいだけでマージするわけにいかないので、gimp-image-duplicateで現在の画像をコピーし、それに対してマージを行い、保存した後でgimp-image-deleteで削除する
; 画像をPNG保存する自作関数。 ; Image 画像番号 ; Drawable レイヤー番号 ; outpath 保存先(ファイル名を含まない) ; filename ファイル名(.pngを含まない) (define (my-save-to-png Image Drawable outpath filename) ; 保存処理 (file-png-save-defaults RUN-NONINTERACTIVE Image Drawable (string-append outpath filename ".png") (string-append filename ".png") ) )
; 全てのレイヤーを統合してpngにエクスポート ; Image 画像番号 (gimp-image-list) で取得可能 ; outpath 出力先のパス。C:\\test\\ (define (my-save-png-as-single-image Image outpath ) (begin ; 現在の画像をコピーする (define dummydup '()) (set! dummydup (car (gimp-image-duplicate Image ) ) ) ; コピーした画像の全レイヤーをマージして一つの画像にする (gimp-image-merge-visible-layers dummydup CLIP-TO-IMAGE ) ; 保存に必要な、dummydupのdrawableを取得する (define activedrawable '()) (set! activedrawable (car (gimp-image-get-active-drawable dummydup ) ) ) (my-save-to-png dummydup activedrawable outpath (car (gimp-image-get-name Image) ); 画像の名前を取得してファイル名に指定 ) (gimp-image-delete dummydup) ) )
;; usage : ;; (gimp-image-list) ;; > (1 #(5)) ;; (my-save-png-as-single-image 5 "C:\\test\\") ;; > (#t)
Import Images as Planeを使えばする必要すらないが、Pythonコードからplaneにテクスチャを設定する場合。
import bpy # @brief Planeオブジェクトのサイズをテクスチャ画像に合わせて調整 # @param [in,out] plane Planeオブジェクト # @param [in] Image Textureノード # @param [in] ratio 何倍のサイズにするか # @return なし def TextureFixSize(plane,imgnode,ratio): maxsize = max( imgnode.image.size[0] , imgnode.image.size[1] ) plane.scale[0] = imgnode.image.size[0] / maxsize * ratio plane.scale[1] = imgnode.image.size[1] / maxsize * ratio # @brief テクスチャをplaneに設定する # @param [in,out] plane Planeオブジェクト # @param [in] filepath 画像データへのパス # @note マテリアルが設定され、Image Textureノードが存在している必要がある # @return なし def TextureFromFile(plane,filepath): #################### ## 画像ファイルを読み込み pngdata = bpy.data.images.load(filepath = filepath) #################### ## planeオブジェクトのImage Textureノードを取得 nodetree = plane.material_slots["Material.001"].material.node_tree imgnode = nodetree.nodes["Image Texture"] #################### ## Image Textureノードへ画像を設定 imgnode.image = pngdata #################### ## 張り付けたPlaneオブジェクトのサイズを画像サイズと同じ縦横比に合わせる TextureFixSize(plane,imgnode,1) act = bpy.context.active_object TextureFromFile(act,'C:/test/lake-6627781_640.jpg')
まず画像ファイルを読み込む
次にマテリアルからImage Textureノードを取得する
ノードに画像を設定
Image TextureノードのImageオブジェクトにsizeがある。
https://docs.blender.org/api/current/bpy.types.ShaderNodeTexImage.html
例えばアニメーションの長さを 500フレーム とする。この時、
F == 500
H == 250 (...500/2)
と定義する。
Particleの発生時間を、以下のように設定
start -(H-1)
stop H
次に、そのParticleをコピーし、、発生時間を以下のように設定
start H+1
stop F+H
500 frameのアニメーションであれば以下のようになる
まずアニメーションを500フレームに設定
次にparticleの発生時間を設定し、それをコピーした二つ目のparticleの設定も行う
particle1 : -249 …. 250
particle2 : 251 …. 750