2010年12月04日

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



GIFファイルの読み込み 第2部」では、GIFファイルを開いてから各GIFブロックを読み込み、指定されたDCに画像を表示するまでを解説します。

GIFファイルの読み込み手順は以下の通りです。

  1. GIFファイルを開いて、ファイルストリームを取得します。
  2. 取得したファイルストリームを使ってGIFライブラリを開き、グローバルデータを保存します。
  3. ローカルデータを順に読み込んでリストに格納します。
  4. ターミネータに突き当たったら読み込みを終了して、GIFライブラリを閉じます。
  5. GIFファイルを閉じた後は、リストに格納されたローカルデータ(CGIFLocalクラス)を元に動画を表示します。





GIFファイル内で指定した画像番号の画像を1つだけ読み込む関数です。

//GIFファイル内で指定した画像番号の画像を読み込みます。
//nImage:読み込む画像番号

HBITMAP __stdcall _LoadGIF(LPCTSTR lpszFileName,HBITMAP* lphbmMask,UINT nImage)
{
CGIFFile gif(0);
if (!gif.LoadFile(lpszFileName)) return FALSE;
CGIFLocal* pLocal=gif.GetLocal(nImage);
if (!pLocal) return FALSE;
return pLocal->Detach(lphbmMask);
}


GIFファイルを開いてStreamIn関数を呼び出します。

//ファイル名のGIFファイルを開いてStreamIn関数を呼び出します。
//rgbTransparent=-1で背景画像に対して透過処理をします。
//bReadOneTime=TRUEで一度に画像をすべて読み出しリストに格納します。

BOOL CGIFFile::LoadFile(LPCTSTR lpszFileName,COLORREF rgbTransparent)
{
if (!lpszFileName) return FALSE;
//メンバー変数を削除します。

CFile infile;
if (!infile.Open(lpszFileName,CFile::modeRead)) return FALSE;
BOOL bResult=StreamIn(&infile,rgbTransparent);
infile.Close();
return bResult;
}


ファイルを読み込むためのユーザー定義関数です。

//GIFファイル読み込み関数
int _DGifInputFunc(GifFileType* pGifInfo, GifByteType* buf, int size)
{
CFile* infile=(CFile*)pGifInfo->UserData;
return infile->Read(buf,(UINT)size); //CFileクラスを使ってファイルを読む
}


GIFファイルストリームを一括読み込みします。

//GIFファイルストリームを一括読み込みします。
BOOL CGIFFile::StreamIn(CFile* infile,COLORREF rgbTransparent)
{
if (!AfxIsValidAddress(infile,sizeof(CFile),0)) return FALSE;

//メンバー変数を削除します。
Delete();

//ファイル名のストリームを作成します。
m_pGifInfo=::DGifOpen((void*)infile,_DGifInputFunc);
if (!m_pGifInfo) return FALSE;

//GIFヘッダーの内容を保存しておきます。
m_LSWidth=m_pGifInfo->SWidth;
m_LSHeight=m_pGifInfo->SHeight;
m_bGct=(m_pGifInfo->SColorMap!=0);
m_nGctCount=(m_bGct)?m_pGifInfo->SColorMap->ColorCount:0;
m_pGct=(m_bGct)?m_pGifInfo->SColorMap->Colors:0;

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

//背景色番号を取得します。
UINT indexBackground=m_pGifInfo->SBackGroundColor;
//グローバルカラーテーブルが存在し、
//背景色インデックスが0以上でグローバルカラーテーブルの色数の範囲内の場合。

if ((m_bGct)&&
(indexBackground>0)&&
(indexBackground<m_nGctCount))
{
//背景色を算出します。
m_rgbBackground=RGB( m_pGct[indexBackground].Red,
m_pGct[indexBackground].Green,
m_pGct[indexBackground].Blue);
m_bBackground=TRUE;
}

//ディスポサル用の24ビットカラーバッファを作成します。
UINT widthBytes24=WIDTHBYTES(24*m_LSWidth);
UINT sizeImage24=widthBytes24*m_LSHeight;
m_pBitsColor=new BYTE[sizeImage24];
::ZeroMemory(m_pBitsColor,sizeImage24);

//ディスポサル用の8ビットマスクバッファを作成します。
UINT sizeImage8=WIDTHBYTES(8*m_LSWidth)*m_LSHeight;
m_pBitsMask =new BYTE[sizeImage8];
::ZeroMemory(m_pBitsMask,sizeImage8);

//画像を頭から順に読み込んでいきます。
while(!m_bTrailer){
//GIFストリームから画像を読み込みます。
if (!ReadLocalBlock()) break;
//画像が読み込まれている場合。
if (m_hbmColor){
//CGIFLocalクラスを作成して読み込んだ画像を格納します。
CGIFLocall* pLocal=new CGIFLocal(m_hbmColor,m_hbmMask,m_delay,
m_disposalMethod,m_bInterlace);
//CGIFLocalクラスをリストに格納します。
m_listLocal.Add(pLocal);
//画像はCGIFLocalクラスに格納したので、DIBのポインタは消去します。
m_hbmColor=0;
m_hbmMask =0;
}
}
//GIFライブラリーをクローズします。
::DGifCloseFile(m_pGifInfo);
m_pGifInfo=0;
//読み込まれた画像がなく、ターミネータも読めなかった場合は、
//メンバー変数を削除してからFALSEを返して終了します。

if ((!m_listLocal.GetCount())||(!m_bTrailer)){
Delete();
return FALSE;
}
//読み込んだ画像数を保存します。
m_nImageCount=(UINT)m_listLocal.GetCount();
//画像番号を0にします。
m_nImage=0;
return TRUE;
}


