Archive for the 'CIFilter' Category

2017/03/21 CoreImage(CIFilter)で指定画像を2階調ポスタライズ v2

CoreImageのCIFilterを用いて、指定の画像を2階調でポスタライズするAppleScriptです。

CPUImageにも同様のポスタライズ用のフィルタが存在しているのですが、パラメータを指定してもうまく効かなかったので、CIFilterを使ってみました。

6ba2129c-12c5-42bf-b1a6-48dc883a97ec.png
▲実行前

81421d35-72aa-4d9d-9e6b-e2c59f9c9109.png
▲実行後

AppleScript名:CoreImageで指定画像を2階調ポスタライズ v2
– Created 2017-03-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”
–http://piyocast.com/as/archives/4541

–画像を選択
set aPath to POSIX path of (choose file of type {“public.image”})
set aNSImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath

set imgRes to execCIFilterWithNSImage(aNSImage, “CIColorPosterize”) of me

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)

set fRes to saveNSImageAtPathAsPNG(imgRes, savePath) of me

on convCIimageToNSImage(aCIImage)
  set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aCIImage
  
set tmpSize to aRep’s |size|()
  
set newImg to current application’s NSImage’s alloc()’s initWithSize:tmpSize
  
newImg’s addRepresentation:aRep
  
return newImg
end convCIimageToNSImage

on convNSImageToCIimage(aNSImage)
  set tiffDat to aNSImage’s TIFFRepresentation()
  
set aRep to current application’s NSBitmapImageRep’s imageRepWithData:tiffDat
  
set newImg to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aRep
  
return newImg
end convNSImageToCIimage

–NSImageをCIImageに変換してCIfilterを実行
on execCIFilterWithNSImage(aNSImage, aFilterName)
  set aCIImage to convNSImageToCIimage(aNSImage) of me
  
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults()
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
aFilter’s setValue:2 forKey:“inputLevels”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
set newNSImage to convCIimageToNSImage(aOutImage) of me
  
return newNSImage
end execCIFilterWithNSImage

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2016/05/02 Google APIを用いてURLを短縮してより小さいQRコードを作成

Google APIを利用して指定のURLを短縮し、QRコードを作成するAppleScriptです。

各種WebサービスをAppleScriptから呼び出して、日々便利に使っています。その中でまったく興味が湧かなかったURL短縮サービスAPI(URL Shortening API)。

たまたま、WebのURLからQRコードを作成して印刷することを検討していたときに、印刷面積を減らしたいというニーズが出てきました(TEPRAで印刷しようとしていたので)。

単純に縮小して印刷する物理的な大きさを小さくすれば、印刷できないこともないのですが、ゴミなどが付着したり経年劣化で退色した場合などに、むりやり小さく印刷するとエラーに遭遇する確率が上がってしまいます。また、解像度の低いプリンターで印刷するときには、エラー発生リスクが上がります。

そこで、長くなりがちなWebのURLを、短縮URLサービスを用いて短くしたうえでQRコード化することを思いつきました(Googleで探してみると、同様の先行事例多数 ^ー^;)。

qrcodes.png

上の図で、左がオリジナルのURLをQRコード化したもの。右がURL短縮してQRコード化したものです。URL短縮がQRコードのサイズの縮小に貢献することが見て取れます。ここで用いた元URLは、

 Original URL—-http://piyocast.com/as/archives/4067
 Shorten URL—-http://goo.gl/kT372B

クラウドストレージ上にあるファイル(Dropboxなど)やGoogle Map上の位置情報を示すURLは長くなりがちですが、いったんURL短縮サービスを経由することで、QRコードに印刷するのに抵抗感のない程度の長さの文字列に圧縮でき、たいへんけっこうなことです(Google Mapsにも短縮URL変換の機能がついていますね、、、)。

実行時には、Googleアカウントを作成してGoogle APIの利用申請を行い、API Keyを取得してAppleScript中に指定してください。また、実行にあたって実行環境にShane StanleyのAppleScript Libraries「Bridge Plus」がインストールしてあることが条件となります。

AppleScript名:POST method REST API_Google Shortener URL and make QR code
– Created 2016-05-01 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

