FC2ブログ

ホーム > アイコンファイルフォーマット > アイコンファイルの読み込み

アイコンファイルの読み込み



アイコンファイル複数のアイコン画像を納めたグループアイコン形式をとっており、以下のような構造をしています。

  1. ICONDIR構造体
    アイコンファイル内にあるアイコン数アイコン/カーソルの区別のための情報と、最初のアイコンの分のICONDIRENTRY構造体が格納されています。
  2. ICONDIRENTRY構造体
    アイコンのサイズ/ビット深度カーソルの場合はホットスポット情報、ファイル内でのICONIMAGE構造体までのオフセット値バイト数が格納されています。アイコンが2つ以上格納されている場合に存在し、ICONDIR構造体のすぐ後に続いて、2つ目のアイコンの分からアイコンの個数-1個だけ存在します。
  3. ICONIMAGE構造体
    アイコンDIBヘッダーカラーテーブルXOR/ANDイメージのピクセルデータが格納されています。アイコンの個数分だけ存在します。




PNGファイルの読み込み」で解説した_PNGStreamIn関数、並びに「libpngのインストール」でダウンロードしたlibpngを使用するためのインクルード定義です。

#include "png.h"
#include "PNGFile.h"
#include "DIBFile.h"


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

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


アイコンファイルの一番先頭にあるICONDIR構造体です。

//ICONDIR構造体
#pragma pack( push )
#pragma pack( 2 )
typedef struct tagICONDIR{
WORD idReserved; //予約済み(常に0)
WORD idType; //リソースタイプ アイコン:1、カーソル:2
WORD idCount; //アイコンの数
ICONDIRENTRY idEntries[1]; //ICONDIRENTRY構造体の配列
}ICONDIR, *LPICONDIR;
#pragma pack( pop )


アイコンファイルに格納されたアイコンの個数分存在するICONDIRENTRY構造体です。

//ICONDIRENTRY構造体
#pragma pack( push )
#pragma pack( 2 )
typedef struct tagICONDIRENTRY{
BYTE bWidth; //画像幅(単位:ピクセル)
BYTE bHeight; //画像高さ(単位:ピクセル)
BYTE bColorCount; //画像の色数(256色以上は0)
BYTE bReserved; //予約済み(常に0)
WORD wPlanes; //カラープレーン数  (カーソル時、Xホットスポット)
WORD wBitCount; //ピクセルのビット深度(カーソル時、Yホットスポット)
DWORD dwBytesInRes; //ピクセルデータのバイト数
DWORD dwImageOffset; //ファイル先頭からピクセルデータまでのオフセット
}ICONDIRENTRY, *LPICONDIRENTRY;
#pragma pack( pop )


ICONDIRENTRY構造体の後にある、アイコンの画像情報を収めたICONIMAGE構造体です。

//ICONIMAGE構造体
typedef struct tagICONIMAGE{
BITMAPINFOHEADER icHeader; //DIBヘッダ
RGBQUAD icColors[1]; //カラーテーブル
BYTE icXOR[1]; //カラーピクセルデータ
BYTE icAND[1]; //マスクピクセルデータ
} ICONIMAGE, *LPICONIMAGE;


アイコンファイルとグループアイコンリソースには通常複数のアイコンが格納されており、このグループアイコン形式に対応するために便宜上それぞれのアイコン毎の情報を管理するCIconクラスとこれらをを総括するCGroupIconクラスを独自に定義しました。
尚これらの構造体については「MSDNライブラリーのIcons」に詳しい解説があります。

まずは単体のアイコン毎の情報を管理するCIconクラスです。

//CIconクラス