ローカルブロックを読み込みます。

//ローカルブロックを読み込んでDIB画像を作成します。
BOOL CGIFFile::ReadLocalBlock()
{
ASSERT(m_pGifInfo);

BOOL bResult=FALSE;
UINT rate=0;
GifRecordType RecordType; //レコードタイプ。
GifByteType *pExtension; //拡張ブロックへのポインタ。
int extensionCode; //拡張コード。

DeleteLocal();

//各ブロックを読み込みます
do{
//レコードタイプを読み込みます。
if (::DGifGetRecordType(m_pGifInfo,&RecordType)==GIF_ERROR) break;
switch(RecordType){
case IMAGE_DESC_RECORD_TYPE:
//イメージブロックの場合、
//イメージブロックを読み込みます。

if (!ReadImageDescriptor((int)m_listLocal.GetCount())) return FALSE;
//アニメーションGIFの場合は、TRUEを返して戻ります。
return TRUE;
break;
case EXTENSION_RECORD_TYPE:
//拡張ブロックを読み込みます。
if (::DGifGetExtension(m_pGifInfo,&extensionCode,&pExtension)==GIF_ERROR) return FALSE;

bResult=FALSE;
//拡張ブロックコードに従って分岐処理します。
switch(extensionCode){
case GRAPHICCONTROLEXTENSION:
//グラフィックブロックの場合、
bResult=ReadGraphicBlock(pExtension);
break;
case COMMENTEXTENSION:
//コメントブロック
bResult=ReadCommentBlock(pExtension);
break;
case PLAINTEXTEXTENSION:
//プレーンテキストブロック
bResult=ReadPlainTextBlock(pExtension);
break;
case APPLICATIONEXTENSION:
//アプリケーションブロック
bResult=ReadApplicationBlock(pExtension);
break;
}
if (!bResult) return FALSE;
break;
case TERMINATE_RECORD_TYPE:
//ターミネータ
break;
default:
break;
}
}
//ターミネータならループから抜けて終了します。
while (RecordType != TERMINATE_RECORD_TYPE);

m_bTrailer=TRUE;

return TRUE;
}


イメージブロックを読み込んで、カラー画像(24ビットDIB)とマスク画像(モノクロDDB)を作成します。

//イメージブロックの読み込み
//nImage:現在の画像番号

