FC2ブログ

ホーム > 未分類 > アイコンファイルの書き込みの修正

アイコンファイルの書き込みの修正

  • 著者名: ひろし
  • 2010-11-07 Sun 03:47:04
  • 未分類


以前解説した「アイコンファイルの読み込み」及び「アイコンリソースの読み込み」で読み込んだグループアイコン(CGroupIconクラス)をファイルに保存する方法を説明します。

  1. ICONDIR構造体をファイルに書き込んでから、エントリーしているアイコンの個数分、空のICONDIRENTRY構造体を先に書いておきます。
  2. エントリーしているアイコン毎に、ICONDIRENTRY構造体ICONIMAGE構造体をファイルに書き込みます。




DIBファイルフォーマット」で解説した一連のDIB関連の関数と「PNGファイルの書き込み」で解説した_PNGStreamOut関数、並びに「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


CIconクラスCGroupIconクラスを格納したファイルです。

GroupIcon.h GroupIcon.cpp



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

「lpng143」フォルダーからコピーするファイル

png.h
pngconf.h

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

zlib.h
zconf.h


アイコンファイルを新たに作成して、CGroupIconクラスStreamOut関数を呼び出します。

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

BOOL CGroupIcon::SaveFile(LPCTSTR lpszFileName,LPCTSTR lpType,BOOL bDeleteDIB,int iPNGMinmunSize)
{
//CFileクラスを使って、指定パス名のファイルを開きます。
CFile outfile;
if (!outfile.Open(lpszFileName,CFile::modeCreate|CFile::modeWrite)) return FALSE;

//グループアイコンをファイルストリームに書き込む関数を呼び出します。
BOOL bResult=StreamOut(outfile,lpType,bDeleteDIB,iPNGMinmunSize);
outfile.Close();

//書き込みに成功したらパス名を保存しておきます。
if (bResult) SetName(::PathFindFileName(lpszFileName));
return bResult;
}


CGroupIconクラスに格納された//CIconクラスのStreamOut関数を呼び出して、グループアイコンをファイルストリームに書き出します。

//ファイルストリームへの書き込み
//bDeleteDIB TRUE:ファイル書き込みに使用したDIBを削除する。