class CIcon : public CObject
{
public:
CIcon();
HICON m_hIcon; //アイコンハンドル
ICONINFO m_IconInfo; //ICONINFO構造体

virtual ~CIcon();
//CIconクラスにアイコンハンドルを結び付けます。
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL Attach(HICON hIcon,UINT bitCount,LPCTSTR lpName,BOOL bDeleteDIB,BOOL bCompressedPNG);
//ICONINFO構造体を元にアイコンを作成し、CIconクラスに結び付けます。
//ICONINFO構造体に包括されているBITMAPハンドルは、呼び出し元で削除してください。

BOOL CreateIndirect(ICONINFO* pIconInfo,LPCTSTR lpName,BOOL bCompressedPNG);
//CIconクラスからアイコンハンドルを切り離します。
HICON Detach();
//CIconクラスのメンバー変数の削除
void Delete();
//指定されたCIconクラスのコピーを作成します。
BOOL Copy(CIcon* pIcon);

//ファイルストリームからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL StreamIn(CFile* infile,BOOL bIcon,LPCTSTR lpName,BOOL bDeleteDIB);
//リソースメモリーからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL LoadResource(HMODULE hModule,LPCTSTR lpName,BOOL bIcon,BOOL bDeleteDIB);

//ファイルストリームへの書き込み
//bDeleteDIB TRUE:ファイル書き込みに使用したDIBを削除する。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

BOOL StreamOut(CFile* outfile,BOOL bIcon,BOOL bDeleteDIB,int iPNGMinimumSize);

//アイコンハンドルの取得
HICON GetSafeHandle(){return m_hIcon;};
//現在のアイコンハンドルからDIBを復元する
BOOL RetrieveDIB();

//DIBを含んだCONINFO構造体の取得
BOOL GetIconInfo(ICONINFO* pIconInfo);
//幅の取得
UINT Width(){return m_width;};
//高さの取得
UINT Height(){return m_height;};
//ビット深度の取得
UINT BitCount(){return m_bitCount;};
//X軸ホットスポットの取得
DWORD GetxHotspot(){return m_IconInfo.xHotspot;};
//Y軸ホットスポットの取得
DWORD GetyHotspot(){return m_IconInfo.yHotspot;};
//ホットスポットの設定
BOOL SetHotspot(DWORD xHotspot=-1,DWORD yHotspot=-1);


//リソース形式の取得
LPCTSTR GetType(){return m_lpType;};
//リソース形式の設定
void SetType(LPCTSTR lpType);
//リソース名の取得
LPCTSTR GetName(){return m_lpName;};
//リソース名の設定
void SetName(LPCTSTR lpName);
//PNG圧縮されているかどうか?
UINT IsCompressedPNG(){return m_bCompressedPNG;};
//PNG圧縮に設定する
void CompressedPNG(BOOL bON=TRUE){m_bCompressedPNG=bON;};
//描画
void OnDraw(CDC* pDC,int x,int y,int cx=0,int cy=0);

private:
UINT m_width; //幅
UINT m_height; //高さ
UINT m_bitCount; //ビット深度
LPCTSTR m_lpType; //リソース形式(RT_ICON/RT_CURSOR)
LPCTSTR m_lpName; //リソース名
BOOL m_bCompressedPNG; //PNG圧縮されていればTRUE
};


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

//CIconクラスの削除
inline void CIcon::Delete()
{
::DestroyIcon(Detach());
}

//リソース形式の設定
inline void CIcon::SetType(LPCTSTR lpType)
{
if (HIWORD(m_lpType)) delete[]m_lpType;
if (HIWORD(lpType)){
m_lpType=new TCHAR[::lstrlen(lpType)+1];
::lstrcpy((LPTSTR)m_lpType,lpType);
}
else m_lpType=lpType;
}

//リソース名の設定
inline void CIcon::SetName(LPCTSTR lpName)
{
if (HIWORD(m_lpName)) delete[]m_lpName;
if (HIWORD(lpName)){
m_lpName=new TCHAR[::lstrlen(lpName)+1];
::lstrcpy((LPTSTR)m_lpName,lpName);
}
else m_lpName=lpName;
}

//描画
inline void CIcon::OnDraw(CDC* pDC,int x,int y,int cx,int cy)
{
if (m_hIcon){
if (cx<=0) cx=m_width;
if (cy<=0) cy=m_height;
::DrawIconEx(pDC->GetSafeHdc(),x,y,m_hIcon,cx,cy,0,0,DI_NORMAL);
}
}


CIconクラスのコンストラクタとデストラクタです。

//コンストラクタ
CIcon::CIcon()
{
m_hIcon =NULL;
m_width =0;
m_height=0;
m_bitCount=0;
m_lpType=0;
m_lpName=0;
m_bCompressedPNG=FALSE;
::ZeroMemory(&m_IconInfo,sizeof(ICONINFO));
}

//デストラクタ
CIcon::~CIcon()
{
Delete();
}


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

