クリップボードからビットマップの保存方法について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
taketoshi

クリップボードからビットマップの保存方法について

#1

投稿記事 by taketoshi » 15年前

こんばんわ、お世話になります。
現在クリップボードにあるビットマップデータを
ビットマップファイルに保存するプログラムをWINAPI32で書いているのですが
どうにもやり方がわからないので質問させて下さい。

試しに以下のようなクリップボードからビットマップのハンドルを取得して
そこからビットマップのヘッダ情報を読み込むようなプログラムを書いてみたのですが
*windowsプログラムだと数値の出力がややこしいのでコンソールで書きました

#include<windows.h>
#include<stdio.h>


int main()
{
HANDLE hBitmap,hMem,hMem2;
HWND std;
LPBITMAPFILEHEADER lpBp;
LPBITMAPINFOHEADER lpBi;
DWORD dwFile;
DWORD dwOffbits,dwFsize;
char szFile[3];
LONG bw,by;
BOOL bRet;

std = FindWindow(NULL,NULL); //コンソールのウインドウハンドル取得
if(std == NULL)
{
printf("ウインドウハンドル取得エラー");
}

OpenClipboard(std);
hBitmap = GetClipboardData(CF_BITMAP); //ビットマップハンドルの取得
if(hBitmap == NULL)
{
printf("ビットマップがクリップボードにありません\n");
return -1;
}

/*ビットマップファイルヘッダーの取得と数値の書き込み*/
hMem = GlobalAlloc(GHND,sizeof(LPBITMAPFILEHEADER));
lpBp = (LPBITMAPFILEHEADER)GlobalLock(hMem);

bRet = ReadFile(hBitmap,lpBp,sizeof(LPBITMAPFILEHEADER),&dwFile,NULL);//ビットマップハンドルからのファイル読み込み ここでエラー発生
if(bRet ==FALSE)
{
printf("ファイル読み込みエラー");
return -1;
}
dwOffbits = lpBp->bfOffBits;
dwFsize = lpBp->bfSize;
szFile[0] = LOBYTE(lpBp->bfType);
szFile[1] = HIBYTE(lpBp->bfType);
szFile[2] = '\0';

printf("offbits=%ld\nFileSize = %ld\nFileType = %s\n",dwOffbits,dwFsize,szFile);

/*ビットマップインフォヘッダーの取得と数値の書き込み*/
hMem2 = GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER));
lpBi = (LPBITMAPINFOHEADER)GlobalLock(hMem2);

ReadFile(hBitmap,lpBi,sizeof(BITMAPINFOHEADER),&dwFile,NULL);

bw = lpBi->biWidth;
by = lpBi->biHeight;

printf("x = %ld\n y = %ld",bw,by);

GlobalUnlock(hMem);
DeleteObject(hBitmap);
CloseClipboard();

return 0;
}

bRet = ReadFile(hBitmap,lpBp,sizeof(LPBITMAPFILEHEADER),&dwFile,NULL);
上記の行で、ファイルが読み込めずエラーが発生してしまいます。
Readfile関数はCreate関数で作成したハンドルしか読めない様子なので行き詰ってしまいました。
根本的なプログラミング方法が間違っている気がします。

クリップボードからBMP保存方法についての考え方をご指導いただけないでしょうか?
よろしくお願いいたします。 画像

シエル

Re:クリップボードからビットマップの保存方法について

#2

投稿記事 by シエル » 15年前

私はWINDOWSAPIは結構使いますが、クリップボード関連は今まで操作したことがありませんでした。

でもちょっと興味があったので、調べてみました。

GetClipboardDataでデータを読み込むときにCF_BITMAPを指定していますが、これだとデバイス依存の
ビットマップ(DDB)のため、たぶん保存することは難しいんじゃないかと思います。
なのでここの定数を、CF_DIBにしてデータを取得すると、デバイスに依存しないビットマップ(DIB)に自動的に
変換して取得してくれるそうです。

取得したDIBは、BITMAPFILEHEADERが無いらしいので、たぶん自分で作ってくっつけてファイルに
書き出すんだと思います。

