hit   今日   昨日

画像ファイルとその他のデータをひとつのファイルに保存

フォーラムルール
フォーラムルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Name: M
[URL]
Date: 2009年3月08日(日) 22:58
No: 1
(OFFLINE)

 画像ファイルとその他のデータをひとつのファイルに保存

Borland C++ において DXライブラリ を使っている者です。

今、セーブ/ロード画面にサムネイルを表示させようとしています。

DXライブラリのGetDrawScreenGraph関数を使ってスクリーンをキャプチャして画像をbmp形式で保存、
その後、ゲームを再起動して読み込み、表示する事はできます。
また、セーブデータだけを、.datファイルにして保存する事もできます。

問題は、これら二つのファイル(.dat と .bmp) データをひとつの.datファイルにして保存したいのですが、
コードがまったく思いつきません。
サムネイルであるbmp形式のデータは、80×60のサイズです。

セーブデータは、クラスであり、クラスのメンバー変数に構造体の配列があります。
class playerInfo {
int numNow;//現在保存されているデータ数。
int activeUserNum;//現在アクティブなデータのインデックス。
struct userData allList[10];//10人分のセーブデータの配列

int slotGraphHandle[10];

//この後は関数に続く


.datのセーブデータは、今はバイナリ書き込み形式でクラスのメンバー関数内で以下のように保存しています。
fwrite(this, sizeof(playerInfo), 1, fp);

fpは FILE* です。

画像の保存も、DXライブラリの関数を利用して以下のようにしています。
SaveDrawScreen( 0 , 0 , 80 , 60 , "save/SaveDat-1.bmp");



こうなると、一度画像をファイルに保存してから、バイナリとして読み込み、
セーブデータのクラスのメンバー変数にそのバイナリを保存するためのメンバー変数が欲しいのかと
思ったのですが、ファイルのサイズからしてどうメンバー変数にするか思いつきません。

他には、画像データをセーブデータに上書きではなく、加算するように書き込めばいいのかと思いました。
この場合、セーブした.datから直接画像としては読み込めないので、一度画像の部分だけを読み込み、bmpとして一時的に保存しなおして
そのファイルをDXライブラリの関数を用いて読み込み、一時的に作ったbmpを消してしまえばいいのでしょうか?

ですが、一部分だけをbmpに書き出すコードが分かりません。
よろしくお願いします。<(_ _)>

Name: lbfuvab
[URL]
Date: 2009年3月09日(月) 00:08
No: 2
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

①bmpを~~.bmpとして書き出し
②そのファイルを読み込みモードでオープンしメモリに内容を全て読み込む
③~~.datにbmpとセーブデータを書き出し。
⑨バカ

読み出し時に関しては
http://studiokingyo.fc2web.com/dxlib/kaibou/k_shiyou.html
↑のサイト様が役に立つと思います


>ですが、一部分だけをbmpに書き出すコードが分かりません。
>よろしくお願いします。<(_ _)>

一部分と言うのは表示画面の一部分と言う事でしょうか?

Name: M
[URL]
Date: 2009年3月09日(月) 01:28
No: 3
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

>一部分と言うのは表示画面の一部分と言う事でしょうか?
.dat形式のデータは、セーブデータと画像の領域にわかれるわけですが、
このデータの前半は、int型やらbooleanやらだとして、途中から画像のデータになるわけですが、
この前半のデータを無視して画像の部分だけという意味です。

>読み出し時に関しては
>http://studiokingyo.fc2web.com/dxlib/kaibou/k_shiyou.html
>↑のサイト様が役に立つと思います

すいません、どの項目を参考にすればいいのか分かりません。。。
一通り全部読みましたが、利用できそうなのが見つけれませんでした。

Name: SooA
[URL]
Date: 2009年3月09日(月) 02:29
No: 4
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

範囲が小さいのでピクセル単位で
取得&描画してみてはどうでしょう。

■保存
1.空のグラフィックを作って現在の画面をコピーする。
 部分的に抜き出す場合は抜き出すサイズと同じサイズの
 グラフィックを作成してコピーする。
 MakeGraph();// グラフィックの作成
 GetDrawScreenGraph();// 描画画面の取得

2.コピーしたグラフィックを 80*60サイズで裏画面に描画。
 DrawModiGraph();// 自由変形描画

3.80*60の領域の色をピクセル単位で取得しデータに渡す。
 GetPixel;// 色の取得

■読み込み
1.裏画面にセーブデータからピクセル復元。
 DrawPixel;// 点の描画

2.空のグラフィック(80*60)を作成して裏画面の80*60の範囲をコピー。

Name: SooA
[URL]
Date: 2009年3月09日(月) 02:41
No: 5
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

追記
呼び出し時にピクセル単位で復元すると
時間が掛かるのでBMP形式に変換して保存すれば
CPUで扱うイメージとしてデータを渡せます。

BMP画像の保存形式の説明が嫌だったのでピクセル単位にしました><;
ので、詳しくはWeb検索で調べてください。

Name: GPGA
[URL]
Date: 2009年3月09日(月) 05:13
No: 6
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

DXライブラリの関数を見たかぎりでは、一度ファイルに保存して、それを読み込んだほうが楽そうです。

読み込みと書き込みのサンプルを作ってみました。
1セーブ情報+サムネイルを1ファイルとして扱っています。
Zキーで保存、Xキーでロードです。
アプリ起動→Zキー投下→アプリ終了→アプリ起動→Xキー投下の順で、サムネイルを保存し
保存したサムネイルを読み込んで表示していることが分かると思います。
#include "DxLib.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <time.h>

struct userData {
int a;
};

/*!
* @brief セーブファイルを書き込みます。
*
* @param szFileName 書き込むファイル名
* @param data 書き込むユーザーデータへの参照
*
* @return 正常に終了した場合は true を返します。
*/
bool Save(const char* szFileName, const userData& data) {
// 画面をセーブ
int ret = SaveDrawScreen(0, 0, 80, 60, "save/temp.bmp");
if (ret != 0) {
return false;
}

// ファイルを開く
std::ifstream ifs("save/temp.bmp", std::ios::in | std::ios::binary);
if (!ifs.is_open()) {
return false;
}

// バッファの確保
ifs.seekg(0, std::ios::end);
std::vector<char> buf(ifs.tellg());
ifs.seekg(0, std::ios::beg);

// ファイル読み込み
ifs.read(&buf[0], buf.size());

// ファイルを閉じて、削除
ifs.close();
DeleteFile("save/temp.bmp");

// セーブファイルを作成
std::ofstream ofs(szFileName, std::ios::out | std::ios::binary);
if (!ofs.is_open()) {
return false;
}
ofs.write((const char*)&data, sizeof(data)); // ユーザーデータ書き込み
size_t size = buf.size();
ofs.write((const char*)&size, sizeof(size)); // BMPのファイルサイズを書き込み
ofs.write(&buf[0], buf.size()); // BMPの書き込み

return true;
}

/*!
* @brief セーブファイルを読み込みます。
*
* @param szFileName 読み込むファイル名
* @param data 読み込むユーザーデータへの参照
* @param handle 読み込むグラフィックハンドルへの参照
*
* @return 正常に終了した場合は true を返します。
*/
bool Load(const char* szFileName, const userData& data, int& handle) {
// ファイルを開く
std::ifstream ifs(szFileName, std::ios::in | std::ios::binary);
if (!ifs.is_open()) {
return false;
}

// ユーザーデータの読み込み
ifs.read((char*)&data, sizeof(data));

// BMPデータの読み込み
size_t size;
ifs.read((char*)&size, sizeof(size)); // ファイルサイズを読み込み
std::vector<char> buf(size); // サイズ分のバッファを確保して
ifs.read(&buf[0], buf.size()); // 確保したバッファにBMPデータを読み込む

// グラフィックハンドルの生成
handle = CreateGraphFromMem(&buf[0], buf.size());

return true;
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
ChangeWindowMode(TRUE);
// DXライブラリ初期化処理
if( DxLib_Init() == -1 ) return -1 ;

// 裏画面を使用
SetDrawScreen(DX_SCREEN_BACK);

// BOXの色をランダムで生成
srand((unsigned int)time(NULL));
unsigned char r = rand();
unsigned char g = rand();
unsigned char b = rand();

// ロード用グラフィックハンドル
int handle = -1;

// 仮のユーザーデータ
userData data;

// キー用
char key[256] = { 0 };
char keyBack[256] = { 0 };

// 終了メッセージがくるまでループ
while(ProcessMessage() == 0) {
// キー取得
memcpy(keyBack, key, sizeof(keyBack));
GetHitKeyStateAll(key);

if ((key[KEY_INPUT_Z] & ~keyBack[KEY_INPUT_Z]) != 0) {
// 現在の画面を保存
Save("save/save.dat", data);
} else if ((key[KEY_INPUT_X] & ~keyBack[KEY_INPUT_X]) != 0) {
// 保存したサムネイルを読み込む
Load("save/save.dat", data, handle);
}

// 画面の初期化
ClearDrawScreen();

// サムネイルとりこみように、矩形を描画
DrawBox(0, 0, 80, 60, GetColor(r, g, b), TRUE);

// サムネイルが読み込まれていれば描画
if (handle != -1) {
DrawGraph(0, 120, handle, FALSE);
}

// 裏画面の内容を表画面に反映
ScreenFlip();

WaitTimer(100);
}

// ロードされていたら画像解放
if (handle != -1) {
DeleteGraph(handle);
}

// DXライブラリ使用の終了処理
DxLib_End() ;

// ソフトの終了
return 0 ;
}
 

Name: M
[URL]
Date: 2009年3月09日(月) 06:03
No: 7
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

>GPGA 様
ちゃんと動きました!!
まだ、コードの内容を理解していませんが、時間をかけて読んでみます。
皆さんありがとうございました。

Name: M
[URL]
Date: 2009年3月09日(月) 10:47
No: 8
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

すいません、詰まってしまいました。。。
教えていただいたコードを元に、複数のサムネイル画像を保存できるようにしたものです。

//StopScreenImage は、800×600の画像へのハンドル

DrawGraph(0,0,StopScreenImage,false);
ScreenFlip();
WaitKey();//ココでは、正常に表示される。



for(int i = 0; i <10;i++){
DrawBox(0,0,80,60,Black,true);

if(i == selection){ //selectionというのは、選択しているデータ番号とします。
DrawExtendGraph(0, 0, 80, 60, StopScreenImage , 0 );
DrawGraph(0,0,StopScreenImage,false);
ScreenFlip();
WaitKey();//ここで、なぜか↑と同じように表示されると思ったのに真っ白になります。
}
else if(isOccupied[i])//i番目のデータはすでに登録されているなら。
DrawExtendGraph(0, 0, 80, 60, slotGraphHandle[i] , 0 ) ;//今保存されているハンドルの画像を描画。
else
DrawString(0,0,"EMPTY",White);

ScreenFlip();

SaveDrawScreen( 0 , 0 , 80 , 60 , "save/temp.bmp") ;

// ファイルを開く
ifstream ifs("save/temp.bmp", ios::in | ios::binary);
// バッファの確保
ifs.seekg(0, ios::end);
vector<char> buf(ifs.tellg());
ifs.seekg(0, ios::beg);

// ファイル読み込み
ifs.read(&buf[0], buf.size());
// ファイルを閉じて、削除
ifs.close();
DeleteFile("save/temp.bmp");
size_t size = buf.size();
ofs.write((const char*)&size, sizeof(size)); // BMPのファイルサイズを書き込み
ofs.write(&buf[0], size); // BMPの書き込み
}



このようなコードをすると、最初は、キャプチャした画像が表示され
次に何かキーを入力すると、真っ白な画面が表示されてしまいます。
この時、本来は同じキャプチャした画像が表示されるはずなのですが・・・

配列のサイズはどれも、10で宣言してあります。

何が原因で、画像が表示されなくなってしまったのでしょう?

Name: GPGA
[URL]
Date: 2009年3月09日(月) 16:31
No: 9
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

DrawExtendGraphの前にClearDrawScreenを入れたらどうなりますか?

Name: M
[URL]
Date: 2009年3月10日(火) 07:10
No: 10
(OFFLINE)

 Re:画像ファイルとその他のデータをひとつのファイルに保存

な、直りました・・・なぜ!?ww
とにかく助かりました<(_ _)>


Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: asdjack & ゲスト[22人]