//CIconクラスにアイコンハンドルを結び付けます。
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CIcon::Attach(HICON hIcon,UINT bitCount,LPCTSTR lpName,BOOL bDeleteDIB,BOOL bCompressedPNG)
{
//入力されたアイコンハンドルからICONINFO構造体を取得します。
ICONINFO IconInfo;
//取得に失敗したら、FALSEを返して終了します。
if (!::GetIconInfo(hIcon,&IconInfo)) return FALSE;

//BITMAP構造体の取得
BITMAP bm;
//カラービットマップからBITMAP構造体を取得します。
if (!::GetObject(IconInfo.hbmColor,sizeof(BITMAP),&bm)){
//カラービットマップがないなら、マスクビットマップから取得します。
//取得に失敗したら、FALSEを返して終了します。

if (!::GetObject(IconInfo.hbmMask,sizeof(BITMAP),&bm)) return FALSE;
//マスクビットマップのみの場合、ビットマップの高さの1/2をアイコンの高さとします。
bm.bmHeight>>=1;
}
//CIconクラスのメンバー変数を削除して、アイコンハンドルを格納します。
Delete();
m_hIcon=hIcon;

//各データを保存しておく
m_width=bm.bmWidth; //DIBの幅をアイコンの幅とします。
m_height=bm.bmHeight; //DIBの高さをアイコンの高さとします。
m_bCompressedPNG=bCompressedPNG;

//ビット深度はPNG圧縮の場合は32ビット、それ以外は引数の値をとります。
m_bitCount=(m_bCompressedPNG)? bm.bmBitsPixel:bitCount;
//リソース形式を設定します。(RT_ICON/RT_CURSOR)
SetType((IconInfo.fIcon)?RT_ICON:RT_CURSOR);
//リソース名を保存します。
SetName(lpName);

//bDeleteDIB(削除フラグ)がTRUEの場合は、DIBを削除します。
if (bDeleteDIB){
::DeleteObject(IconInfo.hbmColor);
::DeleteObject(IconInfo.hbmMask);
IconInfo.hbmColor=0;
IconInfo.hbmMask=0;
}
//ICONINFO構造体をこのクラスに結び付けます。
::CopyMemory(&m_IconInfo,&IconInfo,sizeof(ICONINFO));
return TRUE;
}

//ICONINFO構造体を元にアイコンを作成し、CIconクラスに結び付けます。
//BITMAPハンドルは呼び出し元で削除してください。
BOOL CIcon::CreateIndirect(ICONINFO* pIconInfo,LPCTSTR lpName,BOOL bCompressedPNG)
{
//入力されたICONINFO構造体へのポインタが正しくないなら、FALSEを返して終了します。
if (!AfxIsValidAddress(pIconInfo,sizeof(ICONINFO),0)) return FALSE;

//カラービットマップのBITMAP構造体の取得に失敗したら、FALSEを返して終了します。
BITMAP bm;
if (!::GetObject(pIconInfo->hbmColor,sizeof(BITMAP),&bm)) return FALSE;

//アイコン作成に失敗したらFALSEを返して終了する
HICON hIcon=::CreateIconIndirect(pIconInfo);
if (!hIcon) return FALSE;

//CIconクラスのメンバー変数を削除して、アイコンハンドルを格納します。
Delete();
m_hIcon=hIcon;

//各データを保存しておく
m_width=bm.bmWidth; //DIBの幅をとります。
m_height=bm.bmHeight; //DIBの高さをとります。
m_bitCount=bm.bmBitsPixel; //DIBのビット深度をとります。
m_bCompressedPNG=bCompressedPNG;

//リソース形式を設定します。(RT_ICON/RT_CURSOR)
SetType((pIconInfo->fIcon)?RT_ICON:RT_CURSOR);
//リソース名を保存します。
SetName(lpName);
//ICONINFO構造体をこのクラスに結び付けます。
::CopyMemory(&m_IconInfo,pIconInfo,sizeof(ICONINFO));
m_IconInfo.hbmColor=0;
m_IconInfo.hbmMask=0;

return TRUE;
}

//CIconクラスからアイコンハンドルを切り離します。
HICON CIcon::Detach()
{
HICON hIcon=m_hIcon;
m_hIcon=0;
if (HIWORD(m_lpType)) delete[]m_lpType;
if (HIWORD(m_lpName)) delete[]m_lpName;
m_lpType=m_lpName=0;
if (m_IconInfo.hbmColor) ::DeleteObject(m_IconInfo.hbmColor);
if (m_IconInfo.hbmMask ) ::DeleteObject(m_IconInfo.hbmMask );
m_width =0;
m_height=0;
m_bitCount=0;
m_lpType=0;
m_lpName=0;
m_bCompressedPNG=FALSE;
::ZeroMemory(&m_IconInfo,sizeof(ICONINFO));
return hIcon;
}