property APIKey : “XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX” –Google API Key

set aLongURL to “http://piyocast.com/as/archives/4067″ –Target Long URL
set aShortURL to shortenURL(aLongURL) of me
if aShortURL = “” then return –Error

set dtPath to POSIX path of (path to desktop) & ((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
set aRes to writeQRimageAsPNG(aShortURL, dtPath) of me

–指定パスにQRコードをPNG画像で出力
on writeQRimageAsPNG(aTargStr, aTargPath)
  set aStr to current application’s NSString’s stringWithString:aTargStr
  
set strData to aStr’s dataUsingEncoding:(current application’s NSISOLatin1StringEncoding)
  
set qrFilter to current application’s CIFilter’s filterWithName:“CIQRCodeGenerator”
  
qrFilter’s setValue:strData forKey:“inputMessage”
  
qrFilter’s setValue:“H” forKey:“inputCorrectionLevel”
  
set anImage to qrFilter’s outputImage()
  
saveNSImageAtPathAsPNG(anImage, aTargPath) of me
end writeQRimageAsPNG

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

–与えられたURL文字列を短縮する
on shortenURL(aLongURL)
  set myAPIKey to my APIKey
  
set reqURLStr to “https://www.googleapis.com/urlshortener/v1/url?key=” & myAPIKey
  
set aRec to {longUrl:aLongURL}
  
set aRes to callRestPOSTAPIAndParseResults(reqURLStr, aRec) of me
  
  
set aRESTres to json of aRes
  
set aRESCode to responseCode of aRes
  
set aRESHeader to responseHeader of aRes
  
  
if aRESCode is not equal to 200 then return “”
  
set aShort to (aRESTres’s valueForKey:“id”) as string
  
return aShort
end shortenURL

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL, aPostData)
  
  
load framework
  
  
–Request  
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to ASify from (dRes’s statusCode())
  
  
–Get Response Header
  
set resHeaders to ASify from (dRes’s allHeaderFields())
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResults

★Click Here to Open This Script 

2016/03/16 指定文字列からQRコード画像(PNG)をデスクトップに作成する

指定文字列からQRコードの画像をデスクトップに作成するAppleScriptです。

QRコードやバーコードを作成するためのFrameworkとしてはZXingObjCが有名で、これがAppleScriptでは扱えないCGImageを返してくるのでいろいろ悩んでいたのですが、OS X自体にQRコード作成機能があるとは予想外でした(悩んで損した、、、)。

58e2a470-ee99-4310-8a70-ba2b49c6bd98.png
▲本AppleScriptで生成したQRコードの画像

43d40cb9-6701-49e4-8cff-573570397e40.png
▲AppleScriptでバーコード画像も(CICode128BarcodeGenerator)生成できる(Code 128)

QRコードの認識機能自体もAppleScriptから呼び出せるので、本Scriptで生成したPNG画像を認識用のAppleScriptで確認して、元の文字列がデコードされることを確認しています(でも、なぜかCode128の1Dバーコードの認識機能が用意されていない。とても不思議)。

AppleScript名:指定文字列からQRコード画像(PNG)をデスクトップに作成する
– Created 2016-03-16 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”

set a to “mailto:maro@piyocast.com”

set aStr to current application’s NSString’s stringWithString:a
set strData to aStr’s dataUsingEncoding:(current application’s NSISOLatin1StringEncoding)
set qrFilter to current application’s CIFilter’s filterWithName:“CIQRCodeGenerator”
qrFilter’s setValue:strData forKey:“inputMessage”
qrFilter’s setValue:“H” forKey:“inputCorrectionLevel”
set anImage to qrFilter’s outputImage()

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
saveNSImageAtPathAsPNG(anImage, savePath) of me

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2015/08/19 ASOCで選択した画像をリサイズ v3

Cocoaの機能を使って指定画像を指定サイズにリサイズ(縮小Only)するAppleScriptです。

CIFilterを使って、縮小前にぼかしフィルタを、縮小後にシャープネスフィルタをかけています。

いろいろテストしていたのですが、

  「フィルタ処理するたびに画像が右上にズレるのはなぜ??」

とちょっと悩んでいました・・・どうやら、当初指定していたぼかしフィルタ(Gaussian Blur)の仕様ではないかと考え、別のぼかしフィルタ(CIBoxBlur)に変更したところ、右上への移動問題が発生しなくなりました。

処理結果に癖があるのとフィルタすると処理時間もそれなりにかかるので、Photoshopを使わない処理のほうがよい・・・ともいいにくいものがあります(「餅は餅屋」という表現がぴったり、、、)。ただし、並列処理で大量の画像を処理するような場合にはこっちを使うことになるでしょう(たぶん)。

resized10.png
▲Resized by this AppleScript

resized21.png
▲Resized by other AppleScript using Photoshop

後日談:
指定のフォルダに入っている画像を順次リサイズするように記述してみたところ、1ファイル処理したときに数秒(1〜3秒?)待たされたのがウソのように高速に(^ー^;; 1.3〜6.4MBのPNGファイルを200個処理してみたところ、所要時間55.35秒。画像1枚あたり0.28秒(MacBook Pro Retina 2012)。なかなか高速です。

AppleScript名:ASOCで選択した画像をリサイズ v3
– Created 2015-08-19 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”

set targW to 450 –Target Width (Pixel)

set aPath to POSIX path of (choose file of type {“public.image”})
set aURL to current application’s |NSURL|’s fileURLWithPath:aPath

–指定したURLから画像を読み込み
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL

–出力ファイル名を組み立てる
set aStr to current application’s NSString’s stringWithString:aPath
set bStr to (aStr’s stringByDeletingPathExtension()) as text
set outPath to bStr & “_resized” & “.png” –pngで出力

–ぼかしフィルタ
set aDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSNumber’s numberWithFloat:(2.0 as real)} forKeys:{“inputRadius”}
set bImage to execFilterToNSImage(aImage, “CIBoxBlur”, aDict)

–リサイズ
set cImage to resizeNSImage(targW, bImage)

–シャープフィルタ
set bDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSNumber’s numberWithFloat:(1.0 as real)} forKeys:{“inputSharpness”}
set dImage to execFilterToNSImage(cImage, “CISharpenLuminance”, bDict)

