Re: カラーパレットの操作 ( No.1 ) |
- 名前:管理人 日時:2008/06/10 12:48
LoadGraph や CreateGraphFromMem などの関数で画像ファイルを画像ハンドルにする
前に色を変更することはやろうと思えば可能ですが、画像ハンドルになった後の画像の
パレットを変更することはできません。(画像ハンドルになった時点でハイカラーもしくは
フルカラーの画像になってしまうので)
|
Re: カラーパレットの操作 ( No.2 ) |
- 名前:meigin 日時:2008/06/10 14:01
それでも良いです。
色違いを作る手間も省けると思います。
本当は読み込んだ後に変更出来れば良いんですけど。
|
Re: カラーパレットの操作 ( No.3 ) |
- 名前:SweetBlack 日時:2008/06/10 18:20
参考になるかどうかわかりませんが
私は管理人さんのおっしゃってる方法でパレットの変更を実際に行ってます。
ただし使ってる画像は256色BMPです。
256色BMPの構造をネットで調べると、
カラー情報の場所を知る事ができたので、
画像データをバイナリデータとして読みこんだ後、
カラー情報部分を任意に書き換え、
CreateGraphFromMemで画像ハンドルにする事で実現しています。
ただし、256BMP画像は、使用している色数が少なかったりすると
空いてる部分を詰め、ファイルサイズを小さくされてたりするので
それを把握して対応しておかないと、要らない部分を書き換えてしまいます。
PNG画像の構造についてはわかりませんので
ご自分で調べてみてはどうでしょう。
|
Re: カラーパレットの操作 ( No.4 ) |
- 名前:meigin 日時:2008/06/10 19:47
SweetBlackさん
png形式は、zipのライブラリがいるんですよ。
DXライブラリにもそれが入っているので、
競合してしまい上手く行かなかった記憶があります。
png形式で保存出来たら面白そうと思って……
配布元が英語で書かれたサイトで、
理解するには難しいです。
画像を扱うライブラリを探してみたのですが、
独自のDIBだったりして、
どうやってグラフィックハンドルを獲得するのか解りません。
|
Re: カラーパレットの操作 ( No.5 ) |
- 名前:GPGA 日時:2008/06/10 20:18
PNGのパレット操作を行う関数を作ってみました。
#include <fstream>
#include <cstdio>
#include <vector>
/*!
* @brief PNGのパレットを取得
*
* @param pBuffer PNG画像の先頭のアドレスを指定します。
* @param palette 取得するバッファを指定します。
*
* @return なし
*/
void GetPalette(const char* pBuffer, std::vector<unsigned char>& palette)
{
int length, signature;
int seek = 8 + 25; // ヘッダーを飛ばす
while (true) {
// パレットチャンクを探す
length = ((pBuffer[seek + 0] & 0xff) << 24) |
((pBuffer[seek + 1] & 0xff) << 16) |
((pBuffer[seek + 2] & 0xff) << 8) |
((pBuffer[seek + 3] & 0xff) << 0);
seek += 4;
signature = ((pBuffer[seek + 0] & 0xff) << 24) |
((pBuffer[seek + 1] & 0xff) << 16) |
((pBuffer[seek + 2] & 0xff) << 8) |
((pBuffer[seek + 3] & 0xff) << 0);
seek += 4;
if (signature == 0x504C5445) { // PLTE
palette.resize(length);
std::memcpy(&palette[0], &pBuffer[seek], length);
std::printf("読み込み時のCRC:0x%08x\n", *(unsigned long*)(pBuffer + seek + length));
break;
}
seek += length + 4;
}
}
void SetPalette(char* pBuffer, const std::vector<unsigned char>& palette)
{
int length, signature;
int seek = 8 + 25; // ヘッダーを飛ばす
while (true) {
// パレットチャンクを探す
length = ((pBuffer[seek + 0] & 0xff) << 24) |
((pBuffer[seek + 1] & 0xff) << 16) |
((pBuffer[seek + 2] & 0xff) << 8) |
((pBuffer[seek + 3] & 0xff) << 0);
seek += 4;
signature = ((pBuffer[seek + 0] & 0xff) << 24) |
((pBuffer[seek + 1] & 0xff) << 16) |
((pBuffer[seek + 2] & 0xff) << 8) |
((pBuffer[seek + 3] & 0xff) << 0);
seek += 4;
if (signature == 0x504C5445) { // PLTE
// パレットコピー0
std::memcpy(&pBuffer[seek], &palette[0], palette.size());
// CRC計算
static bool bCrc = false;
static unsigned long crcTable[256];
if (!bCrc) {
// CRCテーブルの作成
for (unsigned long i = 0; i < 256; ++i) {
unsigned long l = i;
for (int j = 0; j < 8; ++j) {
if ((l & 1) != 0) {
l = 0xedb88320 ^ l >> 1;
} else {
l >>= 1;
}
crcTable[i] = l;
}
}
bCrc = true;
}
unsigned long crc;
// calculate CRC
crc = 0xffffffff;
int last = seek + length;
seek -= 4;
for (; seek < last ; ++seek) {
crc = crcTable[(long)(crc ^ (long)pBuffer[seek] & 0xff) & 0x00ff] ^ crc >> 8;
}
crc ^= 0xffffffff;
// write CRC
pBuffer[seek++] = (unsigned char)((crc >> 24) & 0xff);
pBuffer[seek++] = (unsigned char)((crc >> 16) & 0xff);
pBuffer[seek++] = (unsigned char)((crc >> 8) & 0xff);
pBuffer[seek++] = (unsigned char)((crc >> 0) & 0xff);
std::printf("書き込み時のCRC:0x%08x\n", *(unsigned long*)(pBuffer + seek - 4));
break;
}
seek += length + 4;
}
}
|
Re: カラーパレットの操作 ( No.6 ) |
- 名前:GPGA 日時:2008/06/10 20:20
つづき
int main(int argc,char *argv[])
{
if (argc == 1) {
std::printf("引数くれ\n");
}
// ファイルの読み込み
std::ifstream ifs(argv[1], std::ios::in | std::ios::binary);
if (ifs == NULL) {
std::printf("ファイルがない\n");
return 1;
}
ifs.seekg(0, std::ios::end);
unsigned long size = ifs.tellg();
ifs.seekg(0);
std::vector<char> buf(size);
ifs.read(&buf[0], buf.size());
ifs.close();
std::vector<unsigned char> palette;
// パレット取得
GetPalette(&buf[0], palette);
// 1〜4番目を5〜8番目にする
#if 1
for (int i = 0; i < 4; ++i) {
palette[i * 3 + 0] = palette[(i + 4) * 3 + 0]; // 赤
palette[i * 3 + 1] = palette[(i + 4) * 3 + 1]; // 緑
palette[i * 3 + 2] = palette[(i + 4) * 3 + 2]; // 青
}
#else
// 色の反転
for (unsigned long i = 0; i < palette.size(); ++i) {
palette[i] = ~palette[i];
}
#endif
// パレットセット
SetPalette(&buf[0], palette);
// ファイルに書き出す
std::ofstream ofs("out.png", std::ios::out | std::ios::binary);
ofs.write(&buf[0], buf.size());
ofs.close();
return 0;
}
引数にpngファイルを指定すると、パレット操作後のファイルがout.pngとして吐き出されるサンプルです。
|
Re: カラーパレットの操作 ( No.7 ) |
- 名前:meigin 日時:2008/06/10 22:23
GPGAさん
有り難う御座います
変更出来ました。
保存せずにそのままデータを渡せたら良いんですけど。
ここは妥協の範囲ですね
|
Re: カラーパレットの操作 ( No.8 ) |
- 名前:GPGA 日時:2008/06/11 11:40
保存せずというのは、ファイルに保存しないということでしょうか?
画像ハンドルを作成する際に、CreateGraphFromMem関数を使用すれば、毎回ファイルを作成する必要はありません。
サンプルをアップローダーでアップしましたので確認してみてください
h ttp://applis.servehttp.com/
ファイル名:00016103.zip
パスワード:4321
OS:Windows XP
コンパイラ:VS2008 Standard Edition
以下ソースの内容
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
// 初期化
ChangeWindowMode(TRUE);
if (DxLib_Init() == -1) {
return 1;
}
SetDrawScreen(DX_SCREEN_BACK);
// 画像読み込み
std::vector<char> pngbuf;
{
int fh = FileRead_open("test.png");
pngbuf.resize(FileRead_size("test.png"));
FileRead_read(&pngbuf[0], pngbuf.size(), fh);
FileRead_close(fh);
}
// 画像初期化
int iHandle[6];
std::vector<unsigned char> palette;
GetPalette(&pngbuf[0], palette);
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 4; ++j) {
palette[j * 3 + 0] = palette[(j + i * 4) * 3 + 0]; // 赤
palette[j * 3 + 1] = palette[(j + i * 4) * 3 + 1]; // 緑
palette[j * 3 + 2] = palette[(j + i * 4) * 3 + 2]; // 青
}
SetPalette(&pngbuf[0], palette);
iHandle[i] = CreateGraphFromMem(&pngbuf[0], pngbuf.size());
}
// 表示
for (int i = 0; i < 6; ++i) {
DrawGraph(i * 24, 0, iHandle[i], 0);
}
ScreenFlip();
WaitKey();
DxLib_End();
return 0;
}
|
Re: カラーパレットの操作 ( No.9 ) |
- 名前:meigin 日時:2008/06/11 12:55
GPGAさん
有り難う御座います
上手く行きました
あの、フルカラーとか、
256色以外の画像を間違って読み込んだ場合もエラーを出したいのですが、何処で判定していいのか解らないので、教えて頂ければ嬉しいです。
png形式かの判定は始めの部分で区別するんですよね
臼NG
|
Re: カラーパレットの操作 ( No.10 ) |
- 名前:GPGA 日時:2008/06/11 13:14
pngは先頭の8バイトが固定ですので、そこでチェックできます。
bool CheckPng(const char* pBuffer)
{
const unsigned char check[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00 };
return std::memcmp(pBuffer, check, sizeof(check)) == 0;
}
パレットの存在の有無はGetPalette、SetPalette関数の戻り値をbool型にして
一番最後に true を返すようにしておき
if (signature == 0x504C5445) { // PLTE
の上に
// 終端確認
if (signature == 0x49454E44) { // IEND
return false;
}
を追加してください
|
Re: カラーパレットの操作 ( No.11 ) |
- 名前:GPGA 日時:2008/06/11 13:22
色数はGetPalette関数を使った後にパレットのサイズで
確認することができます。
std::vector<char> buf; //すでにpngの情報が入っているものだとする
std::vector<unsigned char> palette;
bool ret = GetPalette(&buf[0], palette);
if (!ret) {
// パレットがない
}
int colorValue = palette.size() / 2;
if (colorValue != 256) {
// 256色ではない
}
PNGのフォーマットは以下のサイトがわかりやすいです。
h ttp://homepage2.nifty.com/sophia0/png.html
後上記で記述したPNGプログラムで、間違えて9バイトチェックしていました。
× const unsigned char check[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00 };
○ const unsigned char check[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
Re: カラーパレットの操作 ( No.12 ) |
- 名前:meigin 日時:2008/06/11 13:55
GPGAさん
助かりました。
色違いの為に時間を取られる事が無くなって、
随分、楽になりそうです。
|
Re: カラーパレットの操作 ( No.13 ) |
- 名前:GPGA 日時:2008/06/11 16:17
あー、色数チェックのところも間違えました。
×int colorValue = palette.size() / 2;
○int colorValue = palette.size() / 3;
|
|