//指定されたCIconクラスのコピーを作成します。
BOOL CIcon::Copy(CIcon* pIcon)
{
if (!AfxIsValidAddress(pIcon,sizeof(CIcon),0)) return FALSE;
Delete();
m_hIcon=::CopyIcon(pIcon->m_hIcon);
::CopyMemory(&m_IconInfo,&pIcon->m_IconInfo,sizeof(ICONINFO));
if (m_IconInfo.hbmColor) m_IconInfo.hbmColor=_CopyDIB(m_IconInfo.hbmColor);
if (m_IconInfo.hbmMask ) m_IconInfo.hbmMask =_CopyDIB(m_IconInfo.hbmMask);

m_width=pIcon->Width();
m_height=pIcon->Height();
m_bitCount=pIcon->BitCount();
SetType(pIcon->GetType());
SetName(pIcon->GetName());
m_bCompressedPNG=pIcon->IsCompressedPNG();
return TRUE;
}

//ホットスポットの設定
BOOL CIcon::SetHotspot(DWORD xHotspot,DWORD yHotspot)
{
if ((HIWORD(xHotspot))&&(HIWORD(yHotspot))) return FALSE;
ICONINFO IconInfo;
if (!::GetIconInfo(m_hIcon,&IconInfo)) return FALSE;
IconInfo.fIcon=FALSE;
if (!HIWORD(xHotspot)) IconInfo.xHotspot=xHotspot;
if (!HIWORD(yHotspot)) IconInfo.yHotspot=yHotspot;
HICON hIcon=::CreateIconIndirect(&IconInfo);
::DeleteObject(IconInfo.hbmColor);
::DeleteObject(IconInfo.hbmMask);
if (!hIcon) return FALSE;
::DestroyIcon(m_hIcon);
m_hIcon=hIcon;
m_IconInfo.fIcon=IconInfo.fIcon;
m_IconInfo.xHotspot=IconInfo.xHotspot;
m_IconInfo.yHotspot=IconInfo.yHotspot;
m_lpType=RT_CURSOR;
return TRUE;
}

//DIBを含んだICONINFO構造体の取得
BOOL CIcon::GetIconInfo(ICONINFO* pIconInfo)
{
if (!AfxIsValidAddress(pIconInfo,sizeof(ICONINFO))) return FALSE;
BOOL bSafeDIB=((m_IconInfo.hbmColor)&&(m_IconInfo.hbmMask));
if (!RetrieveDIB()) return FALSE;
::CopyMemory(pIconInfo,&m_IconInfo,sizeof(ICONINFO));
if (bSafeDIB){
pIconInfo->hbmColor=_CopyDIB(m_IconInfo.hbmColor);
pIconInfo->hbmMask =_CopyDIB(m_IconInfo.hbmMask);
}
else
m_IconInfo.hbmColor=m_IconInfo.hbmMask=0;
return TRUE;
}


引き続いてCIconクラスを総括するCGroupIconクラスです。

// CGroupIconクラス

class CGroupIcon : public CObject
{
public:
CGroupIcon();
virtual ~CGroupIcon();

//すべてのアイコンを削除
void Delete();
//指定されたCGroupIconクラスのコピーを作成します。
BOOL Copy(CGroupIcon* pGrpIcon);

//ファイルの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL LoadFile(LPCTSTR lpszFileName,BOOL bDeleteDIB=TRUE);

//DLL/EXEリソースの読み込み
//lpNameはリソース名で、リソースIDをMAKEINTRESOURCEマクロで型キャストした値が入ります。
//lpTypeはリソース形式で、この関数では以下の4種類のリソースが読み込めます。
// 単体のアイコン :RT_ICON
// 単体のカーソル :RT_CURSOR
// グループアイコン:RT_GROUP_ICON
// グループカーソル:RT_GROUP_CURSOR
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL LoadResource(LPCTSTR lpszExeName,LPCTSTR lpName,LPCTSTR lpType,BOOL bDeleteDIB=TRUE);
//リソースからグループアイコンを読み込む
BOOL LoadResource(HMODULE hModule,LPCTSTR lpName,LPCTSTR lpType,BOOL bDeleteDIB);

//ファイルストリームからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL StreamIn(CFile* infile,BOOL bDeleteDIB);

//ファイルの書き込み
//bDeleteDIB TRUE:ファイル書き込みに使用したDIBを削除する。
//iPNGMinimumSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

BOOL SaveFile(LPCTSTR lpszFileName,LPCTSTR lpType=0,BOOL bDeleteDIB=TRUE,int iPNGMinimumSize=256);
//ファイルストリームへの書き込み
//bDeleteDIB TRUE:ファイル書き込みに使用したDIBを削除する。

BOOL StreamOut(CFile* outfile,LPCTSTR lpType,BOOL bDeleteDIB,int iPNGMinimumSize);

//要求するサイズ、ビット深度に一番近いアイコンを探す
int FindBestIcon(int cxDesired,int cyDesired,int bitsDesired);
//アイコンの描画
void OnDraw(CDC* pDC,int x,int y,int cx=0,int cy=0);
//このクラスが保持しているCIconクラスの数
INT_PTR GetCount(){return m_listIcon.GetCount();};
//指定番号のCIconクラスの取得
CIcon* GetIcon(int index){return (CIcon*)m_listIcon.GetAt(index);};
//現在選択中のアイコン番号の取得
int GetIconIndex(){return m_indexIcon;};
//現在選択中のAアイコン番号の設定
void SetIconIndex(int indexIcon){m_indexIcon=indexIcon;};
//現在選択中のアイコンの取得
CIcon* GetActiveIcon(){return (GetCount())? GetIcon(m_indexIcon):0;};
//アイコンを追加する
INT_PTR AddIcon(CIcon* pIcon){return m_listIcon.Add(pIcon);};
//リソース形式の取得
LPCTSTR GetType(){return m_lpType;}
//リソース形式の設定
void SetType(LPCTSTR lpType);
//リソース名の取得
LPCTSTR GetName(){return m_lpName;}
//リソース名の設定
void SetName(LPCTSTR lpName);

private:
CPtrArray m_listIcon; //このクラスが保持しているCIconクラスのリスト
int m_indexIcon; //現在選択しているCIconクラスの番号
LPCTSTR m_lpType; //リソース形式(RT_GROUP_ICON/RT_GROUP_CURSOR)
LPCTSTR m_lpName; //リソース名
};


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

//このクラスが保持しているすべてのCIconクラスを削除する。
inline void CGroupIcon::Delete()
{
for(int i=0;i<m_listIcon.GetCount();i++)
delete ((CIcon*)m_listIcon.GetAt(i));
m_listIcon.RemoveAll();
if (HIWORD(m_lpType)) delete[]m_lpType;
if (HIWORD(m_lpName)) delete[]m_lpName;
m_lpType=m_lpName=0;
}

//アイコンの描画
inline void CGroupIcon::OnDraw(CDC* pDCint x,int y,int cx,int cy)
{
CIcon* pIcon=GetActiveIcon();
if (pIcon) pIcon->OnDraw(pDC,x,y,cx,xy);
}

//リソース形式の設定
inline void CGroupIcon::SetType(LPCTSTR lpType)
{
if (HIWORD(m_lpType)) delete[]m_lpType;
if (HIWORD(lpType)){
m_lpType=new TCHAR[::lstrlen(lpType)+1];
::lstrcpy((LPTSTR)m_lpType,lpType);
}
else m_lpType=lpType;
}

//リソース名の設定
inline void CGroupIcon::SetName(LPCTSTR lpName)
{
if (HIWORD(m_lpName)) delete[]m_lpName;
if (HIWORD(lpName)){
m_lpName=new TCHAR[::lstrlen(lpName)+1];
::lstrcpy((LPTSTR)m_lpName,lpName);
}
else m_lpName=lpName;
}


CGroupIconクラスのコンストラクタとデストラクタです。

//コンストラクタ
CGroupIcon::CGroupIcon()
{
m_indexIcon=0;
m_lpType=RT_GROUP_ICON;
m_lpName=0;
}

//デストラクタ
CGroupIcon::~CGroupIcon()
{
Delete();
}


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

// CGroupIcon member functions
//指定されたCGroupIconクラスのコピーを作成します。

BOOL CGroupIcon::Copy(CGroupIcon* pGrpIcon)
{
if (!AfxIsValidAddress(pGrpIcon,sizeof(CGroupIcon),0)) return FALSE;
Delete();
INT_PTR nIcons=pGrpIcon->GetCount();
for(int i=0;i<nIcons;i++){
CIcon* pIcon=new CIcon();
pIcon->Copy(pGrpIcon->GetIcon(i));
AddIcon(pIcon);
}
m_indexIcon=pGrpIcon->GetIconIndex();
SetType(pGrpIcon->GetType());
SetName(pGrpIcon->GetName());
return TRUE;
}


アイコンファイルを開いて、CGroupIconクラスStreamIn関数を呼び出します。

//ファイルの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CGroupIcon::LoadFile(LPCTSTR lpszFileName,BOOL bDeleteDIB)
{
CFile infile;
if (!infile.Open(lpszFileName,CFile::modeRead)) return FALSE;
BOOL bResult=StreamIn(&infile,bDeleteDIB);
infile.Close();
if (bResult){
//リソース名にファイル名を設定する
SetName(::PathFindFileName(lpszFileName));
}
return bResult;
}


CIconクラスを作成してアイコン毎に読み込み、CIconクラスのリストに追加します。

//ファイルストリームからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CGroupIcon::StreamIn(CFile* infile,BOOL bDeleteDIB)
{
ASSERT(AfxIsValidAddress(infile,sizeof(CFile),0));

//ICONDIRの読み込み
ICONDIR IconDir;
UINT uSize=infile->Read(&IconDir,sizeof(WORD)*3);
if (uSize<sizeof(WORD)*3) return FALSE;
//リソースタイプがアイコンでもカーソルでもない時はFALSEを返して終了する。
if ((IconDir.idType!=1)&&(IconDir.idType!=2)) return FALSE;
BOOL bIcon=(IconDir.idType==1);

Delete(); //すべてのアイコンを消去しておく
for(UINT i=0;i<IconDir.idCount;i++){
//CIconクラスを作成して、アイコン毎に読み込む
CIcon* pIcon=new CIcon();
//読み込みに失敗したらCIconクラスを削除し、
//成功したらCIconクラスのリストに追加する

if (!pIcon->StreamIn(infile,bIcon,(LPCTSTR)(i+1),bDeleteDIB)) delete pIcon;
else m_listIcon.Add(pIcon);//アイコンリストに追加する
}

//一つも読めなかったのでFALSEを返して終了する。
if (!m_listIcon.GetCount()) return FALSE;

//アイコンリストの中からサイズとビット深度が一番大きいアイコンを選択します。
m_indexIcon=FindBestIcon(256,256,32);
//リソース形式をアイコンならRT_GROUP_ICON、カーソルならRT_GROUP_CURSORとします。
SetType((bIcon)?RT_GROUP_ICON:RT_GROUP_CURSOR);
return TRUE;
}


アイコン毎にICONDIRENTRY構造体を読み込み、その値からICONIMAGE構造体の位置を算出し、読み込んでからアイコンを作成します。

//ファイルストリームからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CIcon::StreamIn(CFile* infile,BOOL bIcon,LPCTSTR lpName,BOOL bDeleteDIB)
{
//ICONDIRENTRY構造体の読み込み
ICONDIRENTRY IdEntry;
UINT uSize=infile->Read(&IdEntry,sizeof(ICONDIRENTRY));
if (uSize<sizeof(ICONDIRENTRY)) return FALSE;

//次のエントリーへのファイルポインターを保存する
ULONGLONG uNextEntry=infile->GetPosition();

//イメージデータの先頭にファイルポインタを移動する
infile->Seek(IdEntry.dwImageOffset,CFile::begin);

//アイコンのイメージデータを読み込む
ICONIMAGE* pIconImage=(ICONIMAGE*)(new BYTE[IdEntry.dwBytesInRes]);
uSize=infile->Read(pIconImage,IdEntry.dwBytesInRes);
if (uSize<IdEntry.dwBytesInRes){
delete[]pIconImage;
return FALSE;
}

//ファイルポインタを次のエントリーの先頭に戻す
infile->Seek(uNextEntry,CFile::begin);

//ICONIMAGE構造体からDIBを得る
HBITMAP hbmMask=0;
HBITMAP hbmColor=_IconImageToDIB(&hbmMask,pIconImage,IdEntry.dwBytesInRes);

//PNG圧縮フラグOFF
BOOL bCompressedPNG=FALSE;

//BITMAP構造体の取得
BITMAP bm;
//DIB作成に失敗していたら、PNGストリームとして再度読み込んでみる。
if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)){
//アイコンのイメージデータを元にCMemFileクラスを作成する。
CMemFile infile((PBYTE)pIconImage,IdEntry.dwBytesInRes);
//PNGファイルストリームとして読み込んでみる。
hbmColor=_PNGStreamIn(&infile);
infile.Close();
//DIBの作成に失敗していたら、
//イメージデータを削除してからFALSEを返して終了する。

if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)){
delete[]pIconImage;
return FALSE;
}
//DIBが作成できたら空のマスクDIBを作成する。
hbmMask=::CreateBitmap(bm.bmWidth,bm.bmHeight,1,1,0);
//PNG圧縮フラグをONにする。
bCompressedPNG=TRUE;
}
//イメージデータはもう要らないので削除する。
delete[]pIconImage;