–ファイル保存
set aRes to saveImageRepAtPathAsPNG(dImage, outPath)

–指定画像を指定の横幅に縦横比を維持したままリサイズ
on resizeNSImage(targW, aImage)
  
  
–とりあえずImageからサイズの情報を取得
  
set sizeInfo to |size|() of aImage
  
  
set wNum to (width of sizeInfo) as integer
  
set hNum to (height of sizeInfo) as integer
  
  
  
–ターゲット横サイズをもとに、縦横のターゲットサイズを計算
  
if wNum > targW then
    –横幅がターゲットサイズよりも大きかった場合
    
set newRatioW to targW / wNum
    
set newRatioH to (hNum * newRatioW)
    
    
set newW to (wNum * newRatioW) as integer
    
set newH to (hNum * newRatioW) as integer
  else
    –横幅がターゲットサイズよりも小さかった場合はオリジナルサイズでそのまま
    
set newW to wNum
    
set newH to hNum
  end if
  
  
  
set tmpSize to current application’s NSZeroSize
  
set tmpSize’s width to newW as real
  
set tmpSize’s height to newH as real
  
  
set resImg to current application’s NSImage’s alloc()’s initWithSize:tmpSize
  
  
resImg’s lockFocus()
  
  
set aTransform to current application’s NSAffineTransform’s transform()
  
aTransform’s scaleBy:(newRatioW as real)
  
aTransform’s concat()
  
aImage’s drawAtPoint:(current application’s NSZeroPoint) fromRect:(current application’s NSZeroRect) operation:(current application’s NSCompositeCopy) fraction:1.0
  
  
resImg’s unlockFocus()
  
  
return resImg
  
end resizeNSImage

–画像を指定パスにPNG形式で保存
on saveImageRepAtPathAsPNG(anImage, outPath)
  
  
–画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
  
end saveImageRepAtPathAsPNG

