カラーパレットの操作について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
けんたろうちゃん

カラーパレットの操作について

#1

投稿記事 by けんたろうちゃん » 17年前

BMPファイルのカラーパレット操作について教えてほしいです
具体的には

BMPファイルから特定の色を検索→その色を変更

によって擬似的に実現したいです
目的は2P、3Pカラー等の実現のためです
DXライブラリ置き場の方で非常に参考になる質問がありました↓
http://hpcgi2.nifty.com/natupaji/bbs/pa ... iew&no=889
しかし、自分の理解力のせいか内容を理解できず、BMP形式に適用させられない状態です
できたらプログラムソースとともに解説もいただきたいです

GPGA

Re:カラーパレットの操作について

#2

投稿記事 by GPGA » 17年前

BMPの説明はWeb上に大量にあるので、それらを参考にしたほうが良いと思います。
http://www.umekkii.jp/data/computer/fil ... bitmap.cgi


とりあえず、DXライブラリ置き場で提示したGetPaletteとSetPaletteのBMP版の
ソースを書いておきますが、解説はしません。
上記のサイトの参考にして、何をやっているかを考えてみてください。
その上で、まだわからなければ、どこからどこまでがわかっていて
どこがわからなかったかを明記して再度質問してください。
#include <vector>

/*!
 * @brief BMPのパレットを取得
 *
 * @param pBuffer BMP画像の先頭のアドレスを指定します。
 * @param palette 取得するパレットバッファを指定します。
 *
 * @return 正常に取得した場合は true を返します。
 */ 
bool GetPalette(const char* pBuffer, std::vector<unsigned char>& palette)
{
	BITMAPFILEHEADER header;
	BITMAPINFOHEADER info;

	std::memcpy(&header, pBuffer, sizeof(header));
	pBuffer += sizeof(header);
	if (header.bfType != 0x4d42) {
		// ビットマップではない
		return false;
	}

	std::memcpy(&info, pBuffer, sizeof(info));
	pBuffer += sizeof(info);
	if (info.biBitCount != 8) {
		// 256色ではない
		return false;
	}

	palette.resize(256 * 3);
	for (int i = 0; i < 256; ++i) {
		const int bmpidx = i * sizeof(RGBQUAD);
		const int palidx = i * 3;
		palette[palidx + 0] = pBuffer[bmpidx + 2];	// 赤
		palette[palidx + 1] = pBuffer[bmpidx + 1];	// 緑
		palette[palidx + 2] = pBuffer[bmpidx + 0];	// 青
	}

	return true;
}

/*!
 * @brief BMPのパレットを設定
 *
 * @param pBuffer BMP画像の先頭のアドレスを指定します。
 * @param palette 設定するパレットバッファを指定します。
 *
 * @return 正常に設定した場合は true を返します。
 */ 
bool SetPalette(char* pBuffer, const std::vector<unsigned char>& palette)
{
	BITMAPFILEHEADER header;
	BITMAPINFOHEADER info;

	std::memcpy(&header, pBuffer, sizeof(header));
	pBuffer += sizeof(header);
	if (header.bfType != 0x4d42) {
		// ビットマップではない
		return false;
	}

	std::memcpy(&info, pBuffer, sizeof(info));
	pBuffer += sizeof(info);
	if (info.biBitCount != 8) {
		// 256色ではない
		return false;
	}

	for (int i = 0; i < 256; ++i) {
		const int bmpidx = i * sizeof(RGBQUAD);
		const int palidx = i * 3;
		pBuffer[bmpidx + 2] = palette[palidx + 0];	// 赤
		pBuffer[bmpidx + 1] = palette[palidx + 1];	// 緑
		pBuffer[bmpidx + 0] = palette[palidx + 2];	// 青
	}

	return true;
}

けんたろうちゃん

Re:カラーパレットの操作について

#3

投稿記事 by けんたろうちゃん » 17年前

ソースありがとうございます
まさか同じ人が来てくれるとは思いませんでした

BITMAPFILEHEADER header;
BITMAPINFOHEADER info;
によってファイルヘッダと情報ヘッダを参照しているのは分かるのですが、

