[C++] 67 アプリ画像ファイルの有効パス その2 : 作業ディレクトリ変更

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, no IDE]

実行ファイルのあるところに作業ディレクトリを変更して相対パスが使えないか検証しました。

実行ファイルのディレクトリの文字列を作成するために文字列分割関数と文字列分割/再結合関数を作りました。これらは後日ライブラリにする予定です。

検証の方は成功しました。手間は掛かりますが、作業ディレクトリを実行ファイルのディレクトリに変更することで相対パスでの画像ファイルの使用は実行ファイル、appファイル共に可能になります。

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_PNG_Image.H>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <vector>

using std::string; using std::vector;
using std::cout; using std::endl;

Fl_Window* window;
Fl_Box* picturebox;
Fl_PNG_Image* pngimage;  

// 文字列を文字列delで分割しリスト化する関数
vector<string> split(string str, char del) {
    int first = 0;
    int last = str.find_first_of(del);
    vector<string> result;
 
    while (first < str.size()) {
        string subStr(str, first, last - first);
        result.push_back(subStr);
 
        first = last + 1;
        last = str.find_first_of(del, first);
 
        if (last == string::npos) {
            last = str.size();
        }
    }
    return result;
}
// 分割リストのstart番目からend番目までの要素を再結合する関数
string splitjoin(string str, char del, int start, int end){
    string result2;
    vector<string> list = split(str, del);

    vector<string> list2;
    for (int i = 0; i < list.size(); i++){
        if (end < 0){
            end += list.size();
        }
        if (i >= start && i <= end) {
            list2.push_back(list[i]);
        }
    }
    for (int i = 0; i< list2.size(); i++){
        result2.append(list[i] + del);
    }
    return result2;
}

int main(int argc, char **argv) {
    // 変更前の作業ディレクトリ確認
    char tmp[256];
    getcwd(tmp, 256);
    cout << "Current working directory: " << tmp << endl;

    // 実行ファイルのパスを出力
    cout << argv[0] << endl;

    // パスをスラッシュで分割しリストにする
    vector<string> l = split(argv[0], '/');

    // リストの内容確認
    int i = 0;
    for (const auto &item : l) {
        cout << i << " " << item << "; ";
        i++;
    }
    cout << endl;

    // リストの0番目から-2番目(最後から2番目)までの文字列を結合して新ディレクトリ作成
    string new_path = splitjoin(argv[0], '/', 0, -2);
    cout << new_path << endl;
    
    // 作業ディレクトリを変更
    int rtn = chdir(new_path.c_str());
    cout << rtn << endl ;

    // 変更後の作業ディレクトリ確認
    getcwd(tmp, 256);
    cout << "Current working directory: " << tmp << endl;

    Fl::set_font(FL_HELVETICA, "Osaka");
    window = new Fl_Window(100,100,360,220,"PLAIN");
    window->color(fl_rgb_color(131,204,210));

    pngimage = new Fl_PNG_Image("star.png");
    picturebox = new Fl_Box(20, 20, 120, 120);
    picturebox->box(FL_UP_BOX);
    picturebox->image(pngimage); 
    picturebox->redraw();  
    window->add(picturebox);

    window->end();
    window->show(argc, argv);
    
    return Fl::run();
}
Current working directory: /Users/[ユーザID]
/Volumes/DATA_m1/code/cpp/projects/plainPNG/bin/plain
0 ; 1 Volumes; 2 DATA_m1; 3 code; 4 cpp; 5 projects; 6 plainPNG; 7 bin; 8 plain; 
/Volumes/DATA_m1/code/cpp/projects/plainPNG/bin/
0
Current working directory: /Volumes/DATA_m1/code/cpp/projects/plainPNG/bin

[C++] 66 アプリ画像ファイルの有効パス SDL, FLTK

[M1 Mac, Big Sur 11.6.7, clang 13.0.0, no IDE]

ゲームプログラミング本のサンプルコードでappファイルを作成しようとするとアイコン以外の画像ファイルを認識できませんでした。このSDLと普段使っているFLTKで画像の有効パスを表にまとめてみました。

FLTKのappファイルで相対パスが使えない、すなわちappファイルの中に画像を入れて相対パスで使うことができないというのは衝撃です。appファイル内画像を絶対パスで捉え続けるのはあまり現実的ではありません。検証の結果は単に私のスキル不足が原因と思いたいところではあります。

FLTKでの検証例(星の画像を配置し表示可否を確認)
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_PNG_Image.H>

Fl_Window* window;
Fl_Box* picturebox;
Fl_PNG_Image* pngimage;  

int main(int argc, char **argv) {
    Fl::set_font(FL_HELVETICA, "Osaka");
    window = new Fl_Window(100,100,360,220,"PLAIN");
    window->color(fl_rgb_color(131,204,210));

    pngimage = new Fl_PNG_Image("star.png"); // ファイルパスを変えて検証した
    picturebox = new Fl_Box(20, 20, 120, 120);
    picturebox->box(FL_UP_BOX);
    picturebox->image(pngimage); 
    picturebox->redraw();  
    window->add(picturebox);

    window->end();
    window->show(argc, argv);
    
    return Fl::run();
}