| 001 | #!/usr/bin/env osascript |
| 002 | #coding: utf-8 |
| 003 | ----+----1----+----2----+-----3----+----4----+----5----+----6----+----7-- |
| 004 | (* |
| 005 |
|
| 006 | 画像ファイルをOCRして |
| 007 | OCRの内容=画像内のテキストを検索します |
| 008 | マッチしたファイルパスをダイアログに戻して |
| 009 | クリップボードにコピー |
| 010 | か |
| 011 | プレビューで開くか選べます |
| 012 |
|
| 013 | 1画像ファイルを検索するのに約0.1秒-0.3前後かかります |
| 014 | 例 |
| 015 | 100ファイルあると約12-5秒かかります |
| 016 |
|
| 017 |
|
| 018 | OCR結果の先頭から500文字までをFinderコメントに入れて |
| 019 | 通常検索でもスポットライト検索の結果に出るようにする処理を入れました |
| 020 | スポットライトへのmdimportは実施しないので |
| 021 | スポットライト検索結果に出るか?は、利用者の環境依存があります。 |
| 022 |
|
| 023 |
|
| 024 |
|
| 025 |
|
| 026 | com.cocolog-nifty.quicktimer.icefloe *) |
| 027 | ----+----1----+----2----+-----3----+----4----+----5----+----6----+----7-- |
| 028 | use AppleScript version "2.8" |
| 029 | use framework "Foundation" |
| 030 | use framework "AppKit" |
| 031 | use framework "Vision" |
| 032 | #使わないことにした |
| 033 | # use framework "NaturalLanguage" |
| 034 | use framework "CoreFoundation" |
| 035 | use framework "UniformTypeIdentifiers" |
| 036 | use scripting additions |
| 037 |
|
| 038 | property refMe : a reference to current application |
| 039 |
|
| 040 | ############################# |
| 041 | #ダイアログ |
| 042 | set appFileManager to refMe's NSFileManager's defaultManager() |
| 043 | set ocidURLsArray to (appFileManager's URLsForDirectory:(refMe's NSDesktopDirectory) inDomains:(refMe's NSUserDomainMask)) |
| 044 | set ocidDesktopDirPathURL to ocidURLsArray's firstObject() |
| 045 | set aliasDefaultLocation to (ocidDesktopDirPathURL's absoluteURL()) as alias |
| 046 | set listUTI to {"public.image", "public.tiff", "public.jpeg", "public.png"} as list |
| 047 |
|
| 048 | set strMsg to ("画像ファイルを選択してください" & return & "画像の中の文字をOCRしてテキスト検索します") as text |
| 049 | set strPrompt to ("画像ファイルを選択してください" & return & "画像の中の文字をOCRしてテキスト検索します") as text |
| 050 | try |
| 051 | tell application "SystemUIServer" |
| 052 | activate |
| 053 | set listAliasFilePath to (choose file strMsg with prompt strPrompt default location aliasDefaultLocation of type listUTI with invisibles and multiple selections allowed without showing package contents) as list |
| 054 | end tell |
| 055 | on error strErrMes number numErrNo |
| 056 | log strErrMes & numErrNo |
| 057 | return false |
| 058 | end try |
| 059 | if listAliasFilePath is {} then |
| 060 | return false |
| 061 | end if |
| 062 |
|
| 063 |
|
| 064 | ############################## |
| 065 | # クリップボードの中身取り出し |
| 066 | set appPasteboard to refMe's NSPasteboard's generalPasteboard() |
| 067 | set ocidPastBoardTypeArray to appPasteboard's types() |
| 068 | set boolContain to ocidPastBoardTypeArray's containsObject:(refMe's NSStringPboardType) |
| 069 | if (boolContain as boolean) is true then |
| 070 | set ocidString to appPasteboard's stringForType:(refMe's NSStringPboardType) |
| 071 | set strDefaultAnswer to ocidString as text |
| 072 | else |
| 073 | set strDefaultAnswer to ("文字入力10文字程度") as text |
| 074 | end if |
| 075 | #ダイアログ保護のため50文字まで |
| 076 | set numCntChar to (count of every character of strDefaultAnswer) as integer |
| 077 | if numCntChar > 50 then |
| 078 | set strDefaultAnswer to (text 1 through 50 of strDefaultAnswer) as text |
| 079 | end if |
| 080 |
|
| 081 | ############################## |
| 082 | # ダイアログ |
| 083 | set strIconFilePath to ("/System/Library/UserNotifications/Bundles/com.apple.identityservicesd.firewall.bundle/Contents/Resources/Apple Care_Mac.icns") as text |
| 084 | set aliasIconFilePath to (POSIX file strIconFilePath) as alias |
| 085 | set strMsg to ("テキストを入力してください" & return & "語句検索します") as text |
| 086 | set strTitle to ("入力してください") as text |
| 087 | set strOK to ("OK") as text |
| 088 | set strCancel to ("キャンセル") as text |
| 089 | set listBotton to {strOK, strCancel} as list |
| 090 | try |
| 091 | tell application "System Events" |
| 092 | activate |
| 093 | set recordResult to (display dialog strMsg with title strTitle default answer strDefaultAnswer buttons listBotton default button strOK cancel button strCancel with icon aliasIconFilePath giving up after 120 without hidden answer) as record |
| 094 | end tell |
| 095 | on error strErrMsg number numErrNo |
| 096 | log strErrMsg & numErrNo |
| 097 | return false |
| 098 | end try |
| 099 |
|
| 100 | set strResponseButton to (button returned of recordResult) as text |
| 101 | set boolGaveUp to (gave up of recordResult) as boolean |
| 102 | if boolGaveUp is true then |
| 103 | log "時間切れ" |
| 104 | return false |
| 105 | else if strResponseButton is strOK then |
| 106 | set strReturnedText to (text returned of recordResult) as text |
| 107 | end if |
| 108 | #スタート計測 |
| 109 | set ocidStart to refMe's CFAbsoluteTimeGetCurrent() |
| 110 |
|
| 111 | ############################## |
| 112 | #戻り値整形 |
| 113 | set ocidOrgStrings to (refMe's NSString's stringWithString:(strReturnedText)) |
| 114 | #NFC処理 |
| 115 | set ocidOrgStringsNFC to ocidOrgStrings's precomposedStringWithCanonicalMapping() |
| 116 | #改行をLFに強制 |
| 117 | set ocidReplacedStrings to (ocidOrgStringsNFC's stringByReplacingOccurrencesOfString:(linefeed) withString:("")) |
| 118 | set ocidReplacedStrings to (ocidReplacedStrings's stringByReplacingOccurrencesOfString:(return) withString:("")) |
| 119 | set ocidSearchStrings to (ocidReplacedStrings's stringByReplacingOccurrencesOfString:(tab) withString:("")) |
| 120 |
|
| 121 | ############################## |
| 122 | #本処理 |
| 123 | #ヒットしたファイルのURL格納用 |
| 124 | set ocidHitsPathArrayM to refMe's NSMutableArray's alloc()'s init() |
| 125 | set ocidDistancePathArrayM to refMe's NSMutableArray's alloc()'s init() |
| 126 |
|
| 127 |
|
| 128 | repeat with itemAliasFilePath in listAliasFilePath |
| 129 | set aliasFilePath to itemAliasFilePath as alias |
| 130 | set strFilePath to (POSIX path of aliasFilePath) as text |
| 131 | set ocidFilePathStr to (refMe's NSString's stringWithString:(strFilePath)) |
| 132 | set ocidFilePath to ocidFilePathStr's stringByStandardizingPath() |
| 133 | set ocidFilePathURL to (refMe's NSURL's alloc()'s initFileURLWithPath:(ocidFilePath) isDirectory:(false)) |
| 134 | #NSDATAで読み込み |
| 135 | set ocidOption to (refMe's NSDataReadingMappedIfSafe) |
| 136 | set listReadData to (refMe's NSData's alloc()'s initWithContentsOfURL:(ocidFilePathURL) options:(ocidOption) |error|:(reference)) |
| 137 | set ocidReadData to (first item of listReadData) |
| 138 | #NSBitmapImageRepに |
| 139 | set ocidImgRep to (refMe's NSBitmapImageRep's imageRepWithData:(ocidReadData)) |
| 140 | #イメージサイズ |
| 141 | set ocidImageWpx to ocidImgRep's pixelsWide() |
| 142 | set ocidImageHpx to ocidImgRep's pixelsHigh() |
| 143 | #半分Pxサイズ |
| 144 | set numHalfWpx to doGetHalfNo(ocidImageWpx) |
| 145 | set numHalfHpx to doGetHalfNo(ocidImageHpx) |
| 146 | #解放 |
| 147 | set ocidImgRep to (missing value) |
| 148 | #最小文字サイズ |
| 149 | set numMinPt to 8 as integer |
| 150 | set intTextHeight to (numMinPt / numHalfHpx) as number |
| 151 | #####OCR |
| 152 | #VNImageRequestHandler's |
| 153 | set ocidHandler to (refMe's VNImageRequestHandler's alloc()'s initWithData:(ocidReadData) options:(missing value)) |
| 154 | #VNRecognizeTextRequest's |
| 155 | set ocidRequest to refMe's VNRecognizeTextRequest's alloc()'s init() |
| 156 | set ocidOption to (refMe's VNRequestTextRecognitionLevelAccurate) |
| 157 | (ocidRequest's setRecognitionLevel:(ocidOption)) |
| 158 | (ocidRequest's setMinimumTextHeight:(intTextHeight)) |
| 159 | (ocidRequest's setAutomaticallyDetectsLanguage:(true)) |
| 160 | (ocidRequest's setRecognitionLanguages:{"en", "ja"}) |
| 161 | (ocidRequest's setUsesLanguageCorrection:(false)) |
| 162 | #results |
| 163 | (ocidHandler's performRequests:(refMe's NSArray's arrayWithObject:(ocidRequest)) |error|:(reference)) |
| 164 | set ocidResponseArray to ocidRequest's results() |
| 165 | set ocidFirstOpinionString to (refMe's NSMutableString's alloc()'s init()) |
| 166 | #missing value対策 |
| 167 | if ocidResponseArray = (missing value) then |
| 168 | (ocidFirstOpinionString's appendString:("テキストは認識されませんでした")) |
| 169 | else |
| 170 | #戻り値の数だけ々 |
| 171 | repeat with itemArray in ocidResponseArray |
| 172 | #候補数指定 1-10 ここでは2種の候補を戻す指定 |
| 173 | set ocidRecognizedTextArray to (itemArray's topCandidates:(1)) |
| 174 | set ocidFirstOpinion to ocidRecognizedTextArray's firstObject() |
| 175 | (ocidFirstOpinionString's appendString:(ocidFirstOpinion's |string|())) |
| 176 | (ocidFirstOpinionString's appendString:(return)) |
| 177 | end repeat |
| 178 | end if |
| 179 | set ocidOpinionString to (ocidFirstOpinionString's stringByReplacingOccurrencesOfString:(return) withString:("")) |
| 180 | #最初から500文字までをコメントに入れる |
| 181 | set numStrLength to ocidOpinionString's |length|() |
| 182 | if numStrLength < 500 then |
| 183 | set numTrimIndex to numStrLength as integer |
| 184 | else |
| 185 | set numTrimIndex to 500 as integer |
| 186 | end if |
| 187 | #500文字までを設定テキストとして後処理に回す |
| 188 | set ocidTrimRange to refMe's NSRange's NSMakeRange(0, numTrimIndex) |
| 189 | set ocidTrimString to (ocidOpinionString's substringWithRange:(ocidTrimRange)) |
| 190 | set strMetaString to ocidTrimString as text |
| 191 | ######################### |
| 192 | #コメント入れ |
| 193 | tell application "Finder" |
| 194 | tell file aliasFilePath |
| 195 | set comment to strMetaString |
| 196 | end tell |
| 197 | end tell |
| 198 | #########判定 |
| 199 | set boolContain to (ocidFirstOpinionString's localizedStandardContainsString:(ocidSearchStrings)) |
| 200 | if boolContain is true then |
| 201 | (ocidHitsPathArrayM's addObject:(ocidFilePath)) |
| 202 | end if |
| 203 | #########判定 |
| 204 | #日本語対応していないので処理はするけど使わない |
| 205 | (* |
| 206 | set appNLLang to (refMe's NLEmbedding's sentenceEmbeddingForLanguage:(refMe's NLLanguageJapanese)) |
| 207 | if appNLLang = (missing value) then |
| 208 | set appNLLang to (refMe's NLEmbedding's sentenceEmbeddingForLanguage:(refMe's NLLanguageEnglish)) |
| 209 | end if |
| 210 | set numDistance to (appNLLang's distanceBetweenString:(ocidFirstOpinionString) andString:(ocidSearchStrings) distanceType:(refMe's NLDistanceTypeCosine)) |
| 211 | if (numDistance as number) < 1.5 then |
| 212 | (ocidDistancePathArrayM's addObject:(ocidFilePath)) |
| 213 | end if |
| 214 | *) |
| 215 | end repeat |
| 216 |
|
| 217 | set ocidEnd to refMe's CFAbsoluteTimeGetCurrent() |
| 218 | set strTime to (ocidEnd - ocidStart) as text |
| 219 |
|
| 220 |
|
| 221 | ################################# |
| 222 | #ソート |
| 223 | set ocidDescriptor to refMe's NSSortDescriptor's sortDescriptorWithKey:("self") ascending:(yes) selector:("localizedStandardCompare:") |
| 224 | set ocidDescriptorArray to refMe's NSArray's arrayWithObject:(ocidDescriptor) |
| 225 | set ocidSortedPathArray to ocidHitsPathArrayM's sortedArrayUsingDescriptors:(ocidDescriptorArray) |
| 226 | set ocidJoinText to ocidSortedPathArray's componentsJoinedByString:(linefeed) |
| 227 | set strJoinText to ocidJoinText as string |
| 228 |
|
| 229 |
|
| 230 | ############################## |
| 231 | # ダイアログ |
| 232 | set strIconFilePath to ("/System/Library/UserNotifications/Bundles/com.apple.identityservicesd.firewall.bundle/Contents/Resources/Apple Care_Mac.icns") as text |
| 233 | set aliasIconFilePath to (POSIX file strIconFilePath) as alias |
| 234 | set strMsg to ("マッチしたファイルパスです" & return & "コピーできます") as text |
| 235 | set strTitle to ("処理の戻り値です") as text |
| 236 | set strOK to ("プレビューで画像を開く") as text |
| 237 | set strCancel to ("キャンセル") as text |
| 238 | set strCopyToClipboard to ("クリップボードにコピー") as text |
| 239 | set listBotton to {strCopyToClipboard, strCancel, strOK} as list |
| 240 | try |
| 241 | tell application "System Events" |
| 242 | activate |
| 243 | set recordResult to (display dialog strMsg with title strTitle default answer strJoinText buttons listBotton default button strCopyToClipboard cancel button strCancel with icon aliasIconFilePath giving up after 20 without hidden answer) as record |
| 244 | end tell |
| 245 | on error strErrMsg number numErrNo |
| 246 | log strErrMsg & numErrNo |
| 247 | return false |
| 248 | end try |
| 249 | try |
| 250 | tell application "System Events" to quit |
| 251 | end try |
| 252 | set strResponseButton to (button returned of recordResult) as text |
| 253 | set boolGaveUp to (gave up of recordResult) as boolean |
| 254 | if boolGaveUp is true then |
| 255 | log "時間切れ" |
| 256 | return false |
| 257 | end if |
| 258 | set strResponseText to (text returned of recordResult) as text |
| 259 | if strResponseButton is strOK then |
| 260 | set listAliasFilePath to {} as list |
| 261 | repeat with itemPath in ocidSortedPathArray |
| 262 | set strItemPath to itemPath as text |
| 263 | set aliasItemPath to (POSIX file strItemPath) as alias |
| 264 | set end of listAliasFilePath to aliasItemPath |
| 265 | end repeat |
| 266 | |
| 267 | tell application id "com.apple.Preview" |
| 268 | activate |
| 269 | open listAliasFilePath |
| 270 | end tell |
| 271 | return true |
| 272 | else if strResponseButton is strCopyToClipboard then |
| 273 | #ペーストボードに格納する |
| 274 | set appPasteboard to refMe's NSPasteboard's generalPasteboard() |
| 275 | set ocidText to (refMe's NSString's stringWithString:(strResponseText)) |
| 276 | appPasteboard's clearContents() |
| 277 | set boolDone to appPasteboard's setString:(ocidText) forType:(refMe's NSPasteboardTypeString) |
| 278 | return boolDone |
| 279 | end if |
| 280 |
|
| 281 | return 0 |
| 282 |
|
| 283 |
|
| 284 |
|
| 285 | ################################# |
| 286 | #偶数を作る |
| 287 | to doGetHalfNo(argInt) |
| 288 | set numInt to argInt as number |
| 289 | set numRound to ((numInt / 2) + 0.5) as integer |
| 290 | set numOddEven to (numRound mod 2) as integer |
| 291 | if numOddEven = 1 then |
| 292 | set numRound to (numRound - 1) as integer |
| 293 | end if |
| 294 | return numRound |
| 295 | end doGetHalfNo |