BOOL CGIFFile::ReadImageDescriptor(int nImage)
{
ASSERT(m_hbmColor==0);
ASSERT(m_hbmMask ==0);
ASSERT(m_pGifInfo);

//イメージブロックを読み込みエラーが出たら、
//FALSEを返して終了します。

if (::DGifGetImageDesc(m_pGifInfo)==GIF_ERROR) return FALSE;

//ローカルデータを保存しておきます。
m_left =m_pGifInfo->Image.Left;
m_top =m_pGifInfo->Image.Top;
m_width =m_pGifInfo->Image.Width;
m_height =m_pGifInfo->Image.Height;
m_bInterlace=m_pGifInfo->Image.Interlace;

//ローカルカラーテーブルがあれば、その値を保存します。--------------------------------------------
if (m_pGifInfo->Image.ColorMap){
m_bLct=TRUE;
m_pLct=m_pGifInfo->Image.ColorMap->Colors;
m_nLctCount =m_pGifInfo->Image.ColorMap->ColorCount;
}

//カラーテーブルと色数の設定
//ローカルカラーテーブルがある場合は、ローカルカーテーブルとその色数を選択し、
//ない場合は、グローバルカラーテーブルとその色数を選択します。

m_pColorTable=(m_bLct)? m_pLct:m_pGct;
m_nColorCount=(m_bLct)? m_nLctCount:m_nGctCount;

//グローバルカラーテーブルもローカルカラーテーブルもなければ、
//FALSEを返して終了します。

if (! m_pColorTable) return FALSE;

ASSERT(m_nColorCount%2==0); //色数が奇数ならエラー
ASSERT(m_nColorCount<=256); //色数が256以上ならエラー

//カラーテーブルへのポインタアドレスが無効ならエラー
ASSERT(AfxIsValidAddress( m_pColorTable,sizeof(GifColorType)*m_nColorCount,FALSE));

//ビットマップバイト幅を算出します。
UINT widthBytes24=WIDTHBYTES(24*m_LSWidth);
UINT widthBytes8 =WIDTHBYTES(8 *m_LSWidth);

//ピクセルサイズの算出
UINT sizeImage24=widthBytes24*m_LSHeight;
UINT sizeImage8 =widthBytes8 *m_LSHeight;

//画像番号0のときにディスポース画像を初期化します。-----------------------------------------------
if (nImage==0){
//ディスポースマスク画像が有って透過画像ではなくて、
//ディスポサル方法1以下(画像を残す)の場合は、
//ディスポースマスク画像を削除してしまいます。

if ((m_pBitsMask)&&(m_indexTransparent==-1)&&
(m_disposalMethod<=GIF_DISPOSE_LEAVE))
{
delete[]m_pBitsMask;
m_pBitsMask=0;
}

//ディスポース画像を黒で塗りつぶします。
::ZeroMemory(m_pBitsColor,sizeImage24);

//マスク画像が有れば白で塗りつぶします。
//色番号0番目が白色(透過部分)になります。

if (m_pBitsMask)
::ZeroMemory(m_pBitsMask ,sizeImage8);
}

//BITMAPINFO構造体を格納するバッファの確保--------------------------------------------------------
BYTE dib[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2]={0};
BITMAPINFO* pBmi=(BITMAPINFO*)&dib;

//BITMAPINFOHEADER構造体を作成します。
pBmi->bmiHeader.biSize =sizeof(BITMAPINFOHEADER);
pBmi->bmiHeader.biBitCount =24;
pBmi->bmiHeader.biClrUsed =0;
pBmi->bmiHeader.biWidth =m_LSWidth;
pBmi->bmiHeader.biHeight =m_LSHeight;
pBmi->bmiHeader.biPlanes =1;
pBmi->bmiHeader.biSizeImage=sizeImage24;

//カラーDIBを作成します。
LPVOID pvBitsColor=0;
HBITMAP hbmColor=::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBitsColor,NULL,NULL);
if (!hbmColor) return FALSE;

//ディスポースカラー画像をコピーしておきます。
::CopyMemory(pvBitsColor,m_pBitsColor,sizeImage24);

//マスクDIBを作成します。
HBITMAP hbmMask=0;
LPVOID pvBitsMask=0;
if ((m_pBitsMask)&&(m_indexTransparent!=-1)){
pBmi->bmiHeader.biBitCount =8;
pBmi->bmiHeader.biClrUsed =2;
pBmi->bmiHeader.biCompression=BI_RGB;
pBmi->bmiHeader.biSizeImage =sizeImage8;

RGBQUAD* pColors=pBmi->bmiColors;
::ZeroMemory(pColors,sizeof(RGBQUAD)*2);
//便宜上色番号0番目を白色(透過部分)にします。
pColors[0].rgbBlue=pColors[0].rgbGreen=pColors[0].rgbRed=0xFF;

hbmMask=::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBitsMask,NULL,NULL);
//ディスポースマスク画像があれば、コピーしておきます。
if (pvBitsMask) ::CopyMemory(pvBitsMask,m_pBitsMask,sizeImage8);
}

