2010年12月04日

GIFファイルの読み込み 第1部



「giflibのインストール」で解説したGIFライブラリ「giflib-4.1.6」にはウィンドウズ向けのサンプルプログラムとしてかなり完成度の高い「gifshow」というサンプルが付属していますが、このサンプルではディスポース方法3番と4番が装備されていないのと、透過画像においてもブラウザの背景色で透過部分を塗りつぶすのみなので、背景画像が絶えず移動するような状態、例えばゲームなどへの転用はできそうにもありません。それから画像を動かしている間絶えずライブラリ関数に読み込みアクセスする為、度重なるアクセスによるライブラリー内部での使用メモリーの肥大化もないとは言えませんし、プログラムの流れがより複雑化して思わぬバグにも繋がりかねません。そこで今回はこのGIFライブラリ「gif-4.1.6」を使用してGIFファイルを一括読み込みし、アニメーションカーソルと同等のパフォーマンスを実現する手法を解説します。

今回は内容が長くなるので3部に分けて解説します。

第1部 CGIFLocalクラスCGIFFileクラスの宣言とメンバー変数について。
第2部 GIFファイルを開いてから各GIFブロックを読み込み、指定されたDCに画像を表示するまで。
第3部 MFCを使った用例とサンプルプログラムを紹介します。


GIFアニメーションには通常複数の画像が格納されており、このアニメーション形式に対応するために便宜上それぞれの画像毎の情報を管理するCGIFLocalクラスとこれらを総括するCGIFFileクラスを独自に定義しました。
まずは画像毎の情報を管理するCGIFLocalクラスです。

// CGIFLocalクラス
// GIFの画像毎のローカル変数を保存します。


class CGIFLocal : public CObject
{
public:
//読み込み表示に使用するメンバー変数です。
HBITMAP m_hbmColor; //24ビットカラーDIB
HBITMAP m_hbmMask; //モノクロマスクDDB
UINT m_delay; //表示時間

//GIFファイル書き込み前に設定が必要なメンバー変数です。
int m_disposalMethod; //ディスポサル方法
BOOL m_bInterlace; //インターレースフラグ

//GIFファイル作成時に使用するメンバー変数です。
UINT m_cEntries; //ローカルカラーテーブルの色数です。
RGBQUAD* m_pRgbq; //ローカルカラーテーブルへのポインタです。
int m_indexTransparent; //透過色番号
PBYTE m_pBitsWrite32; //画像を一時保存しておくための32bitバッファです。


//コンストラクタ

CGIFLocal(HBITMAP hbmColor,HBITMAP hbmMask,UINT delay=0,
int disposalMethod=0,BOOL bInterlace=FALSE)
{
m_hbmColor=hbmColor;
m_hbmMask =hbmMask;
m_delay=delay;
m_disposalMethod=disposalMethod;
m_bInterlace=bInterlace;
m_cEntries=0;
m_pRgbq=0;
m_indexTransparent=-1;
m_pBitsWrite32=0;
};

//デストラクタ
virtual ~CGIFLocal()
{
if (m_hbmColor) ::DeleteObject(m_hbmColor);
if (m_hbmMask) ::DeleteObject(m_hbmMask);
if (m_pRgbq) delete[]m_pRgbq;
if (m_pBitsWrite32) delete[]m_pBitsWrite32;
};

//このクラスにビットマップハンドルを結び付けます。
BOOL Attach(HBITMAP hbmColor,HBITMAP hbmMask=0)
{
//カラービットマップのBITMAP構造体の取得に失敗した場合、
//FALSEを返して終了します。

BITMAP bm;
if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)) return FALSE;
//カラービットマップのハンドルを格納します。
if (m_hbmColor) ::DeleteObject(m_hbmColor);
m_hbmColor=hbmColor;

//マスクビットマップのBITMAP構造体の取得に失敗した場合、
//マスクビットマップのハンドルを0にします。

if (!::GetObject(hbmMask,sizeof(BITMAP),&bm)) hbmMask=0;
//マスクビットマップのハンドルを格納します。
if (m_hbmMask) ::DeleteObject(m_hbmMask);
m_hbmMask=hbmMask;

return TRUE;
};

//このクラスからビットマップハンドルを切り離します。
HBITMAP Detach(HBITMAP* lphbmMask=0)
{
HBITMAP hbmColor= m_hbmColor;
//マスクビットマップハンドルを格納するポインタが有効な値の場合は、
//マスクビットマップを格納し、それ以外は削除します。

if (AfxIsValidAddress(lphbmMask,sizeof(HBITMAP)))
*lphbmMask=m_hbmMask;
else ::DeleteObject(m_hbmMask);
m_hbmColor=0;
m_hbmMask=0;
//カラービットマップのハンドルを返して終了します。
return hbmColor;
};
};


引き続いてCGIFLocalクラスを総括するCGIFFileクラスです。なおこのCGIFFileクラスマルチメディアタイマーを使用するためにスーパークラスCMMTimerクラスを使用しています。このCMMTimerクラスについては「ANIファイルの動画の再生」をご参照ください。

CMMTimerクラスのヘッダーです。(MMTimer.h)
CMMTimerクラスのソースです。(MMTimer.cpp)


//マルチメディアタイマーを使用するために必要です。

#include "MMTimer.h"

//表示時間の最小単位(ms)
//InternetExplorerと同等にする場合は100ms、
//FireFoxと同等にする場合は10msにして下さい。

#define GIF_PERIOD 10

// CGIFFileクラス
// gifibを使ってGIFファイルにアクセスします。


class CGIFFile : public CMMTimer
{
protected:

//内部で使用するメンバー変数です。-------------------------------

//gif_libから読み込んだgif情報を受け取るための構造体です。
GifFileType* m_pGifInfo;
//透過時の背景色になります。
//-1の場合は、背景ウィンドウのDCに対して透過処理をするので、
//ディスポース番号2番の場合、ViewクラスのOnDraw関数で背景画像を再描画して下さい。

COLORREF m_rgbTransparent;
//現在着目されているカラーテーブルへのポインターを格納します。
GifColorType* m_pColorTable;
//現在着目されているカラーテーブルの色数を格納します。
UINT m_nColorCount;
//カラーディスポース画像を保存しておくための24bitバッファです。
PBYTE m_pBitsColor;
//マスクディスポース画像を保存しておくための8bitバッファです。
PBYTE m_pBitsMask;

//内部で使用するメンバー関数です。--------------------------------

//すべてのローカルブロックのメンバー変数を初期化します。
void InitLocal();
//すべてのローカルブロックのメンバー変数を削除します。
void DeleteLocal();
//アプリケーションブロックの読み込み
BOOL ReadApplicationBlock(GifByteType* pApplication);
//イメージブロックの読み込み
//nImage:現在の画像番号

BOOL ReadImageDescriptor(int nImage);
//コメントブロックの読み込み
BOOL ReadCommentBlock(GifByteType* pCommentBlock);
//プレーンテキストブロックの読み込み
BOOL ReadPlainTextBlock(GifByteType* pPlainText);
//グラフィックブロックの読み込み
BOOL ReadGraphicBlock(GifByteType* pGraphicBlock);
//ローカルブロックを読み込んでDIB画像を作成します。
BOOL ReadLocalBlock();

//GIFヘッダーの書き込み
BOOL WriteHeader();
//アプリケーションブロックの書き込み
BOOL WriteApplicationBlock();
//イメージブロックの書き込み
BOOL WriteImageDescriptor();
//コメントブロックの書き込み
BOOL WriteCommentBlock();
//プレーンテキストブロックの書き込み
BOOL WritePlainTextBlock();
//グラフィックブロックの書き込み
BOOL WriteGraphicBlock();
//現在の値から各ブロックを作成して、ファイルに書き込みます。
BOOL WriteLocalBlock();

public:
//外部からアクセスできるメンバー関数です。--------------------------

//コンストラクタ
//pWndOwner:画像を表示するCWndクラスへのポインタが入ります。

CGIFFile(CWnd* pWndOwner);
//デストラクタ
virtual ~CGIFFile();

//メンバー変数を初期化します。
void Init();
//メンバー変数を削除します。
void Delete();

//ファイル名のGIFファイルを開いてStreamIn関数を呼び出します。
//rgbTransparent=-1で背景画像に対して透過処理をします。

BOOL LoadFile(LPCTSTR lpszFileName,COLORREF rgbTransparent=-1);
//GIFファイルストリームを一括読み込みします。
BOOL StreamIn(CFile* infile,COLORREF rgbTransparent);

//GIFファイルの書き込み
BOOL SaveFile(LPCTSTR lpszFileName,COLORREF rgbBackground=-1);
//GIFストリームへの書き込み
BOOL StreamOut(CFile* outfile,COLORREF rgbBackground);

//ブラウザの背景色(透過色)を設定します。
//rgbTransparent=-1で背景画像に対して透過処理をします。

BOOL UpdateBackground(COLORREF rgbTransparent=-1);

//現在読み込まれている画像を表示します。
void OnDraw(CDC* pDC,int x,int y,int cx,int cy);

//グローバルブロック-----------------------------------------
protected:
//GIFヘッダー
UINT m_LSWidth; //理論スクリーンの幅
UINT m_LSHeight; //理論スクリーンの高さ
BOOL m_bBackground; //背景色が有効な値かどうか
COLORREF m_rgbBackground; //背景色
BOOL m_bGct; //グローバルカラーテーブルの有無
UINT m_nGctCount; //グローバルカラーテーブルの色数
GifColorType* m_pGct; //グローバルカラーテーブルのへのポインタ
RGBQUAD* m_prgbqGct; //グローバルカラーテーブルへのポインタ(ファイル作成時のみ使用します。)

public:
//アプリケーションブロック
BOOL m_bNetScapeExt; //アプリケーションブロックが定義されているかどうか
UINT m_nLoopCounts; //ループ回数
UINT m_nBufferBytes; //取り込みバッファサイズ

//ターミネータ
BOOL m_bTrailer; //ターミネータの有無

//CGIFLocalクラスを格納します。
CPtrArray m_listLocal;
//入力された画像番号のCGIFLocalクラスへのポインタを返します。
CGIFLocal* GetLocal(UINT nImage);
//リストにCGIFLocalクラスのポインタを追加します。
INT_PTR AddLocal(CGIFLocal* pLocal);

//ローカルブロック-------------------------------------------
public:
//一番最後に読み込まれたデータが残されます。

//コメントブロック

CString m_strComment; //コメント文字列

//プレーンテキストブロックのパラメータ

UINT m_nTextGridLeft;
UINT m_nTextGridTop;
UINT m_nTextGridWidth;
UINT m_nTextGridHeight;
UINT m_nCharCellWidth;
UINT m_nCharCellHeight;
UINT m_nTextForegroundColorIndex;
UINT m_nTextBackgroundColorIndex;
CString m_strPlainText; //プレーンテキスト文字列

protected:
//現在読み込まれている番号のデータのみを保持しています。

//ハンドル受け渡し用なので削除しないで下さい。
HBITMAP m_hbmColor; //24ビットカラーDIB
HBITMAP m_hbmMask; //モノクロマスクDDB

//ファイル書き込み時に使用する32ビットバッファへのポインタです。
//ポインタ受け渡し用なので削除しないで下さい。

PBYTE m_pBitsWrite32;

//グラフィックブロック
BOOL m_bGraphicBlock; //グラフィックブロックの有無
BOOL m_bTransparent; //透過色の有無
BOOL m_bUserInputMethod; //ユーザー入力の受付有無
int m_disposalMethod; //ディスポサル方法
UINT m_delay; //表示時間
int m_indexTransparent; //透過色番号 -1の時は無効

//イメージブロック
UINT m_left; //画像表示左位置
UINT m_top; //画像表示上位置
UINT m_width; //画像の幅
UINT m_height; //画像の高さ
BOOL m_bLct; //ローカルカラーテーブルの有無
UINT m_nLctCount; //ローカルカラーテーブルの色数
GifColorType* m_pLct; //ローカルカラーテーブルへのポインタ
RGBQUAD* m_prgbqLct; //ローカルカラーテーブルへのポインタ(ファイル作成時のみ使用します。)
BOOL m_bInterlace; //インターレースの有無

public:

//理論スクリーン幅を取得します。
UINT Width(){return m_LSWidth;};
//理論スクリーン高さを取得します。
UINT Height(){return m_LSHeight;};
//表示時間の取得
UINT GetDelay(UINT nImage);
//ディスポサル方法の取得
int GetDisposalMethod(UINT nImage);
//インターレースかどうか
BOOL IsInterlace(UINT nImage);
//このクラスに表示可能な画像が有るかどうか。
BOOL IsEnabled(){return (m_nImageCount>0);};

//MMタイマー関連-------------------------------------------------
public:
UINT m_nLoop; //現在のループ回数
UINT m_nImageCount; //画像の総数
UINT m_nImage; //現在着目している画像番号
CRect* m_lpRect; //描画する領域

private:
BOOL m_bActivate; //動画再生中
BOOL m_bPause; //一時停止中
CWnd* m_pWndOwner; //オーナーウィンドウ

public:
//現在アニメーション動作中かどうか
BOOL IsActivate(){return m_bActivate;};
//現在アニメーション一時停止中かどうか
BOOL IsPaused(){return m_bPause;};
//オーナーウィンドウの描画領域の無効化
void InvalidateOwnerWindow();

public:
//タイマーの停止
void KillTimer();
//アニメーションの再生
void Play(CWnd* pWndOwner=NULL);
//アニメーションの停止
void Stop();
//アニメーションの一時停止
void Pause();
//アニメーションのコマ送り(前進)
BOOL Next();
//アニメーションのコマ送り(後退)
BOOL Prev();

protected:
//タイマーにセットする時間を取得する
UINT GetDelayTime();
//CMMTimerクラスオーバーライド
virtual void OnTimer();
};


CGIFFileクラスのインライン関数です。

//入力された画像番号のCGIFLocalクラスへのポインタを返します。
inline CGIFLocal* CGIFFile::GetLocal(UINT nImage)
{
return (nImage<(UINT)m_listLocal.GetCount())?
(CGIFLocal*)m_listLocal.GetAt(nImage):0;
}

//指定された画像番号の表示時間を取得します。
inline UINT CGIFFile::GetDelay(UINT nImage)
{
CGIFLocal* pLocal=GetLocal(nImage);
return ((pLocal)?pLocal->m_delay:0)*10;
}

//指定された画像番号のディスポサル方法を取得します。
inline int CGIFFile::GetDisposalMethod(UINT nImage)
{
CGIFLocal* pLocal=GetLocal(nImage);
return (pLocal)?pLocal->m_disposalMethod:0;
}

//指定された画像番号がインターレース画像かどうか?
inline BOOL CGIFFile::IsInterlace(UINT nImage)
{
CGIFLocal* pLocal=GetLocal(nImage);
return (pLocal)?pLocal->m_bInterlace:FALSE;
}

//タイマーコントロール-----------------------------------------------

//タイマーの停止
inline void CGIFFile::KillTimer()
{
m_bActivate=FALSE;
CMMTimer::KillTimer();
}

