twain(スキャナ)での画像取得と表示 – プログラミング – Home

twain(スキャナ)での画像取得と表...
 
通知
すべてクリア

[解決済] twain(スキャナ)での画像取得と表示


シオン
 シオン
(@シオン)
ゲスト
結合: 19年前
投稿: 5
Topic starter  

はじめましてシオンといいます。

WindowsXP Professional、VC++6.0 SDK でC言語を使って作成しています。

現在twainを使ってスキャナから画像を直接取得するプログラムを作成しています。
しかし、twainのサンプルが非常に少なく困っています。

twainの使い方を説明しているサイトを調べてみたら、以下のページを見つけました。
http://hp.vector.co.jp/authors/VA011973/prg_twain.htm

スキャナを動作させ、画像データを取り込むまではできたのですが、
肝心の画像を表示する部分の説明がなく、表示することができなくて困っています。

スキャナから取得したビットマップハンドルから画像を表示させるにはどうしたらいい
でしょうか。
また、画像表示部分のソースが公開されているサイトなど、
知っていらっしゃる方がいましたら教えてください。

よろしくお願いします。


引用未解決
トピックタグ
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 22年前
投稿: 1421
 

twain については分かりませんが、
その「ビットマップハンドル」というのがtwain 固有のものでなく、
一般的なビットマップハンドルを表すものでしたら、
たとえば、DrawState で描画できます。

そもそも、画面に描画する方法自体がさっぱりわからない
ということでしたら、このあたりが参考になるのでは。
http://www.kumei.ne.jp/c_lang/sdk/sdk_23.htm


返信引用
シオン
 シオン
(@シオン)
ゲスト
結合: 19年前
投稿: 5
Topic starter  

返信ありがとうございます。
現在、以下のプログラムを作って試しているのですが、

TW_UINT16 rc;
TW_UINT32 hBitmap = NULL;
HANDLE hbm_acq = NULL;
HDC hMemDC;
BITMAP bmp;

:(スキャナの設定など)

// スキャナへ画像取得するよう命令する
rc = lpfnDSM_Entry(&pAppId, &pSourceId, DG_IMAGE, DAT_IMAGENATIVEXFER,
MSG_GET, (TW_MEMREF)&hBitmap);

// 戻値のチェック
switch (rc) {
case TWRC_XFERDONE: // 成功
hbm_acq = (HBITMAP)hBitmap;

hMemDC = CreateCompatibleDC(NULL);
if (NULL == hMemDC) {
// CreateCompatibleDC失敗
}

if (NULL == SelectObject(hMemDC, hbm_acq)) {
// SelectObject失敗
}

if (0 == GetObject(hbm_acq, sizeof(BITMAP), &bmp)) {
// GetObject失敗
}

if (0 == DeleteObject(hbm_acq)) {
// DeleteObject失敗
}

// 表示
BitBlt(表示用hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0,
SRCCOPY);

:(画面更新)
break;

case TWRC_CANCEL: // キャンセル

break;

case TWRC_FAILURE: // 転送中にエラーが発生

break;
}

どうしてもSelectObject関数で失敗してしまうのです。
twainのビットマップハンドルとwindows(?)のビットマップハンドルの型が違うからでし
ょうか。
スキャナから取得したビットマップハンドルはTW_UINT32です。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 22年前
投稿: 1421
 

「12.データ転送(状態5←→状態6)」を見ると、

| LPBITMAPINFOHEADER lpDib;
|
| // 画像転送
| hBitmap = NULL;
| rc = lpfnDSM_Entry(pAppId,pSourceId,DG_IMAGE,
| DAT_IMAGENATIVEXFER,MSG_GET,(TW_MEMREF)&hBitmap);
|
| lpDib = (LPBITMAPINFOHEADER)GlobalLock((void*)hBitmap);

とやって DIB を得ているようですから、
CreateDIBitmap とかでビットマップを作るんじゃないでしょうか。


返信引用
Tonny
 Tonny
(@Tonny)
ゲスト
結合: 21年前
投稿: 32
 