//ディスポサル方法3(一つ前の画像に復元する)の時は先に画像を作成します。-------------------------
if (m_disposalMethod==GIF_DISPOSE_PREV){

//ディスポース画像を黒で塗りつぶします。
::ZeroMemory(m_pBitsColor,sizeImage24);

//マスク画像が有れば白で塗りつぶします。
//色番号0番目が白色(透過部分)になります。

if (m_pBitsMask)
::ZeroMemory(m_pBitsMask ,sizeImage8);
}

//ピクセルデータを受け取るラインバッファを作成します。
GifPixelType* pLine=new BYTE[m_width];

//ピクセルデータをコピーします。------------------------------------------------------------------
BYTE b,g,r;

//インターレースGIFの場合
if (m_bInterlace)
{
//4段階で書き込む行を変更します
for (int pass=0;pass<4;pass++){
for (UINT i=g_InterlacedOffset[pass];i<m_height;i+=g_InterlacedJumps[pass]){
//ラインバッファにGIFデータを読み込みます。
if (::DGifGetLine(m_pGifInfo,pLine,m_width)==GIF_ERROR){
delete[]pLine;
return FALSE;
}

//ピクセルデータへのポインタを算出します。
PBYTE dst=(PBYTE)pvBitsColor+widthBytes24*(m_LSHeight-i-1-m_top)+m_left*3;
PBYTE msk=(pvBitsMask)?(PBYTE)pvBitsMask +widthBytes8 *(m_LSHeight-i-1-m_top)+m_left:0;
PBYTE src=pLine;

PBYTE dsc=0,dsm=0;
//ディスポサル方法3(一つ前の画像に復元する)の時はディスポサルバッファに画像を残しておきます。
if (m_disposalMethod==GIF_DISPOSE_PREV){
dsc=m_pBitsColor+widthBytes24*(m_LSHeight-i-1-m_top)+m_left*3;
dsm=(m_pBitsMask)?m_pBitsMask +widthBytes8 *(m_LSHeight-i-1-m_top)+m_left:0;
}

for(UINT j=0;j<m_width;j++){
int indexPixel=*src++;
//透過色でない場合、ピクセルに色を書き込みます。
if (indexPixel!=m_indexTransparent){
b= m_pColorTable[indexPixel].Blue;
g= m_pColorTable[indexPixel].Green;
r= m_pColorTable[indexPixel].Red;
*dst++=b;
*dst++=g;
*dst++=r;
if (msk) *msk++=1;
if (dsc){
*dsc++=b;
*dsc++=g;
*dsc++=r;
}
if (dsm) *dsm++=1;
}
//透過色の場合は、書き込みせずにポインタを進めます。
else{
dst+=3;
if (msk) msk++;
if (dsc) dsc+=3;
if (dsm) dsm++;
}
}
}
}
}
//通常の画像の場合--------------------------------------------------------------------------------
else{
for (UINT i=0;i<m_height;i++){
//ラインバッファにGIFデータを読み込みます。
if (::DGifGetLine(m_pGifInfo,pLine,m_width)==GIF_ERROR){
delete[]pLine;
return FALSE;
}

//ピクセルデータへのポインタを算出します。
PBYTE dst=(PBYTE)pvBitsColor+widthBytes24*(m_LSHeight-i-1-m_top)+m_left*3;
PBYTE msk=(pvBitsMask)?(PBYTE)pvBitsMask +widthBytes8 *(m_LSHeight-i-1-m_top)+m_left:0;
PBYTE src=pLine;

PBYTE dsc=0,dsm=0;
//ディスポサル方法3(一つ前の画像に復元する)の時はディスポサルバッファに画像を残しておきます。
if (m_disposalMethod==GIF_DISPOSE_PREV){
dsc=m_pBitsColor+widthBytes24*(m_LSHeight-i-1-m_top)+m_left*3;
dsm=(m_pBitsMask)?m_pBitsMask +widthBytes8 *(m_LSHeight-i-1-m_top)+m_left:0;
}

for(UINT j=0;j<m_width;j++){
int indexPixel=*src++;
//透過色でない場合、ピクセルに色を書き込みます。
if (indexPixel!=m_indexTransparent){
b= m_pColorTable[indexPixel].Blue;
g= m_pColorTable[indexPixel].Green;
r= m_pColorTable[indexPixel].Red;
*dst++=b;
*dst++=g;
*dst++=r;
if (msk) *msk++=1;
if (dsc){
*dsc++=b;
*dsc++=g;
*dsc++=r;
}
if (dsm) *dsm++=1;
}
//透過色の場合は、書き込みせずにポインタを進めます。
else{
dst+=3;
if (msk) msk++;
if (dsc) dsc+=3;
if (dsm) dsm++;
}
}
}
}
delete[]pLine;