//DIBからアイコンを作成する
ICONINFO IconInfo;
IconInfo.fIcon=bIcon;
IconInfo.xHotspot=(bIcon)?0:IdEntry.wPlanes; //xHotspot;
IconInfo.yHotspot=(bIcon)?0:IdEntry.wBitCount; //yHotspot;
IconInfo.hbmColor=hbmColor;
IconInfo.hbmMask =hbmMask;
//アイコン作成に失敗したらFALSEを返して終了する。
if (!CreateIndirect(&IconInfo,lpName,bCompressedPNG)){
::DeleteObject(hbmColor);
::DeleteObject(hbmMask);
return FALSE;
}

//DIBを削除する場合
if (bDeleteDIB){
::DeleteObject(hbmColor);
::DeleteObject(hbmMask);
}
//DIBを保存する場合
else{
m_IconInfo.hbmColor=hbmColor;
if (bCompressedPNG){
m_IconInfo.hbmMask=(HBITMAP)::CopyImage(hbmMask,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
::DeleteObject(hbmMask);
}
else m_IconInfo.hbmMask=hbmMask;
}
return TRUE;
}


読み込んだICONIMAGE構造体からカラー/マスクDIBを作成します。

//ICONIMAGE構造体からDIBを作成する
HBITMAP __stdcall _IconImageToDIB(HBITMAP* lphbmMask,ICONIMAGE* pIconImage,
DWORD dwSizeOfIconImage)
{
//パラメータが有効かチェックする
if (!AfxIsValidAddress(lphbmMask,sizeof(HBITMAP))) return FALSE;
if (!AfxIsValidAddress(pIconImage,dwSizeOfIconImage,0)) return FALSE;

//DIBメモリーがDIBでなければFALSEを返して終了する。
if (pIconImage->icHeader.biSize!=sizeof(BITMAPINFOHEADER)) return FALSE;

UINT width =pIconImage->icHeader.biWidth; //DIBの幅
UINT height=abs(pIconImage->icHeader.biHeight/2); //DIBの高さ(絶対値)
UINT nBpp=pIconImage->icHeader.biBitCount; //DIBのビットカウント

DWORD widthBytesColor=WIDTHBYTES(nBpp*width); //カラービットマップバイト幅の算出
DWORD dwColorImage =widthBytesColor*height; //カラーピクセルデータのバイト数
DWORD widthBytesMask =WIDTHBYTES(width); //マスクビットマップバイト幅の算出
DWORD dwMaskImage =widthBytesMask*height; //マスクピクセルデータのバイト数

//使用色数を算出します。
UINT nColors=(nBpp>8)?0:1<<nBpp;

//BITMAPINFO構造体のサイズを算出する
DWORD dwSizeOfBitmapInfo=sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*nColors;
//算出したサイズがメモリーサイズより大きいときはFALSEを返して終了する。
if (dwSizeOfBitmapInfo>dwSizeOfIconImage) return FALSE;

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

//メモリー上にあるBITMAPINFO構造体をコピーする
::CopyMemory(pBmpInfo,pIconImage,dwSizeOfBitmapInfo);

//リソースにあるカラーピクセルデータへのポインタを算出
BYTE* pColorPixel=(BYTE*)pIconImage+dwSizeOfBitmapInfo;
//リソースにあるマスクピクセルデータへのポインタを算出
BYTE* pMaskPixel =pColorPixel+dwColorImage;
//リソースにあるピクセルデータのサイズ(バイト)
DWORD dwBytesInRes=dwSizeOfIconImage-dwSizeOfBitmapInfo;
//リソースサイズが足りない時は、FALSEを返して終了する。
if (dwBytesInRes<dwColorImage) return FALSE;

//カラーDIBを作成
LPVOID pvBitsColor=0;
pBmpInfo->bmiHeader.biHeight=height;
pBmpInfo->bmiHeader.biSizeImage=dwColorImage;
//32ビットDIBの場合。
if (nBpp==32){
//アルファ32ビットDIBで無い場合は、アルファビットに有効な値があるか調べる。
if (pBmpInfo->bmiHeader.biCompression!=BI_BITFIELDS)
{
DWORD* src=(DWORD*)pColorPixel;
UINT nPixels=dwColorImage>>2;
for(UINT i=0;i<nPixels;i++){
if (((*src++)&0xFF000000)!=0){
//アルファビットに有効な値があったので、アルファ32ビットDIBに変更します。
pBmpInfo->bmiHeader.biCompression=BI_BITFIELDS;
break;
}
}
}
//アルファ32ビットDIBの場合は、それぞれのマスク値を設定します。
if (pBmpInfo->bmiHeader.biCompression==BI_BITFIELDS){
pBmpInfo->bmiHeader.biSize=sizeof(BITMAPV5HEADER);
BITMAPV5HEADER* pBmV5=(BITMAPV5HEADER*)(&pBmpInfo->bmiHeader);
pBmV5->bV5RedMask =0x00FF0000;
pBmV5->bV5GreenMask=0x0000FF00;
pBmV5->bV5BlueMask =0x000000FF;
pBmV5->bV5AlphaMask=0xFF000000;
}
}

HBITMAP hbmColor=::CreateDIBSection(0,pBmpInfo,DIB_RGB_COLORS,&pvBitsColor,NULL,NULL);
if (!hbmColor) return FALSE;

//ピクセルをそのままコピーする
::CopyMemory(pvBitsColor,pColorPixel,dwColorImage);

//マスクDIBを作成
pBmpInfo->bmiHeader.biBitCount=1;
pBmpInfo->bmiHeader.biClrUsed=2;
pBmpInfo->bmiHeader.biCompression=BI_RGB;
pBmpInfo->bmiHeader.biSizeImage=dwMaskImage;
RGBQUAD* pColors=pBmpInfo->bmiColors;
::ZeroMemory(pColors,sizeof(RGBQUAD)*2);
pColors[1].rgbBlue=pColors[1].rgbGreen=pColors[1].rgbRed=0xFF;
LPVOID pvBitsMask=0;
HBITMAP hbmMask=::CreateDIBSection(0,pBmpInfo,DIB_RGB_COLORS,&pvBitsMask,NULL,NULL);
//DIBの作成に失敗したらFALSEを返して終了する。
if (!hbmMask){
::DeleteObject(hbmColor);
return FALSE;
}

//ピクセルをそのままコピーする
dwBytesInRes-=dwColorImage;
dwBytesInRes=min(dwBytesInRes,dwMaskImage);
::CopyMemory(pvBitsMask,pMaskPixel,dwBytesInRes);

*lphbmMask=hbmMask; //マスクDIBのハンドルを引数に格納
return hbmColor;
}


