/***************************************************************/
/* 画像ダンプデータ → bitmap画像変換 2010.5.30 */
/* kondo@kk.iij4u.or.jp 2000.08.03 */
/* 1,4,8,24 bits 対応に拡張 Y.Fukui 2010.5.28 */
/* sizeof(char)=1, sizeof(short)=2, sizeof(int)=sizeof(long)=4 */
/***************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define BUF_SIZE (1024)
#ifndef _MAX_PATH
#define _MAX_PATH (255)
#endif
static char cmdname[] = "dump2bmp";
int optind = 1; // オプションでない最初の引数までの文字列数
int optopt; // オプション文字
char *optarg; // オプション引数
double max = 0.0, min = 0.0;
int maxopt = 0, minopt = 0;
void usage(void)
{
fprintf(stderr,
"\n"
"ASCIIテキストデータ ---> BMP フォーマット変換プログラム\n"
"usage : %s [option] <text_file> [bitmap_file]\n"
" bitmap_file の指定が無い場合"
" text_file.bmp のファイルが作成されます\n"
"\n"
"データ形式 : r値 g値 b値\n"
"\tx y z\n"
"\tx y z\n"
"\t: : :\n"
"\t (改行のみでラインの区切り)\n"
"\tx y z\n"
"\t: : :\n"
"\n", cmdname);
exit(1);
}
void openerror(char *filename)
{
fprintf(stderr, "Can't open file: %s\n", filename);
exit(1);
}
void allocerror(char *s)
{
fprintf(stderr, "Memory allocation error at %s.\n");
exit(1);
}
/*----------------*/
/* ファイル名取得 */
/*----------------*/
int getbasename(char *dest, char *src)
{
int i, start, end, ret;
i = -1; start = 0; end = 0;
// ファイル名のはじめと終わりを検出
while (src[++i]) {
if (src[i] == '\\' || src[i] == ':') {
start = i + 1; end = 0;
}
if (src[i] == '.') end = i;
}
if (end == 0) end = i;
// ファイル名が有る場合
if (start < end) {
for (i = 0; i < end; i++) {
dest[i] = src[i];
}
dest[i] = '\0'; ret = 1;
}
else {
dest[0] = '\0'; ret = 0;
}
return ret;
}
/*----------------------*/
/* コメント行読み飛ばし */
/*----------------------*/
void commentskip(FILE * fp)
{
int c;
c = fgetc(fp);
// # ; / があればその行を読み飛ばし
if ((c == '#') || (c == ';') || (c == '/')) {
while ((c = fgetc(fp)) != '\n') ;
}
ungetc(c, fp);
}
/*------------------*/
/* データ数調べ */
/*------------------*/
void maxdata( FILE * fp, int *sx, int *sy )
// sx: 横方向の画素数、sy: 縦方向の画素数(出力)
{
int k, m, n, r, g, b, pixels = 0;
char s[2], buf[BUF_SIZE];
rewind(fp);
commentskip(fp);
m = 0; n = 0; // m: 縦方向、n:横方向
while (fgets(buf, BUF_SIZE, fp) != NULL) {
k = sscanf(buf, "%d %d %d %1s", &r, &g, &b, s);
if( k == 3 ) n++; // R,G,Bのデータ行
else { // 空白行のとき
if( m == 0 ){ // 最初の横方向の画素数を格納
pixels = n;
m++; n = 0;
}
else { // 2行目以降は横方向画素数を確認
if( n != pixels ){
fprintf(stderr,"%d行目の画素数%dが最初%dと異なる\n"
,m+1,n,pixels);
exit( 0 );
}
m++; n = 0;
}
}
}
*sx = pixels; *sy = m;
}
/*-----------------------------------------*/
/* RGBテキストデータ読み込みとパレット作成 */
/*-----------------------------------------*/
void dataread(FILE * fp, int sx, int sy,
unsigned char **red, unsigned char **green, unsigned char **blue,
unsigned char **index, unsigned char *pred, unsigned char *pgreen,
unsigned char *pblue, short *bits, int *usedcolors)
{
int i, j, ix, iy, k, n, count, over256, found;
unsigned int r, g, b;
unsigned char reserved = 0;
char s[2], buf[BUF_SIZE];
rewind(fp);
commentskip(fp);
// データの読み込み
ix = 0; iy = 0;
while (fgets(buf, BUF_SIZE, fp) != NULL) {
n = sscanf(buf, "%d %d %d %1s", &r, &g, &b, s);
if (feof(fp)) {
break;
}
else if (n >= 3) { // 配列は、red[横方向, 縦方向]
red[ix][iy] = (unsigned char)r;
green[ix][iy] = (unsigned char)g;
blue[ix][iy] = (unsigned char)b;
ix++;
if( ix == sx ){ iy++; ix = 0; }
}
}
// データから色パレット生成
over256 = 0; // パレット数が256以上のときに1にセット
count = 0; // パレットの色数
for( j = 0; j < sy; j++ ) {
for( i = 0; i< sx; i++ ) {
found = 0; // 画素の色が既に登録されているときに1にセット
if( i==0 && j==0 ){ // 最初の色をパレットに登録
pred[0] = red[i][j];
pgreen[0] = green[i][j];
pblue[0] = blue[i][j];
index[i][j] = count; // パレット番号を画素に対応付け
count++;
}
else { // 最初でなければ、登録された色と一致するか調べる
for( k = 0; k < count; k++ ) {
if( red[i][j] == pred[k]
&& green[i][j] == pgreen[k]
&& blue[i][j] == pblue[k] ) {
index[i][j] = k; // パレット番号を画素に対応付け
found = 1; // パレットに登録済みの色であった
break;
}
}
if( found == 0 ) { // 登録されてない場合パレット追加
pred[count] = red[i][j];
pgreen[count] = green[i][j];
pblue[count] = blue[i][j];
index[i][j] = count;
if( count < 255 ) count++;
else {
over256 = 1; // 24 bits 対応なので
i = sx; j = sy; break; // パレット作成中断
}
}
}
// 画素の色をパレットに登録されているか調べるルーチンの終わり
}
}
*usedcolors = count;
if( over256 == 1 ) *bits = 24;
else if( count > 16 ) *bits = 8;
else if( count > 2 ) *bits = 4;
else *bits = 1;
}
/*---------------------------------*/
/* ファイルヘッダ BITMAPFILEHEADER */
/*---------------------------------*/
int fileheader(FILE * fp,
long size, long offset)
{
long count, filesize;
short reserved = 0;
char s[2];
rewind(fp);
// 識別文字 BM
s[0] = 'B';
s[1] = 'M';
fwrite(s, sizeof(char), 2, fp);
printf("[BITMAPFILEHEADER]\n");
// ファイルサイズ bfSize
filesize = size + offset;
printf(" File Size = %ld[Bytes]\n", filesize);
fwrite(&filesize, sizeof(long), 1, fp);
// 予約エリア bfReserved1
fwrite(&reserved, sizeof(short), 1, fp);
// 予約エリア bfReserved2
fwrite(&reserved, sizeof(short), 1, fp);
// データ部までのオフセット bfOffBits
printf(" Bitmap Data Offset = %ld [Bytes]\n", offset);
fwrite(&offset, sizeof(long), 1, fp);
// ファイルヘッダサイズ 14 Byte
if ((count = ftell(fp)) != 14) {
fprintf(stderr, "BITMAPFILEHEADER write error : %ld\n", count);
exit(1);
}
return count;
}
/*-----------------------------*/
/* 情報ヘッダ BITMAPINFOHEADER */
/*-----------------------------*/
int bitmapheader(FILE * fp,
long width, long height, long size, short bits)
{
long count, var_long;
short var_short;
fseek(fp, 14, SEEK_SET);
printf("[BITMAPINFOHEADER]\n");
// 情報ヘッダのサイズ biSize (Windows BMP は 40)
var_long = 40;
fwrite(&var_long, sizeof(long), 1, fp);
// 画像の幅 biWidth
var_long = width;
printf(" Width = %ld [pixels]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// 画像の高さ biHeight
// (正数ならば左下から右上, マイナスならば左上から右下)
var_long = height;
printf(" Height = %ld [pixels]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// プレーン数 biPlanes (必ず 1)
var_short = 1;
printf(" Planes = %hd\n", var_short);
fwrite(&var_short, sizeof(short), 1, fp);
// 1ピクセルのデータ数 biBitCount (1, 4, 8, 24, 32)
var_short = bits;
printf(" Bits Per Pixel = %hd [bits]\n", var_short);
fwrite(&var_short, sizeof(short), 1, fp);
// 圧縮 biCompression (無圧縮ならば 0)
var_long = 0;
printf(" Compression = %ld\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// 画像のサイズ biSizeImage
var_long = size;
printf(" Bitmap Data Size = %ld [Bytes]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// 横方向解像度 pixel/m biXPelPerMeter
// (96dpi, 1inch = 0.0254m のとき 96/0.0254 = 3780)
var_long = 3780;
printf(" HResolution = %ld [pixel/m]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// 縦方向解像度 pixel/m biYPelPerMeter
// (96dpi, 1inch = 0.0254m のとき 96/0.0254 = 3780)
var_long = 3780;
printf(" VResolution = %ld [pixel/m]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// パレット数 biClrUsed
var_long = 1 << bits;
printf(" Colors = %ld [colors]\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// パレット中の重要な色 biClrImportant
var_long = 0;
printf(" Important Colors = %ld\n", var_long);
fwrite(&var_long, sizeof(long), 1, fp);
// ファイルヘッダ(14 Byte) + 情報ヘッダサイズ(40 Byte)
if ((count = ftell(fp)) != 54) {
fprintf(stderr, "BITMAPINFOHEADER write error : %ld\n", count);
exit(1);
}
return count;
}
/*------------------------*/
/* パレットデータ RGBQUAD */
/*------------------------*/
long rgbquad(FILE * fp, short bits, unsigned char *red,
unsigned char *green, unsigned char *blue, int usedcolors)
{
int i;
long color, count;
unsigned char reserved = 0;
color = 1 << bits;
printf(" Pallete used = %ld [colors] (%ld [Bytes])\n",
usedcolors, color);
fseek(fp, 54, SEEK_SET);
// パレットを作成(書き出す)
for (i = 0; i < usedcolors; i++) {
fputc(blue[i], fp);
fputc(green[i], fp);
fputc(red[i], fp);
fputc(reserved, fp);
}
for( i=usedcolors; i< color; i++ ){
fputc(reserved, fp);
fputc(reserved, fp);
fputc(reserved, fp);
fputc(reserved, fp);
}
if ((count = ftell(fp)) != 54 + 4 * color) {
fprintf(stderr, "RGBQUAD write error : %ld\n", count);
exit(1);
}
return count;
}
/*--------------------*/
/* 画像データ書き出し */
/*--------------------*/
long imagewrite(FILE * fp, int x, int y, short bits,
unsigned char **red, unsigned char **green, unsigned char **blue,
unsigned char **index, long offset)
{
long i, j;
unsigned char pack, zero = 0;
int sizechar, x1, padding;
fseek(fp, offset, SEEK_SET);
sizechar = sizeof(char);
// 24ビットデータの場合
if( bits == 24 ){
// BGRの3色(3Bytes)をx個の画素を出力したときのBytes数が4の倍数でない時
if( (i = (3*x) % 4) != 0 ) { // 4の倍数にするためのByte数はx1
padding = 1; x1 = 4 - i;
}
else { padding = 0; }
for (j = y-1; j >= 0; j--) {
for (i = 0; i < x; i++) {
fwrite(&blue[i][j], sizechar, 1, fp);
fwrite(&green[i][j], sizechar, 1, fp);
fwrite(&red[i][j], sizechar, 1, fp);
}
// 1ラインは 4Byte(long) 境界にあわせるための詰め物
if ( padding == 1 ) {
for (i = 0; i < x1; i++) {
fwrite(&zero, sizechar, 1, fp);
}
}
}
return ftell(fp);
}
// 8ビットの場合 1パレット番号を1バイトに書く
else if( bits == 8 ){
if( (i = x % 4) != 0 ){
padding = 1; x1 = 4 - i;
} else { padding = 0; }
for (j = y-1; j >= 0; j--) {
for (i = 0; i < x; i++) {
fwrite(&index[i][j], sizechar, 1, fp);
}
if ( padding == 1 ) { // 4バイト単位で1行を描くための詰め物
for (i = 0; i < x1; i++) {
fwrite(&zero, sizechar, 1, fp);
}
}
}
return ftell(fp);
}
// 4ビットの場合 2つのパレット番号を1バイトにまとめて書く
else if( bits == 4 ){
x1 = ((x - 1)/8 + 1)*8; // 32ビット単位で書き出すため
for (j = y-1; j >= 0; j--) {
for (i = 0; i < x; i++) {
if((i % 2) == 0 ) pack = (0xf & index[i][j]) << 4;
else {
pack |= (0xf & index[i][j]);
fwrite(&pack, sizechar, 1, fp);
pack = 0;
}
}
for (i = x; i < x1; i++) {
if((i % 2) == 1) {
pack |= (0xf & zero);
fwrite(&pack, sizechar, 1, fp);
pack = 0;
}
}
}
return ftell(fp);
}
// 1ビットの場合 8画素ごとに1バイトにまとめて書く
else if( bits == 1 ){
x1 = ((x - 1)/32 + 1)*32; // 32ビット単位で書き出すため
for (j = y-1; j >= 0; j--) {
pack = 0;
for (i = 0; i < x; i++) {
if(((i+1) % 8) != 0 ) {
pack |= (1 & index[i][j]) << (7-(i%8));
}
else {
pack |= (1 & index[i][j]);
fwrite(&pack, sizechar, 1, fp);
pack = 0;
}
}
for (i = x; i < x1; i++) {
if(((i+1) % 8) == 0) {
fwrite(&pack, sizechar, 1, fp);
pack = 0;
}
}
}
return ftell(fp);
}
// その他の場合
else {
printf("%dビット画像は対応しません。\n",bits);
exit(0);
}
}
/*-----------------*/
/* BITMAP 書き込み */
/*-----------------*/
void bmpwrite(char *txtfile, char *bmpfile)
{
int i, j, sx, sy, sx1, usedcolors;
short bits;
long size, offset;
double maxx, minx, maxy, miny;
unsigned char **red, **green, **blue;
// パレット情報保存用配列
unsigned char pred[256], pgreen[256], pblue[256], **index;
FILE *fp1, *fp2;
// R, G, B テキストデータ読み込みファイルオープン
if ((fp1 = fopen(txtfile, "r")) == NULL) {
openerror(txtfile);
exit(1);
}
// データ数調べ
maxdata(fp1, &sx, &sy);
// メモリ確保 R, G, B + パレット用インデックス
if ((red = malloc(sx * sizeof(char *))) == NULL) {
allocerror("redi");
}
for (i = 0; i < sx; i++) {
if ((red[i] = malloc(sy * sizeof(char))) == NULL) {
allocerror("redj");
}
for (j = 0; j < sy; j++) {
red[i][j] = 0;
}
}
if ((green = malloc(sx * sizeof(char *))) == NULL) {
allocerror("greeni");
}
for (i = 0; i < sx; i++) {
if ((green[i] = malloc(sy * sizeof(char))) == NULL) {
allocerror("greenj");
}
for (j = 0; j < sy; j++) {
green[i][j] = 0;
}
}
if ((blue = malloc(sx * sizeof(char *))) == NULL) {
allocerror("bluei");
}
for (i = 0; i < sx; i++) {
if ((blue[i] = malloc(sy * sizeof(char))) == NULL) {
allocerror("bluej");
}
for (j = 0; j < sy; j++) {
blue[i][j] = 0;
}
}
if ((index = malloc(sx * sizeof(char *))) == NULL) {
allocerror("indexi");
}
for (i = 0; i < sx; i++) {
if ((index[i] = malloc(sy * sizeof(char))) == NULL) {
allocerror("indexj");
}
for (j = 0; j < sy; j++) {
index[i][j] = 0;
}
}
// データ読み込み
dataread(fp1, sx, sy, // 入力引数
red, green, blue, index, pred, pgreen, pblue, &bits, &usedcolors); // 出力引数
fclose(fp1);
// 画像サイズ (1ラインは4Byte(long)境界にあわせる)
if( bits == 1 || bits == 4 || bits == 8 ){
if (sx % 4 != 0) { sx1 = (sx / 4 + 1)*4; }
else { sx1 = sx; }
size = sx1 * sy;
}
else if( bits == 24 || bits == 32 ){
size = sx * sy;
}
else {
printf("%dbits画像データはサポート外\n");
exit( 0 );
}
// パレットを使わない場合(24ビットの場合)
if (sx % 4 != 0) {
sx1 = (sx / 4 + 1)*4;
}
else sx1 = sx;
size = sx1 * sy * 3;
// 画像データまでのオフセット(ヘッダサイズ)
// パレットを使う場合( bits = 1, 4, 8 )
if( bits ==1 || bits == 4 || bits == 8 )
offset = 14 + 40 + 4 * (1 << bits);
// 24ビットのときはパレット無し
else if( bits == 24 || bits == 32 ) offset = 14 + 40;
// 出力ファイルオープン
if ((fp2 = fopen(bmpfile, "wb")) == NULL) {
openerror(bmpfile);
}
// ファイルヘッダ
fileheader(fp2, size, offset);
// 情報ヘッダ
bitmapheader(fp2, (long) sx, (long) sy, size, bits);
// パレットデータ(パレット有りの場合)
if( bits==1 || bits==4 || bits==8 ) {
rgbquad(fp2, bits, pred, pgreen, pblue, usedcolors);
}
// 画像データ
imagewrite(fp2, sx, sy, bits, red, green, blue, index, offset);
free(red); free(green); free(blue); free(index);
fclose(fp2);
}
/**************/
/* メイン関数 */
/**************/
int main(int argc, char *argv[])
{
int c;
char txtfile[_MAX_PATH], bmpfile[_MAX_PATH], basename[_MAX_PATH];
if (argc - optind < 1) { usage(); }
else if (argc - optind == 1) {
strcpy(txtfile, argv[optind]);
getbasename(basename, argv[optind]);
sprintf(bmpfile, "%s.bmp", basename);
}
else {
strcpy(txtfile, argv[optind]);
strcpy(bmpfile, argv[optind + 1]);
}
bmpwrite(txtfile, bmpfile);
return 0;
}
最終更新:2010年06月01日 20:48