twainが出力するのはHDIBです。
dairygoodsさんの書かれている様にCreateDIBtimapでビットマップも作れますし、
そのままでもSetDIBitsToDeviceで描画できます。

>lpDib = (LPBITMAPINFOHEADER)GlobalLock((void*)hBitmap);
これで幅や高さは取得できますし、

(BYTE)lpDib + sizeof(BITMAPINFOHEADER) (+ あるのならパレットサイズ)
で、画像情報の先頭のアドレスも取得できます。

そのままの方が、bmpファイルに書き出すのには便利です。
(BITMAPFILEHEADERをつけるだけ)
MSDNのDIBLOOKが参考になります。


返信引用
シオン
 シオン
(@シオン)
ゲスト
結合: 19年前
投稿: 5
Topic starter  

dairygoodsさん、Tonnyさんありがとうございます。
以下のソースを見てください。

---------------------------------------------------------------------
TW_UINT16 rc;
TW_UINT32 hBitmap = NULL;
LPBITMAPINFOHEADER lpDIB;

// 画像取得
rc = lpfnDSM_Entry(&pAppId, &pSourceId, DG_IMAGE, DAT_IMAGENATIVEXFER,
MSG_GET, (TW_MEMREF)&hBitmap);

// DIBの情報を取得
lpDIB = (LPBITMAPINFOHEADER)GlobalLock((void*)hBitmap);

// 戻値のチェック
switch (rc) {
case TWRC_XFERDONE:
if (lpDIB != NULL) {
// 取得した画像のサイズを取得
size_x = lpDIB->biWidth;
size_y = lpDIB->biHeight;

// 表示
SetDIBitsToDevice(
win_hdc,
10, 0,
size_x, size_y,
0, 0,
0, size_y,
lpDIB,
// ←ここ
(BITMAPINFO *)lpDIB,
DIB_RGB_COLORS
);

// 画面更新

}
break;

case TWRC_CANCEL: // キャンセル
break;
case TWRC_FAILURE: // エラー
break;
}

---------------------------------------------------------------------

SetDIBitsToDevice関数を使って表示することができたのですが、
第10引数(ピクセルビットの配列の先頭へのポインタ)を上記のまま実行すると、
色がおかしくなってしまいました。
赤が青になって、黄色が紫色になってしまうのです。
RGBが、(255, 0, 0) → (0, 0, 255)となって1バイトずれているみたいです。
(取得した画像は24ビットです)
また、画像も左の一部分が右側に表示されてしまいます。

表示する関数を、
SetDIBitsToDevice(
win_hdc,
10, 0,
size_x, size_y,
0, 0,
0, size_y,
lpDIB + 1,
// ←ここ
(BITMAPINFO *)lpDIB,
DIB_RGB_COLORS
);

+ 1 すると正常に表示できました。

一応表示できたのですが、なぜ+1しないと正常に表示できないかわかりません。
もう少し情報をいただけないでしょうか。お願いします。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 22年前
投稿: 1421
 

まず、SetDIBitsToDevice の引数

CONST VOID *lpvBits, // DIB ビットからなる配列
CONST BITMAPINFO *lpbmi, // ビットマップ情報

は違う情報を求めているのに、
両方に同じポインタを指定することは変だとは思いませんか?
#キャストしても指す先は同じです。
#ビットマップ情報がビットデータに化けるわけではありません。

では、lpvBits に指定すべき「DIB ビットからなる配列」は
どこにあるのかということについては、
DIBの構造を調べてみてください。

例: http://www.kk.iij4u.or.jp/~kondo/bmp/


返信引用
Tonny
 Tonny
(@Tonny)
ゲスト
結合: 21年前
投稿: 32
 

>+ 1 すると正常に表示できました。
1番下の列にノイズが入っている + 1番上の列が切れている状態で、正常でないはずです。
たまたまバイト区切りが一致した為そう見えているだけです。

lpvBits = (BYTE)lpDib + sizeof(BITMAPINFOHEADER) (+ あるのならパレットサイズ)
って書いたのに。