//ディスポース画像を作成しておきます。------------------------------------------------------------
switch(m_disposalMethod){
case GIF_DISPOSE_NONE:
case GIF_DISPOSE_LEAVE:
//何もしない場合は現在の画像を残しておきます。
::CopyMemory(m_pBitsColor,pvBitsColor,sizeImage24);
if ((m_pBitsMask)&&(pvBitsMask))
::CopyMemory(m_pBitsMask, pvBitsMask ,sizeImage8);
break;
case GIF_DISPOSE_BACKGND:
//背景色で塗りつぶす場合
//カラー画像を黒で塗りつぶしておきます。

::ZeroMemory(m_pBitsColor,sizeImage24);
//マスク画像が有れば白で塗りつぶします。
//色番号0番目が白色(透過部分)になります。

if (m_pBitsMask)
::ZeroMemory(m_pBitsMask ,sizeImage8);
break;
case GIF_DISPOSE_PREV:
//一つ前の画像に復元する場合
//ピクセルデータのコピーのところで作成済みなのでここでは何もしません。

break;
case GIF_DISPOSE_FIRST:
//一番最初の画像に復元する場合
//画像番号0の時に画像を残しておきます。

if (nImage==0){
::CopyMemory(m_pBitsColor,pvBitsColor,sizeImage24);
if ((m_pBitsMask)&&(pvBitsMask))
::CopyMemory(m_pBitsMask, pvBitsMask ,sizeImage8);
}
break;
}

//カラーDIBを保存しておきます。
m_hbmColor=hbmColor;

//8ビットマスクDIBをモノクロDDBに変換します。
if (hbmMask){
m_hbmMask=(HBITMAP)::CopyImage(hbmMask,IMAGE_BITMAP,0,0,LR_MONOCHROME);
::DeleteObject(hbmMask);
}
else m_hbmMask=0;

return TRUE;

}


拡張ブロックを読み込む関数です。

//アプリケーションブロックの読み込み
BOOL CGIFFile::ReadApplicationBlock(GifByteType* pApplication)
{
ASSERT(m_pGifInfo);
//ブロックサイズが11byteでなければ、
//FALSEを返して終了します。

int blockSize=pApplication[0];
if (blockSize!=APPLICATION_SIZE) return FALSE;
m_bNetScapeExt=(::StrCmpN((LPCSTR)&pApplication[1],_T("NETSCAPE2.0"),APPLICATION_SIZE)==0);

//サブブロックを読み込みます。
GifByteType* pSubBlock=0;
while(TRUE){
//ブロックターミネータに突き当たれば、ループを抜けます。
if (::DGifGetExtensionNext(m_pGifInfo, &pSubBlock)==GIF_ERROR) return FALSE;
if (!pSubBlock) break;

int subBlockSize=pSubBlock[0];
//IDがNetScape2.0でサブブロックのサイズが3バイト以上の場合。
if ((m_bNetScapeExt)&&(subBlockSize>=3)){
//フィールドコードを取得します。
int fieldCode=pSubBlock[1]&0x07;
switch(fieldCode){
case LOOP_COUNT_CODE:
//フィールドコードがループ回数の場合は、
//ループ回数をメンバー変数に格納します。

m_nLoopCounts=(UINT)(*((WORD*)(&pSubBlock[2])));
break;
case BUFFER_BYTES_CODE:
//フィールドコードがバッファバイト数の場合は、
//バッファサイズをメンバー変数に格納します。

if (subBlockSize=5)
m_nBufferBytes=*((DWORD*)(&pSubBlock[2]));
break;
}
}
}
return TRUE;
}

