Last active
December 23, 2015 04:09
-
-
Save a-kaneda/6577750 to your computer and use it in GitHub Desktop.
PNGファイルに等間隔で隙間を入れます。隙間には隣接するドットをコピーします。ビット深度4bitのファイルのみ対応しています。libpngを使用しています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include "png.h" | |
/*! | |
@brief PNG隙間作成処理 | |
PNGファイルのタイルごと間に隙間を挿入する。ビット深度4bitのファイルのみに対応する。 | |
オプションは以下のとおり、 | |
- 1個目:タイルのサイズ | |
- 2個目:入力画像ファイル | |
- 3個目:出力画像ファイル | |
@param argc コマンドラインオプションの数 | |
@param argv コマンドラインオプション | |
@return 0:正常終了、非0:エラー終了 | |
*/ | |
int main(int argc, char **argv) | |
{ | |
int ret = 0; // 戻り値 | |
int tilesize = 0; // タイルのサイズ | |
char *inputfile = NULL; // 入力ファイル名 | |
FILE *inputfp = NULL; // 入力ファイルポインタ | |
png_byte header[8] = ""; // シグネチャ比較用バッファ | |
png_structp inputpngstr = NULL; // 入力png_struct構造体ポインタ | |
png_infop inputinfo = NULL; // 入力png_info構造体ポインタ | |
png_byte **inputdata = NULL; // 入力ファイルデータ | |
png_byte buf = 0; // データコピー時の作業用バッファ | |
char *outputfile = NULL; // 出力ファイル名 | |
FILE *outputfp = NULL; // 出力ファイルポインタ | |
png_structp outputpngstr = NULL; // 出力png_struct構造体ポインタ | |
png_infop outputinfo = NULL; // 出力png_info構造体ポインタ | |
png_byte **outputdata = NULL; // 出力ファイルデータ | |
unsigned int width = 0; // 入力画像の幅 | |
unsigned int height = 0; // 入力画像の高さ | |
int bit_depth = 0; // 入力画像のビット深度 | |
int color_type = 0; // カラー/アルファチャンネルの設定 | |
int interlace_type = 0; // インターレースタイプ | |
int compression_type = 0; // 圧縮方式 | |
int filter_method = 0; // フィルター形式 | |
int num_palette = 0; // パレット数 | |
png_color *inputpalette = NULL; // 入力画像のパレット | |
png_color *outputpalette = NULL; // 出力画像のパレット | |
png_color_16p inputbackground = NULL; // 入力画像の背景色 | |
int enablebackground = 0; // 背景色取得に成功したかどうか | |
png_color_16 outputbackground; // 出力画像の背景色 | |
png_bytep inputtrans = NULL; // 入力画像の透過パレットエントリ | |
int num_trans = 0; // 透過エントリの数 | |
png_color_16p inputtransvalues = NULL; // 入力画像の非パレット画像用の単一透過色のカラーサンプル値かグレーレベル | |
png_bytep outputtrans = NULL; // 出力画像の透過パレットエントリ | |
png_color_16 outputtransvalues; // 出力画像の非パレット画像用の単一透過色のカラーサンプル値かグレーレベル | |
int x = 0; // x座標ループ用 | |
int y = 0; // y座標ループ用 | |
int xoffset = 0; // x方向の隙間を考慮したオフセット値 | |
int yoffset = 0; // y方向の隙間を考慮したオフセット値 | |
// オプション数が正しくない場合は使い方を表示して終了する | |
// 1個目:タイルサイズ | |
// 2個目:入力ファイル名 | |
// 3個目:出力ファイル名 | |
if (argc != 4) { | |
fprintf(stderr, "Usage : pngspace tilesize input output\n"); | |
ret = -1; | |
goto PROC_END; | |
} | |
// タイルサイズを取得する | |
tilesize = atoi(argv[1]); | |
if (tilesize <= 0) { | |
fprintf(stderr, "Parameter error : tilesize=%d\n", tilesize); | |
ret = -2; | |
goto PROC_END; | |
} | |
// 入力ファイル名を取得する | |
inputfile = argv[2]; | |
// 入力ファイルを開く | |
inputfp = fopen(inputfile, "rb"); | |
if (inputfp == NULL) { | |
fprintf(stderr, "File open error : %s\n", inputfile); | |
ret = -3; | |
goto PROC_END; | |
} | |
// ヘッダ部分を取得する | |
fread(header, 1, sizeof(header), inputfp); | |
// シグネチャをチェックする | |
if (png_sig_cmp(header, 0, sizeof(header)) != 0) { | |
fprintf(stderr, "Input file is not PNG file.\n"); | |
ret = -4; | |
goto PROC_END; | |
} | |
// 入力用png_struct構造体のメモリ確保と初期化を行う | |
inputpngstr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
if (inputpngstr == NULL) { | |
fprintf(stderr, "Memory error png_create_read_struct().\n"); | |
ret = -5; | |
goto PROC_END; | |
} | |
// 入力用info_ptr構造体のメモリ確保と初期化を行う | |
inputinfo = png_create_info_struct(inputpngstr); | |
if (inputinfo == NULL) { | |
fprintf(stderr, "Memory error png_create_info_struct().\n"); | |
ret = -6; | |
goto PROC_END; | |
} | |
// libpng内部でのエラー発生時にlongjmp()で戻れるようにsetjmp()をしておく | |
if (setjmp(png_jmpbuf(inputpngstr)) == 0) { | |
// libpngに入力ファイルポインタを設定する | |
png_init_io(inputpngstr, inputfp); | |
// 事前に読み込んだシグネチャのサイズをlibpngに知らせる | |
png_set_sig_bytes(inputpngstr, sizeof(header)); | |
// pngファイルを読み込む | |
png_read_png(inputpngstr, inputinfo, PNG_TRANSFORM_IDENTITY, NULL); | |
// 画像データのポインタを取得する | |
inputdata = png_get_rows(inputpngstr, inputinfo); | |
// 入力画像の画像ヘッダ・チャンクを取得する | |
png_get_IHDR(inputpngstr, inputinfo, &width, &height, &bit_depth, | |
&color_type, &interlace_type, &compression_type, &filter_method); | |
// ビット深度が4bit以外の場合はサポート対象外とする | |
if (bit_depth != 4) { | |
fprintf(stderr, "Support only 4 bit depth : bit_depth=%d\n", bit_depth); | |
ret = -7; | |
goto PROC_END; | |
} | |
// 入力画像のパレット・チャンクを取得する | |
png_get_PLTE(inputpngstr, inputinfo, &inputpalette, &num_palette); | |
// 出力画像パレットのメモリを確保する | |
outputpalette = (png_color*)malloc(sizeof(png_color) * num_palette); | |
// 入力画像のパレットをコピーする | |
memcpy(outputpalette, inputpalette, sizeof(png_color) * num_palette); | |
// 入力画像の背景色・チャンクを取得する | |
if (png_get_bKGD(inputpngstr, inputinfo, &inputbackground)) { | |
// 背景色取得成功を記憶する | |
enablebackground = 1; | |
// 入力画像の背景色をコピーする | |
memcpy(&outputbackground, inputbackground, sizeof(outputbackground)); | |
} | |
else { | |
// 背景色取得失敗を記憶する | |
enablebackground = 0; | |
// 出力画像の背景色を初期化する | |
memset(&outputbackground, 0x00, sizeof(outputbackground)); | |
} | |
// 入力画像の透明度・チャンクを取得する | |
png_get_tRNS(inputpngstr, inputinfo, &inputtrans, &num_trans, &inputtransvalues); | |
// 出力画像の透過パレットのメモリを確保する | |
outputtrans = (png_bytep)malloc(sizeof(png_byte) * num_trans); | |
// 入力画像の透過パレットをコピーする | |
memcpy(outputtrans, inputtrans, sizeof(png_byte) * num_trans); | |
// 出力画像の単一透過色をコピーする | |
memcpy(&outputtransvalues, inputtransvalues, sizeof(outputtransvalues)); | |
// 出力データ用のメモリを確保する | |
outputdata = (png_byte**)malloc(sizeof(png_byte*) * (height + (height / tilesize) * 2)); | |
for (y = 0; y < (height + (height / tilesize) * 2); y++) { | |
outputdata[y] = (png_byte*)malloc(sizeof(png_byte) * (width + (width / tilesize) * 2) / 2); | |
} | |
// yが0のときの隙間を無効化するために-1からオフセット値はスタートする | |
yoffset = -1; | |
// データを出力データに拡大コピーする | |
for (y = 0; y < height; y++) { | |
// 1タイル分処理した場合は間に隙間を入れる | |
if (y % tilesize == 0) { | |
yoffset += 2; | |
} | |
// xが0のときの隙間を無効化するために-1からオフセット値はスタートする | |
xoffset = -1; | |
for (x = 0; x < width; x++) { | |
// 1タイル分処理した場合は間に隙間を入れる | |
if (x % tilesize == 0) { | |
xoffset += 2; | |
} | |
// 上位4bitの場合 | |
if (x % 2 == 0) { | |
buf = inputdata[y][x / 2] >> 4; | |
} | |
// 下位4bitの場合 | |
else { | |
buf = inputdata[y][x / 2] & 0x0F; | |
} | |
// 上位4bitの場合 | |
if ((x + xoffset) % 2 == 0) { | |
outputdata[y + yoffset][(x + xoffset) / 2] |= buf << 4; | |
} | |
// 下位4bitの場合 | |
else { | |
outputdata[y + yoffset][(x + xoffset) / 2] |= buf; | |
} | |
// タイル上端の場合、一つ上のドットにもコピーする | |
if (y % tilesize == 0) { | |
// 上位4bitの場合 | |
if ((x + xoffset) % 2 == 0) { | |
outputdata[y + yoffset - 1][(x + xoffset) / 2] |= buf << 4; | |
} | |
// 下位4bitの場合 | |
else { | |
outputdata[y + yoffset - 1][(x + xoffset) / 2] |= buf; | |
} | |
} | |
// タイル下端の場合、一つ下のドットにもコピーする | |
if (y % tilesize == tilesize - 1) { | |
// 上位4bitの場合 | |
if ((x + xoffset) % 2 == 0) { | |
outputdata[y + yoffset + 1][(x + xoffset) / 2] |= buf << 4; | |
} | |
// 下位4bitの場合 | |
else { | |
outputdata[y + yoffset + 1][(x + xoffset) / 2] |= buf; | |
} | |
} | |
// タイル左端の場合、一つ左のドットにもコピーする | |
if (x % tilesize == 0) { | |
// 上位4bitの場合 | |
if ((x + xoffset - 1) % 2 == 0) { | |
outputdata[y + yoffset][(x + xoffset - 1) / 2] |= buf << 4; | |
} | |
// 下位4bitの場合 | |
else { | |
outputdata[y + yoffset][(x + xoffset - 1) / 2] |= buf; | |
} | |
} | |
// タイル右端の場合、一つ右のドットにもコピーする | |
if (x % tilesize == tilesize - 1) { | |
// 上位4bitの場合 | |
if ((x + xoffset + 1) % 2 == 0) { | |
outputdata[y + yoffset][(x + xoffset + 1) / 2] |= buf << 4; | |
} | |
// 下位4bitの場合 | |
else { | |
outputdata[y + yoffset][(x + xoffset + 1) / 2] |= buf; | |
} | |
} | |
} | |
} | |
} | |
else { | |
fprintf(stderr, "libpng error.\n"); | |
ret = -8; | |
goto PROC_END; | |
} | |
// 入力用のpng_struct構造体、info_ptr構造体のメモリを解放する | |
if (inputpngstr != NULL || inputinfo != NULL) { | |
png_destroy_read_struct(&inputpngstr, &inputinfo, (png_infopp)NULL); | |
inputpngstr = NULL; | |
inputinfo = NULL; | |
} | |
// 出力ファイル名を取得する | |
outputfile = argv[3]; | |
// 出力ファイルを開く | |
outputfp = fopen(outputfile, "wb"); | |
if (outputfp == NULL) { | |
fprintf(stderr, "File open error : %s\n", outputfile); | |
ret = -9; | |
goto PROC_END; | |
} | |
// 出力用png_struct構造体のメモリ確保と初期化を行う | |
outputpngstr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
if (outputpngstr == NULL) { | |
fprintf(stderr, "Memory error at png_create_write_struct().\n"); | |
ret = -10; | |
goto PROC_END; | |
} | |
// 出力用info_ptr構造体のメモリ確保と初期化を行う | |
outputinfo = png_create_info_struct(outputpngstr); | |
if (outputinfo == NULL) { | |
fprintf(stderr, "Memory error at png_create_info_struct().\n"); | |
ret = -11; | |
goto PROC_END; | |
} | |
// libpng内部でのエラー発生時にlongjmp()で戻れるようにsetjmp()をしておく | |
if (setjmp(png_jmpbuf(outputpngstr)) == 0) { | |
// libpngに出力ファイルポインタを設定する | |
png_init_io(outputpngstr, outputfp); | |
// 出力画像の画像ヘッダ・チャンクをセットする | |
png_set_IHDR(outputpngstr, outputinfo, (width + (width / tilesize) * 2), (height + (height / tilesize) * 2), bit_depth, | |
color_type, interlace_type, compression_type, filter_method); | |
// 出力画像のパレット・チャンクをセットする | |
png_set_PLTE(outputpngstr, outputinfo, outputpalette, num_palette); | |
// 出力画像の背景色・チャンクをセットする | |
if (enablebackground) { | |
png_set_background(outputpngstr, &outputbackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); | |
} | |
else { | |
png_set_background(outputpngstr, &outputbackground, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); | |
} | |
// 出力画像の透明度・チャンクを取得する | |
png_set_tRNS(outputpngstr, outputinfo, outputtrans, num_trans, &outputtransvalues); | |
// 出力データを出力pngにセットする | |
png_set_rows(outputpngstr, outputinfo, outputdata); | |
// pngファイルを書き出す | |
png_write_png(outputpngstr, outputinfo, PNG_TRANSFORM_IDENTITY, NULL); | |
} | |
else { | |
fprintf(stderr, "libpng error.\n"); | |
ret = -12; | |
goto PROC_END; | |
} | |
PROC_END: | |
// 出力用透過パレットのメモリを解放する | |
if (outputtrans != NULL) { | |
free(outputtrans); | |
} | |
// 出力用パレットのメモリを解放する | |
if (outputpalette != NULL) { | |
free(outputpalette); | |
} | |
// 出力用データのメモリを解放する | |
if (outputdata != NULL) { | |
for (y = 0; y < height; y++) { | |
free(outputdata[y]); | |
} | |
free(outputdata); | |
} | |
// 入力用のpng_struct構造体、info_ptr構造体のメモリを解放する | |
if (inputpngstr != NULL || inputinfo != NULL) { | |
png_destroy_read_struct(&inputpngstr, &inputinfo, (png_infopp)NULL); | |
} | |
// 出力用のpng_struct構造体、info_ptr構造体のメモリを解放する | |
if (outputpngstr != NULL || outputinfo != NULL) { | |
png_destroy_write_struct(&outputpngstr, &outputinfo); | |
} | |
// 入力ファイルを閉じる | |
if (inputfp != NULL) { | |
fclose(inputfp); | |
} | |
// 出力ファイルを閉じる | |
if (outputfp != NULL) { | |
fclose(outputfp); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment