[C++] 55 FLTK : 画像加工アプリ / iOSアプリ用iconset作成機能の実装 Contents.json

iOSアイコンのAppicon.appiconset内にあるContents.jsonはアイコン作成サイトで作ったものを一部書き換えて使っています。

内容は以下の通りです。

{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"3x"},
        {"size":"40x40","expected-size":"80","filename":"80.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"2x"},
        {"size":"40x40","expected-size":"120","filename":"120.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"3x"},
        {"size":"60x60","expected-size":"120","filename":"120.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"2x"},
        {"size":"57x57","expected-size":"57","filename":"57.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"1x"},
        {"size":"29x29","expected-size":"58","filename":"58.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"2x"},
        {"size":"29x29","expected-size":"29","filename":"29.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"1x"},
        {"size":"29x29","expected-size":"87","filename":"87.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"3x"},
        {"size":"57x57","expected-size":"114","filename":"114.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"2x"},
        {"size":"20x20","expected-size":"40","filename":"40.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"2x"},
        {"size":"20x20","expected-size":"60","filename":"60.png","folder":"AppIcon.appiconset/","idiom":"iphone","scale":"3x"},
        {"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"AppIcon.appiconset/","scale":"1x"},
        {"size":"40x40","expected-size":"80","filename":"80.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"72x72","expected-size":"72","filename":"72.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"76x76","expected-size":"152","filename":"152.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"50x50","expected-size":"100","filename":"100.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"29x29","expected-size":"58","filename":"58.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"76x76","expected-size":"76","filename":"76.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"29x29","expected-size":"29","filename":"29.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"50x50","expected-size":"50","filename":"50.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"72x72","expected-size":"144","filename":"144.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"40x40","expected-size":"40","filename":"40.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"},
        {"size":"20x20","expected-size":"20","filename":"20.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"1x"},
        {"size":"20x20","expected-size":"40","filename":"40.png","folder":"AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]}  

[C++] 54 FLTK : 画像加工アプリ / iOSアプリ用iconset作成機能の実装 appiconset

とりあえずmacOSアプリとiOSアプリに必要なアイコン類を作成できるようにしました。画像処理ライブラリとしてOpenCV(開発はインテル)を使っています。用意するのは2048*2048のpngファイルだけです。

iOSに必要なContents.jsonは前もってホームディレクトリに配置したものをコピーしました。

iOS
macOS
#include <opencv2/opencv.hpp>

void makeIcnsIOS(const char* filename){
	// AppIcon.appiconsetパス作成
	string path_str = string(filename);
	char del = '/';
	vector<string> list = split(path_str, del);
	string imagename = list.back(); 
	list.pop_back();

	const char* del2 = "/";
	string prefix = join(list,del2);
	string dir = prefix + "/" + "AppIcon.appiconset";

	cout<<"dir "<<dir<<endl;

	// iconsetディレクトリ作成
	mkdir(dir.c_str(),
		S_IRUSR | S_IWUSR | S_IXUSR |  // USR RWX
		S_IRGRP | S_IWGRP | S_IXGRP |  // GRP RWX
		S_IROTH | S_IWOTH | S_IXOTH);  // OTH RWX

	// 各種pngファイル作成
	int pixels[19] = {20, 29, 40, 50, 57, 58, 60, 72, 76, 80, 87, 100, 114, 120, 144, 152, 167, 180, 1024};
	string filenames[19] = {"20.png","29.png","40.png","50.png","57.png","58.png","60.png","72.png","76.png","80.png","87.png","100.png","114.png","120.png","144.png","152.png","167.png","180.png","1024.png"};
	
	int num = 0;
	for (int pixel:pixels){
		cv::Mat img,img_resize;
		img = cv::imread(filename,cv::IMREAD_UNCHANGED);
		cv::resize(img,img_resize, cv::Size(pixel,pixel),0,0,cv::INTER_LINEAR);
		// リサイズファイルパス作成
		string filename2 = filenames[num];
		string filepath = dir + "/" + filename2;
		cv::imwrite(filepath, img_resize);

		num += 1;
	}

	// JSONファイルコピー
	std::string jsonname1 = "/Users/[ユーザID]/ImageInspector/Contents.json";
    std::string jsonname2 = prefix + "/AppIcon.appiconset/Contents.json";
	system(("cp " + jsonname1 + " " + jsonname2).c_str());
}

[C++] 53 FLTK : 画像加工アプリ / iOSアプリ用iconset作成機能の実装 Fl_Choice

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

macOSアプリ, iOSアプリではアイコン登録に必要な画像ファイル数、サイズおよびファイルタイプが異なるため、都度選択し作成できるよう自製アプリの機能追加に着手しました。XCodeへのiOSアプリ登録に必要なのは正確にはicnsファイルではなくappiconsetフォルダです。

まずはガワだけ、プルダウンメニューを配置しました。中身はこれから書きます。

<該当箇所のみ>

Fl_Choice *choice;

// icnsタイプ選択項目
Fl_Menu_Item icns_type[3] = {
    {"macOS"},
    {"iOS"},
};

// icnsタイプ選択メニュー
choice = new Fl_Choice(135, 90, 80, 20, nullptr);
choice->menu(icns_type);

[C++] 52 FLTK : findコマンド生成アプリ/ FL_Menu_Itemの設定ミス その2

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

前回の続きです。

FL_Menu_Itemの配列の書き方でイテレータの存在を忘れていて修正を施しましたが、コードの見た目がいまひとつなので以下のように書き換えました。

Fl_Menu_Item pulldown[4] = {
  {"and"},
  {"or"},
  {"not"}
};

実際のアイテム数3に最後のヌルポインタを加えた4を記述する必要があります。こちらの方がすっきりしている感じがします。公式サイトにあるような複雑なメニューであれば最後に0を書くでしょう。

Fl_Menu_Item popup[] = {
 {"&alpha",    FL_ALT+'a', the_cb, (void*)1},
 {"&beta",     FL_ALT+'b', the_cb, (void*)2},
 {"gamma",     FL_ALT+'c', the_cb, (void*)3, FL_MENU_DIVIDER},
 {"&strange",  0,          strange_cb},
 {"&charm",    0,          charm_cb},
 {"&truth",    0,          truth_cb},
 {"b&eauty",   0,          beauty_cb},
 {"sub&menu",  0,          0, 0, FL_SUBMENU},
 {"one"},
 {"two"},
 {"three"},
 {0},
 {"inactive", FL_ALT+'i', 0, 0, FL_MENU_INACTIVE|FL_MENU_DIVIDER},
 {"invisible",FL_ALT+'i', 0, 0, FL_MENU_INVISIBLE},
 {"check",    FL_ALT+'i', 0, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
 {"box",      FL_ALT+'i', 0, 0, FL_MENU_TOGGLE},
 {0}};

お遊びで私のアプリにこの複雑なメニューを実装してみました。余談ですが、今になって何故altキーの記号が⎇なのかが理解できました。確かに左から右にまっすぐ進まずもう一方に変わっている様子で意味が伝わります。

それにしてもMontereyでは何故間違ったコードでも動いたのか、謎です。

[C++] 51 FLTK : findコマンド生成アプリ/ FL_Menu_Itemの設定ミス

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

macOS MontereyからBig Surにダウングレードしたところ、コマンドキーを押すとアプリが落ちるようになりました。エラー発生時に表示される解析情報を読むとどうやらFL_Menu_Itemまわりがおかしいようでした。

参考サイトのコードと全く同じようにプルダウンメニュー項目の最後に0を追加すると直りました。Montereyやアップグレード前のBig Surでは0がなくても正常に動いていたのに不思議です。

2022/5/18追記:
0(ヌルポインタ)が必要なのはイテレータに次の要素がないことを知らせるためでした。こんなことがすぐに分からないようではまだまだです。

Process:               FileFinder [8791]
Path:                  /Volumes/VOLUME/*/FileFinder
Identifier:            FileFinder
Version:               0
Code Type:             ARM-64 (Native)
Parent Process:        bash [8781]
Responsible:           Terminal [414]
User ID:               501

Date/Time:             2022-05-17 00:09:08.114 +0900
OS Version:            macOS 11.6.5 (20G527)
Report Version:        12
Anonymous UUID:        8099E198-41F7-976F-694A-6B1FB4EBE622


Time Awake Since Boot: 45000 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x1600000000000000 -> 0x0000000000000000 (possible pointer authentication failure)
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [8791]

VM Regions Near 0:
--> 
    __TEXT                      102480000-10248c000    [   48K] r-x/r-x SM=COW  /Volumes/*

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libfltk.1.3.dylib             	0x00000001026d90e0 Fl_Menu_Item::test_shortcut() const + 20
1   libfltk.1.3.dylib             	0x00000001026d912c Fl_Menu_Item::test_shortcut() const + 96
2   libfltk.1.3.dylib             	0x00000001026d912c Fl_Menu_Item::test_shortcut() const + 96
3   libfltk.1.3.dylib             	0x00000001026bcdbc Fl_Choice::handle(int) + 384
4   libfltk.1.3.dylib             	0x00000001026c69b8 Fl_Group::handle(int) + 960
5   libfltk.1.3.dylib             	0x00000001026b4650 send_event(int, Fl_Widget*, Fl_Window*) + 148
6   libfltk.1.3.dylib             	0x00000001026b45ac Fl::handle_(int, Fl_Window*) + 1656
7   libfltk.1.3.dylib             	0x00000001026b4388 Fl::handle_(int, Fl_Window*) + 1108
8   libfltk.1.3.dylib             	0x00000001026aa2c0 -[FLView flagsChanged:] + 308
9   com.apple.AppKit              	0x00000001a1594c10 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 5644
10  com.apple.AppKit              	0x00000001a1593398 -[NSWindow(NSEventRouting) sendEvent:] + 352
11  com.apple.AppKit              	0x00000001a1592270 -[NSApplication(NSEvent) sendEvent:] + 2568
12  libfltk.1.3.dylib             	0x00000001026a636c fl_mac_flush_and_wait(double) + 536
13  libfltk.1.3.dylib             	0x00000001026b373c Fl::run() + 44
14  FileFinder                    	0x0000000102485e88 main + 3836 (FileFinder.cpp:491)
15  libdyld.dylib                 	0x000000019eb41430 start + 4
# 最後の要素の0は無意味ではなかったようです

Fl_Menu_Item pulldown[] = {
  {"and"},
  {"or"},
  {"not"},
  0
};

[C++] 50 FLTK : findコマンド生成アプリ/ 濁音かなの判定

[M1 Mac, Monterey 12.3, FLTK 1.3.8]

macOSではfindコマンドの検索語に濁音・半濁音のかなを使えないため、これらを判定する関数を実装しました。イテレータを使えるケースですが、今回は不使用です。

正規表現が使えないようなので地道に配列を作成しました。検出するとダイアログが表示されます。

std::vector<string> dakuon = {"が","ぎ","ぐ","げ","ご","ざ","じ","ず","ぜ","ぞ","だ","ぢ","づ","で","ど","ば","び","ぶ","べ","ぼ" \
                                "ガ","ギ","グ","ゲ","ゴ","ザ","ジ","ズ","ゼ","ゾ","ダ","ヂ","ヅ","デ","ド","バ","ビ","ブ","ベ","ボ" \
                                "ぱ","ぴ","ぷ","ぺ","ぽ","パ","ピ","プ","ペ","ポ"};

bool dakuon_detection(const char* name_char) {
    string name_str = string(name_char);

    for (size_t i = 0; i < dakuon.size(); ++i) {
        if (name_str.find(dakuon[i]) != std::string::npos) {
            const char* msg = "検索不可\n濁音・半濁音の平仮名・片仮名が\n含まれています";
            dlg = new modalDialog(400, 200, "Attention", msg);
            dlg->hotspot(window);
            int x = dlg->x_root();
            int y = dlg->y_root();
            dlg->resize(x+20,y+120,250,150);
            dlg->set_modal();
            dlg->show();

            cout << msg << endl;

            return true;
        }
    }
    return false;
}

bool judge = dakuon_detection(name_char);

if (judge){
    <濁音かな検出時の処理>
}else{
    <濁音かな非検出時の処理>
}

[C++] 49 FLTK : findコマンド生成アプリ/ 大文字小文字区別なし

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

大文字小文字の区別なくgrep検索できるようにしました。オプション –ignore-caseをつけるだけです。なぜか -iではうまくできませんでした。

<該当箇所のみ>
if (onoff_grep == 1){
    const char* grep_char = grep_input->value();
    if (onoff_Aa == 0){
        cmd << "grep --ignore-case -r " << string(grep_char) << " " << string(dir_char);
        std::cout << cmd.str() << endl;
        system((cmd.str()).c_str());
    }else{
        cmd << "grep -r " << string(grep_char) << " " << string(dir_char);
        std::cout << cmd.str() << endl;
        system((cmd.str()).c_str());
    }
    // 件数表示
    cmd << " | wc -l";
    std::cout << cmd.str() << endl;
    system((cmd.str()).c_str());
}

[C++] 47 FLTK : findコマンド生成アプリ/ grep機能

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

最後の仕上げとしてgrep機能(テキスト内文字列検索)を追加しました。

findコマンドと区別するためにgrepの上に長い横線を引きたいのですが、どうもうまくできません。

たかが線を簡単に描画させてくれないFLTK、恐るべしです。JavaのSwingと比較して時間的開発コストは体感的に5〜10倍位といったところでしょうか。気長に取り組まないといらだちを鎮められないですね。線を描くのは基本ですからいずれできるようにします。

アプリの機能も充実し、これからヘビーユースすることになりそうです。

[C++] 46 FLTK : findコマンド生成アプリ/ Fl_Choice

[M1 Mac, Big Sur 11.6.5, FLTK 1.3.8]

Fl_Choiceを使ってプルダウンメニューを作成しました。

ネットにあるFl_Choiceのコード例は小難しいばかりで要領を得ませんでしたが、自分で意味を考えながら書くと内容が単純だからかシンプルな表現になりました。

外観をスッキリさせたいのでボタンへのpngファイルの埋め込みは見送りました。あとはgrep機能を追加して完成にするつもりです。

<関連部分のみ抜粋>
Fl_Menu_Item pulldown[] = {
  {"and"},
  {"or"},
  {"not"}
};

if (onoff_free == 1){
   string choices[3] = {"-and","-or","-not"};
   int choice_num = choice->value();
   string choice_str = choices[choice_num];

   cmd << choice_str << " " ;
   std::cout << cmd.str() << endl;

   const char* free_char = free_input->value();
   string free_str = string(free_char);

   cmd << free_str << " " ;
   std::cout << cmd.str() << endl;
}

<main関数内> 変数freeは既に存在するのでfree2とした
// Free
// free_rbtn
free_rbtn = new Fl_Round_Button(40,115,20,20,nullptr);
// free_label
free2 = new Fl_Box(58,120,26,12,"Free");
free2->labelcolor(fl_rgb_color(234,237,247));
free2->align(Fl_Align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT));
// free_choice
choice = new Fl_Choice(95, 115, 50, 20,nullptr);
choice->menu(pulldown);

[C++] 45 FLTK : findコマンド生成アプリ/機能追加

もう少し完成度を高めるべくGUIをデザインしてみました。

検索条件(自由記述)、各項目クリアボタンの追加です。検索条件の”and/or/not”をプルダウンメニューで選択できるようにし、ゴミ箱のpngファイルをボタンに組み込みます。いずれもFLTKで実装するのは初めてです。

骨組みができてからのこういった作業がプレッシャーもなくのんびり進められるので一番楽しい時間かもしれません。