CAD日記

主にAutoCADのことについて書いているけど、近頃は投資系ネタに注力している。自動売買、仮想通貨、PC関係、プログラミングなど。@caddiary

ソフト開発 DWG

dwgからサムネイル用画像を抜き出す方法2

投稿日:

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

-ソフト開発, DWG

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

マルチスレッドプログラミング(C++編)

マルチスレッドプログラミング(VB.net編) マルチスレッドプログラミング(C#編) もあるので、ご覧あれ。 5秒以上の時間を要する処理をやらせていると応答なしになってかっこ悪い、なんてことをアラフ …

PDFに捺印したけりゃコレ使え「PDFアレコレ」

こんな感じでPDFに捺印したいことはよくある。 Adobe Readerでもできるんだけど、ちゃんとした印鑑を押そうとするとかなりタイヘン。 【Acrobat Reader】PDFで簡単に電子印鑑する …

zipcopyの画面設計と動作仕様をまとめた

以下の課題について、まずは画面設計と画面設計をまとめた。 コピー元でzip圧縮後にネットワーク越しにファイルコピーしてコピー先で解凍するのを自動化できないか アプリ名はzipcopyとした。ググったと …

コマンドラインからパラメータを指定すればテキスト抽出や画像変換ができるPDFアレコレを公開

exeがパラメータを受け取って、GUI操作でできていることをCUI操作でやってやろうじゃないかという企画。以下の記事を書いたのが1週間前。ここまで設計したなら実装しなきゃいかんということで、ヒマな週末 …

no image

TEMPフォルダ書き込みエラーが頻発したのはなぜだろう

「環境変数TEMPトラブルについて振り返る」という記事に書いた出来事は1か月ほど前に起きたことでありWindows Serverでもあったから、レアな事象としてとらえていたが、一昨日の金曜日に起きたこ …