スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

C言語によるBMP編集 その2

読み込もうと思っていたbmp画像がパレットタイプだったので適応。

詳細は前の記事。
http://shonen9th.blog.fc2.com/blog-entry-53.html

今回は構造体を定義してあります…一部外道な手段を取っていますが。


2015/09/07追記
良く考えたら256色bmpしか読み込めない。if文で弾いておきました。
libeasybmp.h

typedef struct defRGB{
unsigned char b;
unsigned char g;
unsigned char r;
}RGB,RGBt;

typedef struct defRGBq{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char a;
}RGBq;

typedef struct defImage{
int width;
int height;
RGB *data;
}Image;

typedef struct defImagePat{
int width;
int height;
int numpalette;
unsigned char *data;
RGBq *palette;
}ImagePat;

// Image領域をmallocする
Image* createimage(int,int);
// 解放
void freeimage(Image *);

// ImagePat領域をmallocする
ImagePat* createimagePat(int,int,int);
// 解放
void freeimagePat(ImagePat *);

// bmpファイルを読み込む
// パレットbmp等であれば変換する。
Image* loadbmp(const char *);
// パレットbmpを読み込む。パレットは保持される。
//ImagePat* loadbmpPat(const char *);

// Imageをbmpに保存する。
void savebmp(const Image *,const char *);
// ImagePatをbmpに保存する。パレットは保持される。
//void savebmpPat(const ImagePat *,const char *);

// ImagePatをImageに変換する
Image* convertImage(ImagePat *);

// RGBq -> RGB の変換
// 確保済みであること
void convertRGBq2t(RGBq *,RGB *);


libeasybmp.c

// int 4byte / short 2byte / char 1byte

#include <stdio.h>
#include <stdlib.h>
#include "libeasybmp.h"

// define byte
typedef unsigned char byte;

// -------------------------------------------
// Header Struct
// -------------------------------------------
typedef struct defBmpFileHeader{
byte filetype [2];
byte size [4];
byte reserved1[2];
byte reserved2[2];
byte offsetBit[4];
byte infosize [4];
}BmpFileHeader;

typedef struct defBmpInfoHeader{
byte size[4];
byte width[4];
byte height[4];
byte planes[2];
byte bitcount[2];
byte compression[4];
byte sizeimage[4];
byte xdpm[4];
byte ydpm[4];
byte cused[4];
byte cimp[4];
}BmpInfoHeader;

/*
typedef struct defRGBquad{
byte b;
byte g;
byte r;
byte reserved;
}RGBquad;
*/

// -------------------------------------------
// memory allocate
// -------------------------------------------

Image* createimage(int w,int h){
Image *img = (Image*)malloc(sizeof(Image));
if (img == 0) return 0;
img->width =w;
img->height=h;
// note:余分な3byteを付加
img->data = (RGB*)malloc(sizeof(RGB)*(w*h)+3);

return img;
}
void freeimage(Image *img){
free(img->data);
free(img);
}

ImagePat* createimagePat(int w,int h,int pat){
ImagePat *img = (ImagePat*)malloc(sizeof(ImagePat));
img->width =w;
img->height=h;
img->numpalette=pat;
img->data =(unsigned char*)malloc(sizeof(unsigned char)*(w*h));
img->palette= (RGBq*)malloc(sizeof(RGBq)*pat);
return img;
}

void freeimagePat(ImagePat *img){
free(img->data);
free(img->palette);
free(img);
}


// -------------------------------------------
// load
// -------------------------------------------

Image* loadbmp(const char *filename){
FILE *fp;
Image *image;
ImagePat *imagepat;
int bit_pix,cpxtype,colornum;
int i,l;
BmpFileHeader bfh;
BmpInfoHeader bih;

if (filename == 0){
printf("loadbmp:filename null\n");
return 0;
}
if ((fp = fopen(filename,"r")) == 0){
printf("loadbmp:failed open file\n");
return 0;
}

// read header + infosize
fread(&bfh,1,18,fp);

// "BM"であることを調べる
if (bfh.filetype[0]!='B' || bfh.filetype[1]!='M'){
printf("loadbmp:not bmp file\n");
return 0;
}

// 情報ヘッダのサイズが40のヘッダでなければ
// 読み込まない(思考放棄)
if (*(int*)(bfh.infosize)!=40){
printf("loadbmp:not INFO type\n");
goto loadbmp_close;
}

// 続きを読み込む(INFO)
fread((bih.width),1,36,fp);

// bitfield持ってるor圧縮されたファイルは
// 読み込まない(思考放棄)
cpxtype = *(int*)(bih.compression);
if (cpxtype==3){
printf("loadbmp:bitfields\n");
goto loadbmp_close;
}
if (cpxtype!=0){
printf("loadbmp:compressed bmp\n");
goto loadbmp_close;
}
// bit per pixel
bit_pix=*(int*)(bih.bitcount);
// ビットフィールドのファイルを読み込まない
// (放棄)
if (bit_pix==16 || bit_pix==32){
printf("loadbmp:palette bmp\n");
goto loadbmp_close;
}

if (bit_pix==24){
// 24bitImage

// カラーインデックス数(24bitパレット)
if (*(int*)(bih.cused)>1){
printf("loadbmp:3byte palette\n");
goto loadbmp_close;
}

// image構造体作成
image = createimage(*(int*)(bih.width),*(int*)(bih.height));

// イメージデータサイズは信用しない
// イメージデータオフセットの適応
if (*(int*)(bfh.offsetBit)!=0)
fseek(fp,*(int*)(bfh.offsetBit),SEEK_SET);

// note:行データは4nbyteでなければならない
l = ((image->width)*3+3)/4;
for (i=0;i<(image->height);i++)
fread(&(image->data[i*(image->width)]),4,l,fp);

// 最後も同様に操作すると一般にオーバーフローするよ
// image型に助長を含ませる対策

//}else if (bit_pix==1 || bit_pix==4 || bit_pix==8){
}else if (bit_pix==8){
// palette Image

// カラーインデックス数
colornum=*(int*)(bih.cused);
if (colornum==0) colornum=1<<bit_pix;

// パレットイメージ作成
imagepat = createimagePat(*(int*)(bih.width),*(int*)(bih.height),colornum);
// パレット読み込み
fread(imagepat->palette,4,colornum,fp);

//
// イメージデータサイズは信用しない
// イメージデータオフセットの適応
if (*(int*)(bfh.offsetBit)!=0)
fseek(fp,*(int*)(bfh.offsetBit),SEEK_SET);

// note:行データは4nbyteでなければならない
l = ((imagepat->width)*bit_pix+31)/32;
for (i=0;i<(imagepat->height);i++)
fread(&(imagepat->data[i*(imagepat->width)]),4,l,fp);

image = convertImage(imagepat);

// パレット画像は解放
freeimagePat(imagepat);
}else{
// ピクセル毎のビット数が不明
printf("loadbmp:bitcount error\n");
goto loadbmp_close;
}

loadbmp_close:
fclose(fp);
return image;
}


// -------------------------------------------
// save
// -------------------------------------------

void savebmp(const Image *image,const char *filename){
FILE *fp;
int imagesize;
int i,l;
BmpFileHeader bph;
BmpInfoHeader bih;
if (image == 0 || filename == 0) return;
if ((fp = fopen(filename,"w")) == 0) return;


// note:行データは4nbyteでなければならない
l = ((image->width)*3+3)/4;

imagesize=l*4*(image->height);
// fileHeader
bph.filetype[0] ='B';
bph.filetype[1] ='M';
*(int*)(bph.size)=54+imagesize; // filesize
*(short*)(bph.reserved1)=0;
*(short*)(bph.reserved2)=0;
*(int*)(bph.offsetBit)=54;

// infomationHeader INFO
*(int*)(bih.size)=40;
*(int*)(bih.width)=image->width;
*(int*)(bih.height)=image->height;
*(short*)(bih.planes)=1;
*(short*)(bih.bitcount)=24;
*(int*)(bih.compression)=0;
*(int*)(bih.sizeimage)=0; //imagesize;
*(int*)(bih.xdpm)=0;
*(int*)(bih.ydpm)=0;
*(int*)(bih.cused)=0; // nopalette
*(int*)(bih.cimp)=0; //clrImpt

fwrite(&bph,1,14,fp);
fwrite(&bih,1,40,fp);

for (i=0;i<(image->height);i++)
fwrite(&(image->data[i*(image->width)]),4,l,fp);
//本来は末端はゴミではなく0で埋めるべき

// 最後も同様に操作すると一般にオーバーフローするよ
// image型に助長を含ませる対策

fclose(fp);
}

// -------------------------------------
// convertreate
// -------------------------------------
Image* convertImage(ImagePat *imgp){
int i,size;
Image *img;
img = createimage(imgp->width,imgp->height);
size = (imgp->width)*(imgp->height);
for (i=0;i<size;i++){
convertRGBq2t(&(imgp->palette[imgp->data[i]]),&(img->data[i]));
}
return img;
}

// RGBq -> RGB
// 確保済みであること
void convertRGBq2t(RGBq *from,RGB *to){
to->b = from->b;
to->g = from->g;
to->r = from->r;
}


必要になったらコメントアウトの関数や、RLE圧縮のbmpの読み込み・保存も実装しますが、不要でしょう。

そもそもRLEにぶち当たったら他のライブラリに頼りますけどね。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

tag : C 画像解析

コメントの投稿

非公開コメント

ブログ移転のお知らせ
ブログをshonen.hateblo.jpに移転します. 新規の記事はこちらに投稿します.
プロフィール

舞葉(ぶよう)

Author:舞葉(ぶよう)
github.io
はてなブログ(競プロ)

古い記事のソースコードは色分けしていないので、高機能テキストエディタに貼り付けたほうが見やすいかも。

検索フォーム
このブログについて
自分がつまづいた話題、なんとなく書きたいと思ったこと、ググったけど殆ど資料なかったぞオイ な話等をアップする予定。通りすがりでも、参考になっていただければと。プログラムの例外入力、メモリリークは責任負いません。投稿された記事は修正・削除する場合があります。
カテゴリ
タグ

HSP3アルゴリズムとデータ構造c++RubyJavaUnity画像解析C機械学習C#LinuxcodeIQKinectMinecraftTonyuSystemraspberrypiPythonHTML5音声制御Simulinkruby俺ルール通信制御Javascriptシミュレーション

counter-shinobi
固定記事
最新記事
最新コメント
月別アーカイブ
ブロとも申請フォーム

この人とブロともになる

アクセスランキング
[ジャンルランキング]
コンピュータ
635位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
94位
アクセスランキングを見る>>
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。