FC2ブログ

ホーム > GIFファイルフォーマット > GIFファイルの書き込み 第3部

GIFファイルの書き込み 第3部



「GIFファイルの書き込み 第3部」では、 ANI/ICO→GIFGIF→ANI/ICOファイル変換とそのサンプルプログラムを紹介します。



グループアイコンやアニメーションカーソルのファイル操作には、以下のインクルード定義が必要となります。

#include "GroupIcon.h"
#include "ANIFile.h"
#include "PNGFile.h"
#include "DIBFile.h"
#include "MedianCut.h"
#include "Dither.h"


上記インクルード定義で必要となるファイルです。

ANIFile.h ANIFile.cpp
GroupIcon.h GroupIcon.cpp
PNGFile.h PNGFile.cpp
DIBFile.h DIBFile.cpp
Rle.h Rle.cpp
MedianCut.h MedianCut.cpp
Dither.h Dither.cpp


libpngのインストール」でダウンロードした二つのフォルダーから、以下のファイルを今回のプログラムを格納したファイルのあるフォルダーにコピーしておきます。

//「lpng143」フォルダーからコピーするファイル
png.h
pngconf.h

//「zlib」フォルダーからコピーするファイル
zlib.h
zconf.h


アイコン/カーソルGIFファイルに書き込む関数です。

//アイコン/カーソルをGIFファイルに書き込みます。
BOOL __stdcall _SaveGIF(LPCTSTR lpszFileName,HICON hIcon)
{
//入力されたアイコンハンドルのICONINFO構造体を取得します。
ICONINFO IconInfo={0};
if (!::GetIconInfo(hIcon,&IconInfo)) return FALSE;
//CGIFLocalクラスを作成して、取得したアイコンのDIBを格納します。
CGIFLocal* pLocal=new CGIFLocal(IconInfo.hbmColor,IconInfo.hbmMask);
//CGIFFileクラスを作成して、作成したCGIFLocalクラスへのポインタを格納します。
CGIFFile GIFFile(0);
GIFFile.AddLocal(pLocal);
//CGIFFileクラスSaveFile関数でGIFファイルに書き込みます。
return GIFFile.SaveFile(lpszFileName);
}


アニメーションカーソル(CANIFileクラス)をGIFファイルに書き込む関数です。

//アニメーションカーソル(CANIFileクラス)をGIFファイルに書き込みます。
BOOL __stdcall _SaveGIF(LPCTSTR lpszFileName,CANIFile* pANIFile)
{
if(!AfxIsValidAddress(pANIFile,sizeof(CANIFile),FALSE)) return FALSE;
//アニメーションのコマ数を取得します。
DWORD nSteps=pANIFile->GetCount();
if (!nSteps) return FALSE;
//CGIFFileクラスを定義します。
CGIFFile GIFFile(0);
for(UINT i=0;i<nSteps;i++){
//CANIFileクラスの現在着目している、CIconへのポインタを取得します。
ICONINFO IconInfo={0};
CIcon* pIcon=pANIFile->GetGroupIcon(i)->GetActiveIcon();
//取得したCIconからICONINFO構造体を取得します。
if ((pIcon)&&(pIcon->GetIconInfo(&IconInfo))){
//CANIFileクラスからJIF時間を取得し、10ms単位に変換します。
UINT delay=ROUND((double)(pANIFile->GetRate(i))*ANI_PERIOD/10.0);
//マスク画像にマスク情報があれば2(背景色にディスポースする。)、
//それ以外は1(何もしない。)にディスポサル方法を設定します。

int disposalMethod=((_IsValidMaskDIB(IconInfo.hbmMask)||pIcon->BitCount()==32))?2:1;
//CGIFFileクラスを作成して、取得したアイコンのDIBを格納します。
CGIFLocal* pLocal=new CGIFLocal(IconInfo.hbmColor,IconInfo.hbmMask,delay,disposalMethod);
GIFFile.AddLocal(pLocal);
}
else return FALSE;
}
//著作者名があればコメントとして格納します。
if (!pANIFile->m_strAuthorName.IsEmpty())
GIFFile.m_strComment.SetString(pANIFile->m_strAuthorName.GetBuffer());
//上記以外でファイル名があれば、コメントとして格納します。
else if (!pANIFile->m_strFileName.IsEmpty())
GIFFile.m_strComment.SetString(pANIFile->m_strFileName.GetBuffer());

//CGIFFileクラスSaveFile関数でGIFファイルに書き込みます。
return GIFFile.SaveFile(lpszFileName);
}