DIBとDDBがわからなければ、下記を参照。
http://wisdom.sakura.ne.jp/system/winap ... in105.html
http://wisdom.sakura.ne.jp/system/winap ... in117.html


あと、上記の説明が書いてあったページがここ。
VBですが、たぶん読めばわかります。
http://www.geocities.jp/fbasic63/api16.txt


参考になれば幸いです。

#クリップボードの操作もなかなかおもしろそうですね。興味がわいてきました。


追記:
リンクのページはVBじゃないかも?何の言語かわかりませんが、感じはつかめると思います。
画像

taketoshi

Re:クリップボードからビットマップの保存方法について

#3

投稿記事 by taketoshi » 15年前

シエルさんありがとうございます。

DIBで取得するっていうヒントを頂いてから、ご紹介頂いたホームページや
他のサイトで調べまくって、やっとクリップボードから画像の取得が出来ました。

ビットマップ構造を調べながらプログラミングしていたので、非常に時間がかかりましたが
目的が達成できて非常にうれしいです。

デバッグしながらやってたので、作業ファイル作成とか不必要な部分も含まれてて汚いですが
他の方の参考になればとソースを晒しておきます。ありがとうございました

#include<windows.h>
#include<stdio.h>

int main()
{
HWND std;
HANDLE hBitmap,hFile;
HANDLE hMem;
char *szBuffer;
char szFileName[128];
DWORD dwAccWriteByte,dwAccReadByte,dwBitSize;
LPBITMAPINFOHEADER lpBi;
BITMAPFILEHEADER Bf;

//ウインドウハンドル取得
std = FindWindow(NULL,NULL);

//クリップボードオープン
OpenClipboard(std);

//DIBハンドルの取得
hBitmap = GetClipboardData(CF_DIB);
if(hBitmap == NULL)
{
printf("BITMAPがクリップボードにありません\n");
return -1;
}

//クリップボードクローズ
CloseClipboard();

//DIBハンドルをポインタに変換
szBuffer = (char *)GlobalLock(hBitmap);

//BITMAP FILEHEADER用にINFOHEADER以降のファイルサイズ取得
dwBitSize = GlobalSize(hBitmap);

//作業用ファイルの作成
strcpy(szFileName,"test.bmp");
hFile = CreateFile(szFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
perror("ファイル生成エラー\n");
return -2;
}
WriteFile(hFile,szBuffer,GlobalSize(hBitmap),&dwAccWriteByte,NULL);
CloseHandle(hFile);

//作業ファイルからBITMAP INFOHEADERの読み込み
hMem = GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER));
lpBi = (LPBITMAPINFOHEADER)GlobalLock(hMem);
hFile = CreateFile(szFileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
ReadFile(hFile,lpBi,sizeof(BITMAPINFOHEADER),&dwAccReadByte,NULL);
CloseHandle(hFile);

//作業ファイルの削除
remove(szFileName);

////debug
printf("WIDTH = %d\nHEIGHT = %d\nINFO以降のサイズ = %ld\n",lpBi->biWidth,lpBi->biHeight,dwBitSize);

//BITMAP FILEHEADER設定
Bf.bfType = 0x4d42;
Bf.bfSize = dwBitSize + sizeof(BITMAPFILEHEADER);
Bf.bfOffBits = sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER);

//BITMAP FILEHEADERの書き込み
strcpy(szFileName,"Header書き込みあと.bmp");
hFile = CreateFile(szFileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(hFile,&Bf,sizeof(BITMAPINFOHEADER),&dwAccWriteByte,NULL);

//進んだBITMAP FILEHEADER書き込み直後に移動
SetFilePointer(hFile,sizeof(BITMAPFILEHEADER),0,FILE_BEGIN);

//BITMAP FILEHEADER以外の書き込み
WriteFile(hFile,szBuffer,dwBitSize,&dwAccWriteByte,NULL);
CloseHandle(hFile);

//メモリの開放
GlobalUnlock(hMem);
GlobalFree(hMem);
GlobalUnlock(hBitmap);

return 0;
}

閉鎖

“C言語何でも質問掲示板” へ戻る