//コメントブロックの読み込み
BOOL CGIFFile::ReadCommentBlock(GifByteType* pCommentBlock)
{
ASSERT(pCommentBlock);
ASSERT(m_pGifInfo);

//ブロックサイズが0ならFALSEを返して終了します。
int blockSize=pCommentBlock[0];
if (!blockSize) return TRUE;

//サブブロックがあればこれを読み捨てながら、
//ブロックターミネータを探します。

GifByteType* pSubBlock=0;
do{
if (::DGifGetExtensionNext(m_pGifInfo, &pSubBlock)==GIF_ERROR)
return FALSE;
}
while(pSubBlock);

//CString文字列にコピーします。
LPTSTR lpsz=m_strComment.GetBufferSetLength(blockSize+1);
::CopyMemory(lpsz,&pCommentBlock[1],blockSize);

//文字列の最後にASCIIZデリミタを追加します。
lpsz[blockSize]='\0';

return TRUE;
}

//プレーンテキストブロックの読み込み
BOOL CGIFFile::ReadPlainTextBlock(GifByteType* pPlainText)
{
ASSERT(pPlainText);
ASSERT(m_pGifInfo);

//ブロックサイズが12byteでなければ、
//FALSEを返して終了します。

int blockSize=pPlainText[0];
if (blockSize!=PLAIN_TEXT_SIZE) return FALSE;

//サブブロックを読み込みます。
GifByteType* pSubBlock=0;
while(TRUE){
//ブロックターミネータに突き当たれば、ループを抜けます。
if (::DGifGetExtensionNext(m_pGifInfo, &pSubBlock)==GIF_ERROR) return FALSE;
if (!pSubBlock) break;
//サブブロックがあればプレーンテキストをCString文字列にコピーします。
int subBlockSize=pSubBlock[0];
if (subBlockSize){
LPTSTR lpsz=m_strPlainText.GetBufferSetLength(subBlockSize+1);
::CopyMemory(lpsz,&pSubBlock[1],subBlockSize);
//文字列の最後にASCIIZデリミタを追加します。
lpsz[subBlockSize]='\0';
}
}
//プレーンテキストの各値をメンバー変数に格納します。
m_nTextGridLeft =*((WORD*)(&pPlainText[1]));
m_nTextGridTop =*((WORD*)(&pPlainText[3]));
m_nTextGridWidth =*((WORD*)(&pPlainText[5]));
m_nTextGridHeight=*((WORD*)(&pPlainText[7]));
m_nCharCellWidth =pPlainText[9];
m_nCharCellHeight=pPlainText[10];
m_nTextForegroundColorIndex=pPlainText[11];
m_nTextBackgroundColorIndex=pPlainText[12];
return TRUE;
}

//グラフィックブロックの読み込み
BOOL CGIFFile::ReadGraphicBlock(GifByteType* pGraphicBlock)
{
ASSERT(pGraphicBlock);
ASSERT(m_pGifInfo);

//ブロックサイズが4byteでなければ、
//FALSEを返して終了します。

int blockSize=pGraphicBlock[0];
if (blockSize!=GRAPHIC_CONTROL_SIZE) return FALSE;

//サブブロックがあればこれを読み捨てながら、
//ブロックターミネータを探します。

GifByteType* pSubBlock=0;
do{
if (::DGifGetExtensionNext(m_pGifInfo, &pSubBlock)==GIF_ERROR)
return FALSE;
}
while(pSubBlock);

//グラフィックブロックの各値をメンバー変数に格納します。
BYTE PackedField =pGraphicBlock[1];
m_bTransparent =PackedField&1;
m_bUserInputMethod=(PackedField>>1)&1;
m_disposalMethod =(PackedField>>2)&7;
m_delay =(DWORD)(*((WORD*)(&pGraphicBlock[2])));
m_indexTransparent=(m_bTransparent)?pGraphicBlock[4]:-1;
m_bGraphicBlock =TRUE;

return TRUE;
}