//入力されたマスクDIBが有効かどうかを調べます。
BOOL __stdcall _IsValidMaskDIB(HBITMAP hbmMask)
{
//入力されたマスクビットマップから、32ビットDIBを作成します。
HBITMAP hbmMask32=_CopyDIB(hbmMask,32,0);
//BITMAP構造体を取得します。
BITMAP bm={0};
if (!::GetObject(hbmMask32,sizeof(BITMAP),&bm)) return FALSE;
//ピクセル数を算出します。
UINT nPixels=(bm.bmHeight*bm.bmWidthBytes)>>2;
DWORD* src=(DWORD*)bm.bmBits;
//マスクデータがあるか検査します。
for (UINT i=0;i<nPixels;i++)
//マスクデータがあれば、TRUEを戻して終了します。
if ((*src++)!=0) return TRUE;

//黒一色だったので、FALSEを戻して終了します。
return FALSE;
}


CGIFFileからアニメーションカーソルCANIFileクラス)を作成して、ANIファイルに保存する関数です。

//CGIFFileクラスからCANIFileクラスを作成して、ファイルに保存します。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

BOOL __stdcall _SaveANI(LPCTSTR lpszFileName,CGIFFile* pGIFFile,BOOL bIcon,DWORD xHotspot,DWORD yHotspot,
int iPNGMinimumSize)
{
if (!AfxIsValidAddress(pGIFFile,sizeof(CGIFFile),FALSE)) return FALSE;

//CGIFFileクラス内の画像数を取得します。
UINT nImages=pGIFFile->m_nImageCount;
if (!nImages) return FALSE;

CANIFile ANIFile(0);
//画像数が複数の場合は、ANIHEADER構造体を新たに作成します。
//(画像数が一個の場合は自動的に作成されます。)

if (nImages>1){
ANIHEADER AniHeader;
::ZeroMemory(&AniHeader,sizeof(ANIHEADER));
AniHeader.dwSize =sizeof(ANIHEADER);
AniHeader.dwFrames =(DWORD)nImages;
AniHeader.dwSteps =AniHeader.dwFrames;
AniHeader.dwDefaultRate=60;
AniHeader.dwFlags =ANI_FLAG_ICON;
::CopyMemory(&ANIFile.m_AniHeader,&AniHeader,sizeof(ANIHEADER));
}
ANIFile.SetType((bIcon)? RT_ANIICON:RT_ANICURSOR);
//CGIFLocalクラスのメンバー変数から、
//CGroupIconクラスを作成して、リストに格納します。

for(UINT i=0;i<nImages;i++){
CGIFLocal* pLocal=pGIFFile->GetLocal(i);
//表示時間の単位を㍉秒からジフ速度に変更します。
UINT rate=ROUND((double)(pLocal->m_delay*10)/ANI_PERIOD);
if (rate==0) rate=1;
ANIFile.SetRate(i,rate);
//CGIFLocalクラス内のビットマップ画像からCGroupIconクラスを作成します。
CGroupIcon* pGrpIcon=_DIBToGroupIcon(pLocal->m_hbmColor,pLocal->m_hbmMask,bIcon,xHotspot,yHotspot,
iPNGMinimumSize);
if (!pGrpIcon) return FALSE;
//CANIFileクラスに格納します。
ANIFile.m_listGrpIcon.Add(pGrpIcon);
}

//コメントがあればCANIFileクラスの著作者名に格納します。
if(!pGIFFile->m_strComment.IsEmpty())
ANIFile.m_strAuthorName.SetString(pGIFFile->m_strComment.GetBuffer());

//CANIFileクラスSaveFileを呼び出して、ファイルに書き込みます。
return ANIFile.SaveFile(lpszFileName,TRUE,iPNGMinimumSize);
}


CGIFFileの現在着目している画像から、グループアイコンを作成してアイコンファイルに保存する関数です。

//CGIFFileクラスからグループアイコンを作成して、ファイルに保存します。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