//アニメーションの再生
inline void CGIFFile::Play(CWnd* pWndOwner)
{
if (pWndOwner) m_pWndOwner=pWndOwner;
if ((m_bActivate)&&(!m_bPause)) return;
m_bActivate=TRUE;
if (!m_bPause) m_nLoop=0;
m_bPause=FALSE;
CMMTimer::SetIntervalTimer(GetDelayTime());
InvalidateOwnerWindow();
}

//アニメーションの停止
inline void CGIFFile::Stop()
{
KillTimer();
m_nImage=0;
InvalidateOwnerWindow();
}

//アニメーションの一時停止
inline void CGIFFile::Pause()
{
if (m_bPause) Play();
else{
KillTimer();
m_bPause=TRUE;
InvalidateOwnerWindow();
}
}

//タイマーにセットする時間を取得する
inline UINT CGIFFile::GetDelayTime()
{
UINT delayTime=GetDelay(m_nImage);
if (delayTime<GIF_PERIOD) delayTime=GIF_PERIOD;
return delayTime;
}


giflibをインクルードするための定義です。「giflib-4.1.6\lib」フォルダーにある「gif_lib.h」を、このプログラムソースのあるフォルダーにコピーしておいて下さい。

extern "C"
{
#include "gif_lib.h"
}


ビットマップバイト幅の算出マクロです。

//ビットマップバイト幅の算出マクロ
#ifndef WIDTHBYTES
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
#endif//WIDTHBYTES


GIFファイル読み込みに必要な定数の定義です。
//ブロック識別コード(レコードタイプ)
#define EXTENSIONBLOCK 0x021
#define IMAGEDESCRIPTOR 0x02C
#define GRAPHICCONTROLEXTENSION 0x0F9
#define COMMENTEXTENSION 0x0FE
#define PLAINTEXTEXTENSION 0x001
#define APPLICATIONEXTENSION 0x0FF
#define GIFTRAILER 0x03b

//アプリケーションブロックのフィールドコードです。
#define LOOP_COUNT_CODE 0x01 //ループ回数指定
#define BUFFER_BYTES_CODE 0x02 //バッファリングバイト数指定

//ブロックサイズ
#define GIF_HEADER_SIZE 13
#define IMAGE_DESCRIPTOR_SIZE 9
#define GRAPHIC_CONTROL_SIZE 4
#define PLAIN_TEXT_SIZE 12
#define APPLICATION_SIZE 11

