UWSCで画像をクリップボード経由で扱う
UWSCのSAVEIMG/CHKIMG/PEEKCOLORが4.9でクリップボードに対応した記念。
PEEKCOLORは使ってないけど、SAVEIMGでクリップボードに放り込んだり、クリップボードの画像を文字列にしてみたり、その文字列から画像をクリップボードに戻したり、クリップボードからCHKIMGするサンプル!
何ができるって、認識させたい画像をスクリプトに内包できるのですよ、はい!
あと、できる人ならメモリー上でHBITMAPを作って、それをクリップボードに転送して認識、なんてこともできる。
画像ファイルに依存しない神経衰弱を解くスクリプトとか、フォントに依存したOCRとかできそうですね!
追記 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でクリップボードを管理する - じゅんじゅんのきまぐれ
それも嫌なら、現状では無理だす。