–NSImageにCIFilterを実行して返す
on execFilterToNSImage(aNSImage, aFilterName, aParamDic)
  
  
–NSImageからCIImageを生成
  
set aTiff to aNSImage’s TIFFRepresentation()
  
set aBitmap to current application’s NSBitmapImageRep’s imageRepWithData:aTiff
  
set aCIImage to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aBitmap
  
  
– CIFilter をフィルタの名前で生成してフィルタ実行
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults() –各フィルタのパラメータはデフォルト
  
aFilter’s setValuesForKeysWithDictionary:aParamDic
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
  
–フィルター結果のbitmapImageRepをNSImageに変換して返す
  
set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aOutImage
  
set outImage to current application’s NSImage’s alloc()’s initWithSize:(aRep’s |size|())
  
outImage’s addRepresentation:aRep
  
  
return outImage –NSImage
  
end execFilterToNSImage

★Click Here to Open This Script 

2014/12/09 CoreImageでフィルタしまくり

指定画像に対して、CoreImageのFilterをかけまくるAppleScriptです。オリジナルの画像は破壊せず、

 「オリジナルファイル名」_「Filter名」.jpg

の画像を(オリジナル画像と同じフォルダ内に)生成します。オリジナルはbadcharanさんのScriptですが、いろいろ(どうでもいいところを)書き換えました。主に、AppleScript Libraries用だったものを、Yosemite以降の普通のAppleScriptのフォーマットにして、ASObjCExtrasの機能を用いて簡略化。

OS X上で実行可能なフィルタのうち、リストの上の方から(いやになるまで)順にテストしてみました。Transitionなどの明らかにアニメーション用と思われるもの以外はほとんど実行可能なようです。

ただし、各フィルタのパラメータはデフォルトのままなので、各フィルタごとのパラメータを明示的に指定するような処理を付加すべきところでしょう。

現在、本Blogに画面キャプチャを掲載するさいに、Photoshopでぼかしフィルタをかけてからリサイズし、リサイズ後にシャープフィルタをかけています(びみょ〜に、JavaScriptでWebブラウザ上でサムネールを生成させたほうがいいような気もしないではないですが)。かような処理をPhotoshopなしで行う際に、このような機能が利用できることでしょう。

AppleScript名:CoreImageでフィルタしまくり
– Created 2014-12-09 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”

–CIFilters (Not everything!!) From Apple’s Core Image Filter Reference
set ciList to {“CIColorInvert”, “CIBoxBlur”, “CIDiscBlur”, “CIGaussianBlur”, “CIMedianFilter”, “CIMotionBlur”, “CINoiseReduction”, “CIZoomBlur”, “CIColorMonochrome”, “CIColorPosterize”, “CIPhotoEffectChrome”, “CISepiaTone”, “CISharpenLuminance”, “CIUnsharpMask”, “CIKaleidoscope”}

–画像を選択
set aPath to choose file of type {“public.image”}

–すべてのフィルタを実行
repeat with i in ciList
  set j to contents of i
  
set aRes to convAsFilteredJPEG(aPath, j) of me
end repeat

–CIFilterをかけたJPEG画像を生成
–参照:http://ashplanning.blogspot.jp/ のうちのどこか
on convAsFilteredJPEG(aPath, aFilterName)
  
  
–aliasをURL(input)とPOSIX path(output) に変換
  
set aURL to (current application’s SMSFord’s URLFrom:aPath) –Input
  
set aPOSIX to (POSIX path of aPath) & “_” & aFilterName & “.jpg” –Output
  
  
–CIImageを生成
  
set aCIImage to current application’s CIImage’s alloc()’s initWithContentsOfURL:aURL
  
  
– CIFilter をフィルタの名前で生成
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults() –各フィルタのパラメータはデフォルト
  
  
–Filterを実行
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
– NSBitmapImageRep を CIImage から生成
  
set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aOutImage
  
  
– NSBitmapImageRep から JPEG データを取得
  
set jpegData to aRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:(missing value)
  
  
– ファイルに保存
  
set fsRes to jpegData’s writeToFile:aPOSIX atomically:true
  
return fsRes as boolean
  
end convAsFilteredJPEG

★Click Here to Open This Script