BOOL __stdcall _SaveGrpIcon(LPCTSTR lpszFileName,CGIFFile* pGIFFile,BOOL bIcon,DWORD xHotspot,DWORD yHotspot,
iPNGMinimumSize)
{
if (!AfxIsValidAddress(pGIFFile,sizeof(CGIFFile),FALSE)) return FALSE;

//入力されたCGIFFileクラス内で、現在選択されているCGIFLocalクラスを取り出します。
CGIFLocal* pLocal=pGIFFile->GetLocal(pGIFFile->m_nImage);
//CGIFLocalクラス内のビットマップハンドルから、CGroupIconクラスを作成します。
CGroupIcon* pGrpIcon=_DIBToGroupIcon(pLocal->m_hbmColor,pLocal->m_hbmMask,bIcon,xHotspot,yHotspot,iPNGMinimumSize);
//CGroupIconクラスSaveFileを呼び出して、ファイルに書き込みます。
BOOL bResult=pGrpIcon->SaveFile(lpszFileName,(bIcon)?RT_GROUPICON:RT_GROUPICON,TRUE,iPNGMinimumSize);
//CGroupIconクラスはもう要らないので削除します。
delete pGrpIcon;
return bResult;
}

//CGIFLocalクラスからCGroupIconクラスを作成します。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

CGroupIcon* __stdcall _DIBToGroupIcon(HBITMAP hbmColor,HBITMAP hbmMask,BOOL bIcon,DWORD xHotspot,DWORD yHotspot,
int iPNGMinimumSize)
{
//入力されたビットマップのBITMAP構造体を取得します。
BITMAP bm;
if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)) return FALSE;

//ビットマップの幅と高さを取得します。
UINT width =bm.bmWidth;
UINT height=abs(bm.bmHeight);

//iPNGMinimumSizeの値に従ってPNG圧縮するかどうかを決めます。
BOOL bCompressedPNG=((iPNGMinimumSize>0)&&(iPNGMinimumSize<=256)&&
(width>=(UINT)iPNGMinimumSize)&&(height>=(UINT)iPNGMinimumSize));

//ICONINFO構造体を作成します。
ICONINFO IconInfo={0};
IconInfo.fIcon=bIcon;
//PNG圧縮する場合は、カラー画像をDDB->DIB変換します。
IconInfo.hbmColor=(bCompressedPNG)? hbmColor:_DDBToDIB(hbmColor,0);
//マスク画像がなければ、空のモノクロDDBを作成します。
IconInfo.hbmMask =(hbmMask)?hbmMask: ::CreateBitmap(width,height,1,1,0);
//カーソルを作成する場合は、ホットスポットを設定します。
if (!bIcon){
IconInfo.xHotspot=(xHotspot<width)? xHotspot:width;
IconInfo.yHotspot=(yHotspot<height)? yHotspot:height;
}
//CIconを作成して、ICONINFO構造体からアイコンを作成します。
CIcon* pIcon=new CIcon;
BOOL bResult=pIcon->:CreateIndirect(&IconInfo,(LPCTSTR)1,FALSE);
//この関数で作業用に作成したDIBを削除します。
if (IconInfo.hbmColor!=hbmColor) ::DeleteObject(IconInfo.hbmColor);
if (IconInfo.hbmMask !=hbmMask ) ::DeleteObject(IconInfo.hbmMask );
//アイコンの作成に失敗していた場合は、CIconを削除してから
//FALSEを戻して、エラー終了します。

if (!bResult){
delete pIcon;
return FALSE;
}
//CGroupIconクラスを作成して、CIconを格納します。
CGroupIcon* pGrpIcon=new CGroupIcon();
pGrpIcon->AddIcon(pIcon);
//作成したCGroupIconクラスを戻して、終了します。
return pGrpIcon;
}


CGroupIconクラスからアニメーションカーソル(CANIFileクラス)を作成して、ANIファイルに保存します。

//CGroupIconクラスからCANIFileクラスを作成して、ANIファイルに保存します。
BOOL __stdcall _SaveANI(LPCTSTR lpszFileName,CGroupIcon* pGrpIcon,DWORD xHotspot,DWORD yHotspot,
int iPNGMinimumSize)
{
if (!AfxIsValidAddress(pGrpIcon,sizeof(CGroupIcon),FALSE)) return FALSE;

//CGroupIconクラス内のアイコン数を取得します。
INT_PTR nIcons=pGrpIcon->GetCount();
if (!nIcons) return FALSE;

//リソース形式を取得します。
BOOL bIcon=(pGrpIcon->GetType()==RT_GROUP_ICON);
//カーソルの場合はホットスポットを設定します。
if (!bIcon){
for (int i=0;i<pGrpIcon->GetCount();i++)
pGrpIcon->GetIcon(i)->SetHotspot(xHotspot,yHotspot);
}

//CANIFileクラスをスタック上に作成します。
CANIFile ANIFile(0);
//入力されたCGroupIconクラスCANIFileクラスに格納します。
ANIFile.m_listGrpIcon.Add(pGrpIcon);
//アニメーションのリソース形式を決定します。
ANIFile.SetType((bIcon)? RT_ANIICON:RT_ANICURSOR);

//CANIFileクラスSaveFile関数を呼び出して、ファイルに書き込みます。
BOOL bResult=ANIFile.SaveFile(lpszFileName,TRUE,iPNGMinimumSize);
//CANIFileクラスに格納していたCGroupIconクラスを解放します。
ANIFile.m_listGrpIcon.RemoveAll();
return bResult;
}