for (int i = 0; i < 256; ++i) {
const int bmpidx = i * sizeof(RGBQUAD);
const int palidx = i * 3;
pBuffer[palidx + 2] = palette[bmpidx + 0]; // 赤
pBuffer[palidx + 1] = palette[bmpidx + 1]; // 緑
pBuffer[palidx + 0] = palette[bmpidx + 2]; // 青
}
からよく分からないです(GetPallete,SetPallete同様
BMPのパレットデータが青、緑、赤という順番にあわせて読んでパレット用データに入れてるのだと思いますけど
いまいち自身がないです
あとpBufferとpalletteによりどのように色が変換されているのかも良く分かりません
このままだと
・BMPからパレットデータを読み取り
・パレットデータをBMPへ
という作業であって
特定の色を検索→その色を変換
という作業ではないと思います
初心者のような質問ですいませんm(_ _)m

けんたろうちゃん

Re:カラーパレットの操作について

#4

投稿記事 by けんたろうちゃん » 17年前

すいません少し理解できてきました;
ちょっと上のを使って実際に特定の色を変換するプログラムを作ってみます

けんたろうちゃん

Re:カラーパレットの操作について

#5

投稿記事 by けんたろうちゃん » 17年前

GPGAさんのコードを参考にして、パレット変更のプログラムを作成しました
以下ソースコードです
#include "DxLib.h"
#include <vector>

bool GetPalette(const char* pBuffer, std::vector<unsigned char>& palette);
bool SetPalette(char* pBuffer, const std::vector<unsigned char>& palette);
bool ConvertPalette(std::vector<unsigned char>& palette);

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	// 初期化
	ChangeWindowMode(TRUE);
	if (DxLib_Init() == -1) {
		return 1;
	}
	SetDrawScreen(DX_SCREEN_BACK);
	
	// 画像読み込み
	std::vector<char> bmpbuf;
	{
		int fh = FileRead_open("test.bmp");
		bmpbuf.resize(FileRead_size("test.bmp"));
		FileRead_read(&bmpbuf[0], bmpbuf.size(), fh);
		FileRead_close(fh);
	}

	// 画像初期化
	int iHandle[2];
	std::vector<unsigned char> palette;
	GetPalette(&bmpbuf[0], palette);

	iHandle[0] = CreateGraphFromMem(&bmpbuf[0], bmpbuf.size());

	ConvertPalette(palette);

	SetPalette(&bmpbuf[0], palette);
	iHandle[1] = CreateGraphFromMem(&bmpbuf[0], bmpbuf.size());

	// 表示
	DrawGraph(0, 0, iHandle[0], 0);
	DrawGraph(64, 0, iHandle[1], 0);


	ScreenFlip();

	WaitKey();
	DxLib_End();
	return 0;
}




/*!
 * @brief BMPのパレットを取得
 *
 * @param pBuffer BMP画像の先頭のアドレスを指定します。
 * @param palette 取得するパレットバッファを指定します。
 *
 * @return 正常に取得した場合は true を返します。
 */ 
bool GetPalette(const char* pBuffer, std::vector<unsigned char>& palette)
{
	BITMAPFILEHEADER header;
	BITMAPINFOHEADER info;

	std::memcpy(&header, pBuffer, sizeof(header));
	pBuffer += sizeof(header);
	if (header.bfType != 0x4d42) {
		// ビットマップではない
		return false;
	}

	std::memcpy(&info, pBuffer, sizeof(info));
	pBuffer += sizeof(info);
	if (info.biBitCount != 8) {
		// 256色ではない
		return false;
	}

	palette.resize(256 * 3);
	for (int i = 0; i < 256; ++i) {
		const int bmpidx = i * sizeof(RGBQUAD);
		const int palidx = i * 3;
		palette[palidx + 0] = pBuffer[bmpidx + 2];	// 赤
		palette[palidx + 1] = pBuffer[bmpidx + 1];	// 緑
		palette[palidx + 2] = pBuffer[bmpidx + 0];	// 青
	}

	return true;
}

/*!
 * @brief BMPのパレットを設定
 *
 * @param pBuffer BMP画像の先頭のアドレスを指定します。
 * @param palette 設定するパレットバッファを指定します。
 *
 * @return 正常に設定した場合は true を返します。
 */ 
bool SetPalette(char* pBuffer, const std::vector<unsigned char>& palette)
{
	BITMAPFILEHEADER header;
	BITMAPINFOHEADER info;

	std::memcpy(&header, pBuffer, sizeof(header));
	pBuffer += sizeof(header);
	if (header.bfType != 0x4d42) {
		// ビットマップではない
		return false;
	}

	std::memcpy(&info, pBuffer, sizeof(info));
	pBuffer += sizeof(info);
	if (info.biBitCount != 8) {
		// 256色ではない
		return false;
	}

	for (int i = 0; i < 256; ++i) {
		const int bmpidx = i * sizeof(RGBQUAD);
		const int palidx = i * 3;
		pBuffer[bmpidx + 2] = palette[palidx + 0];	// 赤
		pBuffer[bmpidx + 1] = palette[palidx + 1];	// 緑
		pBuffer[bmpidx + 0] = palette[palidx + 2];	// 青
	}

	return true;
}

bool ConvertPalette(std::vector<unsigned char>& palette)
{
	int ph;
	char palBuf[1024];

	ph = FileRead_open("palette1.txt");

	while(FileRead_eof(ph) == 0)
	{

		FileRead_gets(palBuf, 1023, ph);
		int original_R, original_G, original_B;
		int convert_R, convert_G, convert_B;
		sscanf_s(palBuf, "%d,%d,%d=%d,%d,%d;", &original_R, &original_G, &original_B, &convert_R, &convert_G, &convert_B);

		for(int i=0; i<256; i++){

			if(palette[i * 3 + 0]==original_R && palette[i * 3 + 1]==original_G && palette[i * 3 + 2]==original_B){
				palette[i * 3 + 0]=convert_R;
				palette[i * 3 + 1]=convert_G;
				palette[i * 3 + 2]=convert_B;			
			}
		}
	}
	return true;
}
そのうち、ConvertPalette関数を指定したファイル名により読み取るパレットファイルを変更できるように直したいです

閉鎖

“C言語何でも質問掲示板” へ戻る