ページ 1 / 1
どこが間違っていますか?
Posted: 2018年2月18日(日) 19:24
by fabersid
起きる問題:強制終了
もっと効率的な宣言があれば教えていただきたいです。
コード:
#include <stdio.h>
#include <string.h>
typedef struct type_BMP{
char H00[(2+1)*2]; //bfType 'As Integer 'ファイルタイプ
char H02[(2+1)*4]; //bfSize 'As Long 'ファイルサイズ[byte]
char H06[(2+1)*2]; //bfReserved1 'As Integer '予約領域1
char H08[(2+1)*2]; //bfReserved2 'As Integer '予約領域2
char H0A[(2+1)*4]; //bfOffBits 'As Long 'ファイル先頭から画像データまでのオフセット[byte]
char H0E[(2+1)*4]; //biSize 'As Long '情報ヘッダサイズ[byte]
char H12[(2+1)*4]; //biWidth 'As Long '画像の幅[ピクセル]
char H16[(2+1)*2]; //biHeight 'As Long '画像の高さ[ピクセル]
char H1A[(2+1)*2]; //biPlanes 'As Integer 'プレーン数
char H1C[(2+1)*2]; //biBitCount 'As Integer '色ビット数[bit]
char H1E[(2+1)*4]; //biCompression 'As Long '圧縮形式
char H22[(2+1)*4]; //biSizeImage 'As Long '画像データサイズ[byte]
char H26[(2+1)*4]; //biXPixPerMeter 'As Long '水平解像度[dot/m]
char H2A[(2+1)*4]; //biYPixPerMeter 'As Long '垂直解像度[dot/m]
char H2E[(2+1)*4]; //biClrUsed 'As Long '格納パレット数[使用色数]
char H32[(2+1)*4]; //biCirImportant 'As Long '重要色数
}BMP;
void BMP_set(BMP *);//,int,char);
/* 4バイトデータをリトルエンディアンに変換する */
#define ULONG_B2L(a) \
(unsigned long) \
( \
((unsigned long)(*((unsigned char *)a )) << 24) | \
((unsigned long)(*((unsigned char *)a + 1)) << 16) | \
((unsigned long)(*((unsigned char *)a + 2)) << 8) | \
((unsigned long)(*((unsigned char *)a + 3)) ) \
)
/* 2バイトデータをリトルエンディアンに変換する */
#define USHORT_B2L(a) \
(unsigned long) \
( \
((unsigned long)(*((unsigned char *)a + 2)) << 8) | \
((unsigned long)(*((unsigned char *)a + 3)) ) \
)
int main(int argc,char *argv[]){//設定値上書き用
BMP outFile;
BMP_set(&outfile);//,argc,*argv[0]);
//argc==where_exe+row
printf("%d",ULONG_B2L(16));
}
void BMP_set(BMP *outfile){//,int argc,char argv0){//初期値設定用
strncpy(outfile->H00,"42 4d",sizeof(outfile->H00));
//strcpy(file->H0A,"36 00");
}
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 21:24
by みけCAT
fabersid さんが書きました:どこが間違っていますか?
- 未定義の識別子outfileが使われている (コンパイルエラー、outFileの間違い?)
- ULONG_B2Lの「返り値」はprintfで出力するには書式%luを使うはずのunsigned long型なのに、
int型のデータを出力するための書式%dが使われている (int型のサイズとlong型のサイズが違う環境では誤動作の原因)
- 16という適当な数値をULONG_B2Lの引数として渡し、同マクロ中でそれを無理やりポインタにキャストしてデリファレンスしている (致命的)
というところが間違っていますね。
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 21:39
by みけCAT
fabersid さんが書きました:もっと効率的な宣言があれば教えていただきたいです。
「宣言」の目的によるかもしれません。
何がしたいのでしょうか?
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 22:27
by へにっくす
コードから察するに
Bitmapファイルフォーマット
http://www.umekkii.jp/data/computer/fil ... bitmap.cgi
を作成したいのでしょうか。
であればいろいろ間違っています。
何ですべてchar[]型に統一してるのでしょうか?
バイナリと文字列の違いは分かっていますか?
ULONG_B2L(16)と何で数値を引数にしているのでしょうか?
ULONG_B2Lの引数の型は数値を想定していないですよ。
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 22:42
by fabersid
例えばexe に ffffffffffffffffff000000 ffffffffffffffffff000000 ffffffffffffffffff000000
18個のf&6個の0 18個のf&6個の0 18個のf&6個の0
のようにコマンドライン引数として入力すると
白3×3のbmpができるというものを作っています。
VBA(String型がある・バイナリは不得意)や
C(String型がない・バイナリは得意)でも意外と難しい
なのでそれぞれ質問サイトで質問しプログラミングしています。
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 22:48
by へにっくす
ULONG_B2L、USHORT_B2Lなんて定義しなくてもちゃんとエンディアン変換関数があります。
ネットワーク関数の一つなので、Winsock2.hをインクルードする必要がありますが。
https://corgi-lab.com/programming/c-lang/warn-endian/
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 22:51
by へにっくす
fabersid さんが書きました:例えばexe に ffffffffffffffffff000000 ffffffffffffffffff000000 ffffffffffffffffff000000
18個のf&6個の0 18個のf&6個の0 18個のf&6個の0
のようにコマンドライン引数として入力すると
白3×3のbmpができるというものを作っています。
ということは、argvにわたってくるのは文字列なので、それをバイナリに変換する必要があるってことです。
そこのところ分かっていますか?
Re: どこが間違っていますか?
Posted: 2018年2月18日(日) 23:28
by fabersid
fopen をwbで呼び出し
argvをintに変換し
putc で ファイルに出力すればいいと思いますが、
自分だけでは組むことができません。
オフトピック
へにっくす さんが書きました:ネットワーク関数の一つなので
盲点でした。
わざわざ「-ネットワーク」をつけて調べてました。
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 00:59
by かずま
3x3 の場合、引数は 3個ですが、
1ピクセルが RGB 3バイトで、1行 3ピクセルなら 9バイト。
ビットマップファイルは、1行が 4 の倍数でなければならないので
3バイトのパディングを入れて 12バイトにし、16進文字列で
24文字ですね。パディングは 16進6文字の 0。
4x4 の場合は、引数は 4個で、1行12バイト。パディングなしの 24文字。
5x5 の場合は、引数は 5個で、1行(15+パディング1)バイトの 32文字。
コード:
#include <stdio.h> // fopen, fclose, fwrite, puts
#include <string.h> // strlen
#include <windows.h> // BITMAPFILEHEADER, BITMAPINFOHEADER
const char *filename = "3x3.bmp";
void set2(void *vp, unsigned short x)
{
char *p = (char *)vp;
p[0] = x; p[1] = x >> 8;
}
void set4(void *vp, unsigned int x)
{
char *p = (char *)vp;
p[0] = x; p[1] = x >> 8; p[2] = x >> 16; p[3] = x >> 24;
}
unsigned char *set(unsigned char *p, const char *v)
{
int x;
for (; *v; v += 2) {
sscanf(v, "%2x", &x);
*p++ = x;
}
return p;
}
int main(int argc, char *argv[])
{
if (argc < 4) return puts("no args"), 1;
int height = argc - 1;
int width = height;
int dataSize = strlen(argv[1]) / 2 * height;
int headerSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
printf("width=%d, dataSize = %d\n", width, dataSize);
static unsigned char buf[1024] = "BM";
BITMAPFILEHEADER *bf = (BITMAPFILEHEADER *)buf;
BITMAPINFOHEADER *bi = (BITMAPINFOHEADER *)(buf + sizeof(BITMAPFILEHEADER));
set4(&bf->bfSize, headerSize + dataSize);
set4(&bf->bfOffBits, headerSize);
set4(&bi->biSize, sizeof(BITMAPINFOHEADER));
set4(&bi->biWidth, width);
set4(&bi->biHeight, height);
set2(&bi->biPlanes, 1);
set2(&bi->biBitCount, 24);
set4(&bi->biSizeImage, dataSize);
unsigned char *p = buf + headerSize;
for (int i = argc; --i > 0; ) p = set(p, argv[i]);
FILE *fp = fopen(filename, "wb");
if (!fp) return puts("fopen failed"), 1;
fwrite(buf, 1, headerSize + dataSize, fp);
fclose(fp);
}
現在のコード
Posted: 2018年2月19日(月) 02:39
by fabersid
出力期待値
► スポイラーを表示
コード:
42 4d
00 00 00 00
00 00
00 00
36 00 00 00
28 00 00 00
00 00 00 00
00 00 00 00
00 00
00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
実際の出力
► スポイラーを表示
コード:
42 4d
00 00 00 00
00 00
00 00
36 00 00 00
28 00 00 00
00k00 //不定
00 //不定
00 00
00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
現在のコード
► スポイラーを表示
コード:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <winsock2.h>
typedef struct type_BMP{
char H00[(2+1)*2]; //bfType 'As Integer 'ファイルタイプ
char H02[(2+1)*4]; //bfSize 'As Long 'ファイルサイズ[byte]
char H06[(2+1)*2]; //bfReserved1 'As Integer '予約領域1
char H08[(2+1)*2]; //bfReserved2 'As Integer '予約領域2
char H0A[(2+1)*4]; //bfOffBits 'As Long 'ファイル先頭から画像データまでのオフセット[byte]
char H0E[(2+1)*4]; //biSize 'As Long '情報ヘッダサイズ[byte]
char H12[(2+1)*4]; //biWidth 'As Long '画像の幅[ピクセル]
char H16[(2+1)*4]; //biHeight 'As Long '画像の高さ[ピクセル]
char H1A[(2+1)*2]; //biPlanes 'As Integer 'プレーン数
char H1C[(2+1)*2]; //biBitCount 'As Integer '色ビット数[bit]
char H1E[(2+1)*4]; //biCompression 'As Long '圧縮形式
char H22[(2+1)*4]; //biSizeImage 'As Long '画像データサイズ[byte]
char H26[(2+1)*4]; //biXPixPerMeter 'As Long '水平解像度[dot/m]
char H2A[(2+1)*4]; //biYPixPerMeter 'As Long '垂直解像度[dot/m]
char H2E[(2+1)*4]; //biClrUsed 'As Long '格納パレット数[使用色数]
char H32[(2+1)*4]; //biCirImportant 'As Long '重要色数
}BMP;
void space_htonl(int,char []);
BMP BMP_set(int,char []);
//htons(16) 1000
//htonl(16) 10000000
int main(int argc,char *argv[]){
BMP outFile=BMP_set(argc,argv[1]);
//system("cls");
printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
outFile.H00,outFile.H02,outFile.H06,
outFile.H08,outFile.H0A,outFile.H0E,
outFile.H12,outFile.H16,outFile.H1A,
outFile.H1C,outFile.H1E,outFile.H22,
outFile.H26,outFile.H2A,outFile.H2E,
outFile.H32);
//argc==where_exe+row
}
BMP BMP_set(int argc,char argv1[]){
BMP outFile;
char row[(2+1)*4];
char col[(2+1)*4];
space_htonl(argc-1,row);
if(1<argc)space_htonl(strlen(argv1),col);
else space_htonl( 0,col);
strcpy(outFile.H00,"42 4d"); //2
strcpy(outFile.H02,"00 00 00 00"); //4
strcpy(outFile.H06,"00 00"); //2
strcpy(outFile.H08,"00 00"); //2
strcpy(outFile.H0A,"36 00 00 00"); //4
strcpy(outFile.H0E,"28 00 00 00"); //4
strcpy(outFile.H12,col); //4
strcpy(outFile.H16,row); //4
strcpy(outFile.H1A,"00 00"); //2
strcpy(outFile.H1C,"00 00"); //2
strcpy(outFile.H1E,"00 00 00 00"); //4
strcpy(outFile.H22,"00 00 00 00"); //4
strcpy(outFile.H26,"00 00 00 00"); //4
strcpy(outFile.H2A,"00 00 00 00"); //4
strcpy(outFile.H2E,"00 00 00 00"); //4
strcpy(outFile.H32,"00 00 00 00"); //4
return outFile;
}
char * str_init(char *s){
assert(s != NULL);
return strdup(s);
}
char * str_append(char *dst, char *src){
size_t dstlen;
size_t srclen;
assert(dst != NULL);
assert(src != NULL);
dstlen = strlen(dst);
srclen = strlen(src);
dst = realloc(dst, dstlen + srclen + 1);
if (dst == NULL) {
free(dst);
return NULL;
}
strncat(dst, src, srclen);
return dst;
}
void space_htonl(int num,char ret[(2+1)*4]){
int i;
char arg[2*4+1];
sprintf(arg,"%08x",htonl(num));
for(i=0;i<4;i++){
ret[i*3]=arg[i*2];
ret[i*3+1]=arg[i*2+1];
}
ret[4*3-1]='\0';
//numが固定なら配列出力用retは
//変わらないはずなのになぜか
//printf("%s",ret);は毎回ランダム
}
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 03:52
by かずま
コード:
ret[i*3+1]=arg[i*2+1]; のあとに
ret[i*3+2] = ' '; がないからでは?
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 04:28
by かずま
次のようにすれば、strcpy も space_htonl も要りません。
コード:
BMP BMP_set(int argc, char argv1[])
{
static BMP outFile = {
"42 4d", //2
"00 00 00 00", //4
"00 00", //2
"00 00", //2
"36 00 00 00", //4
"28 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00", //2
"00 00", //2
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
};
int row = argc - 1, col = 0;
if (argc > 1) col = strlen(argv1);
sprintf(outFile.H12, "%02x %02x %02x %02x",
col & 0xff, col>>8 & 0xff, col>>16 & 0xff, col>>24 & 0xff);
sprintf(outFile.H16, "%02x %02x %02x %02x",
row & 0xff, row>>8 & 0xff, row>>16 & 0xff, row>>24 & 0xff);
return outFile;
}
でも、col = strlen(argv1); は間違っていると思います。
3x3 のビットマップファイルを作りたいのに、
これでは、24x3 になってしまいますよ。
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 14:56
by fabersid
現在のコード(BMP_setの更新)
► スポイラーを表示
コード:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <winsock2.h>
typedef struct type_BMP{
char H00[(2+1)*2]; //bfType 'As Integer 'ファイルタイプ
char H02[(2+1)*4]; //bfSize 'As Long 'ファイルサイズ[byte]
char H06[(2+1)*2]; //bfReserved1 'As Integer '予約領域1
char H08[(2+1)*2]; //bfReserved2 'As Integer '予約領域2
char H0A[(2+1)*4]; //bfOffBits 'As Long 'ファイル先頭から画像データまでのオフセット[byte]
char H0E[(2+1)*4]; //biSize 'As Long '情報ヘッダサイズ[byte]
char H12[(2+1)*4]; //biWidth 'As Long '画像の幅[ピクセル]
char H16[(2+1)*4]; //biHeight 'As Long '画像の高さ[ピクセル]
char H1A[(2+1)*2]; //biPlanes 'As Integer 'プレーン数
char H1C[(2+1)*2]; //biBitCount 'As Integer '色ビット数[bit]
char H1E[(2+1)*4]; //biCompression 'As Long '圧縮形式
char H22[(2+1)*4]; //biSizeImage 'As Long '画像データサイズ[byte]
char H26[(2+1)*4]; //biXPixPerMeter 'As Long '水平解像度[dot/m]
char H2A[(2+1)*4]; //biYPixPerMeter 'As Long '垂直解像度[dot/m]
char H2E[(2+1)*4]; //biClrUsed 'As Long '格納パレット数[使用色数]
char H32[(2+1)*4]; //biCirImportant 'As Long '重要色数
}BMP;
BMP BMP_set(int,char []);
int main(int argc,char *argv[]){
BMP outFile=BMP_set(argc,argv[1]);
//system("cls");
printf("%s\n%s\t<―\n%s\n%s\n%s\n%s\n%s\n%s\n%s\t\t<―\n%s\t\t<―\n%s\n%s\t<―\n%s\n%s\n%s\n%s",
outFile.H00,outFile.H02,outFile.H06,
outFile.H08,outFile.H0A,outFile.H0E,
outFile.H12,outFile.H16,outFile.H1A,
outFile.H1C,outFile.H1E,outFile.H22,
outFile.H26,outFile.H2A,outFile.H2E,
outFile.H32);
//argc==where_exe+row
return 0;
}
BMP BMP_set(int argc, char argv1[])
{
static BMP outFile = {
"42 4d", //2
"00 00 00 00", //4
"00 00", //2
"00 00", //2
"36 00 00 00", //4
"28 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00", //2
"00 00", //2
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
"00 00 00 00", //4
};
int row = argc - 1, col = 0;
if (argc > 1) col = strlen(argv1)/8;
sprintf(outFile.H12, "%02x %02x %02x %02x",
col & 0xff, col>>8 & 0xff, col>>16 & 0xff, col>>24 & 0xff);
sprintf(outFile.H16, "%02x %02x %02x %02x",
row & 0xff, row>>8 & 0xff, row>>16 & 0xff, row>>24 & 0xff);
return outFile;
}
実行
► スポイラーを表示
コード:
BMP_maker ffffff00
42 4d
00 00 00 00 <―
00 00
00 00
36 00 00 00
28 00 00 00
01 00 00 00
01 00 00 00
00 00 <―
00 00 <―
00 00 00 00
00 00 00 00 <―
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
あとは矢印のところを計算しargvをくっつけてファイル出力するだけですよね?
出力ファイル名は後で引数に足します
コード:
現在の引数:BMP_maker.exe 16進数 16進数 16進数..........
完成時の引数:BMP_maker.exe ファイル名 16進数 16進数 16進数..........
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 19:46
by みけCAT
fabersid さんが書きました:あとは矢印のところを計算しargvをくっつけてファイル出力するだけですよね?
BMP 画像の扱いかたを参考にすると
コード:
BMP_maker ffffff00
42 4d
00 00 00 00 <― 画像ファイルの大きさ。固定、または複数の大きさに対応するなら計算する
00 00
00 00
36 00 00 00
28 00 00 00
01 00 00 00 ← 画像の横幅。3x3のビットマップを作りたかったはずなのになんで1?
01 00 00 00 ← 画像の縦幅。3x3のビットマップを作りたかったはずなのになんで1?
00 00 <― 「プレーン数」。1固定で計算の必要は無い
00 00 <― ピクセルあたりのビット数。計算というよりフォーマットに応じて決め打ち?長さから計算する?
00 00 00 00
00 00 00 00 <― 画像データ本体の大きさ。固定、または複数の大きさに対応するなら計算する
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
なので、そうだとは言えないと思います。
オフトピック
参考サイトには「識別バイト。BM(0x45 0x4d)でなければならない。」と書かれていますが、
実際のBMPファイルを確認すると42 4Dだったので、ここは現状でいいと思います。
引数を書き忘れていました。
Posted: 2018年2月19日(月) 21:53
by fabersid
すみません、引数を乗せ忘れていました。
出力を簡単にテストするために
引数:ffffff00
でテストしてました。
コード:
BMP_maker ffffff00
42 4d
00 00 00 00 <― 画像ファイルの大きさ。固定、または複数の大きさに対応するなら計算する
00 00
00 00
36 00 00 00
28 00 00 00
01 00 00 00 ← 画像の横幅。3x3のビットマップを作りたかったはずなのになんで1?
01 00 00 00 ← 画像の縦幅。3x3のビットマップを作りたかったはずなのになんで1?
00 00 <― 「プレーン数」。1固定で計算の必要は無い
00 00 <― ピクセルあたりのビット数。計算というよりフォーマットに応じて決め打ち?長さから計算する?
00 00 00 00
00 00 00 00 <― 画像データ本体の大きさ。固定、または複数の大きさに対応するなら計算する
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
Re: どこが間違っていますか?
Posted: 2018年2月19日(月) 21:57
by へにっくす
みけCAT さんが書きました:オフトピック
参考サイトには「識別バイト。BM(0x45 0x4d)でなければならない。」と書かれていますが、
実際のBMPファイルを確認すると42 4Dだったので、ここは現状でいいと思います。
BMのアスキーコードは0x42 0x4Dです。 0x45は'E'を示すので間違いですね。
参考サイトのソースにも
コード:
bmpFileHeader.bfType = 0x4d42; /* "BM" */
となっていますね。誰も突っ込まれなかったのだろうか…
先ほどの追記
Posted: 2018年2月19日(月) 22:06
by fabersid
先ほどの内容
► スポイラーを表示
すみません、引数を乗せ忘れていました。
出力を簡単にテストするために
引数:ffffff00
でテストしてました。
コード:
BMP_maker ffffff00
42 4d
00 00 00 00 <― 画像ファイルの大きさ。固定、または複数の大きさに対応するなら計算する
00 00
00 00
36 00 00 00
28 00 00 00
01 00 00 00 ← 画像の横幅。3x3のビットマップを作りたかったはずなのになんで1?
01 00 00 00 ← 画像の縦幅。3x3のビットマップを作りたかったはずなのになんで1?
00 00 <― 「プレーン数」。1固定で計算の必要は無い
00 00 <― ピクセルあたりのビット数。計算というよりフォーマットに応じて決め打ち?長さから計算する?
00 00 00 00
00 00 00 00 <― 画像データ本体の大きさ。固定、または複数の大きさに対応するなら計算する
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
計算するといっても詰め物である00の数がわからない以上
ファイルとデータ本体の大きさがわかりません。
また、初期値の値を変更したので
「プレーン数」とピクセル当たりのビット数(biBitCount 2byte 色ビット数[bit])
がそれぞれ
01 00(10行目)
18 00(11行目)
になりました。
現在のコード
► スポイラーを表示
コード:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <winsock2.h>
typedef struct type_BMP{
char H00[(2+1)*2]; //bfType 'As Integer 'ファイルタイプ
char H02[(2+1)*4]; //bfSize 'As Long 'ファイルサイズ[byte]
char H06[(2+1)*2]; //bfReserved1 'As Integer '予約領域1
char H08[(2+1)*2]; //bfReserved2 'As Integer '予約領域2
char H0A[(2+1)*4]; //bfOffBits 'As Long 'ファイル先頭から画像データまでのオフセット[byte]
char H0E[(2+1)*4]; //biSize 'As Long '情報ヘッダサイズ[byte]
char H12[(2+1)*4]; //biWidth 'As Long '画像の幅[ピクセル]
char H16[(2+1)*4]; //biHeight 'As Long '画像の高さ[ピクセル]
char H1A[(2+1)*2]; //biPlanes 'As Integer 'プレーン数
char H1C[(2+1)*2]; //biBitCount 'As Integer '色ビット数[bit]
char H1E[(2+1)*4]; //biCompression 'As Long '圧縮形式
char H22[(2+1)*4]; //biSizeImage 'As Long '画像データサイズ[byte]
char H26[(2+1)*4]; //biXPixPerMeter 'As Long '水平解像度[dot/m]
char H2A[(2+1)*4]; //biYPixPerMeter 'As Long '垂直解像度[dot/m]
char H2E[(2+1)*4]; //biClrUsed 'As Long '格納パレット数[使用色数]
char H32[(2+1)*4]; //biCirImportant 'As Long '重要色数
}BMP;
BMP BMP_set(int,char []);
int main(int argc,char *argv[]){
BMP outFile=BMP_set(argc,argv[1]);
//system("cls");
printf("%s\n%s\t<―\n%s\n%s\n%s\n%s\n%s\n%s\n%s\t\t<―\n%s\t\t<―\n%s\n%s\t<―\n%s\n%s\n%s\n%s",
outFile.H00,outFile.H02,outFile.H06,
outFile.H08,outFile.H0A,outFile.H0E,
outFile.H12,outFile.H16,outFile.H1A,
outFile.H1C,outFile.H1E,outFile.H22,
outFile.H26,outFile.H2A,outFile.H2E,
outFile.H32);
//argc==where_exe+row
return 0;
}
BMP BMP_set(int argc, char argv1[])
{
static BMP outFile = {
"42 4d", //2 ファイルタイプ
"00 00 00 00", //4 ファイルサイズ[byte]
"00 00", //2 予約領域1
"00 00", //2 予約領域2
"36 00 00 00", //4 ファイル先頭から画像データまでのオフセット[byte]
"28 00 00 00", //4 情報ヘッダサイズ[byte]
"00 00 00 00", //4 画像の幅[ピクセル]
"00 00 00 00", //4 画像の高さ[ピクセル]
"01 00", //2 プレーン数
"18 00", //2 色ビット数[bit]
"00 00 00 00", //4 圧縮形式
"00 00 00 00", //4 画像データサイズ[byte]
"00 00 00 00", //4 水平解像度[dot/m]
"00 00 00 00", //4 垂直解像度[dot/m]
"00 00 00 00", //4 格納パレット数[使用色数]
"00 00 00 00", //4 重要色数
};
int row = argc - 1, col = 0;
if (argc > 1) col = strlen(argv1)/8;
sprintf(outFile.H12, "%02x %02x %02x %02x",
col & 0xff, col>>8 & 0xff, col>>16 & 0xff, col>>24 & 0xff);
sprintf(outFile.H16, "%02x %02x %02x %02x",
row & 0xff, row>>8 & 0xff, row>>16 & 0xff, row>>24 & 0xff);
return outFile;
}
char * str_init(char *s){
assert(s != NULL);
return strdup(s);
}
char * str_append(char *dst, char *src){
size_t dstlen;
size_t srclen;
assert(dst != NULL);
assert(src != NULL);
dstlen = strlen(dst);
srclen = strlen(src);
dst = realloc(dst, dstlen + srclen + 1);
if (dst == NULL) {
free(dst);
return NULL;
}
strncat(dst, src, srclen);
return dst;
}
void space_htonl(int num,char ret[(2+1)*4]){
int i;
char arg[2*4+1];
sprintf(arg,"%08x",htonl(num));
for(i=0;i<4;i++){
ret[i*3]=arg[i*2];
ret[i*3+1]=arg[i*2+1];
ret[i*3+2]=' ';
}
ret[4*3-1]='\0';
//numが固定なら配列出力用retは
//変わらないはずなのになぜか
//printf("%s",ret);は毎回ランダム
}
Re: どこが間違っていますか?
Posted: 2018年2月20日(火) 10:43
by かずま
ビットマップファイルというバイナリファイルを作りたいのに、
文字列のデータをプログラム内に作るという意味が理解できません。
No.9 のプログラムは無視されたようですね。
引数でデータを指定すると大きなビットマップファイルが
作りづらいのでファイルから読み込むようにしました。
mkbm.c
コード:
#include <stdio.h> // fopen, fclose, fscanf, fwrite, fputc
#include <windows.h> // BITMAPFILEHEADER, BITMAPINFOHEADER
#define HEADER_SIZE (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER))
int main(int argc, char *argv[])
{
FILE *fin, *fout;
int width, height, widthByte, padding, dataSize, byte, i, j;
BITMAPFILEHEADER bf = { 0 };
BITMAPINFOHEADER bi = { 0 };
if (argc < 3) return printf("usage: %s infile outfile\n", argv[0]), 1;
fin = fopen(argv[1], "r");
if (!fin) return printf("can't open %s\n", argv[1]), 2;
fout = fopen(argv[2], "wb");
if (!fout) return printf("can't create %s\n", argv[2]), 3;
if (fscanf(fin, "%d%d", &width, &height) != 2)
return puts("width, height: read error"), 4;
widthByte = width * 3;
padding = ((widthByte + 3) & ~3) - widthByte;
dataSize = (widthByte + padding) * height;
bf.bfType = 0x4d42; // "BM" little endian
bf.bfSize = HEADER_SIZE + dataSize;
bf.bfOffBits = HEADER_SIZE;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = height;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biSizeImage = dataSize;
fwrite(&bf, 1, sizeof bf, fout);
fwrite(&bi, 1, sizeof bi, fout);
for (i = 0; i < height; i++) {
for (j = 0; j < widthByte; j++) {
if (fscanf(fin, "%2x", &byte) != 1)
return puts("can't read image data"), 5;
fputc(byte, fout);
}
for (j = 0; j < padding; j++) fputc(0, fout);
}
fclose(fout);
fclose(fin);
return 0;
}
3x3.txt
コード:
3 3
000000 0000ff 00ff00
00ffff ffffff ff0000
ff00ff ffff00 808080
実行例
コード:
C:\tmp\BM>mkbm 3x3.txt 3x3.bmp
できた 3x3.bmp をペイントで開いてみましょう。
上下は逆になります。
また、certutil -f -encodehex 3x3.bmp 3x3dmp.txt で
16進ダンプファイルを作り、それを見てもよいでしょう。
入力ファイルのデータは、16進2文字ずつ読み込むので
スペースや改行は適当に入れて構いません。
パディングは内部で計算するので、データには含めません。
Re: どこが間違っていますか?
Posted: 2018年2月20日(火) 11:52
by かずま
かずま さんが書きました:
コード:
padding = ((widthByte + 3) & ~3) - widthByte;
padding の計算はもっと簡単にできます。
コード:
padding = -widthByte & 3;
Re: どこが間違っていますか?
Posted: 2018年2月20日(火) 20:25
by fabersid
かずま さんが書きました:ビットマップファイルというバイナリファイルを作りたいのに、
文字列のデータをプログラム内に作るという意味が理解できません。
No.9 のプログラムは無視されたようですね。
>文字列のデータをプログラム内に作るという意味が理解できません。
冗長性がありますがコードで書くよりも少なくとも
私は理解しやすかったからです。また、コードを参考に
今度は質問サイトを使わずにそのほかの
画像にも対応させたいため
定数部(BMなど)の変更を容易にしました。
>No.9 のプログラムは無視されたようですね。
すみませんまだ読んでません
プログラムを組むこととネットを見ることが
同時にできない環境で8割は数多くのエラーを
眺めて修正してという風にしてますので
このコメントを書き込んでいる媒体では
プログラミングができません。
フォーラムチェック用に借りました。
次にC言語開発ができるのは
早くて2月23日、遅くて4月といった具合です。
なので、コメントを読み動作を予想することしかできません。
Re: 先ほどの追記
Posted: 2018年2月21日(水) 20:08
by かずま
fabersid さんが書きました:
計算するといっても詰め物である00の数がわからない以上
ファイルとデータ本体の大きさがわかりません。
BM_maker.c
コード:
#include <stdio.h>
#include <string.h> // strlen
typedef struct type_BMP {
char H00[(2+1)*2]; //bfType 'As Integer 'ファイルタイプ
char H02[(2+1)*4]; //bfSize 'As Long 'ファイルサイズ[byte]
char H06[(2+1)*2]; //bfReserved1 'As Integer '予約領域1
char H08[(2+1)*2]; //bfReserved2 'As Integer '予約領域2
char H0A[(2+1)*4]; //bfOffBits 'As Long 'ファイル先頭から画像データまでのオフセット[byte]
char H0E[(2+1)*4]; //biSize 'As Long '情報ヘッダサイズ[byte]
char H12[(2+1)*4]; //biWidth 'As Long '画像の幅[ピクセル]
char H16[(2+1)*4]; //biHeight 'As Long '画像の高さ[ピクセル]
char H1A[(2+1)*2]; //biPlanes 'As Integer 'プレーン数
char H1C[(2+1)*2]; //biBitCount 'As Integer '色ビット数[bit]
char H1E[(2+1)*4]; //biCompression 'As Long '圧縮形式
char H22[(2+1)*4]; //biSizeImage 'As Long '画像データサイズ[byte]
char H26[(2+1)*4]; //biXPixPerMeter 'As Long '水平解像度[dot/m]
char H2A[(2+1)*4]; //biYPixPerMeter 'As Long '垂直解像度[dot/m]
char H2E[(2+1)*4]; //biClrUsed 'As Long '格納パレット数[使用色数]
char H32[(2+1)*4]; //biCirImportant 'As Long '重要色数
} BMP;
BMP BMP_set(int, char []);
int main(int argc, char *argv[])
{
BMP outFile = BMP_set(argc, argv[1]);
printf("%s\n%s\t<―\n%s\n%s\n%s\n%s\n%s\n%s\n"
"%s\t\t<―\n%s\t\t<―\n%s\n%s\t<―\n%s\n%s\n%s\n%s\n",
outFile.H00, outFile.H02, outFile.H06,
outFile.H08, outFile.H0A, outFile.H0E,
outFile.H12, outFile.H16, outFile.H1A,
outFile.H1C, outFile.H1E, outFile.H22,
outFile.H26, outFile.H2A, outFile.H2E,
outFile.H32);
return 0;
}
void set4(char *p, int x)
{
sprintf(p, "%02x %02x %02x %02x",
x & 0xff, x>>8 & 0xff, x>>16 & 0xff, x>>24 & 0xff);
}
BMP BMP_set(int argc, char argv1[])
{
static BMP outFile = {
"42 4d", //2 ファイルタイプ
"00 00 00 00", //4 ファイルサイズ[byte]
"00 00", //2 予約領域1
"00 00", //2 予約領域2
"36 00 00 00", //4 ファイル先頭から画像データまでのオフセット[byte]
"28 00 00 00", //4 情報ヘッダサイズ[byte]
"00 00 00 00", //4 画像の幅[ピクセル]
"00 00 00 00", //4 画像の高さ[ピクセル]
"01 00", //2 プレーン数
"18 00", //2 色ビット数[bit]
"00 00 00 00", //4 圧縮形式
"00 00 00 00", //4 画像データサイズ[byte]
"00 00 00 00", //4 水平解像度[dot/m]
"00 00 00 00", //4 垂直解像度[dot/m]
"00 00 00 00", //4 格納パレット数[使用色数]
"00 00 00 00", //4 重要色数
};
int row = argc - 1;
int col = row;
int colByte = col * 3; // RGB24ビット、3バイト/ピクセル
int padding = -colByte & 3; // 4の倍数にするための詰め物(0~3)
int dataSize = (colByte + padding) * row;
int fileSize = 14 + 40 + dataSize;
if (argc > 1 && strlen(argv1) != (colByte + padding) * 2u)
printf("'%s': invalid length\n", argv1);
set4(outFile.H02, fileSize);
set4(outFile.H12, col);
set4(outFile.H16, row);
set4(outFile.H22, dataSize);
return outFile;
}
実行例
コード:
C:\tmp\BM>BM_maker ffffff00
42 4d
3a 00 00 00 <―
00 00
00 00
36 00 00 00
28 00 00 00
01 00 00 00
01 00 00 00
01 00 <―
18 00 <―
00 00 00 00
04 00 00 00 <―
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
C:\tmp\BM>BM_maker ffffffffffffffffff000000 ffffffffffffffffff000000 ffffffffffffffffff000000
42 4d
5a 00 00 00 <―
00 00
00 00
36 00 00 00
28 00 00 00
03 00 00 00
03 00 00 00
01 00 <―
18 00 <―
00 00 00 00
24 00 00 00 <―
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00
このあと、どうやってビットマップファイルの作るんでしょうか?
Re: 先ほどの追記
Posted: 2018年2月23日(金) 06:54
by かずま
かずま さんが書きました:
このあと、どうやってビットマップファイルの作るんでしょうか?
こうやってビットマップファイルを作っては、いかがでしょうか?
コード:
void put2(FILE *fp, const char *p)
{
int x[2];
sscanf(p, "%x%x", x, x + 1);
fputc(x[0], fp), fputc(x[1], fp);
}
void put4(FILE *fp, const char *p)
{
int x[4], i;
sscanf(p, "%x%x%x%x", x, x + 1, x + 2, x + 3);
for (i = 0; i < 4; i++) fputc(x[i], fp);
}
int BMP_put(const BMP *bmp, const char *name, int argc, char *argv[])
{
int x, i;
char *p;
FILE *fp = fopen(name, "wb");
if (!fp) return printf("can't create %s\n", name), 3;
put2(fp, bmp->H00); put4(fp, bmp->H02); put2(fp, bmp->H06);
put2(fp, bmp->H08); put4(fp, bmp->H0A); put4(fp, bmp->H0E);
put4(fp, bmp->H12); put4(fp, bmp->H16); put2(fp, bmp->H1A);
put2(fp, bmp->H1C); put4(fp, bmp->H1E); put4(fp, bmp->H22);
put4(fp, bmp->H26); put4(fp, bmp->H2A); put4(fp, bmp->H2E);
put4(fp, bmp->H32);
for (i = argc; --i > 0; )
for (p = argv[i]; p[0] && p[1]; p += 2) {
if (sscanf(p, "%2x", &x) != 1)
return puts("image data: read error"), 4;
fputc(x, fp);
}
fclose(fp);
return 0;
}
そして、main の return 0; を次のように変更します。
コード:
return BMP_put(&outFile, "out.bmp", argc, argv);
出力ファイルの名前が固定ですが、コマンドラインの
引数で指定したいのなら、さらに変更が必要です。