返信引用
Tonny
 Tonny
(@Tonny)
ゲスト
結合: 21年前
投稿: 32
 

void* GetLpBits(void* lpDib)
{
BITMAPINFOHEADER* lpHeader = (BITMAPINFOHEADER*)lpDIB ;

// biClrUsedに数値が入っていれば、それがパレットの数
DWORD pal = lpHeader->biClrUsed ;

// biClrUsedが0でもパレットがある場合がある。
if(pal == 0 )
{
switch(lpHeader->biBitCount)
{
case 1: pal= 2; break;
case 4: pal= 16; break;
case 8: pal=256; break;
default : pal= 0;
}
}

// BI_BITFIELDSの場合はビットフィールドを持っている
DWORD fields = 0 ;
if( lpHeader->biCompression == BI_BITFIELDS &&
(lpHead->biBitCount == 32 || pHead->biBitCount == 16 ) )
fields = 3 * sizeof(DWORD) ;

return (BYTE*)lpDIB + sizeof(BITMAPINFOHEADER)
+ pal * sizeof(RGBQUAD) + fields;
}


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 22年前
投稿: 1421
 

> 1番下の列にノイズが入っている + 1番上の列が切れている状態で、正常でないはずです。

LPBITMAPINFOHEADER lpDIB;
なので、パレットがない場合は、lpDIB+1 は正しい値だったりします。


返信引用
Tonny
 Tonny
(@Tonny)
ゲスト
結合: 21年前
投稿: 32
 

>LPBITMAPINFOHEADER lpDIB;
>なので、パレットがない場合は、lpDIB+1 は正しい値だったりします。
ああ、+1 がsizeof(BITMAPINFOHEADER) に相当するということですね。


返信引用
シオン
 シオン
(@シオン)
ゲスト
結合: 19年前
投稿: 5
Topic starter  

> 両方に同じポインタを指定することは変だとは思いませんか?
> #キャストしても指す先は同じです。
> #ビットマップ情報がビットデータに化けるわけではありません。
よく考えてみればそうでした。キャストの意味がわっていなかったみたいです。ごめん
なさい。

Tonnyさん、すみません。見逃していました。
関数のところを以下に変更しました。
それから、biBitCountが違う場合のソースを書いていただきありがとうございます。

-------------------------------------------------------------------
BYTE *lpvBits;

lpvBits = (BYTE *)lpDIB + sizeof(BITMAPINFOHEADER);
SetDIBitsToDevice(
win_hdc,
0, 0,
size_x, size_y,
0, 0,
0, size_y,
lpvBits,
(BITMAPINFO *)lpDIB,
DIB_RGB_COLORS
);
-------------------------------------------------------------------

> >LPBITMAPINFOHEADER lpDIB;
> >なので、パレットがない場合は、lpDIB+1 は正しい値だったりします。
> ああ、+1 がsizeof(BITMAPINFOHEADER) に相当するということですね。
それはどういうことでしょうか。
sizeof(BITMAPINFOHEADER)は40バイトですよね。
ということは、+ 1 は40バイトずらしたことと同じことなのでしょうか。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 22年前
投稿: 1421
 

> ということは、+ 1 は40バイトずらしたことと同じことなのでしょうか。

はい。


返信引用
Tonny
 Tonny
(@Tonny)
ゲスト
結合: 21年前
投稿: 32
 

char* c = XX ;
char* cc = c + 1 ; // ccは1バイトずれる。

int* i = XX ;
int* ii = i + 1 ; // iiは4バイトずれる。

BITMAPINFOHEADER* pInfo = XX ;
BITMAPINFOHEADER* pInfo2 = pInfo + 1 ; //pInfo2は40バイトずれる。

です。


返信引用
シオン
 シオン
(@シオン)
ゲスト
結合: 19年前
投稿: 5
Topic starter  

大変よくわかりました。
その型によって+1でずれるバイト数が変わってくるのですね。

dairygoodsさん、Tonnyさんどうもありがとうございました。
画像も無事表示できました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました