png画像のカラーパレット変更について

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

png画像のカラーパレット変更について

#1

投稿記事 by まっつぁん » 8年前

初めて書き込ませていただきます。
まっつぁんと申します。

開発環境は
windows10
VisualStudio2015
Dxライブラリを使用

当方、2Dゲームを制作しておりまして、キャラクターの色違いを作りたいと思い、png画像の色データを変更するプログラムを作っています。

経緯は、キャラクターの色違いをそれぞれ画像として持つと、データ容量が大きくなってしまったり、一部アニメーションなどを変更した場合、すべてのカラーに反映させなければならないので、基準の画像のカラーパレットから色を変更してゲーム画面に表示させたほうが効率的ではないのかと考えたからです。


まず最初はDxライブラリを使用して、GetPixelSoftImageやDrawPixelSoftImageを使って画像の色を取得し、自作パレットを参考に色を変更し、CreateGraphFromSoftImageで画像ハンドルを作って表示させるプログラムを作りました。
しかし、小さな画像ならまだしも、変更する画像のサイズが大きくなってくると処理にも時間がかかってしまうのでこれではだめだと思いました。

次に自分なりに調べて、libpngライブラリを使用すればいいと思ったのですが、どうも色の取得方法と変更方法がわからず、今に至ります。

コード:

#include "DxLib.h"
#include "png.h"


// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	FILE            *fp;									
	png_structp     png_ptr;
	png_infop       info_ptr;
	png_uint_32		width, height;
	int             bit_depth, color_type, interlace_type;
	unsigned char   **image;

	fopen_s(&fp, "number.png", "rb");                       // まずファイルを開きます
	png_ptr = png_create_read_struct(                       // png_ptr構造体を確保・初期化します
		PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	info_ptr = png_create_info_struct(png_ptr);             // info_ptr構造体を確保・初期化します
	png_init_io(png_ptr, fp);                               // libpngにfpを知らせます
	png_read_info(png_ptr, info_ptr);                       // PNGファイルのヘッダを読み込みます
	png_get_IHDR(png_ptr, info_ptr, &width, &height,        // IHDRチャンク情報を取得します
		&bit_depth, &color_type, &interlace_type,
		NULL, NULL);

	//パレットがあれば、パレットを読み込む(PNGパレットは、libpng側で開放する)
	int num_palette = 0;		//色数
	png_color *palette = 0;		//PNGパレット
	if (color_type == PNG_COLOR_TYPE_PALETTE) {
		//PNGパレットを読み込む
		png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
	}

	// チャンネル数
	png_byte channels = png_get_channels(png_ptr, info_ptr);
	// ビット深度
	int pixel_depth = bit_depth * channels;
	BYTE *byBmp = (BYTE*)::malloc(height * (((width * pixel_depth / 8) + 3) & ~3));

	for (int i = 0; i < num_palette; i++)
	{
		byBmp[i * 4 + 0] = palette[i].blue;
		byBmp[i * 4 + 1] = palette[i].green;
		byBmp[i * 4 + 2] = palette[i].red;
	}

	free(byBmp);


	image = (png_bytepp)malloc(height * sizeof(png_bytep)); // 以下3行は2次元配列を確保します
	for (int i = 0; i < height; i++)
		image[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr));
	png_read_image(png_ptr, image);                         // 画像データを読み込みます
	for (int i = 0; i < height; i++) free(image[i]);         // 以下2行は2次元配列を解放します
	free(image);
	png_destroy_read_struct(                                // 2つの構造体のメモリを解放します
		&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fp);                                             // ファイルを閉じます
	return 0;
}
主に下のサイトを参考にしています。
http://gmoon.jp/png/#program_writing


最終手段としてはキャラクター画像をそれぞれ作ったほうがいいのかなと考えています。

それと、キャラクターの色変更の考えとしてはこれでいいのでしょうか?
それとも効率のいい別の方法があるのでしょうか?

よろしくお願いいたします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: png画像のカラーパレット変更について

#2

投稿記事 by softya(ソフト屋) » 8年前

libpngをちゃんと使ったことはないですが、インデックカラーpngをつかってパレットだけ入れ替えれば色違いキャラは作れるはずです。
昔は普通にやってとことですが、インデックカラーpngは256色に制限されるのでドット絵の得意じゃないと辛いかもしれません。
フルカラーをインデックカラーpngに自動変換するとかなりディザが発生します。
それとキャラを全部同じインデックカラーで描かないといけませんので絵を描く人は注意が必要です。
※ パレットを保存して使いまわします。

libpngは使ったことがないので、注意事項だけですがテストで使ったpngがインデックカラーpngで有ったかは心配されるところです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

まっつぁん

Re: png画像のカラーパレット変更について

#3

投稿記事 by まっつぁん » 8年前

お返事ありがとうございます。


変更画像は256色以内で作られているドット絵なので、たぶんインデックスカラーに対応しております。

インデックスカラーという単語をヒントに調べてみましたが、256色のパレットデータを持つpng形式ということはわかったのですが、やはりプログラムでのパレット変更の仕方がわかりません。


改めてGetPixelPalCodeSoftImageを使って画像から直接、パレット番号を取得しなおしてみましたが、
ビット深度4の画像はパレット番号を取得できましたが、
ビット深度8、32の画像ではパレット番号を取得できませんでした。

libpngライブラリを使わずにカラー変更ができる方法があるのならば、教えていただけませんか?

まっつぁん

自己解決しました。

#4

投稿記事 by まっつぁん » 8年前

libpngを使わずに、今までのSoftImage関係の関数を使用してカラー変更ができるようになりました。

「LoadSoftImageで読み込んだpngのパレットについて」
http://hpcgi2.nifty.com/natupaji/bbs/pa ... ew&no=3665
↑こちらの管理人様の記事を読みまして、
ここでのDxライブラリを導入すると、透過情報のついたpngデータのままカラー変更が行えるようになりました。

どうやらSoftImageを経由してのバグみたいでした。
同じ時期に同じバグで悩んでいた方がいたんですね・・・

softya(ソフト屋) 様、どうもご迷惑をおかけしました。
そしてご意見ありがとうございました。

閉鎖

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