UWSCで画像をクリップボード経由で扱う

UWSCのSAVEIMG/CHKIMG/PEEKCOLORが4.9でクリップボードに対応した記念。
PEEKCOLORは使ってないけど、SAVEIMGでクリップボードに放り込んだり、クリップボードの画像を文字列にしてみたり、その文字列から画像をクリップボードに戻したり、クリップボードからCHKIMGするサンプル!


何ができるって、認識させたい画像をスクリプトに内包できるのですよ、はい!
あと、できる人ならメモリー上でHBITMAPを作って、それをクリップボードに転送して認識、なんてこともできる。
画像ファイルに依存しない神経衰弱を解くスクリプトとか、フォントに依存したOCRとかできそうですね!



追記 2014/08/16
ファイルからクリップボードに転送する例をサンプルに追加しました。

追記 2014/06/19
にゃんこさんの指摘を受けて、初期フォーマットをCF_DIBにしました。
一応V5ヘッダーでもImage.Getできるようにしました。(引数指定)
v5.0.0以降に対応しました。(VAR_BSTRをVAR_USTRにしただけ。もどすならそこを戻してください)
にゃんこさん、ありがとうございます!

スクリプト

Image.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "Image.uws" THEN

	IFB MSGBOX("イメージを取得しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN
		IFB MSGBOX("ファイルから取得しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN
			DIM path = INPUT("ビットマップファイルパスを入力するかDrag&Dropしてください")
			IFB LENGTH(path) THEN
				DEF_DLL DeleteObject(DWORD): BOOL: gdi32
				DEF_DLL LoadImageW(DWORD, wstring, DWORD, int, int, DWORD): DWORD: user32
				DIM hImage = LoadImageW(0, path, 0, 0, 0, $10)
				Image.Set(hImage, Image.F_BITMAP)
				DeleteObject(hImage)
			ENDIF
		ELSE
			MSGBOX("始点でOKしてください")
			DIM x1 = G_MOUSE_X, y1 = G_MOUSE_Y
			MSGBOX("終点でOKしてください")
			DIM x2 = G_MOUSE_X, y2 = G_MOUSE_Y, w = x2 - x1, h = y2 - y1
			IFB w < 0 THEN
				w = ABS(w)
				x1 = x2
			ENDIF
			IFB h < 0 THEN
				h = ABS(h)
				y1 = y2
			ENDIF
			SAVEIMG(, , x1, y1, w, h)
		ENDIF
	ENDIF
	IF MSGBOX("クリップボードのイメージをログ出力しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT Image.Get()

	TEXTBLOCK _Image_Uwsc_Icon
		KAAAAA8AAAAPAAAAAQAgAAMAAACEAwAAAAAAAAAAAAAAAAAAAAAAAAAA/wAA/wAA
		/wAAAP8AAAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AP8AAAD/AAAA
		/wAAAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AP8AAAD/AAAA/wAAAP8AAAAAAP8A
		AAD/AAAA/wD/AAAA/wAAAP8AAAAAAP8AAAD/AAAA/wAAAP8A/wAAAP8AAAD/AAAA
		/wAAAP8AAAD/AAAAAAD/AAAA/wD/AAAA/wAAAAAA/wAAAP8AAAD/AAAA/wAAAP8A
		/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
		AAD/AAAA/wAAAP8A/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAAAD/AAAA/wAAAP8A
		AAD/AAAA/wD/AAAA/wAAAAAA/wAAAP8A/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA
		AAD/AAAA/wAAAP8AAAD/AP8AAAD/AAAA/wAAAAAA/wAAAP8AAAD/AP8AAAD/AAAA
		/wAAAP8AAAAAAP8AAAD/AAAA/wAAAP8A/wAAAP8AAAD/AAAA/wAAAP8AAAAAAP8A
		AAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wD/AAAA/wAAAP8AAAD/AAAA
		/wAAAP8AAAD/AAAAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AP8AAAAA//8A
		AP//AAD//wAA//8A/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAAAA/wAAAP8A
		/wAAAAD//wAA//8A/wAAAP8AAAAA//8AAP//AP8AAAD/AAAA/wAAAP8AAAD/AAAA
		AAD/AAAA/wAAAP8A/wAAAAD//wAA//8A/wAAAP8AAAAA//8AAP//AP8AAAD/AAAA
		/wAAAP8AAAAAAP8AAAD/AAAA/wD/AAAA/wAAAAD//wAA//8A/wAAAP8AAAAA//8A
		AP//AP8AAAD/AAAAAAD/AAAA/wAAAP8AAAD/AP8AAAD/AAAA/wAAAAD//wAA//8A
		/wAAAP8AAAAA//8AAP//AAAA/wAAAP8AAAD/AAAA/wAAAP8A/wAAAP8AAAD/AAAA
		/wAAAAD//wAA//8A/wAAAP8AAAAA//8AAP//AAAA/wAAAP8AAAD/AP8AAAD/AAAA
		/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAA==
	ENDTEXTBLOCK
	IF MSGBOX("クリップボードにUWSCのアイコンを設定しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT Image.Set(_Image_Uwsc_Icon)

	IF MSGBOX("クリップボードの画像をCHKIMGしますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT CHKIMG()
ENDIF


MODULE Image
	CONST ERR_OPENCLIPBOARD = "OpenClipboard fail."
	CONST ERR_GET_LENGTH = "Get length error."
	CONST ERR_CONVERT = "Convert error."
	CONST ERR_SETCLIPBOARDDATA = "SetClipboardData fail."
	CONST ERR_GLOBALLOCK = "GlobalLock fail."

	CONST F_BITMAP = 2
	CONST F_DIB = 8
	CONST F_DIBV5 = 17

	DEF_DLL OpenClipboard(HWND): BOOL: user32
	DEF_DLL CloseClipboard(): BOOL: user32
	DEF_DLL EmptyClipboard(): BOOL: user32
	DEF_DLL EnumClipboardFormats(DWORD): DWORD: user32
	DEF_DLL GetClipboardFormatNameW(DWORD,var wstring,int): int: user32
	DEF_DLL GetClipboardData(DWORD): DWORD: user32
	DEF_DLL SetClipboardData(DWORD, DWORD): DWORD: user32

	DEF_DLL GlobalAlloc(DWORD, DWORD): DWORD: kernel32
	DEF_DLL GlobalLock(DWORD): DWORD: kernel32
	DEF_DLL GlobalUnlock(DWORD): BOOL: kernel32
	DEF_DLL GlobalSize(DWORD): DWORD: kernel32
	DEF_DLL GlobalFree(DWORD): DWORD: kernel32

	DEF_DLL CryptBinaryToStringA(DWORD,DWORD,DWORD,DWORD,var DWORD): BOOL: crypt32
	DEF_DLL RtlMoveMemory(var string,DWORD,DWORD): kernel32
	DEF_DLL CryptStringToBinaryA(string,DWORD,DWORD,DWORD,var DWORD,var DWORD,var DWORD): BOOL: crypt32

	DIM _hwnd


	PROCEDURE Image
		_hwnd = IDTOHND(GETID(GET_THISUWSC_WIN))
	FEND


	FUNCTION Get(fm=F_DIB)
		RESULT = EMPTY
		DIM res = OpenClipboard(_hwnd)
		IFB !res THEN
			RESULT = ERR_OPENCLIPBOARD
			EXIT
		ENDIF
		DIM hClip, size, nstr = 0, m = 0, j, i = 0, wksize = 66, wk = FORMAT(CHR(0), wksize)
		DIM hMem, fmt = EnumClipboardFormats(0)
		WHILE fmt <> 0
			IFB fmt = fm THEN
				hClip = GetClipBoardData(fmt)
				size = GlobalSize(hClip)
				IFB size > 200000 THEN
					IFB MSGBOX("時間がかかりそうなので、やめていいですか?", BTN_YES OR BTN_NO) = BTN_YES THEN
						RESULT = "Abort."
						BREAK
					ENDIF
				ENDIF
				hMem = GlobalLock(hClip)
				IFB CryptBinaryToStringA(hMem, size, 1, NULL, nstr) THEN
					m = GlobalAlloc(2, nstr)
					j = GlobalLock(m)
					IFB j THEN
						IFB CryptBinaryToStringA(hMem, size, 1, j, nstr) THEN
							WHILE i < nstr
								RtlMoveMemory(wk, j + i, wksize)
								PRINT TRIM(wk)
								i = i + wksize
							WEND
						ELSE
							RESULT = ERR_CONVERT
						ENDIF
						GlobalUnlock(m)
					ELSE
						RESULT = ERR_GLOBALLOCK
					ENDIF
					GlobalFree(m)
				ELSE
					RESULT = ERR_GET_LENGTH
				ENDIF
				GlobalUnlock(hClip)
				BREAK
			ENDIF
			fmt = EnumClipboardFormats(fmt)
		WEND
		CloseClipboard()
		IF m = 0 THEN RESULT = "Image not found."
	FEND

	FUNCTION Set(data, fmt=F_DIB)
		RESULT = EMPTY
		DIM res = OpenClipboard(_hwnd)
		IFB res THEN
			res = EmptyClipboard()
		ELSE
			RESULT = ERR_OPENCLIPBOARD
			EXIT
		ENDIF
		IFB res THEN
			IFB VARTYPE(data) = VAR_USTR THEN
				DIM size = 0, m, j, dwFlag = 0
				IFB !CryptStringToBinaryA(data,0,7,NULL,size,NULL,dwFlag) THEN
					RESULT = ERR_GET_LENGTH
					EXIT
				ENDIF
				m = GlobalAlloc(2, size)
				j = GlobalLock(m)
				IFB j THEN
					res = CryptStringToBinaryA(data,0,dwFlag,j,size,NULL,NULL)
					IF !res THEN RESULT = ERR_CONVERT
					GlobalUnlock(m)
					IFB res THEN
						IF SetClipboardData(fmt, m) = 0 THEN RESULT = ERR_SETCLIPBOARDDATA
					ENDIF
				ELSE
					RESULT = ERR_GLOBALLOCK
				ENDIF
				IF RESULT <> EMPTY THEN GlobalFree(m)
			ELSE
				IF SetClipboardData(fmt, data) = 0 THEN RESULT = ERR_SETCLIPBOARDDATA
			ENDIF
		ELSE
			RESULT = "EmptyClipboard fail."
		ENDIF
		CloseClipboard()
	FEND

ENDMODULE


でも、ビットマップデータをBase64エンコードするから、画像データが巨大になるんですよね、、、。
少し大きい画像をクリップボードに保持していると、Get関数も泣き言をいうし。


、、、圧縮でしょう。

LZSS圧縮した操作

Lzssモジュールに依存してます。
UWSCでLZSS圧縮 - じゅんじゅんのきまぐれ


ImageLzss.uws

OPTION EXPLICIT

CALL Lzss


IFB GET_UWSC_NAME = "ImageLzss.uws" THEN

	IFB MSGBOX("イメージを取得しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN
		MSGBOX("始点でOKしてください")
		DIM x1 = G_MOUSE_X, y1 = G_MOUSE_Y
		MSGBOX("終点でOKしてください")
		DIM x2 = G_MOUSE_X, y2 = G_MOUSE_Y, w = x2 - x1, h = y2 - y1
		IFB w < 0 THEN
			w = ABS(w)
			x1 = x2
		ENDIF
		IFB h < 0 THEN
			h = ABS(h)
			y1 = y2
		ENDIF
		SAVEIMG(, , x1, y1, w, h)
	ENDIF
	IF MSGBOX("クリップボードのイメージをログ出力しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT Image.Get()

	TEXTBLOCK _Image_Uwsc_Icon
		AAAAALgDAACvAAAAAgAAACgAAAAPAgQEAAAAAQAgAAMAAACEAgUEAAIEBAIICAIE
		BP8AAP8CBgUCBAQCBgYCDgkCDAwCCAYCDgwCJCQCKBACQBwCdhgCIBACdCQC0CgC
		PDAClBgCPCACHBgCOCwC1EQCQCACIAX//wIEBAIICAJMJQI4DAIcCQJAGwJ0GAI8
		IALkFAI8IALkFAI8IALuFAKMEQI8IwJKFgIUFAIIBg==
	ENDTEXTBLOCK
	IF MSGBOX("クリップボードにUWSCのアイコンを設定しますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT Image.Set(_Image_Uwsc_Icon)

	IF MSGBOX("クリップボードの画像をCHKIMGしますか?", BTN_YES OR BTN_NO) = BTN_YES THEN PRINT CHKIMG()
ENDIF


MODULE Image
	CONST ERR_OPENCLIPBOARD = "OpenClipboard fail."
	CONST ERR_GET_LENGTH = "Get length error."
	CONST ERR_CONVERT = "Convert error."
	CONST ERR_SETCLIPBOARDDATA = "SetClipboardData fail."
	CONST ERR_GLOBALLOCK = "GlobalLock fail."

	CONST F_BITMAP = 2
	CONST F_DIB = 8
	CONST F_DIBV5 = 17

	DEF_DLL OpenClipboard(HWND): BOOL: user32
	DEF_DLL CloseClipboard(): BOOL: user32
	DEF_DLL EmptyClipboard(): BOOL: user32
	DEF_DLL EnumClipboardFormats(DWORD): DWORD: user32
	DEF_DLL GetClipboardFormatNameW(DWORD,var wstring,int): int: user32
	DEF_DLL GetClipboardData(DWORD): DWORD: user32
	DEF_DLL SetClipboardData(DWORD, DWORD): DWORD: user32

	DEF_DLL GlobalAlloc(DWORD, DWORD): DWORD: kernel32
	DEF_DLL GlobalLock(DWORD): DWORD: kernel32
	DEF_DLL GlobalUnlock(DWORD): BOOL: kernel32
	DEF_DLL GlobalSize(DWORD): DWORD: kernel32
	DEF_DLL GlobalFree(DWORD): DWORD: kernel32

	DEF_DLL CryptBinaryToStringA(DWORD,DWORD,DWORD,DWORD,var DWORD): BOOL: crypt32
	DEF_DLL CryptStringToBinaryA(string,DWORD,DWORD,DWORD,var DWORD,var DWORD,var DWORD): BOOL: crypt32

	DIM _hwnd


	PROCEDURE Image
		_hwnd = IDTOHND(GETID(GET_THISUWSC_WIN))
	FEND

	PROCEDURE Dispose()
		Lzss.Dispose()
	FEND


	FUNCTION Get(fm=F_DIB)
		RESULT = EMPTY
		DIM res = OpenClipboard(_hwnd)
		IFB !res THEN
			RESULT = ERR_OPENCLIPBOARD
			EXIT
		ENDIF
		DIM hClip, size, nstr = 0, m = 0, cm, i = 0, wksize = 66, wk = FORMAT(CHR(0), wksize)
		DIM hMem, fmt = EnumClipboardFormats(0)
		WHILE fmt <> 0
			IFB fmt = fm THEN
				hClip = GetClipBoardData(fmt)
				size = GlobalSize(hClip)
				hMem = GlobalLock(hClip)
				cm = Lzss.Compress(hMem, size)
				GlobalUnlock(hClip)
				size = Lzss.GetCompressSize(cm)
				IFB size > 200000 THEN
					IFB MSGBOX("時間がかかりそうなので、やめていいですか?", BTN_YES OR BTN_NO) = BTN_YES THEN
						RESULT = "Abort."
						BREAK
					ENDIF
				ENDIF
				IFB CryptBinaryToStringA(cm, size, 1, NULL, nstr) THEN
					m = Lzss.Alloc(nstr)
					IFB m THEN
						IFB CryptBinaryToStringA(cm, size, 1, m, nstr) THEN
							DEF_DLL RtlMoveMemory(var string,DWORD,DWORD): kernel32
							WHILE i < nstr
								RtlMoveMemory(wk, m + i, wksize)
								PRINT TRIM(wk)
								i = i + wksize
							WEND
						ELSE
							RESULT = ERR_CONVERT
						ENDIF
					ELSE
						RESULT = ERR_GLOBALLOCK
					ENDIF
					Lzss.Free(m)
				ELSE
					RESULT = ERR_GET_LENGTH
				ENDIF
				Lzss.Free(cm)
				BREAK
			ENDIF
			fmt = EnumClipboardFormats(fmt)
		WEND
		CloseClipboard()
		IF m = 0 THEN RESULT = "Image not found."
	FEND

	FUNCTION Set(data, fmt=F_DIB)
		RESULT = EMPTY
		DIM res = OpenClipboard(_hwnd)
		IFB res THEN
			res = EmptyClipboard()
		ELSE
			RESULT = ERR_OPENCLIPBOARD
			EXIT
		ENDIF
		IFB res THEN
			IFB VARTYPE(data) = VAR_USTR THEN
				DIM size = 0, m, j, cm = 0, bm = 0, dwFlag = 0
				IFB CryptStringToBinaryA(data,0,7,NULL,size,NULL,dwFlag) THEN
					cm = Lzss.Alloc(size)
				ELSE
					RESULT = ERR_GET_LENGTH
				ENDIF
				IFB cm THEN
					res = CryptStringToBinaryA(data,0,dwFlag,cm,size,NULL,NULL)
				ELSEIF RESULT = EMPTY THEN
					RESULT = "Alloc fail."
				ENDIF
				IFB res THEN
					size = Lzss.GetOriginalSize(cm)
					bm = Lzss.Decompress(cm)
					cm = 0
				ELSEIF RESULT = EMPTY THEN
					RESULT = ERR_CONVERT
				ENDIF
				IF cm THEN Lzss.Free(cm)
				IFB RESULT = EMPTY THEN
					m = GlobalAlloc(2, size)
					j = GlobalLock(m)
					IFB j THEN
						DEF_DLL RtlMoveMemory(DWORD,DWORD,DWORD): kernel32
						RtlMoveMemory(j, bm, size)
						GlobalUnlock(m)
						IF SetClipboardData(fmt, m) = 0 THEN RESULT = ERR_SETCLIPBOARDDATA
					ELSE
						RESULT = ERR_GLOBALLOCK
					ENDIF
					IF RESULT <> EMPTY THEN GlobalFree(m)
				ENDIF
				IF bm THEN Lzss.Free(bm)
			ELSE
				IF SetClipboardData(fmt, data) = 0 THEN RESULT = ERR_SETCLIPBOARDDATA
			ENDIF
		ELSE
			RESULT = "EmptyClipboard fail."
		ENDIF
		CloseClipboard()
	FEND

ENDMODULE

機能は同じですが、Lzss対応のスクリプト増分を、UWSCアイコンの圧縮分が上回って、小さくなっています。
(もちろん、Lzssスクリプトを取り込んだら大きくなってしまいますが、、、)
写真のような画像の圧縮率は悪いですが、アイコンのような画像では、それなりな圧縮率です。


何、クリップボードの内容を書き換えるのが嫌?
一旦待避して、確認後戻してはどうでしょうか?
UWSCでクリップボードを管理する - じゅんじゅんのきまぐれ
それも嫌なら、現状では無理だす。