//ディスポース方法
#define GIF_DISPOSE_NONE 0 //何もしません。
#define GIF_DISPOSE_LEAVE 1 //後処理しないで画像を残します。
#define GIF_DISPOSE_BACKGND 2 //背景色で復元します。
#define GIF_DISPOSE_PREV 3 //一つ前の画像を復元します。
#define GIF_DISPOSE_FIRST 4 //一番最初の画像を復元します。

//インターレース時に使用するグローバルの配列変数です。
static const int g_InterlacedOffset[]={0,4,2,1}; //インターレース時の行の順番
static const int g_InterlacedJumps[]= {8,8,4,2}; //インターレース時の行の飛び間隔


CGIFFileクラスのコンストラクタ/デストラクタです。

//コンストラクタ
CGIFFile::CGIFFile(CWnd* pWndOwner)
{
m_pWndOwner=pWndOwner;
Init();
}

//デストラクタ
CGIFFile::~CGIFFile()
{
//基底クラスのデストラクタを先に呼ぶ。
CMMTimer::~CMMTimer();
Delete();
}

CGIFFileクラスのメンバー関数です。

//メンバー変数を初期化します。
void CGIFFile::Init()
{
m_pGifInfo =0;
m_pBitsColor =0;
m_pBitsMask =0;
m_rgbTransparent=-1;
m_listLocal.RemoveAll();
m_pColorTable =0;
m_nColorCount =0;

//GIFヘッダー
m_LSWidth =0;
m_LSHeight =0;
m_bGct =0;
m_nGctCount =0;
m_pGct =0;
m_prgbqGct =0;

m_bBackground =FALSE;
m_rgbBackground =-1;

//アプリケーションブロック
m_bNetScapeExt =FALSE;
m_nLoopCounts =0;
m_nBufferBytes =0;

//トレーラーの有無
m_bTrailer =FALSE;

//アニメーション
m_nLoop =0;
m_nImageCount =0;
m_nImage =0;
m_bActivate =FALSE;
m_bPause =FALSE;
m_lpRect =0;

//コメントブロック
m_strComment.Empty();

//プレーンテキストブロック
m_nTextGridLeft =0;
m_nTextGridTop =0;
m_nTextGridWidth =0;
m_nTextGridHeight=0;
m_nCharCellWidth =0;
m_nCharCellHeight=0;
m_nTextForegroundColorIndex=0;
m_nTextBackgroundColorIndex=0;
m_strPlainText.Empty();

InitLocal();
}

//メンバー変数を削除します。
void CGIFFile::Delete()
{
//libgifファイルストリームを閉じる
if (m_pGifInfo){
::DGifCloseFile(m_pGifInfo);
m_pGifInfo=0;
}

//ディスポサルDIBがあれば削除します。
if (m_pBitsColor) delete[]m_pBitsColor;
if (m_pBitsMask) delete[]m_pBitsMask;

//格納されていたCGIFLocalクラスを削除します。
for(int i=0;i<m_listLocal.GetCount();i++)
delete ((CGIFLocal*)m_listLocal.GetAt(i));

//書き込み用のグローバルカラーテーブルを削除します。
if (m_prgbqGct) delete[]m_prgbqGct;

//ローカルブロックのメンバー変数を削除します。
DeleteLocal();

//メンバー変数を初期化します。
Init();
}

//すべてのローカルブロックのメンバー変数を初期化します。
void CGIFFile::InitLocal()
{
//カラー/マスク画像
m_hbmColor=0;
m_hbmMask =0;
m_pBitsWrite32=0;

//グラフィックブロック
m_bGraphicBlock =FALSE;
m_bTransparent =FALSE;
m_bUserInputMethod=FALSE;
m_disposalMethod=0;
m_delay =0;
m_indexTransparent=-1;

//イメージブロック
m_left =0;
m_top =0;
m_width =0;
m_height =0;
m_bLct =FALSE;
m_nGctCount =0;
m_pLct =0;
m_bInterlace =FALSE;

}

//すべてのローカルブロックのメンバー変数を削除します。
void CGIFFile::DeleteLocal()
{
InitLocal();
}

//リストにCGIFLocalクラスのポインタを追加します。
INT_PTR CGIFFile::AddLocal(CGIFFile* pLocal)
{
//スクリーンサイズが未定の場合は、
//カラー画像のサイズを設定します。

if ((m_LSWidth==0)||(m_LSHeight==0)){
BITMAP bm={0};
if (!::GetObject(pLocal->m_hbmColor,sizeof(BITMAP),&bm))
return FALSE;
m_LSWidth=bm.bmWidth;
m_LSHeight=abs(bm.bmHeight);
}
//リストに追加します。
INT_PTR nResult=m_listLocal.Add(pLocal);
//画像数を登録します。
m_nImageCount=(UINT)m_listLocal.GetCount();
return nResult;
}