BOOL CGroupIcon::StreamOut(CFile& outfile,LPCTSTR lpType,BOOL bDeleteDIB,int iPNGMinmunSize)
{
//グループアイコンに格納されたアイコン数を取得する。
INT_PTR nIcons=m_listIcon.GetCount();
//格納されたアイコンがなければ、FALSEを返して終了する。
if (nIcons<1) return FALSE;

//指定のリソース形式がRT_GROUP_CONかRT_GROUP_CURSORなら、メンバー変数を変更する
if ((lpType==RT_GROUP_ICON)||(lpType==RT_GROUP_CURSOR)) m_lpType=lpType;
//リソース形式がRT_GROUP_ICONなら1、RT_GROUP_CURSORなら2、
//その他はFALSEを返して終了する。

UINT idType=(m_lpType==RT_GROUP_ICON)? 1:((m_lpType==RT_GROUP_CURSOR)?2:0);
if (!idType) return FALSE;
BOOL bIcon=(idType==1); //リソース形式がRT_GROUP_ICONのとき、TRUEになる

//ICONDIRの書き込み
ICONDIR IconDir={0};
IconDir.idCount=(WORD)nIcons; //格納するアイコンの個数
IconDir.idType=(WORD)idType; //リソース形式 アイコン:1、カーソル:2

//ICONDIR構造体の最初の3ワードのみ、ファイルに書き出す
outfile.Write(&IconDir,sizeof(WORD)*3);

//現在のファイル位置を取得する
ULONGLONG IdEntryPos=outfile.GetPosition();

//エントリーしているアイコンの個数分、空のICONDIRENTRY構造体を先に書いておく
for(int i=0;i<nIcons;i++)
outfile.Write(&IconDir.idEntries,sizeof(ICONDIRENTRY));

//ファイル位置をICONDIRENTRY構造体の先頭に戻す
outfile.Seek(IdEntryPos,CFile::begin);

//エントリーしているアイコン毎に書き込む
for(int i=0;i<nIcons;i++){
//CIconクラスを作成
CIcon* pIcon=(CIcon*m_listIcon.GetAt(i);
//単体のアイコン毎の書き込みに失敗したらFALSEを返して終了する
if (!pIcon->StreamOut(outfile,bIcon,bDeleteDIB,iPNGMinmunSize)) return FALSE;
}
return TRUE;
}


エントリーしているアイコン毎に、ICONDIRENTRY構造体ICONIMAGE構造体をファイルに書き込みます。

//ファイルストリームへの書き込み
//bDeleteDIB TRUE:ファイル書き込みに使用したDIBを削除する。

BOOL CIcon::StreamOut(CFile& outfile,BOOL bIcon,BOOL bDeleteDIB,int iPNGMinmunSize)
{
//ICONDIRENTRY構造体の先頭位置を保存しておく
ULONGLONG IdEntryPos=outfile.GetPosition();
//ファイル末尾に移動
ULONGLONG ImageOffset=outfile.Seek(0L,CFile::end);

//DIBの復元
if (!RetrieveDIB()){
//ICONDIRENTRY構造体の先頭位置に戻る
outfile.Seek(IdEntryPos,CFile::begin);
return FALSE;
}

//DIBSECTION構造体の取得
DIBSECTION ds={0},dsm={0};
::GetObject(m_IconInfo.hbmColor,sizeof(DIBSECTION),&ds);
::GetObject(m_IconInfo.hbmMask,sizeof(DIBSECTION),&dsm);
m_IconInfo.fIcon=bIcon;

//アイコンのサイズを取得する
UINT width =ds.dsBmih.biWidth; //アイコンの幅
UINT height=abs(ds.dsBmih.biHeight); //アイコンの高さ

//iPNGMinmunSize 0:PNG圧縮しない。
// 1~256:アイコンサイズが指定されたサイズ以上ならPNG圧縮する。
// それ以外:CIcon::m_bCompressedPNGに従って処理する。

if ((iPNGMinmunSize>0)&&(iPNGMinmunSize<=256)&&
(width>=(UINT)iPNGMinmunSize)&&(height>=(UINT)iPNGMinmunSize))
m_bCompressedPNG=TRUE;
else if (iPNGMinmunSize==0)
m_bCompressedPNG=FALSE;

//アイコンイメージを書き込む
BOOL bResult=FALSE;
//PNG圧縮データ書き込みの時
if (m_bCompressedPNG){
//アルファブレンド32ビットDIBではないときは、
//カラー画像とマスク画像から新たに作成する。

if ((ds.dsBmih.biBitCount!=32)||(ds.dsBmih.biCompression!=BI_RGB)){
HBITMAP hbmAlpha=_CreateAlphaBlendDIB(m_IconInfo.hbmColor,m_IconInfo.hbmMask);
if (hbmAlpha){
::DeleteObject(m_IconInfo.hbmColor);
m_IconInfo.hbmColor=hbmAlpha;
}
}
//PNG圧縮データをファイルに書き込む
bResult=_PNGStreamOut(hbmColor,outfile);
}
//通常の書き込み
else bResult=_WriteIconImage(m_IconInfo.hbmColor,m_IconInfo.hbmMask,outfile);

//書き込みに失敗したかDIBを保持しない時は、削除する
if ((!bResult)||(bDeleteDIB))
{
::DeleteObject(m_IconInfo.hbmColor);
::DeleteObject(m_IconInfo.hbmMask);
m_IconInfo.hbmColor=0;
m_IconInfo.hbmMask =0;
}
if (!bResult){
//ICONDIRENTRY構造体の先頭位置に戻る
outfile.Seek(IdEntryPos,CFile::begin);
return FALSE;
}

//アイコンイメージを書き込んだ後のファイル末尾の位置を取得
ULONGLONG FileEnd=outfile.GetPosition();

//ICONDIRENTRY構造体の先頭位置に戻る
outfile.Seek(IdEntryPos,CFile::begin);

//色数を算出
UINT nBpp=ds.dsBmih.biBitCount; //ビット深度
UINT nColors=(nBpp>8)?0:1<<nBpp; //カラーテーブルの色数

//ICONDIRENTRY構造体の作成
ICONDIRENTRY IdEntry={0};
if (width<256) IdEntry.bWidth =(BYTE)width;
if (height<256) IdEntry.bHeight=(BYTE)height;
if (nColors<256) IdEntry.bColorCount=(BYTE)nColors;
IdEntry.wPlanes =(WORD)((m_IconInfo.fIcon)?1 :m_IconInfo.xHotspot);
IdEntry.wBitCount=(WORD)((m_IconInfo.fIcon)?nBpp:m_IconInfo.yHotspot);
IdEntry.dwImageOffset=(DWORD)ImageOffset;
IdEntry.dwBytesInRes=(DWORD)(FileEnd-ImageOffset);

//ICONDIRENTRY構造体をファイルに書き込む
outfile.Write(&IdEntry,sizeof(ICONDIRENTRY));

return TRUE;
}


CIconクラスに格納されたアイコンハンドルからDIBを復元する関数です。すでに有効なDIBがこのクラス内に存在する場合は、何もせずにTRUEを返して終了します。

//アイコンハンドルからDIBを復元する

BOOL CIcon::RetrieveDIB()
{
//DIBSECTION構造体の取得
DIBSECTION ds={0},dsm={0};
//カラー画像が保持されていてどちらもDIBの時は、
//そのまま保持していたICONINFO構造体をコピーして戻る。

if ((::GetObject(m_IconInfo.hbmColor,sizeof(DIBSECTION),&ds))&&
(ds.dsBmih.biSize==sizeof(BITMAPINFOHEADER))&&
(::GetObject(m_IconInfo.hbmMask,sizeof(DIBSECTION),&dsm))&&
(dsm.dsBmih.biSize==sizeof(BITMAPINFOHEADER)))
return return;

//アイコンハンドルからICONINFO構造体を取得する
ICONINFO IconInfo;
if (!::GetIconInfo(m_hIcon,&IconInfo)) return FALSE;
::ZeroMemory(&ds,sizeof(DIBSECTION));
::ZeroMemory(&dsm,sizeof(DIBSECTION));
//カラー画像がある時
if (::GetObject(IconInfo.hbmColor,sizeof(DIBSECTION),&ds)){
//カラー画像がDDBの場合、DDB->DIB変換
if (ds.dsBmih.biSize!=sizeof(BITMAPINFOHEADER)){
HBITMAP hbmColorDIB=_DDBToDIB(IconInfo.hbmColor,m_bitCount);
::DeleteObject(IconInfo.hbmColor);
IconInfo.hbmColor=hbmColorDIB;
}
//マスク画像が正しくない時はFALSEを返して終了する。
if (!::GetObject(IconInfo.hbmMask,sizeof(DIBSECTION),&dsm)){
::DeleteObject(IconInfo.hbmColor);
return FALSE;
}
//マスク画像がDDBの場合、DDB->DIB変換
if (dsm.dsBmih.biSize!=sizeof(BITMAPINFOHEADER)){
HBITMAP hbmMaskDIB=(HBITMAP)::CopyImage(IconInfo.hbmMask,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
::DeleteObject(IconInfo.hbmMask);
IconInfo.hbmMask=hbmMaskDIB;
}
}
//マスク画像のみの時

else if (::GetObject(IconInfo.hbmMask,sizeof(DIBSECTION),&dsm)){
IconInfo.hbmColor=0;
HBITMAP hbmMaskDIB=IconInfo.hbmMask;
//画像がDDBの場合、DDB->DIB変換
if (dsm.dsBmih.biSize!=sizeof(BITMAPINFOHEADER)){
hbmMaskDIB=(HBITMAP)::CopyImage(IconInfo.hbmMask,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
::DeleteObject(IconInfo.hbmMask);
IconInfo.hbmMask=0;
::GetObject(hbmMaskDIB,sizeof(DIBSECTION),&dsm);
}
//BITMAPINFO構造体の作成
BYTE dib[,sizeof(BITMAPINFOHEADER)+,sizeof(RGBQUAD)*2]={0};
BITMAPINFO* pBmi=(BITMAPINFO*)&dib;
::CopyMemory(&pBmi->bmiHeader,&dsm.dsBmih,,sizeof(BITMAPINFOHEADER));
pBmi->bmiHeader.biHeight>>=1; //画像高さを1/2にする
pBmi->bmiHeader.biSizeImage>>=1;//ピクセルバイト数を1/2にする
pBmi->bmiColors[1].rgbBlue=pBmi->bmiColors[1].rgbGreen=pBmi->bmiColors[1].rgbRed=0xFF;
//カラーDIBの作成
LPVOID pvBits=0;
IconInfo.hbmColor=::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBits,NULL,NULL);
DWORD dwSizeImage=pBmi->bmiHeader.biSizeImage;
::CopyMemory(pvBits,dsm.dsBm.bmBits,dwSizeImage);
//マスクDIBの作成
IconInfo.hbmMask =::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBits,NULL,NULL);
::CopyMemory(pvBits,(PBYTE)dsm.dsBm.bmBits+dwSizeImage,dwSizeImage);
//元のマスク画像を削除する
::DeleteObject(hbmMaskDIB);
}
else return FALSE;

::CopyMemory(&m_IconInfo,&IconInfo,sizeof(ICONINFO));
return TRUE;
}


デバイス依存ビットマップ(DDB)からデバイスに依存しないビットマップ(DIB)を作成する関数です。アイコンハンドルからAPI関数のGetIconInfo関数を使って得られるビットマップは一般にDDBなので、ファイルに書き込むためには一度DIBに変換しなければなりません。API関数のCopyImage関数のfuFlagパラメータにLR_CREATEDIBSECTIONをいれて得られるDIBは32ビットRGBかモノクロのどちらかであるため、アイコンをファイルやリソースから読み込んだ時の元来のビット深度が復元されません。そこでビット深度を後から指定したり、パレットDIBを復元するために敢えてこの関数を作成しました。尚速度を重視する場合は_CopyDIB関数に置き換えても構いませんが、パレットの色がシステムパレットに制限されるので、システムパレット以外の色を使用したアイコンの場合、本来の色を忠実に再現できない恐れがあります。

//指定したビット深度に従い、DDBからDIBを作成する

HBITMAP __stdcall _DDBToDIB(HBITMAP hBitmap,UINT bitCount)
{
//DIBSECTION構造体を取得する
DIBSECTION ds={0};//入力ビットマップが正常でないなら、FALSEを返して終了する。
if (!::GetObject(hBitmap,sizeof(DIBSECTION),&ds)) return FALSE;

//指定のビット深度が有効な値で、モノクロビットマップか、
//指定のビット深度がビットマップのビット深度より大きいか、
//指定のビット深度が8以上のときは、ビット深度の変更関数を呼び出す。

if ((_IsDIBitCount(bitCount))&&((ds.dsBm.bmBitsPixel==1)||
(ds.dsBm.bmBitsPixel<=bitCount)||(bitCount>8)))
return _CopyDIB(hBitmap,bitCount,0);

//API関数を使って、DDBからDIB32/MONOへコピーする。
HBITMAP hbmDIB32=(HBITMAP)CopyImage(hBitmap,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
if (!::GetObject(hbmDIB32,sizeof(DIBSECTION),&ds)) return FALSE;

UINT width=ds.dsBmih.biWidth; //画像幅
UINT height=abs(ds.dsBmih.biHeight); //画像高さ

//BITMAPINFO構造体の領域をスタックに確保します。(高速化のため)
BYTE dib[sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256];
BITMAPINFO* pBmi=(BITMAPINFO*)&dib;
::ZeroMemory(pBmi,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256);

//32ビットDIBの色数を求める
UINT nColors=_CountDIB32ColorTable(256,pBmi->bmiColors,hbmDIB32);
::DeleteObject(hbmDIB32);
//色数が256以上のときは、ビット深度の変更関数を呼び出す。
if (!nColors) return _CopyDIB(hBitmap,bitCount,0);

//色を暗い順から並べる
nColors=_SortColorTable(nColors,pBmi->bmiColors);
if (nColors%2) nColors++; //色数が奇数個なら偶数にする

//最小ビット深度を算出する
UINT bitCountMin=1;
if (nColors>16) bitCountMin=8;
else if (nColors>2) bitCountMin=4;

//指定のビット深度が有効な値でないときは、最小値を代入する
if (!_IsDIBitCount(bitCount)) bitCount=bitCountMin;
//指定のビット深度が最小値より大きいときは色数を2の(ビット深度)乗にする。
else if (bitCount>bitCountMin) nColors=1<<bitCount;
//指定のビット深度が最小値より小さいときは、ビット深度の変更関数を呼び出す。
else if (bitCount<bitCountMin) return _CopyDIB(hBitmap,bitCount,0);

//BITMAPINFO構造体の作成
::CopyMemory(&pBmi->bmiHeader,&ds.dsBmih,sizeof(BITMAPINFOHEADER));
pBmi->bmiHeader.biBitCount=bitCount;
pBmi->bmiHeader.biSizeImage=WIDTHBYTES(bitCount*width)*height;
pBmi->bmiHeader.biClrUsed=nColors&0xFF;

//DIBセクションの作成
LPVOID pvBits;
HBITMAP hbmDIB=::CreateDIBSection(0,pBmi,DIB_RGB_COLORS,&pvBits,0,0);
//DIBの作成に失敗したら、FALSEを返して終了する。
if (!hbmDIB) return FALSE;

//メモリーデバイスコンキストを作成する
HDC hDstDC=::CreateCompatibleDC(0);
HDC hSrcDC=::CreateCompatibleDC(0);

//メモリーデバイスコンキストにビットマップを設定する
HGDIOBJ hDstObj=::SelectObject(hDstDC, hbmDIB);
HGDIOBJ hSrcObj=::SelectObject(hSrcDC, hBitmap);

//空のDIBへ転送して変換する
::BitBlt(hDstDC,0,0,width,height,hSrcDC,0,0,SRCCOPY);

//メモリーデバイスコンキストからビットマップを開放する
::SelectObject(hDstDC, hDstObj);
::SelectObject(hSrcDC, hSrcObj);

//後片付け
::DeleteDC(hDstDC);
::DeleteDC(hSrcDC);

return hbmDIB;
}

32ビットDIBの全ピクセルデータからカラーテーブルを作成し、その色数を返す関数です。尚DIBの色数が入力され色バッファの色数より多い場合は、FALSEを返します。

//32ビットDIBの色数を求める

UINT __stdcall _CountDIB32ColorTable(UINT cEntries,RGBQUAD* pRgbq,HBITMAP hbmDIB32)
{
//与えられたカラーテーブル領域が有効でなければ、FALSEを返して終了する。
if (!AfxIsValidAddress(pRgbq,sizeof(RGBQUAD)*cEntries,0)) return FALSE;

//DISECTION構造体を求めて、エラーがでたり、DIBではなかったり、
//ビット深度が32ビットでなかったりしたら、FALSEを返して終了する。

DIBSECTION ds={0};
if ((!::GetObject(hbmDIB32,sizeof(DIBSECTION),&ds))||
(ds.dsBmih.biSize!=sizeof(BITMAPINFOHEADER))||
(ds.dsBm.bmBitsPixel!=32)) return FALSE;

//与えられたカラーテーブルを0で初期化する。
::ZeroMemory(pRgbq,cEntries*sizeof(RGBQUAD));
UINT width=ds.dsBmih.biWidth; //画像の幅
UINT height=abs(ds.dsBmih.biHeight); //画像の高さ

UINT nCount=0; //色数カウントを0にする。
DWORD* src=(DWORD*)ds.dsBm.bmBits; //ピクセルビットへのポインタを取得する。
DWORD* dst=(DWORD*)pRgbq; //カラーテーブルへのポインタを取得する。
UINT nPixels=ds.dsBmih.biSizeImage>>2; //ピクセルの総数を算出する。

//すべてのピクセルの色を読み込んでカラーテーブルを作成する。
for(UINT i=0;i<nPixels;i++){
//ピクセルの色を読み込み、アルファビットをマスクする。
DWORD dw=(*src++)&0x00FFFFFF;
BOOL bFind=FALSE; //カラーテーブルに同じ色があればTRUE

//カラーテーブルにある色を読み込み、ピクセルの色と比較する。
for (UINT j=0;j<nCount;j++){
//同じ色ならbFindをTRUEにしてループを抜ける。
if (dst[j]==dw){
bFind=TRUE;
break;
}
}
if (!bFind){//色が見つからなかった。
//カラーテーブルが一杯の時は、FALSEを返して終了する。
if (nCount>=cEntries) return FALSE;
//カラーテーブルに色を加える。
dst[nCount++]=dw;
}
}
return nCount;
}

入力されたカラーテーブルの色を指定されたフラグの順に並べ替えます。

//カラーテーブルのソート

UINT __stdcall _SortColorTable(UINT cEntries,RGBQUAD *prgbq,BOOL bDarkToBlight)
{
if (!AfxIsValidAddress(prgbq,cEntries*sizeof(RGBQUAD))) return FALSE;

BYTE* pYiq=new BYTE[cEntries];
::ZeroMemory(pYiq,cEntries);

//色の明るさをもとにヒストグラムを作成する
for (UINT i=0;i<cEntries;i++)
pYiq[i]=(BYTE)(0.299*(double)(prgbq[i].rgbRed)+
0.587*(double)(prgbq[i].rgbGreen)+
0.114*(double)(prgbq[i].rgbBlue));

//偏差の多いものから順に並べる
BYTE Temp;
RGBQUAD rgbTemp;
if (!bDarkToBlight){
for(UINT i=0;i<cEntries;i++){
for(UINT j=i+1;j<cEntries;j++){
if (pYiq[i]<pYiq[j]){
Temp=pYiq[j];
pYiq[j]=pYiq[i];
pYiq[i]=Temp;
rgbTemp=prgbq[j];
prgbq[j]=prgbq[i];
prgbq[i]=rgbTemp;
}
}
}
}

//偏差の少ないものから順に並べる
else {
for(UINT i=0;i<cEntries;i++){
for(UINT j=i+1;j<cEntries;j++){
if (pYiq[i]>pYiq[j]){
Temp=pYiq[j];
pYiq[j]=pYiq[i];
pYiq[i]=Temp;
rgbTemp=prgbq[j];
prgbq[j]=prgbq[i];
prgbq[i]=rgbTemp;
}
}
}
}
delete[]pYiq;

//同じ色が並んでいれば1つにする
COLORREF crColor,crColorLast=-1;
RGBQUAD* prgbqTemp=new RGBQUAD[cEntries];
::ZeroMemory(prgbqTemp,sizeof(RGBQUAD)*cEntries);
UINT cNewEntries=0;
for (UINT i=0;i<cEntries;i++){
crColor=RGB(prgbq[i].rgbRed,prgbq[i].rgbGreen,prgbq[i].rgbBlue);
if (crColorLast!=crColor){
crColorLast=crColor;
prgbqTemp[cNewEntries++]=prgbq[i];
}
}
::CopyMemory(prgbq,prgbqTemp,sizeof(RGBQUAD)*cEntries);
delete[]prgbqTemp;

return cNewEntries;
}


カラーDIBとマスクDIBからICONIMAGE構造体を作成して、ファイルに書き込む関数です。

//ICONIMAGE構造体の書き込み

BOOL __stdcall _WriteIconImage(HBITMAP hbmColor,HBITMAP hbmMask,CFile& outfile)
{
//DIBSECTION構造体を取得する。
//エラーになったり、DIBではない場合はFALSEを返して終了する。

DIBSECTION ds={0};
if ((!::GetObject(hbmColor,sizeof(DIBSECTION),&ds))||
(ds.dsBmih.biSize!=sizeof(BITMAPINFOHEADER))) return FALSE;
DIBSECTION dsm={0};
if ((!::GetObject(hbmMask,sizeof(DIBSECTION),&dsm))||
(dsm.dsBmih.biSize!=sizeof(BITMAPINFOHEADER))) return FALSE;

UINT width =ds.dsBmih.biWidth; //DIBの幅
UINT height=abs(ds.dsBmih.biHeight); //DIBの高さ
UINT nBpp=ds.dsBmih.biBitCount; //DIBのビットカウント

//BITMAPINFOHEADER構造体の書き込み
BITMAPINFOHEADER bh={0};
bh.biSize=sizeof(BITMAPINFOHEADER);
bh.biWidth=ds.dsBmih.biWidth;
bh.biHeight=ds.dsBmih.biHeight*2;
bh.biPlanes=1;
bh.biBitCount=ds.dsBmih.biBitCount;
bh.biSizeImage=ds.dsBmih.biSizeImage;
outfile.Write(&bh,sizeof(BITMAPINFOHEADER));

//カラーテーブルの色数を算出します。
UINT nColors=(nBpp>8)?0:1<<nBpp;

//カラーテーブルがあれば、書き込む
if (nColors){
DWORD dwSizeOfColorTable=sizeof(RGBQUAD)*nColors;
//DIBからカラーテーブルを取り出すAPI関数
RGBQUAD* pColorTable=(RGBQUAD*)(new BYTE[dwSizeOfColorTable]);
::ZeroMemory(pColorTable,dwSizeOfColorTable);
HDC hMemDC=::CreateCompatibleDC(0);
HGDIOBJ hOldObj=::SelectObject(hMemDC,hbmColor);
::GetDIBColorTable(hMemDC,0,nColors,pColorTable);
::SelectObject(hMemDC,hOldObj);
::DeleteDC(hMemDC);
//ファイルに書き込む
outfile.Write(pColorTable,dwSizeOfColorTable);
delete[]pColorTable;
}

//カラーデータの書き込み
outfile.Write(ds.dsBm.bmBits,ds.dsBmih.biSizeImage);

//マスクデータの書き込み
outfile.Write(dsm.dsBm.bmBits,dsm.dsBmih.biSizeImage);

return TRUE;
}



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

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



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



"C:\WINDOWS\system32"フォルダー(※システムフォルダーがドライブC:にある場合)内の「shell32.dll」を選択し「開く」ボタンを押すと、「shell32.dll」のリソースにあるすべてのグループカーソルとグループアイコンがリストビューに表示されます。



「Ctrl+A」で表示されたアイテムをすべて選択しておいてから、「ファイル」/「名前を付けて保存」を選択して、「名前を付けて保存」のダイヤログを表示させ、「IconFileTest03」フォルダー内にある「res」フォルダー内に新たに「shell32dllアイコン」フォルダーを作成します。



「shell32dllアイコン」フォルダーを開いて、ファイル名は「shell32.dll」のままで「保存」ボタンを押します。ファイルの書き込みに暫らく時間が掛かりますが、終了した後メニューから「ファイル」/「ファイルを開く」を選択して、「shell32dllアイコン」フォルダーに「shell32.dll」のすべてのアイテムが書き込まれているか確認してください。



PNG圧縮されたビスタアイコンについても、読み書きが正しく出来たかどうか確認してください。



尚OSがウィンドウズ7やビスタではない方は、「res」フォルダー内にある「shell32-16.ico」や「shell32-48.ico」にて、ビスタアイコンの読み書きができるか確認してください。


スポンサーサイト



コメント: 0

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

Trackback+Pingback: 0

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

Home > 未分類 > アイコンファイルの書き込みの修正

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

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る