dwgからサムネイル用画像を抜き出す方法として理屈上の話を書いたが、これだけでは片手落ちだと考えて、プログラム実装のところまで踏み込むことにした。
まずは、dwgからサムネイル用画像を取得して、同名ファイル(拡張子ちがい)で保存するというメイン処理。
どういうことをやっているかは、前の記事および以下の処理から読み取ってくれればよい。
bool CDwgThumbCppDlg::Exec(LPCTSTR pFile)
{
// ファイルを開く
CFile file;
CFileException e;
if (!file.Open(pFile, CFile::modeRead | CFile::shareDenyNone, &e))
return false;
// データのバージョンチェック
char szBuff[MAX_PATH] = {0};
file.Seek(0, CFile::begin);
if (file.Read(szBuff, 6) != 6)
return false;
if (lstrcmpA(szBuff, "AC1012") < 0)
return false; // バージョンが古い
// イメージの開始アドレスを得る
// - 0x0000000D から4バイトがイメージのアドレスになる
file.Seek(0x0000000D, CFile::begin);
ULONG lImgOffset = 0;
if (file.Read(&lImgOffset, 4) != 4)
return false;
if (lImgOffset <= 0)
return false;
// イメージのブロック数の取得
// - イメージ関連基準アドレス+20バイトの位置にイメージのブロック数
// - イメージ関連基準アドレス+21以降9バイト単位でイメージの情報が続く
BYTE nBlock = 0;
file.Seek(lImgOffset + 20, CFile::begin);
file.Read(&nBlock, 1);
file.Seek(lImgOffset + 21, CFile::begin);
bool stat = false;
for (int n = 0; n < (int)nBlock && stat == false; n++) // 読めたら終了
{
if (file.Read(&sImgInf, sizeof(sImgInf)) != sizeof(sImgInf))
break;
// ビットマップ
if (sImgInf.type == 2 && sImgInf.lSize > 0 && sImgInf.lStart >= 0)
{
// ビットマップデータの読込
BYTE* mem = new BYTE[sImgInf.lSize + 10];
file.Seek(sImgInf.lStart, CFile::begin);
if (file.Read(mem, sImgInf.lSize) == (UINT)sImgInf.lSize)
{
CClientDC dc(this);
stat =_WriteBitmap(&dc, mem, _MakeRasterFileNmae(pFile, 0));
}
delete[] mem;
}
// PNG
if (sImgInf.type == 6 && sImgInf.lSize > 0 && sImgInf.lStart >= 0)
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, sImgInf.lSize + 10);
if (hGlobal == NULL)
continue;
BYTE* mem1 = (BYTE*)GlobalLock(hGlobal);
file.Seek(sImgInf.lStart, CFile::begin);
if (file.Read(mem1, sImgInf.lSize) == (UINT)sImgInf.lSize)
{
// PNGをIStreamに読込み
GlobalUnlock(hGlobal);
IStream* pIStream = NULL;
HRESULT hres = CreateStreamOnHGlobal(hGlobal, TRUE, &pIStream);
if (hres == S_OK)
{
CImage img;
img.Load(pIStream);
img.Save(_MakeRasterFileNmae(pFile, 1));
stat = true;
}
}
GlobalFree(hGlobal);
}
}
return stat;
}
画像ファイル名作成の_MakeRasterFileNmaeは、拡張子を差し替えただけの処理で単純だが、一応以下に載せておく。
static CString _MakeRasterFileNmae(LPCTSTR pFile, int type)
{
CString src(pFile);
int pos = src.ReverseFind('.');
CString dst;
if (pos != -1)
{
dst = src.Mid(0, pos + 1);
if (type == 0)
dst += _T("bmp");
else if (type == 1)
dst += _T("png");
}
return dst;
}
画像のファイル化ということでは、pngは上記処理で完結していてシンプルなのに対して、bmpだと別関数_WriteBitmapを呼び出している。ビットマップファイルはなかなか手ごわくて、DIBとかDDBとかのちがいがあり、パレットで色数を定義してなんてとてもややこしい。ネットで調べて、動くよう組んでみた結果を以下に載せておく。古い形式のビットマップまでサポートしているっぽく汎用性が高いためか、コードが長い。ムダがあるかもしれないが動くからヨシとしておく。
コードが長いことが影響してか、コードをそのまま載せるとWordPressがエラーを返してくるので、テキストファイルでアップロードした。
WriteBitmap