CANIFileクラスの現在着目しているグループアイコンを取り出して、アイコンファイルに保存します。

//CANIFileクラスからグループアイコンを作成してファイルに保存します。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

BOOL __stdcall _SaveGrpIcon(LPCTSTR lpszFileName,CANIFile* pANIFile,BOOL bIcon,DWORD xHotspot,DWORD yHotspot,
int iPNGMinimumSize)
{
if (!AfxIsValidAddress(pANIFile,sizeof(CANIFile),FALSE)) return FALSE;

//スタック上にCGroupIconクラスを作成して、
//入力されたCANIFileクラス内で、現在選択されているCGroupIconクラスの内容をコピーします。

CGroupIcon GrpIcon;
if (!GrpIcon.Copy(pANIFile->GetActiveGroupIcon())) return FALSE;
//カーソルを作成する場合は、ホットスポットを設定します。
if (!bIcon){
for (int i=0;i<GrpIcon.GetCount();i++)
GrpIcon.GetIcon(i)->SetHotspot(xHotspot,yHotspot);
}
//CGroupIconクラスSaveFileを呼び出して、ファイルに書き込みます。
return GrpIcon.SaveFile(lpszFileName,(bIcon)?RT_GROUPICON:RT_GROUPICON,TRUE,iPNGMinimumSize);
}


サンプルプログラム(VisualC++net2003ソリューション)GIFFileTest03B.zip

上記のzipファイルをダウンロードして、「giflibのインストール」で作成した「giflib-4.1.6」フォルダー、「libgif」フォルダー並びに「GIFファイルの読み込み 第3部」で作成した「GIFFileTest02A」フォルダーがある同じフォルダー内にWinRAR等を使って解凍すると、「GIFFileTest03B」と言う名のフォルダーが作成されます。



「GIFFileTest03B」フォルダー内にある「GIFFileTest.sln」を開きます。
「F5」キーを押すと、ビルド確認のダイヤログが表示されるので「Yes」を選択してソリューションをビルドします。



ビルドが終わると、直ちにプログラムが自動起動してウィンドウが表示されます。ウィンドウ内にあるトラッカーの範囲内で、右クリックしてポップアップメニューで「開く」を選択して、「ファイルを開く」ダイヤログを表示させます。



resフォルダー内の「shell32-16.ico」を選択し、「開く」ボタンを押して読み込みます。画像が表示されたところで、トラッカーの範囲内で、右クリックしてポップアップメニューで「名前を付けて保存」を選択し、「名前を付けて保存」ダイヤログを表示させます。



ファイル名の拡張子を「.ico」から「.gif」に変更して「保存」ボタンを押すと、アイコンからGIFフォーマットに変換された画像が表示されます。



32ビットアルファアイコンからメディアンカット減色ディザ合成で、256色GIF画像にきれいに変換されているか確認して下さい。

次に画像のない所を左クリックしてトラッカーのフォーカスを移動させ、新しいトラッカーの範囲内で再び右クリックしてポップアップメニューで「開く」を選択し、「aero_working_xl.ani」を選択します。
トラッカーの範囲内で、右クリックしてポップアップメニューで「名前を付けて保存」を選択し、GIFファイルに変換してみます。「metronom.ani」についても同様に変換して下さい。変換したらそれぞれの画像を「左クリック」して、アニメーション動作を確認して下さい。


sideback
aero_working_xl.gif
metronom.gif



他にもGIFファイルからANI/ICONファイルへの変換やPNG/JPEG/BMPファイルへの変換、またその逆の動作についても確認して下さい。

<<GIFファイルの書き込み 第2部ページの先頭WAVEファイルの読み込み>>


スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/44-ebe4e957
Listed below are links to weblogs that reference
GIFファイルの書き込み 第3部 from マルチメディアファイルフォーマット

Home > GIFファイルフォーマット > GIFファイルの書き込み 第3部

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る