最後に指定DCに画像を表示する関数です。

//現在着目している画像を表示します。
void CGIFFile::OnDraw(CDC* pDC,int x,int y,int cx,int cy)
{

//現在着目しているCGIFLocalクラスへのポインタを取得します。
CGIFLocal* pLocal=GetLocal(m_nImage);
if (!pLocal) return;

//表示対象のDCハンドルを取得します。
HDC hDC=pDC->GetSafeHdc();

//CGIFLocalクラスから画像を取り出します。
HBITMAP hbmColor=pLocal->m_hbmColor;
HBITMAP hbmMask =pLocal->m_hbmMask;

//メモリーDCを作成します。
HDC hMemDC=::CreateCompatibleDC(hDC);
//きれいに縮小するために必要です。
::SetStretchBltMode(hMemDC,COLORONCOLOR);
::SetStretchBltMode(hDC,COLORONCOLOR);

//マスク画像がない場合は、カラー画像のみをコピーします。
if (!hbmMask){
HGDIOBJ hMemObj=::SelectObject(hMemDC,hbmColor);
::StretchBlt(hDC,x,y,cx,cy,hMemDC,0,0,m_LSWidth,m_LSHeight,SRCCOPY);
::SelectObject(hMemDC,hMemObj);
}
//透過画像の描画の場合
else{
//背景色が無効でブラウザの背景色も指定されていない場合は、
//背景画像をそのまま透過します。

if (m_rgbTransparent==-1){
//マスク画像で背景画像を切り取る
HGDIOBJ hMemObj=::SelectObject(hMemDC,hbmMask);
::StretchBlt(hDC,x,y,cx,cy,hMemDC,0,0,m_LSWidth,m_LSHeight,SRCAND);

//カラー画像をORコピーする
::SelectObject(hMemDC,hbmColor);
::StretchBlt(hDC,x,y,cx,cy,hMemDC,0,0,m_LSWidth,m_LSHeight,SRCPAINT);

//指定されたDCに画像をコピーする
::SelectObject(hMemDC,hMemObj);
}
//背景色若しくはブラウザの背景色が指定されている場合は、
//背景を指定の背景色で塗りつぶします。

else{
//背景のためのメモリーDCを作成します。
HDC hBackDC=::CreateCompatibleDC(hDC);
//きれいに縮小するために必要です。
::SetStretchBltMode(hBackDC,COLORONCOLOR);

//作成した背景DCに選択させるビットマップを作成します。
HBITMAP hbmBack=::CreateCompatibleBitmap(hDC,m_LSWidth,m_LSHeight);
HGDIOBJ hBackObj=::SelectObject(hBackDC,hbmBack);

//背景DCを指定の背景色で塗りつぶします。
CRect rect(0,0,m_LSWidth,m_LSHeight);
HBRUSH hbrBack=::CreateSolidBrush(m_rgbBackground);
::FillRect(hBackDC,&rect,hbrBack);
::DeleteObject(hbrBack);

//マスク画像で背景DCを切り取ります。
HGDIOBJ hMemObj=::SelectObject(hMemDC,hbmMask);
::BitBlt(hBackDC,0,0,m_LSWidth,m_LSHeight,hMemDC,0,0,SRCAND);

//背景DCにカラー画像をORコピーします。
::SelectObject(hMemDC,hbmColor);
::BitBlt(hBackDC,0,0,m_LSWidth,m_LSHeight,hMemDC,0,0,SRCPAINT);

//指定されたDCに画像をコピーします。
::StretchBlt(hDC,x,y,cx,cy,hBackDC,0,0,m_LSWidth,m_LSHeight,SRCCOPY);

//後片付けです。
::SelectObject(hBackDC,hBackObj);
::SelectObject(hMemDC,hMemObj);
::DeleteDC(hBackDC);
::DeleteObject(hbmBack);
}
}
::DeleteDC(hMemDC);
}


<<GIFファイルの読み込み 第1部ページの先頭GIFファイルの読み込み 第3部>>





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

メールアドレス:

ホームページアドレス:

コメント:

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


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

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