//ブラウザの背景色(透過色)を設定します。
//rgbTransparent=-1で背景画像に対して透過処理をします。

BOOL CGIFFile::UpdateBackground(COLORREF rgbTransparent)
{
Pause();

//オーナーウィンドウの透過色を保存しておきます。
m_rgbTransparent=rgbTransparent;

//背景色が有効な値ではない場合は、
//透過色を背景色にコピーする。

if (!m_bBackground)
m_rgbBackground=m_rgbTransparent;

Play();
return TRUE;
}

//オーナーウィンドウの描画領域の無効化
void CGIFFile::InvalidateOwnerWindow()
{
//オーナーウィンドウが表示中の場合
if ((AfxIsValidAddress(m_pWndOwner,sizeof(CWnd),0))&&
(m_pWndOwner->IsWindowVisible()))
{
//オーナーウィンドウの表示領域へのポインタがある場合
if (m_lpRect){
CRect rect=*m_lpRect;
//オーナーウィンドウがCScrollViewクラスの場合
if (m_pWndOwner->IsKindOf(RUNTIME_CLASS(CScrollView))){
//スクロール値を取得して座標から差し引く
int cx=m_pWndOwner->GetScrollPos(SB_HORZ);
int cy=m_pWndOwner->GetScrollPos(SB_VERT);
rect.OffsetRect(-cx,-cy);
}
//オーナーウィンドウの指定領域を無効化する。
m_pWndOwner->InvalidateRect(&rect,FALSE);
}
//オーナーウィンドウの表示領域へのポインタがない場合は、全面を無効化する。
else m_pWndOwner->Invalidate(FALSE);
}
}

//アニメーションのコマ送り
BOOL CGIFFile::Next()
{
//画像番号をインクリメント
m_nImage++;
//画像番号が最後の画像番号を超えた場合。
if (m_nImage>=m_nImageCount){
//指定されたループ回数が無効な値の場合は、
//画像番号を0にします。

if (m_nLoopCounts==0) m_nImage=0;
//指定されたループ回数が有効な値なら
else{
//現在のループ回数をインクリメントします。
m_nLoop++;
//現在のループ回数が指定されたループ回数を超えた場合。
if (m_nLoopCounts<=m_nLoop){
//画像番号をデクリメントします。
m_nImage--;
//現在のループ回数を指定ループ回数-1にしてから、
//FALSEを返して終了します。

m_nLoop=m_nLoopCounts-1;
return FALSE;
}
//それ以外なら画像番号を0にします。
m_nImage=0;
}
}
//画像を再描画して正常終了します。
InvalidateOwnerWindow();
return TRUE;
}

//アニメーションのコマ戻し
BOOL CGIFFile::Prev()
{
//画像番号が0以上なら、画像番号をデクリメントします。
if (m_nImage>0) m_nImage--;
//画像番号が0の場合。
else {
//指定されたループ回数が無効な値の場合は、
//画像番号を最後の画像番号にします。

if (m_nLoopCounts==0) m_nImage=m_nImageCount-1;
//指定されたループ回数が有効な値なら
else{
//現在のループ回数が0以上なら
if (m_nLoop>0){
//現在のループ回数をデクリメントします。
m_nLoop--;
//画像番号を最後の画像番号にします。
m_nImage=m_nImageCount-1;
}
//それ以外ならFALSEを返して終了します。
else return FALSE;
}
}
//画像を再描画して正常終了します。
InvalidateOwnerWindow();
return TRUE;
}

//CMMTimerクラスオーバーライド---------------------------------------

//タイマーイベント

void CGIFFile::OnTimer()
{
//アニメーションのコマ送りに失敗した場合。
if (!Next()){
//タイマーを止めて、現在の画像を再描画させます。
KillTimer();
InvalidateOwnerWindow();
}
//それ以外で現在活動中で、一時停止中ではない場合は、
//現在の画像の表示時間を取得して、
//インターバルタイマーを再起動します。

else if ((m_bActivate)&&(!m_bPause))
CMMTimer::SetIntervalTimer(GetDelayTime());
}


<<giflibのインストールページの先頭GIFファイルの読み込み 第2部>>





posted by ひろし at 00:34| Comment(0) | GIFファイルフォーマット | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。