最後に読み込んだアイコンの中からサイズとビット深度が一番大きいアイコンを選択します。

//要求するサイズ、ビット深度に一番近いアイコンを探す
int CGroupIcon::FindBestIcon(int cxDesired,int cyDesired,int bitsDesired)
{
INT_PTR nIcons=GetCount();
if (!nIcons) return 0;

int maxwidth,maxheight,maxbits,cx,cy,bits,bestEntry=-1;

//まずは要求サイズと同じかそれより小さいアイコンのうち最大のものを探す
maxwidth=maxheight=maxbits=0;
for(int i=0;i<nIcons;i++){
CIcon* pIcon=GetIcon(i);
cx=pIcon->Width();
cy=pIcon->Height();
bits=pIcon->BitCount();
if ((cx<=cxDesired)&&(cy<=cyDesired)&&(bits<=bitsDesired)&&
(cx>=maxwidth)&&(cy>=maxheight)&&(bits>=maxbits))
{
bestEntry=i;
maxwidth =cx;
maxheight=cy;
maxbits=bits;
}
}
if (bestEntry!=-1) return bestEntry;

//次に要求サイズより大きいアイコンのうち最小のものを探す
maxwidth=maxheight=255;
maxbits=32;
for(UINT i=0;i<nIcons;i++){
CIcon* pIcon=GetIcon(i);
cx=pIcon->Width();
cy=pIcon->Height();
bits=pIcon->BitCount();
if (((cx<=maxwidth)&&(cy<=maxheight)&&(bits<=maxbits))||(bestEntry==-1))
{
bestEntry=i;
maxwidth =cx;
maxheight=cy;
maxbits=bits;
}
}
//見つからなければ一番最初のアイコンを選ぶ
if (bestEntry==-1) return 0;
return bestEntry;
}


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

上記のzipファイルをダウンロードしてからWinRAR等で解凍し、IconFileTest01フォルダー内にある「IconFileTest.sln」を開きます。「F5」キーを押すとビルド確認のダイヤログが表示されるので、「Yes」ボタンを押してソリューションをビルドします。



ビルドが終わると、直ちにプログラムが自動起動してウィンドウが表示されます。メニューから「ファイル」/「開く」を選択して、「ファイルを開く」ダイヤログを表示させます。



resフォルダー内の「explorer00100.ico」を選択し、「開く」ボタンを押して読み込みます。画像が表示されたところで、アイコン番号の選択コンボで複数個アイコンが読み込まれているか確認してください。




スポンサーサイト



コメント: 0

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

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/21-c75ee68c
Listed below are links to weblogs that reference
アイコンファイルの読み込み from マルチメディアファイルフォーマット

Home > アイコンファイルフォーマット > アイコンファイルの読み込み

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

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る