Archive for the 'Framework (third party)' Category

2017/03/02 指定の画像が真っ白かどうか判定する

オープンソースのフレームワーク「GPUImage」(By Brad Larson)を利用して、指定の画像が真っ白かどうかを判定するAppleScriptです。指定画像が真っ白の場合にはtrueを、そうでない場合にはfalseを返します。

テストにあたっては、GPUImageフレームワークをXcodeでビルドして、~/Library/Frameworksフォルダに入れておいてください。

GPUImage.frameworkには特殊なフィルタが存在しており、その中で最もユニークなのが指定画像(NSImage)のヒストグラムを求めるものです。つまり、画像をフィルタ加工するのではなく、分析した結果を画像(NSImage)に出力します。

そのうちの「明度ヒストグラム」のフィルタ(?)を指定して、指定画像の明度分布を求めます(一瞬で)。明度分布のヒストグラムは、横256ドット・高さ3ドットの画像(NSImage)として出力されます。うち、中央の1ドットが左側が0(暗い=黒)右側が255(明るい=白)を表現しています。

white.png
▲GPUImage.frameworkで出力した明度ヒストグラム(真っ白な画像を処理した場合)。幅256ドット、高さ3ドットの画像(高さを90ドットに拡大)。右端(明度=255)のみ白く反応しており、他に明度分布は存在しないことが見て取れる

test2.png

test1.png
▲GPUImage.frameworkで出力した明度ヒストグラム(真っ白ではない画像を処理した場合の処理例)

つまり、画像が真っ白かどうかを判定するという、気が遠くなるほど重そうな画像処理が、わずか256箇所の色情報を調べるだけで、しかもGPUの機能を活用して一瞬で処理できることになります。しかも、AppleScriptで。

  1024×768@72DPIの画像=786,432ドット
  1920×1200@72DPIの画像=2,304,000ドット

これらを全部ループで色検出処理すると、相当の時間がかかるはずです。230万アイテム超のループ処理なんて想像したくもありません。

一応、テストのために、

  1024×768@72DPIの画像で、1ドットだけ黒くしたもの
  1920×1200@72DPIの画像で、1ドットだけ黒くしたもの

の2つを用意して、黒くした1ドットの存在を検出できるかテストしてみたところ、無事検出できました(しかも一瞬で)。

ただし、このことが4Kとか5Kの白い画像に1ドットだけ黒くした場合でも同様に検出できるかどうかは保証のかぎりではありません。

実際に利用するさいには事前にターゲットサイズの白い画像に1ドットだけ黒くして実験して検出可能かどうかを確認。検出できなかった場合には事前に解像度を落とす処理を行うなどの対応が必要です。

AppleScript名:指定の画像が真っ白かどうか判定する
– Created 2017-02-12 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “GPUImage”
–http://piyocast.com/as/archives/4492

set aFile to POSIX path of (choose file of type {“public.image”} with prompt “Select a Image to check it is white (or not) “)
set anNSImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile
set wRes to my detectAllWhite:anNSImage

–指定のNSImageが真っ白かどうかをチェック
on detectAllWhite:anNSImage
  
  
–明度ヒストグラム画像を取得
  
set imgRes to getHistogramFromImage(anNSImage, 4) of me
  
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:(imgRes’s TIFFRepresentation())
  
  
–白い画像のデータパターン
  
set aWhitePattern to current application’s NSMutableArray’s arrayWithArray:{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0}
  
  
set resArray to current application’s NSMutableArray’s alloc()’s init()
  
repeat with i from 0 to 255
    set origColor to (aRawimg’s colorAtX:i y:1)
    
set srgbColSpace to current application’s NSColorSpace’s genericGrayColorSpace
    
set aColor to (origColor’s colorUsingColorSpace:srgbColSpace)
    
set aWhite to aColor’s whiteComponent()
    (
resArray’s addObject:aWhite)
  end repeat
  
  
set aRes to (resArray’s isEqualTo:aWhitePattern) as boolean
  
return aRes
  
end detectAllWhite:

–指定のNSImageをGPUImage.frameworkで明度ヒストグラム化してNSImageで返す
on getHistogramFromImage(aNSImage, histogramType)
  set aFilter to current application’s GPUImageHistogramFilter’s alloc()’s initWithHistogramType:histogramType
  
set aProcImg to (aFilter’s imageByFilteringImage:aNSImage)
  
return aProcImg
end getHistogramFromImage

–NSImageをGPUImage.frameworkの指定フィルタで処理してNSImageを返す
on filterWithNSImage(aNSImage, filterName as string)
  set aClass to current application’s NSClassFromString(filterName)
  
set aImageFilter to aClass’s alloc()’s init()
  
set aProcImg to (aImageFilter’s imageByFilteringImage:aNSImage)
  
return aProcImg
end filterWithNSImage

★Click Here to Open This Script 

2017/02/16 YAMLのじっけん

オープンソースのフレームワーク「YAML.framework」(Mirek Rusin)を用いて、構造化データ記述言語であるYAMLとオブジェクト(listやrecord)との間の相互変換を行うAppleScriptです。

これまでYAMLとは縁のない生活を送ってきましたが、とくに問題はありませんでした。構造を持つデータの分量が増えた場合には、プログラム中に直接記述せず、Excelの表からデータを読み取って処理したり、データベースなど他のデータソースからデータを取得していました。

ただ、listとかrecordの内容が込み入ってくる(フィールド数が多いとか、入れ子構造の段数が深いとか)と、こういう仕組みがあったほうが便利なんだろうな、ということは理解できます。

YAML.frameworkのプロジェクトをXcodeでビルドし、出来上がったフレームワークを~/Library/Frameworksに入れてテストしてみてください。

途中、Githubに掲載されているObjective-CのサンプルプログラムがNSInputStreamを使っており、これをAppleScriptに書き換えて呼び出すとAppleScriptの処理系が100%クラッシュ。NSDataを経由して変換する方法なども試してみましたがNSInputStreamを作りにいくとクラッシュ。

結局、Stringから直接変換するメソッドがあったため、これを使用することで安定して処理できるようになりました。

当初は機械学習フレームワークの「YCML」をいじくっていたのですが、その過程で本フレームワークを発見。なかなか有用性が高そうなので試してみた次第です。

AppleScript名:YAMLのじっけん
– Created 2017-02-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “YAML” –https://github.com/mirek/YAML.framework
–http://piyocast.com/as/archives/4464

–YAMLの文字列からオブジェクトを生成する
set aYAMLstr to
items:
- name: Foo
- name: Bar

set aStr to current application’s NSString’s stringWithString:aYAMLstr
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)

set aData to current application’s YAMLSerialization’s objectsWithYAMLString:aStr options:(4096) |error|:(missing value)
–>  (NSArray) {{items:{{name:”Foo”}, {name:”Bar”}}}}

–オブジェクトからYAMLの文字列を取得する
set aString to (current application’s YAMLSerialization’s createYAMLStringWithObject:aData options:(1) |error|:(missing value)) as string
(* –>
“—
- items:
- name: Foo
- name: Bar
…”
*)

★Click Here to Open This Script 

AppleScript名:YAMLのじっけん4
– Created 2017-02-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “YAML” –https://github.com/mirek/YAML.framework
–http://piyocast.com/as/archives/4464

–YAMLの文字列からオブジェクトを生成する
set aYAMLstr to
- name: Smith
email: smith@mail.com
- name: Shelton
email: shelton@mail.com
- name: Kelly
email: kelly@mail.com

set aRes to retObjectFromYAMLString(aYAMLstr) of me
–>  {{{name:”Smith”, email:”smith@mail.com”}, {name:”Shelton”, email:”shelton@mail.com”}, {name:”Kelly”, email:”kelly@mail.com”}}}

set bYAMLstr to
names: [Smith, Shelton, Kelly]
emails: [smith@mail.com, shelton@mail.com, kelly@mail.com]

set bRes to retObjectFromYAMLString(bYAMLstr) of me
–>  {{names:{”Smith”, “Shelton”, “Kelly”}, emails:{”smith@mail.com”, “shelton@mail.com”, “kelly@mail.com”}}}

–オブジェクト(list)からYAMLの文字列を生成する
set bStr to retYAMLStringFromObject(bRes)
(*  
“—
- names:
- Smith
- Shelton
- Kelly
emails:
- smith@mail.com
- shelton@mail.com
- kelly@mail.com


*)

on retObjectFromYAMLString(aYAMLstr as string)
  set aStr to current application’s NSString’s stringWithString:aYAMLstr
  
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aData to current application’s YAMLSerialization’s objectsWithYAMLString:aStr options:(4096) |error|:(missing value)
  
return aData as list
end retObjectFromYAMLString

on retYAMLStringFromObject(anObject)
  set aString to (current application’s YAMLSerialization’s createYAMLStringWithObject:anObject options:(1) |error|:(missing value)) as string
  
return aString
end retYAMLStringFromObject

★Click Here to Open This Script 

2017/02/12 GPUImageで輪郭抽出フィルタを実行

オープンソースのフレームワーク「GPUImage」(By Brad Larson)を呼び出して、指定画像に輪郭抽出フィルタを実行して、デスクトップにフィルタ名でPNGに保存するAppleScriptです。

テストにあたっては、GPUImageフレームワークをXcodeでビルドして、~/Library/Frameworksフォルダに入れておいてください。

実際にはもっと凝った処理に使っていますが、その過程でフィルタ名を文字列で間接指定して実行するルーチンが出来てきて、なかなか使い勝手もよくなってきています。

気になる処理速度ですが、MacBook Pro Mid 2012 Core i7 2.6GHzの環境で、

 3,264 × 2,448 pixel、1.2MB → 0.7sec
 3,024 × 4,032 pixel、2.8MB → 1.2sec

ぐらいでした(10回計測時の平均。2回目以降はキャッシュが効いている可能性もあります)。処理中にはこの4Core/8Threadの環境でCPUのロードアベレージが20%ぐらいでまだ余裕があり、AppleScriptで並列処理するともうちょっと速度を稼げるかもしれません。

sample1.png

sample2.png

AppleScript名:GPUImageで輪郭抽出フィルタを実行
– Created 2017-02-12 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “GPUImage” –https://github.com/BradLarson/GPUImage
use framework “AppKit”
–http://piyocast.com/as/archives/4451

set aFile to POSIX path of (choose file of type {“public.image”})
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile
set imgRes to filterWithNSImage(anImage, “GPUImageSobelEdgeDetectionFilter”) of me
set newPath to retUUIDfilePath(aFile, “png”) of me
set sRes to saveNSImageAtPathAsPNG(imgRes, newPath) of me

on retUUIDfilePath(aPath, aEXT)
  set aUUIDstr to (current application’s NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((current application’s NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDfilePath

on filterWithNSImage(aNSImage, filterName as string)
  set aClass to current application’s NSClassFromString(filterName)
  
set aImageFilter to aClass’s alloc()’s init()
  
set aProcImg to (aImageFilter’s imageByFilteringImage:aNSImage)
  
return aProcImg
end filterWithNSImage

–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 

2017/02/05 GPUImageで画像にすべてのフィルタを実行してデスクトップにPNG形式で保存

オープンソースのフレームワーク「GPUImage」(By Brad Larson)を呼び出して、指定画像にGPUImageのすべてのフィルタを実行して、デスクトップにフィルタ名でPNGに保存するAppleScriptです。

テストにあたっては、GPUImageフレームワークをXcodeでビルドして、~/Library/Frameworksフォルダに入れておいてください。

ドキュメントによれば125種類ものフィルタを内蔵しているというGPUImageですが、どれがどのような処理を行ってくれるのかは、実際に呼び出してみないとわかりません。また、単に呼び出して画像にフィルタを実行しただけでは記述内容が不足しているというものもありそうです(パラメータを指定しないと意味がないケース、フィルタが仕様の都合で複数の画像を要求するものも)。

そこで、ヘッダーファイルからすべてのフィルタ名称を取り出して、ループで順次実行させてみました。デスクトップにフィルター名称でPNG画像を書き出します。

ヘッダーファイルに記載されていたフィルターとおぼしきものが145、うち実行可能だったものが100、エラーが45となりました。また、エラーは出なかったものの何らかのパラメータを指定しないとおそらく意味がない(オリジナル画像と変わらない)ものもありました。

samples_out.png

フィルタをallocしてinitした段階でエラーが出るものもあったり、エラーをキャッチできるまでに時間がかかるものもありましたが、with timedoutでタイムアウト時間を指定してもエラーとして検出することはできませんでした。

フレームワークを呼び出すのはAppleEventの枠組みの中でやっているわけではないはずなので、タイムアウトを仕掛けて適用されなくても仕方ありません。

AppleScript名:GPUImageで画像にすべてのフィルタを実行してデスクトップにPNG形式で保存
– Created 2017-02-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “GPUImage”
–https://github.com/BradLarson/GPUImage
–http://piyocast.com/as/archives/4441

–Read JPEG file
set aFile to POSIX path of (choose file of type {“public.image”})
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile

–Select Filter
set erroredFilter to {}
set aList to {“GPUImageFilter”, “GPUImageTwoPassFilter”, “GPUImage3×3TextureSamplingFilter”, “GPUImageContrastFilter”, “GPUImageSaturationFilter”, “GPUImageBrightnessFilter”, “GPUImageLevelsFilter”, “GPUImageExposureFilter”, “GPUImageRGBFilter”, “GPUImageHueFilter”, “GPUImageWhiteBalanceFilter”, “GPUImageMonochromeFilter”, “GPUImagePixellateFilter”, “GPUImageSobelEdgeDetectionFilter”, “GPUImageSketchFilter”, “GPUImageToonFilter”, “GPUImageGrayscaleFilter”, “GPUImageKuwaharaFilter”, “GPUImageFalseColorFilter”, “GPUImageSharpenFilter”, “GPUImageUnsharpMaskFilter”, “GPUImageTwoInputFilter”, “GPUImageGaussianBlurFilter”, “GPUImageTwoPassTextureSamplingFilter”, “GPUImageFilterGroup”, “GPUImageTransformFilter”, “GPUImageCropFilter”, “GPUImageGaussianBlurPositionFilter”, “GPUImageGaussianSelectiveBlurFilter”, “GPUImageBilateralFilter”, “GPUImageBoxBlurFilter”, “GPUImageSingleComponentGaussianBlurFilter”, “GPUImageMedianFilter”, “GPUImageMotionBlurFilter”, “GPUImageZoomBlurFilter”, “GPUImageAddBlendFilter”, “GPUImageColorBurnBlendFilter”, “GPUImageDarkenBlendFilter”, “GPUImageDivideBlendFilter”, “GPUImageLightenBlendFilter”, “GPUImageMultiplyBlendFilter”, “GPUImageOverlayBlendFilter”, “GPUImageColorDodgeBlendFilter”, “GPUImageLinearBurnBlendFilter”, “GPUImageScreenBlendFilter”, “GPUImageColorBlendFilter”, “GPUImageExclusionBlendFilter”, “GPUImageHueBlendFilter”, “GPUImageLuminosityBlendFilter”, “GPUImageNormalBlendFilter”, “GPUImagePoissonBlendFilter”, “GPUImageSaturationBlendFilter”, “GPUImageSoftLightBlendFilter”, “GPUImageHardLightBlendFilter”, “GPUImageSubtractBlendFilter”, “GPUImageTwoInputCrossTextureSamplingFilter”, “GPUImageDifferenceBlendFilter”, “GPUImageDissolveBlendFilter”, “GPUImageChromaKeyBlendFilter”, “GPUImageMaskFilter”, “GPUImageOpacityFilter”, “GPUImageAlphaBlendFilter”, “GPUImageColorMatrixFilter”, “GPUImageSepiaFilter”, “GPUImageGammaFilter”, “GPUImageHazeFilter”, “GPUImageToneCurveFilter”, “GPUImageHighlightShadowFilter”, “GPUImageLookupFilter”, “GPUImageAmatorkaFilter”, “GPUImageMissEtikateFilter”, “GPUImageSoftEleganceFilter”, “GPUImage3×3ConvolutionFilter”, “GPUImageEmbossFilter”, “GPUImageLaplacianFilter”, “GPUImageLanczosResamplingFilter”, “GPUImageThreeInputFilter”, “GPUImageFourInputFilter”, “GPUImageColorInvertFilter”, “GPUImageHistogramFilter”, “GPUImageHistogramGenerator”, “GPUImageAverageColor”, “GPUImageLuminosity”, “GPUImageSolidColorGenerator”, “GPUImageAdaptiveThresholdFilter”, “GPUImageAverageLuminanceThresholdFilter”, “GPUImageLuminanceThresholdFilter”, “GPUImageSolarizeFilter”, “GPUImageHalftoneFilter”, “GPUImagePixellatePositionFilter”, “GPUImagePolarPixellateFilter”, “GPUImagePolkaDotFilter”, “GPUImageCrosshatchFilter”, “GPUImageXYDerivativeFilter”, “GPUImageDirectionalNonMaximumSuppressionFilter”, “GPUImageDirectionalSobelEdgeDetectionFilter”, “GPUImageCannyEdgeDetectionFilter”, “GPUImagePrewittEdgeDetectionFilter”, “GPUImageThresholdEdgeDetectionFilter”, “GPUImageHarrisCornerDetectionFilter”, “GPUImageNobleCornerDetectionFilter”, “GPUImageShiTomasiFeatureDetectionFilter”, “GPUImageThresholdedNonMaximumSuppressionFilter”, “GPUImageColorPackingFilter”, “GPUImageHoughTransformLineDetector”, “GPUImageParallelCoordinateLineTransformFilter”, “GPUImageCrosshairGenerator”, “GPUImageLineGenerator”, “GPUImageBuffer”, “GPUImageLowPassFilter”, “GPUImageHighPassFilter”, “GPUImageMotionDetector”, “GPUImageThresholdSketchFilter”, “GPUImageSmoothToonFilter”, “GPUImageTiltShiftFilter”, “GPUImageCGAColorspaceFilter”, “GPUImagePosterizeFilter”, “GPUImageKuwaharaRadius3Filter”, “GPUImageChromaKeyFilter”, “GPUImageVignetteFilter”, “GPUImageBulgeDistortionFilter”, “GPUImagePinchDistortionFilter”, “GPUImageStretchDistortionFilter”, “GPUImageClosingFilter”, “GPUImageRGBClosingFilter”, “GPUImageDilationFilter”, “GPUImageRGBDilationFilter”, “GPUImageErosionFilter”, “GPUImageRGBErosionFilter”, “GPUImageOpeningFilter”, “GPUImageRGBOpeningFilter”, “GPUImageSphereRefractionFilter”, “GPUImageGlassSphereFilter”, “GPUImageSwirlFilter”, “GPUImageJFAVoronoiFilter”, “GPUImageVoronoiConsumerFilter”, “GPUImageLocalBinaryPatternFilter”, “GPUImageColorLocalBinaryPatternFilter”, “GPUImageMosaicFilter”, “GPUImagePerlinNoiseFilter”, “GPUImageWeakPixelInclusionFilter”, “GPUImageNonMaximumSuppressionFilter”, “GPUImageSourceOverBlendFilter”, “GPUImageColourFASTFeatureDetector”, “GPUImageColourFASTSamplingOperation”}

repeat with i in aList
  set j to contents of i
  
set aClass to current application’s NSClassFromString(j)
  
  
–Filter Image
  
set errorFlag to true
  
try
    with timeout of 5 seconds
      set stillImageFilter to aClass’s alloc()’s init()
      
set aProcImg to (stillImageFilter’s imageByFilteringImage:anImage)
    end timeout
  on error erM
    set the end of erroredFilter to {j, erM, 1}
    
set errorFlag to false
  end try
  
  
if errorFlag = true then
    –Make New File Name
    
set aPath to (((current application’s NSString’s stringWithString:aFile)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:j)’s stringByAppendingPathExtension:“png”)
    
try
      set sRes to saveNSImageAtPathAsPNG(aProcImg, aPath as string) of me
    on error erM
      set the end of erroredFilter to {j, erM, 2}
    end try
  end if
end repeat

return erroredFilter
–> {{”GPUImageTwoInputFilter”, “missing valueは“representationUsingType_properties_”メッセージを認識できません。”, 2}, …..

–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 

2017/02/05 GPUImageで画像にGPUImageMonochromeFilterを実行してデスクトップにPNG形式で保存

オープンソースのフレームワーク「GPUImage」(By Brad Larson)を呼び出して、指定画像にフィルタ(モノクローム画像化)を実行して、デスクトップにPNGで保存するAppleScriptです。

テストにあたっては、GPUImageフレームワークをXcodeでビルドして、~/Library/Frameworksフォルダに入れておいてください。

GPUImageはもともとiOSデバイス用に作られたようですが、Macもサポートしており、さまざまな(125種類もの)画像フィルタが用意されており、手軽に利用できます。CoreImageをAppleScriptから呼び出してフィルタを実行してみたこともありますが、CoreImageよりも手軽に感じられました。

フィルタ実行部分は2行だけで、ファイルを選択したり画像を保存する部分がほとんどなので、やることはほとんどありません。ある意味、Photoshopを呼び出すよりも手軽です。

img_0007_resized.png
▲実行前のオリジナル画像(Haneda Airport, Tokyo, Japan)

a5dfc34c-d1e4-47e6-8379-f46412dbc30d_resized.png
▲GPUImageMonochromeFilterを実行した画像

AppleScript名:GPUImageで画像にGPUImageMonochromeFilterを実行してデスクトップにPNG形式で保存
– Created 2017-02-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “GPUImage”
–https://github.com/BradLarson/GPUImage
–http://piyocast.com/as/archives/4438

–Read JPEG file
set aFile to POSIX path of (choose file of type {“public.image”})
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile

–Filter Image
set stillImageFilter to current application’s GPUImageMonochromeFilter’s alloc()’s init()
set aProcImg to stillImageFilter’s imageByFilteringImage:anImage

–Make New File Name
set aUUIDstr to (current application’s NSUUID’s UUID()’s UUIDString()) as string
set aPath to ((current application’s NSString’s stringWithString:aFile)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:“png”
set sRes to saveNSImageAtPathAsPNG(aProcImg, aPath as string) 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 

2016/02/16 FBEncryptorで文字列の暗号化、復号化(ASOC版)

xcatsanさんが公開されている「AES128暗号化ライブラリ FBEncryptor」を少々書き変えて(ARC対応&フレームワーク化。単なる作業レベル)作ったFBEncryptorKitを呼び出して文字列の暗号化、復号化を行うAppleScriptです。

以前にXcode上のAppleScriptObjCでこれを呼び出すものを書いてみましたが、通常のScript Editorで利用できるようにした方が応用が効くため、Cocoa Frameworkとして別途ビルドしてみました。

OS X 10.10以降用にビルドしたバイナリを用意しましたので、試したい方は(自己責任で)~/Library/Frameworksフォルダに入れて呼び出してください。

–> Download Binary

AppleScript名:FBEncryptorで文字列の暗号化、復号化
– Created 2016-02-16 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “FBEncryptorKit” –https://github.com/dev5tec/FBEncryptor

set aStr to “ABCDEFあいうえお
かきくけこGHIJKLMN”

set aKey to “piyomaru”

–Encryption
set aEnc to current application’s FBEncryptorAES’s encryptBase64String:aStr keyString:aKey separateLines:true
–>  (NSString) “N0/E5FB97DY+qOFtfKK9CCsAMKznyej94Ons1lC90V/9vMJIaBw5R+mbaxaTm711″

–Decription
set aDec to current application’s FBEncryptorAES’s decryptBase64String:aEnc keyString:aKey
(*
(NSString) “ABCDEFあいうえお
かきくけこGHIJKLMN”
*)

★Click Here to Open This Script 

2015/11/19 度量衡の変換

オープンソースの「DDUnitConverter」(By Dave DeLong)を用いて、度量衡(measurement unit)の変換を行うAppleScriptです。AppleScriptから呼び出すために、DDUnitConverterをフレームワーク化した「ddUnitConversionKit」を作成しています。

もともと、AppleScriptには内蔵の度量衡変換機能があり、

AppleScript名:インチからセンチへの変換
set a to 1
set a to a as inches
–> inches 1.0

set b to a as centimeters
–> centimeters 2.54

set c to a as meters
–> meters 0.0254

set d to a as kilometers
–> kilometers 2.54E-5

★Click Here to Open This Script 

とか、

AppleScript名:液体の容積の単位変換
–液体の容積の単位変換
set a to 10 as liters
–> liters 10.0

set b to a as gallons
–> gallons 2.641720372842

set c to a as quarts
–> quarts 10.566881491367

★Click Here to Open This Script 

ぐらいは簡単にできます。AppleScriptがサポートしている度量衡は、長さ、重さ、温度、液体の容積です。

ただ、mmの下のμmとか、オングストロームとか、そういう単位には対応していませんし、重量でいえばKgに対応していてもt(トン)の単位はサポートしていなかったりと、日常的な度量衡の単位の世界でも不十分な感じが否めません(数値の有効桁数が10桁と小さいことも影響?)。

Cocoaの世界で度量衡変換機能について調べてみたところ、km→m→cm→mmといった変換はしてくれるものの、他の単位への変換は行ってくれていなかったりして、標準機能だけではいまひとつな印象です。

AppleScript名:NSLengthFormatterのじっけん
– Created 2015-11-18 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://dev.classmethod.jp/references/ios8-new-formatter/

set aLengthFormatter to current application’s NSLengthFormatter’s alloc()’s init()
set aMeters to 5000
set aRes to (aLengthFormatter’s stringFromMeters:aMeters) as text
–>  "5 km"
set bRes to (aLengthFormatter’s stringFromMeters:500) as text
–>  "500 m"
set cRes to (aLengthFormatter’s stringFromMeters:0.5) as text
–>  "50 cm"
set dRes to (aLengthFormatter’s stringFromMeters:0.005) as text
–>  "5 mm"
set eRes to (aLengthFormatter’s stringFromMeters:("0.000005" as real)) as text
–>  "0.005 mm"

set res2 to aLengthFormatter’s getObjectValue:(missing value) forString:aRes errorDescription:(missing value)
–>  false

set res3 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitMillimeter)) as text
–>  "5,000 mm"
set res4 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitCentimeter)) as text
–>  "5,000 cm"
set res5 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitMeter)) as text
–>  "5,000 m"
set res6 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitKilometer)) as text
–>  "5,000 km"
set res7 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitInch)) as text
–>  "5,000 in"
set res8 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitFoot)) as text
–>  "5,000 ft"
set res9 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitYard)) as text
–>  "5,000 yd"
set res10 to (aLengthFormatter’s stringFromValue:aMeters unit:(current application’s NSLengthFormatterUnitMile)) as text
–>  "5,000 mi"

★Click Here to Open This Script 

AppleScript名:NSMassFormatterのじっけん
– Created 2015-11-18 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://dev.classmethod.jp/references/ios8-new-formatter/

set aMasFormatter to current application’s NSMassFormatter’s alloc()’s init()
set aKilloGrams to 60.0
set aRes to (aMasFormatter’s stringFromKilograms:aKilloGrams) as text
–>  "60 kg"
set a2Res to (aMasFormatter’s stringFromKilograms:(0.5)) as text
–>  "500 g"
set a3Res to (aMasFormatter’s stringFromKilograms:(5000000)) as text
–>  "5,000,000 kg"
set a4Res to (aMasFormatter’s stringFromKilograms:("0.0005" as real)) as text
–>  "0.5 g"

set bRes to (aMasFormatter’s stringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitGram)) as text
–>  "60 g"
set cRes to (aMasFormatter’s stringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitKilogram)) as text
–>  "60 kg"
set dRes to (aMasFormatter’s stringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitOunce)) as text
–>  "60 oz"
set eRes to (aMasFormatter’s stringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitPound)) as text
–>  "60 lb"
set fRes to (aMasFormatter’s stringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitStone)) as text
–>  "60 st"

set gRes to (aMasFormatter’s unitStringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitGram)) as text
–>  "g"
set hRes to (aMasFormatter’s unitStringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitKilogram)) as text
–>  "kg"
set iRes to (aMasFormatter’s unitStringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitOunce)) as text
–>  "oz"
set jRes to (aMasFormatter’s unitStringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitPound)) as text
–>  "lb"
set kRes to (aMasFormatter’s unitStringFromValue:aKilloGrams unit:(current application’s NSMassFormatterUnitStone)) as text
–>  "st"

set res01 to aMasFormatter’s getObjectValue:(missing value) forString:fRes errorDescription:(missing value)
–>  false

set res02 to (aMasFormatter’s stringFromKilograms:80) as text
–>  "80 kg"

set res03 to aMasFormatter’s unitStyle()
–>  2 = NSFormattingUnitStyleMedium

★Click Here to Open This Script 

そこで、冒頭に紹介したようにDDUnitConverterを導入してみたわけですが、これはこれで問題がないわけでもありません。本来、通貨同士の変換をサポートしており、通貨レートの更新機能を持っているのですが、実際に呼び出してみると更新されていない雰囲気が濃厚です(呼び出し方を間違っているのか?)。

なので、「通貨レート以外」の度量衡変換にのみ用いるのが安全な使い方なのかもしれない、というところです。

例によって、OS X 10.10以降用にビルドしたバイナリを用意しておきましたので、興味のある方はアーカイブを展開したあとで、~/Library/Frameworksに入れておためしください。

–> Download ddUnitConversionKit.framework binary

AppleScript名:DDUnitConverterのじっけん1
– Created 2015-11-19 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ddUnitConversionKit” –davedelong/DDUnitConverter
–https://github.com/davedelong/DDUnitConverter

–enums in DDVelocityUnitConverter.h
property DDVelocityUnitCentimetersPerHour : 0
property DDVelocityUnitCentimetersPerMinute : 1
property DDVelocityUnitCentimetersPerSecond : 2
property DDVelocityUnitFeetPerHour : 3
property DDVelocityUnitFeetPerMinute : 4
property DDVelocityUnitFeetPerSecond : 5
property DDVelocityUnitInchesPerHour : 6
property DDVelocityUnitInchesPerMinute : 7
property DDVelocityUnitInchesPerSecond : 8
property DDVelocityUnitKilometersPerHour : 9
property DDVelocityUnitKilometersPerMinute : 10
property DDVelocityUnitKilometersPerSecond : 11
property DDVelocityUnitKnots : 12
property DDVelocityUnitLight : 13
property DDVelocityUnitMach : 14
property DDVelocityUnitMetersPerHour : 15
property DDVelocityUnitMetersPerMinute : 16
property DDVelocityUnitMetersPerSecond : 17
property DDVelocityUnitMilesPerHour : 18
property DDVelocityUnitMilesPerMinute : 19
property DDVelocityUnitMilesPerSecond : 20
property DDVelocityUnitFurlongsPerFortnight : 21

–時速100kmを秒速kmに変換
set aVal to ((current application’s DDUnitConverter’s velocityUnitConverter())’s convertNumber:100 fromUnit:(DDVelocityUnitKilometersPerHour) toUnit:(DDVelocityUnitKilometersPerSecond)) as real
–>  0.027777777778

★Click Here to Open This Script 

AppleScript名:DDCurrencyUnitConverterのじっけん
– Created 2015-11-19 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ddUnitConversionKit” –davedelong/DDUnitConverter
–https://github.com/davedelong/DDUnitConverter

–enums in DDCurrencyUnitConverter.h
property DDCurrencyUnitEuro : 0
property DDCurrencyUnitJapaneseYen : 1
property DDCurrencyUnitUKPoundSterling : 2
property DDCurrencyUnitUSDollar : 3
property DDCurrencyUnitAlgerianDinar : 4
property DDCurrencyUnitArgentinePeso : 5
property DDCurrencyUnitAustralianDollar : 6
property DDCurrencyUnitBahrainDinar : 7
property DDCurrencyUnitBotswanaPula : 8
property DDCurrencyUnitBrazilianReal : 9
property DDCurrencyUnitBruneiDollar : 10
property DDCurrencyUnitCanadianDollar : 11
property DDCurrencyUnitChileanPeso : 12
property DDCurrencyUnitChineseYuan : 13
property DDCurrencyUnitColombianPeso : 14
property DDCurrencyUnitCzechKoruna : 15
property DDCurrencyUnitDanishKrone : 16
property DDCurrencyUnitHungarianForint : 17
property DDCurrencyUnitIcelandicKrona : 18
property DDCurrencyUnitIndianRupee : 19
property DDCurrencyUnitIndonesianRupiah : 20
property DDCurrencyUnitIranianRial : 21
property DDCurrencyUnitIsraeliNewSheqel : 22
property DDCurrencyUnitKazakhstaniTenge : 23
property DDCurrencyUnitKoreanWon : 24
property DDCurrencyUnitKuwaitiDinar : 25
property DDCurrencyUnitLibyanDinar : 26
property DDCurrencyUnitMalaysianRinggit : 27
property DDCurrencyUnitMauritianRupee : 28
property DDCurrencyUnitMexicanPeso : 29
property DDCurrencyUnitNepaleseRupee : 30
property DDCurrencyUnitNewZealandDollar : 31
property DDCurrencyUnitNorwegianKrone : 32
property DDCurrencyUnitRialOmani : 33
property DDCurrencyUnitPakistaniRupee : 34
property DDCurrencyUnitNuevoSol : 35
property DDCurrencyUnitPhilippinePeso : 36
property DDCurrencyUnitPolishZloty : 37
property DDCurrencyUnitQatarRiyal : 38
property DDCurrencyUnitRussianRuble : 39
property DDCurrencyUnitSaudiArabianRiyal : 40
property DDCurrencyUnitSingaporeDollar : 41
property DDCurrencyUnitSouthAfricanRand : 42
property DDCurrencyUnitSriLankaRupee : 43
property DDCurrencyUnitSwedishKrona : 44
property DDCurrencyUnitSwissFranc : 45
property DDCurrencyUnitThaiBaht : 46
property DDCurrencyUnitTrinidadAndTobagoDollar : 47
property DDCurrencyUnitTunisianDinar : 48
property DDCurrencyUnitUAEDirham : 49
property DDCurrencyUnitPesoUruguayo : 50
property DDCurrencyUnitBolivarFuerte : 51
property DDCurrencyUnitSDR : 52

–最初に通貨レートの更新を行う必要があるが、実行しても変わらないのはなぜ????
set aConv to current application’s DDUnitConverter’s currencyUnitConverter()
aConv’s refreshExchangeRates()
set aVal to (aConv’s convertNumber:100 fromUnit:(DDCurrencyUnitUSDollar) toUnit:(DDCurrencyUnitJapaneseYen))
–>  (NSNumber) 1.006839721743

★Click Here to Open This Script 

2015/11/13 MIKMIDIでMIDIデバイス一覧を取得

MIDIで接続されたデバイス一覧を取得するAppleScriptです。

まず、MIDIデバイスとMacの接続を行うわけですが、これについては安価なUSB-MIDI I/Fが市販されているため、こうしたものを利用するのが手軽でよいでしょう。自分はRolandのUM-ONEを試してみました。

top_l_resized.png

UM-Oneは専用のデバイスドライバをインストールすれば使えるようになります。

次に、AppleScriptからMIDIにアクセスする方法を模索することになります。現時点では3つの方法を見つけています。

1つめは、Apple純正のCoreMIDIを利用する方法。CのAPIなのでAppleScript-Cocoa Bridgeには手に負えない箇所が出てきそうですし、仕様を読んでいると何から何まで自分で記述しないといけないようなので、ちょっとウンザリします。

2つめは、オープンソースのフレームワーク「MIDIKit」(By Randy Weinstein)を利用する方法。いろいろAppleScriptからこづき回してみたところ、接続確認やMIDIデバイスのオンライン状態は調べられたものの、それ以上のことができません。たとえば、MIDIデバイスの名称(name)をAppleScriptから取得しようとするとすべてmissing valueが返ってくるなど、相性の悪さを感じました(日本語環境なのでなおさら未検証だったりするのかも)。

3つめが、今回紹介する同じくオープンソースのフレームワーク「MIKMIDI」(By Andrew Madsen)を利用する方法です。

midistudio.png
▲実験時の機器構成をOS X標準装備の「Audio MIDI設定」アプリで確認したところ。IAC Driverに「GarageBand」という名前のポートを宣言している。

自分がいろいろ試した中では、MIKMIDIが一番各種情報にアクセスしやすい印象を持っています。まだ、MIDI機器の接続状態を調べたぐらいなので、指定のデバイスにメッセージを送ったりできているレベルではありませんが、いろいろ調べてみるとできそうな感じがします。

img_3175.jpg
▲LAN経由でMIDI音源(Sound Canvas for iOS)をつないでみた。まだ、AppleScriptからメッセージを送れてはいない状況

AppleScript名:MIKMIDIでデバイス一覧を取得
– Created 2015-11-13 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MIKMIDI” –mixedinkey-opensource/MIKMIDI
–https://github.com/mixedinkey-opensource/MIKMIDI

set availableMIDIDevices to current application’s MIKMIDIDeviceManager’s sharedDeviceManager()’s availableDevices()
(*
–>  (NSArray) {(MIKMIDIDevice) <MIKMIDIDevice: 0×7f8a5e972a80> IAC Driver:
Entities: {
GarageBand:
Sources: {
<MIKMIDISourceEndpoint: 0×7f8a63a65610> IAC Driver GarageBand,
}
Destinations: {
<MIKMIDIDestinationEndpoint: 0×7f8a61bbc130> IAC Driver GarageBand,
},
}, (MIKMIDIDevice) <MIKMIDIDevice: 0×7f8a5e8d4320>ネットワーク:
Entities: {
}, (MIKMIDIDevice) <MIKMIDIDevice: 0×7f8a638a5fc0> Bluetooth:
Entities: {
}, (MIKMIDIDevice) <MIKMIDIDevice: 0×7f8a59e16360> UM-ONE:
Entities: {
<MIKMIDIEntity: 0×7f8a59ed8990> UM-ONE:
Sources: {
<MIKMIDISourceEndpoint: 0×7f8a61d47950> 新しい外部装置,
}
Destinations: {
<MIKMIDIDestinationEndpoint: 0×7f8a5ecadcf0> 新しい外部装置,
},
}}
*)

set aCount to availableMIDIDevices’s |count|()
–> 4

set availableVDevices to current application’s MIKMIDIDeviceManager’s sharedDeviceManager()’s virtualSources()
–>  (NSArray) {(MIKMIDISourceEndpoint) IAC Driver GarageBand, (MIKMIDISourceEndpoint) 新しい外部装置}

★Click Here to Open This Script 

2015/11/09 ムービーからオーディオのみ抽出してm4aで保存

Cocoaの機能を用いて、指定のQuickTimeムービーから音声のみ抽出してM4A(MPEG-4 Audio)で保存して指定のメタデータを付与するAppleScriptです。

Alex Nichol氏の「MP4Audio」をFramework化した「mp4AudioExportKit」を作って、それをAppleScriptから呼び出しています。

ただ、ビルド時に「それはもうdeprecatedだよー」というwarningが大量に出ているので、OS X 10.12以降で使えるかどうかは未知数です。

meta2.png
▲出力した音声データ(audiotest1.m4a)のmetadataをTerminal.app上で確認したところ。たしかに指定のデータが入っている

本Scriptでは、常識的な処理をひととおり試しているだけです。Sampling Rateを変更したりといったことは行っていません。

例によって、OS X 10.10以降用にビルドしたバイナリをあげておきますので、興味のある方は、アーカイブを展開して~/Library/Frameworksに入れてお試しください。

→ Download mp4AudioExportKit.framework

AppleScript名:MP4Audioのじっけん(ムービーからオーディオのみ抽出してM4Aで保存)
– Created 2015-11-09 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mp4AudioExportKit” –unixpickle/MP4Audio
–https://github.com/unixpickle/MP4Audio

–Open Original Movie
set aFile to POSIX path of (choose file of type {“com.apple.quicktime-movie”} with prompt “Choose a QuickTime movie to export as MP4 audio”)
set aPath to current application’s NSString’s stringWithString:aFile
set aMovie to current application’s ANMovie’s alloc()’s initWithFile:aPath

–Select Export File Name
set bFile to POSIX path of (choose file name with prompt “Input Export file name”)
set bPath to current application’s NSString’s stringWithString:bFile
if (bPath’s hasSuffix:“.m4a”) as boolean = false then
  set bPath to bPath’s appendString:“.m4a”
end if

–Export as MP4 audio
with timeout of 3600 seconds
  aMovie’s exportAACToFile:bPath
  
aMovie’s |close|()
end timeout

–Add Metadata
set aMetaData to current application’s ANMetadata’s alloc()’s init()
aMetaData’s setTitle:“戦場の絆ポータブル リプレイムービーNY音声編(1)”
aMetaData’s setAlbum:“戦場の絆ポータブル”
aMetaData’s setYear:“2015″
aMetaData’s setArtist:“Bandai Namco Entertainment”
aMetaData’s setTrackNumber:(current application’s ANMetadataTrack’s alloc()’s initWithTrackNumber:5 tracks:12)

set bMovie to current application’s ANMovie’s alloc()’s initWithFile:bPath
bMovie’s setMovieMetadata:aMetaData
bMovie’s |close|()

★Click Here to Open This Script 

2015/10/24 シリアルコードの生成と検証

オープンソースのSerialKeyGeneratorをもとに作成した「serialKeyGenKit」フレームワークを用いて、シリアルコードの生成(Generation)と検証(Validation)を行うAppleScriptです。

ソフトウェアの販売時などに、シリアルコードを発行することがあります。Mac App Storeのソフトウェア販売ではあまり見られませんが(自社ストア販売バージョンからMac App Store販売バージョンへのアップグレードでOmniGraffleあたりで見かけました)、Mac App Store以外でオンライン販売するような場合には必要になってきます。

キーの重複がなく、偽造されにくく、必要な情報を含んでいるようなシリアルコード体系が理想的です。しかも、使用する文字はA〜Z、0〜9の文字だけで、「XXXXX-XXXXX-XXXXX-XXXXX-XXXXX」のフォーマットで・・・・

そんなシリアルコードを手軽かつ高速に生成できるのがSerialKeyGeneratorです。シークレットキーをもとに乱数要素や日時の要素を勘案したシリアルコードを生成してくれます。

仕事で何度かシリアルコードの作成を行ったことがありますが、なかなかこれが大変でした。「SerialKeyGenerator」は非常に簡単なシリアルコードを生成するためのものですが、シリアルコードによって動作許可する機能を作ったり、指定日時まで動作許可するコードだったりと・・・それだけで相当の手間になりました。

また、流失したシリアルコードについてはオンラインで失効手続きを行えるようにしたりと、本気で作り出すと「ソフトウェア本体よりもでかい処理」になったりします(頭痛が、、、)。

例によって、serialKeyGenKit.frameworkをOS X 10.10以降用にビルドしておきましたので、興味のある方は~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScript名:SerialKeyGeneratorサンプル1
– Created 2015-10-24 18:27:16 +0900 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “serialKeyGenKit” –danielvy/SerialKeyGenerator
–https://github.com/danielvy/SerialKeyGenerator

set aGen to current application’s SerialKeyGenerator’s alloc()’s initWithSecret:“Piyomaru”
–>  (SerialKeyGenerator)

set aList to {}
repeat with i from 1 to 10
  set aRes to (aGen’s generateSerialWithSequence:i |data|:10)
  
set the end of aList to (aRes as text)
end repeat

aList
–>  {”1CHH8-BJY89-TR9Z9-AKSTL-70JZF”, “4KXCF-LS6P5-7BKYN-CUMPY-NM072″, “41GO2-OGZ3T-83YP9-2LS4J-9W3MI”, “CA3WV-C7FU7-PSPJ3-LNGT7-N6AJT”, “3OG0B-MCFUM-7YKHT-EE533-LNJEJ”, “4SKWQ-9G8XE-ZCE6K-APSAL-R0T8S”, “CTEZT-H4AQQ-BM15H-FH2DG-P7K7O”, “4BZ1X-2OHKF-5FWND-7SZVA-EBR89″, “BDKRI-9JU7T-G6N20-YPU9K-6FXQW”, “9EWW5-O3FMV-SDEZA-77JZE-OY8FL”}

★Click Here to Open This Script 

AppleScript名:SerialKeyGeneratorサンプル2
– Created 2015-10-24 18:27:16 +0900 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “serialKeyGenKit” –danielvy/SerialKeyGenerator
–https://github.com/danielvy/SerialKeyGenerator

–シリアルコードの生成(エンコード)

–シークレットキー「Piyomaru」をもとにシリアルコードジェネレータを生成
set aGen to current application’s SerialKeyGenerator’s alloc()’s initWithSecret:“Piyomaru”
–>  (SerialKeyGenerator)

–指定個数のシリアルコードを生成。生成するたびに毎回シリアルコードは異なる
set anArray to (aGen’s generateSerials:10 start:1 |data|:10) as list
–>  {”0YR0Q-Y5FZP-A25EI-TK3YI-78L5U”, “7VZSX-S87LJ-812L7-A2XC6-Q9DBQ”, “C3HYG-H4HPP-FPP6A-1PH1L-MVVF0″, “B7FHO-AQ4E0-Y0AQG-YYFVX-XSEWA”, “0C4GP-M46PY-BD7J9-878SG-FSZP3″, “5OLK7-C3R3R-IVKX5-7FUIT-GJA07″, “2KA8T-PFIC4-PII60-QBRWN-ZPJWE”, “325M7-8KR60-2X1G8-EF7OA-UP06I”, “CIH21-H6H1O-31AA4-12ZSD-0ZBT3″, “8NA54-0W8R5-0VI34-X1L5F-5E0GS”}

–シリアルコードの検証(デコード)

–シークレットキー「Piyomaru」をもとにシリアルコードジェネレータを生成
set bGen to current application’s SerialKeyGenerator’s alloc()’s initWithSecret:“Piyomaru”

set bRes to bGen’s decodeSerial:(contents of first item of anArray)

set aDate to bRes’s |date| as date
–>  date “2015年10月24日土曜日 18:37:25″
set aSeq to bRes’s sequence as integer
–>  1
set aData to bRes’s |data| as integer
–>  10

★Click Here to Open This Script 

2015/10/23 RFKeychain経由でKeychainアクセス

オープンソースのRFKeychain(By Rheinfabrik)をframework化したもの(rfKeychainKit.framework)を呼び出して、キーチェーンへのアクセスを行うAppleScriptです。

Keychainについては、かつてはKeychain AccessというAppleScript専用のヘルパーアプリが存在していましたが、いまはshell commandの「security」が用意されているので、そちら経由でアクセスしてくれという状況です。

OS X標準搭載のそれらヘルパーアプリのメンテナンス状況は正直言って期待できないので、AppleScriptがScriptring Bridge対応したタイミングで、Apple純正ヘルパーアプリ群への依存度を下げるための布石が必要だと思っていました。

たまたま見つけたRFKeychainですが、正直機能が足りているとも思えないので(すでに登録されているキーチェーン項目を検索するような機能がない)、ほかにもいろいろ探してみたほうがよさそうです。

例によって、フレームワークをOS X 10.10以降用にビルドしたものを用意しておきました。興味のある方は~/Library/Frameworksフォルダに入れてためしてみてください。

→ Download Framework Binary

AppleScript名:ASOCでRFKeychain経由でKeychainアクセス
– Created 2015-10-23 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “rfKeychainKit” –rheinfabrik/RFKeychain
–https://github.com/rheinfabrik/RFKeychain

–Register Password
set aRes to (current application’s RFKeychain’s setPassword:“piyopiyo” account:“piyomaru” service:“piyocast.com” accessGroup:“other”) as boolean
–> true

–Get Password
set bRes to (current application’s RFKeychain’s passwordForAccount:“piyomaru” service:“piyocast.com”) as text
–>  ”piyopiyo”

–Delete Password
set cRes to (current application’s RFKeychain’s deletePasswordForAccount:“piyomaru” service:“piyocast.com” accessGroup:“other”) as boolean
–>  true

★Click Here to Open This Script 

2015/10/22 辞書.appの指定名称の辞書でキーワード検索

オープンソースのプログラムDictionaryKit(By Mattt Thompson)をフレームワークに入れた「dictKit」を介して、OS X内蔵の辞書でキーワード検索を行うAppleScriptです。

DictionaryKitの内部機能を直接AppleScriptから呼ぶことはできませんが、DictionaryKitのプログラムを突っ込んだFramework「dictKit.framework」を作成し、これをインストールしてAppleScriptから呼べるようにしました。

注意点:DictionaryKitの説明にもあるのですが、OS XのPrivate APIを呼んでいるため、本プログラム(dictKit)を用いて作ったアプリケーションをMac App Store向けに申請することはできません。

でも、超〜便利なんで(^ー^;;; 日常的なScriptで使わない手はありません。

例によって、dictKitのバイナリをOS X 10.10以降用にビルドしておきましたので、興味のある方は~/Library/Frameworksフォルダに入れておためしください。

–> Download Framework Binary

AppleScript名:ASOCで辞書.appで検索可能な辞書名称一覧を取得する
– Created 2015-10-22 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “dictKit” –mattt/DictionaryKit
–https://github.com/mattt/DictionaryKit

set dSet to current application’s TTTDictionary’s availableDictionaries()
set dList to dSet’s allObjects()
set dNameList to {}
repeat with i in dList
  set the end of dNameList to (i’s |name|()) as text
end repeat
dNameList
–>  {”뉴에이스 영한사전 / 뉴에이스 한영사전“, “Apple 用語辞典”, “Multidictionnaire de la langue française”, “राजपाल हिन्दी शब्दकोश“, “Dizionario italiano da un affiliato di Oxford University Press”, “Oxford-Hachette French Dictionary”, “NE Ordbok”, “牛津英汉汉典”, “Oxford Thesaurus of English”, “スーパー大辞林”, “Oxford Dictionary of English”, “Oxford American Writer’s Thesaurus”, “Norsk Ordbok”, “Gran Diccionario Oxford - Español-Inglés Inglés-Español”, “Wikipedia”, “Duden-Wissensnetz deutsche Sprache”, “Толковый словарь русского языка”, “뉴에이스 국어사전“, “Prisma woordenboek Nederlands”, “New Oxford American Dictionary”, “Dicionário de Português licenciado para Oxford University Press”, “Oxford German Dictionary”, “Diccionario General de la Lengua Española Vox”, “ウィズダム英和辞典 / ウィズダム和英辞典”, “Arkadaş Türkçe Sözlük”, “พจนานุกรมไทย ฉบับทันสมัยและสมบูรณ์“, “汉语规典”}

★Click Here to Open This Script 

AppleScript名:ASOCで辞書検索じっけん
– Created 2015-10-22 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “dictKit” –mattt/DictionaryKit
–https://github.com/mattt/DictionaryKit

set aDictionary to current application’s TTTDictionary’s dictionaryNamed:“Apple 用語辞典”
set dRes to aDictionary’s |name|()
set dRes to dRes as text
–>  ”Apple 用語辞典”

set aTerm to “AppleScript”
set hitEntryList to (aDictionary’s entriesForSearchTerm:aTerm) as list
if hitEntryList = {missing value} then return “” –ヒットしなかった場合

repeat with i in hitEntryList
  set j to contents of i
  
  
set headW to (j’s headword)
  
set headW to headW as text
  
–>  ”AppleScript”
  
  
set aText to (j’s |text|)
  
set aText to aText as text
  
(*)
  –>  ”AppleScript
OS X に内蔵されたスクリプト言語です。AppleScript 言語のコマンドを使用すれば、“メール”、Safari、“カレンダー”など、さまざまなアプリケーションで繰り返しの作業や複雑な作業を自動化できます。
*)

  
end repeat

★Click Here to Open This Script 

2015/10/21 ステガノグラフィーを用いて画像に情報を埋め込む

オープンソースのステガノグラフィーのプログラム「ISStego」(By Isaac Stevao Sena氏)を用いて、PNG画像に文字情報を埋め込む/取り出すAppleScriptです。

ISStegoは普通にObjective-Cで書かれたGUIベースのアプリケーションだったので、そのままではAppleScriptから呼び出せませんでした。

そこで、中身をそのままそっくり移し替えた新規フレームワーク「stegLib.framework」をでっちあげてビルドし、AppleScriptから呼び出してみました(フレームワークをはじめて作ってみましたが、えっらい簡単で驚きました)。

PNG画像にUTF-8の文字情報(日本語文字列)を埋め込んで別のPNG画像に書き出し、書き出した画像からUTF-8の文字情報を取り出す実験を行ってみました。エンコードもデコードもうまく行っているようなので、うまく処理できていると思います。

ステガノグラフィーについて初めて聞いたのは20年ぐらい前のことと記憶していますが、こんなに手軽に使えるようになっていたとは驚きです。

Twitterにプログラムを投稿するのに、(140文字制限を回避するため)文字を画像化して投稿しているのを見て、「そこまでやるなら、画像にプログラムの文字データを埋め込めばいいのに」と思い、「ステガノグラフィーで埋め込めばいいんじゃないか?」ということで、埋め込めるようになったのですが、肝心のTwitterクライアントから画像をダウンロードする手段がなかったのがダメダメでした(Webブラウザ経由ならOKです)。

custf11.png
▲ステガノグラフィー処理前の画像

custf1_stego.png
▲ステガノグラフィーによって文字情報を埋め込んだ画像(本当に埋め込んであります^ー^;)

stegLib.framework(ISStegoをFramework化したもの)のバイナリを例によってOS X 10.10以降用にビルドしておきましたので、興味のある方は~/Library/Frameworksに入れて使ってみてください。

–> Download Framework

AppleScript名:ASOCで画像にステガノグラフィーで情報を埋め込む
– Created 2015-10-21 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “stegLib” –ISStegoをフレームワーク化
–https://github.com/isena/ISStego

set aFile to POSIX path of (choose file of type {“public.image”})
set encString to “長野谷隆昌/ぴよまるソフトウェア/Piyomaru Software”

set aFilePath to current application’s NSString’s stringWithString:aFile
set aExt to aFilePath’s pathExtension()

set newPath to aFilePath’s stringByDeletingPathExtension()
set newPath2 to newPath’s stringByAppendingString:“_stego”
set newPath3 to newPath2’s stringByAppendingPathExtension:aExt

set aURL to current application’s |NSURL|’s fileURLWithPath:aFilePath
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL
set strData to current application’s NSString’s stringWithString:encString

set aEncimage to current application’s ISStegoEncoder’s alloc()’s init()’s stegoImageForImage:aImage |data|:strData |error|:(missing value)
my saveImageRepAtPathAsPNG(aEncimage, newPath3)

–画像を指定パスに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

★Click Here to Open This Script 

AppleScript名:ASOCで画像にステガノグラフィーで埋め込まれた文字列を取り出す
– Created 2015-10-21 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “stegLib” –ISStegoをフレームワーク化
–https://github.com/isena/ISStego

set aFile to POSIX path of (choose file of type {“public.image”})
set aFilePath to current application’s NSString’s stringWithString:aFile
set aURL to current application’s |NSURL|’s fileURLWithPath:aFilePath
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL

set aDecodedData to current application’s ISStegoDecoder’s alloc()’s init()’s decodeStegoImage:aImage |error|:(missing value)
set resStr to current application’s NSString’s alloc()’s initWithData:aDecodedData encoding:(current application’s NSUTF8StringEncoding)
–>  (NSString) “長野谷隆昌/ぴよまるソフトウェア/Piyomaru Software”

★Click Here to Open This Script 

2015/10/11 ZipZap frameworkを使ってZipアーカイブ内の情報を取得

オープンソースのZipZapフレームワーク(By Pixelglow Software)を利用して、選択したZipアーカイブ中の情報を取得するAppleScriptです。

たまたまCocoa dev MLの過去ログを漁っていたら、ZipZapフレームワークを見つけました。GitHubのサイトはキーワード検索がいまひとつで、以前に検索したときにはひっかかってこなかったものです(ひととおり、めぼしいのは調べたので)。

それはともかく、GitHubのサイトからClone in DesktopでMacにXcodeプロジェクトをクローンして、Xcode 7.0.1でプロジェクトをビルド。生成したフレームワークをAppleScriptから呼び出すテストを行ってみたものです。

ほぼ、READMEに書いてある通り書いてそのまま動きました。ヘッダーファイルに書いてあるいくつかのプロパティも試してみたところ納得の結果が(READMEどおりに書いて動かないものも、他にいろいろみかけますが・・・本プロジェクトは実に素直でした)。

さまざまなプロパティをAppleScriptの型にcastしてログ表示しているため、OS X 10.11用(AppleScript version 2.5が必要)になっていますが、castしたりlog表示しなければOS X 10.10でも動きます(安全のために10.11専用に)。

例によって、OS X 10.10以降用にビルドしたZipZapフレームワークを置いておきます。興味のある方はお試しください(~/Library/Frameworks/にインストール)。

–> Download Framework Binary (OS X 10.10 or later)

AppleScript名:ASOCでZipZap frameworkを使ってZipアーカイブ内の情報を取得
– Created 2015-10-11 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “ZipZap”
–https://github.com/pixelglow/zipzap

set aPath to POSIX path of (choose file of type {“public.zip-archive”})
set oldArchive to current application’s ZZArchive’s archiveWithURL:(current application’s |NSURL|’s fileURLWithPath:aPath) |error|:(missing value)
–>  (ZZArchive)

set entryCount to oldArchive’s entries()’s |count|()
–>  180 –this zip archive includes 180 file or folders inside

set firstArchEntry to oldArchive’s entries()’s firstObject()
–>  (ZZOldArchiveEntry)

set aList to oldArchive’s entries() as list

repeat with i in aList
  set uSize to i’s uncompressedSize() as real
  
set cSize to i’s compressedSize() as real
  
set comF to i’s compressed() as boolean
  
set encF to i’s encrypted() as boolean
  
set modD to i’s lastModified() as date
  
set chkSum to i’s crc32() as text –The CRC32 code of the entry file: 0 for new entries.
  
set aFileMode to i’s fileMode() as text – The UNIX file mode for the entry: 0 for new or non-UNIX entries. This includes the file type bits.
  
set aFileName to i’s fileName() as text
  
  
log {aFileName, aFileMode, chkSum, modD, encF, comF, cSize, uSize}
  
–> 21:28:01.817 (* {”ZXingObjC.framework/”, “16877d”, “0″, date “2015年10月10日土曜日 10:07:16″, false, false, 0.0, 0.0} *)
  
–> 21:28:01.818 (* {”ZXingObjC.framework/Headers”, “41453d”, “2.393740531E+9″, date “2015年10月10日土曜日 10:07:10″, false, false, 24.0, 24.0} *)
  
–> 21:28:01.820 (* {”ZXingObjC.framework/Versions/”, “16877d”, “0″, date “2015年10月10日土曜日 10:07:10″, false, false, 0.0, 0.0} *)
  
–> 21:28:01.821 (* {”ZXingObjC.framework/Versions/3.1.0/”, “16877d”, “0″, date “2015年10月10日土曜日 10:07:16″, false, false, 0.0, 0.0} *)
  
–> 21:28:01.822 (* {”ZXingObjC.framework/Versions/3.1.0/Headers/”, “16877d”, “0″, date “2015年10月10日土曜日 10:07:16″, false, false, 0.0, 0.0} *)
  
  
–set aData to (i’s newDataWithError:false)–Uncompressed raw data
  
–log aData
end repeat

★Click Here to Open This Script 

2015/10/08 Excelデータを組み立てて書き出し(フォント指定、カラー指定)

オープンソースのExcelデータ書き出しフレームワーク「JXLS」(By David Hoerl)を利用して、Excelのない環境でもExcelデータを作成するAppleScriptです。

デフォルトのままではあまりにも味気なかったので、フォント名、フォントサイズ、カラーを指定してみたものです。

サンプルがほとんど存在していないので手探り状態でしたが、なんとかなりました。

OS XのFinder上でもXLSファイルのプレビュー機能があるため、類似のフレームワークはOS X自体に搭載していそうです(というより、機能があるからプレビューできているんでしょう)。

xls.png

AppleScript名:ASOCでExcelファイル生成テスト v2
– Created 2015-10-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “JXLS”

set aFile to POSIX path of (choose file name)
set filePath to current application’s NSString’s stringWithString:aFile

set workBook to current application’s JXLSWorkBook’s new()
set workSheet to workBook’s workSheetWithName:“ぴよぴよシート”
workSheet’s setWidth:1000 forColumn:0 defaultFormat:(missing value)

repeat with i from 0 to 64
  set aCell to (workSheet’s setCellAtRow:i column:0 toString:(current application’s NSString’s stringWithString:(“ぴよまる “ & (i as text))))
  (
aCell’s setFontName:“HiraKakuStd-W8″)
  (
aCell’s setFontHeight:320) –this is point * 20
  (
aCell’s setFontColorIndex:i)
end repeat

workBook’s writeToFile:filePath

★Click Here to Open This Script 

2015/10/08 Excelデータを組み立てて書き出し

オープンソースのExcelデータ書き出しフレームワーク「JXLS」(By David Hoerl)を利用して、Excelのない環境でもExcelデータを作成するAppleScriptです。

正直、Excelデータを書き出せるNumbers.appがあるので、そこまで頑張らなくてもよさそうな気配がしていますが、たまたま「Excelデータを読むフレームワーク」を探していたら見つけたものです(読み込む方は、iOS用のみだったという)。

無人島に流されてExcelがない極限環境であっても、AppleScriptだけでExcelデータを生成できます。

何も考えずに、サンプル中に書かれていたObjective-CのプログラムをAppleScriptで再現してみたものですが、出来上がったExcel書類(のフォント)がちょっと気持ち悪いです。フォントについては、しかるべきもの(ヒラギノとか)を指定する必要性を感じます。

excel1.png

OS X 10.10以降用にビルドしたJXLSフレームワークを置いておきます。興味のある方はお試しください(~/Library/Frameworks/にインストール)。

→ Download Framework (Binary)

AppleScript名:ASOCでExcelファイル生成テスト
– Created 2015-10-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “JXLS”

set aFile to POSIX path of (choose file name)
set filePath to current application’s NSString’s stringWithString:aFile

set workBook to current application’s JXLSWorkBook’s new()

set workSheet to workBook’s workSheetWithName:“ぴよぴよシート”
workSheet’s setWidth:1000 forColumn:0 defaultFormat:(missing value)

repeat with i from 0 to 10
  set aCell to (workSheet’s setCellAtRow:i column:0 toString:(current application’s NSString’s stringWithFormat_(“ぴよまる %d”, i + 1)))
  (
aCell’s setHorizontalAlignment:1) —-HALIGN_LEFT
  (
aCell’s setIndentation:(0 + i)) —– INDENT_0
end repeat

workBook’s writeToFile:filePath

★Click Here to Open This Script 

2015/10/06 XML-RPCのテスト

オープンソースのXML-RPCフレームワークを利用して、Web上のXML-RPCのサービスを呼び出すAppleScriptです。

AppleScriptにはcall soapやcall xmlrpc命令などが標準で実装されており、割と便利に使っています。

ただし、複雑な処理を行った場合に問題が見られました。たとえばWordPressに対して新規記事作成をリクエストした場合に、call xmlrpc命令自体が実行途中で100%クラッシュするなど、信頼性については疑問符がつき、安定性については「出たとこ勝負」なヤケッパチ感が漂っておりました。

AppleScriptの処理系がSOAPやXML-RPCの命令を実装したのは比較的早く、Mac OS X登場後間もないタイミングであったと記憶しています。ただし、この「早すぎた登場」にのちのち苦しめられることになります。

のちにAppleがOS XのIntel移行+64bitへの移行を決定。これに伴い、Carbon系の機能を使っているプログラムは事実上アップデートされないことになりました。

AppleScriptの処理系自体はIntel対応→Cocoa化→64bit化→マルチスレッド化+Scripting Bridge対応など進化して行ったのですが、call xmlrpcの機能モジュールについては「Carbon APIを使っているためアップデートしない(=バグ修正しない)」との明確な回答がAppleのエンジニアからありました。

XML-RPCの利用頻度自体はそれほど高くないため、致命的な問題にはなってはいないものの「いつか、Apple標準のcall xmlrpc命令の代わりになるものを見つけなくては」という問題意識は持っていました。

そんな中、オープンソースのXML-RPCのフレームワークをいくつか見つけ、AppleScriptから呼び出す実験を実施。その中で同期通信の機能を持っていたEric Czarny氏とNikolay Kasyanov氏のフレームワークにたどりつきました。

いろいろ試行錯誤して、AppleScriptからこのオープンソースのXML-RPCフレームワークを呼び出して、インターネット上のサービスを呼び出して使えることを確認したのが本AppleScriptです。Script Editor+ASObjC Explorer 4+OS X 10.11.0、Script Editor+OS X 10.10.5上での動作を確認しています。

XML-RPC frameworkについて、OS X 10.10以降をターゲットOSにしてビルドしたものも用意しておきました。興味のある方はおためしを(~/Library/Frameworks/にインストール)。

→ Download Framework(binary)

AppleScript名:ASOCでXML-RPCのテスト v3
– Created 2015-10-06 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “XMLRPC”
–XMLRPC.framework
–https://cocoapods.org/pods/xmlrpc
–Cocoa XML-RPC Framework © 2011 Divisible by Zero
–v2.3.4

set aRes to (my callXMLRPC(“http://yubin.senmon.net/service/xmlrpc/”, “yubin.getMaxFetchCount”, missing value)) as integer
–>  100

set bRes to (my callXMLRPC(“http://yubin.senmon.net/service/xmlrpc/”, “yubin.getVersion”, missing value)) as text
–> “15.09a”

on callXMLRPC(paramURL, aMethod, aParamList)
  
  
set aURL to current application’s |NSURL|’s URLWithString:paramURL
  
set aReq to current application’s XMLRPCRequest’s alloc()’s initWithURL:aURL
  
aReq’s setMethod:aMethod withParameter:aParamList
  
set aRes to current application’s XMLRPCConnection’s sendSynchronousXMLRPCRequest:aReq |error|:(missing value)
  
  
set errF to (aRes’s isFault()) as boolean
  
  
if errF = true then
    set xmlRPCres to faultCode of aRes
    
–set xmlRPCbody to faultString of aRes
  else
    set xmlRPCres to aRes’s object()
    
–set xmlRPCbody to aRes’s body()
  end if
  
  
return xmlRPCres
  
end callXMLRPC

★Click Here to Open This Script 

2015/10/03 UniversalDetectorで文字コード判定

オープンソースの文字コード判別フレームワーク「UniversalDetector」の機能を用いて与えられたテキストファイルの文字コードを判定するAppleScriptです。

たまたまGitHubでUniversalDetectorを見つけたので、ダウンロードしてビルドしてAppleScriptから呼び出して試してみました。AppleScriptで自動判定したもの(左側)との比較を行った結果がこれです(↓)。

btable.png

日本語のテキストに限定して試してみると、なかなかつらいです。AppleScriptだけで判定したほうが良好な結果が出ています。

AppleScript名:UniversalDetectorで文字コード判定
– Created 2015-10-03 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “UniversalDetector”
–https://github.com/JanX2/UniversalDetector

set aPath to (POSIX path of (choose file))
set aStr to current application’s NSString’s stringWithString:aPath
set aDetector to current application’s UniversalDetector’s new()
aDetector’s analyzeContentsOfFile:aStr
set aStr to current application’s NSString’s localizedNameOfStringEncoding:(aDetector’s encoding())

–>  (NSString) “日本語(EUC)”
–>  (NSString) “日本語(ISO 2022-JP)”
–>  (NSString) “日本語(Shift JIS)”
–>  (NSString) “Unicode(UTF-8)”
–>  (NSString) “キリル文字(Windows)” –NG。本当はUTF-16 no BOM
–>  (NSString) “中国語(GB 18030)”–NG。本当はUTF-16BE
–>  (NSString) “Unicode(UTF-16)”

set bStr to aDetector’s MIMECharset()

–>  (NSString) “EUC-JP”
–>  (NSString) “ISO-2022-JP”
–>  (NSString) “Shift_JIS”
–>  (NSString) “UTF-8″
–>  (NSString) “windows-1251″–NG
–>  (NSString) “gb18030″–NG
–>  (NSString) “UTF-16″

set aNum to (aDetector’s confidence()) * 100
–>  100.0–”EUC-JP”
–>  100.0–”ISO-2022-JP”
–>  100.0–”Shift_JIS”
–>  100.0–”UTF-8″
–>  5.271286144853–UTF-16 no BOM
–>  100.0–NGだが100%といっている
–>  100.0– “UTF-16″

★Click Here to Open This Script 

2015/07/23 ASOCでレコードのリストをユニーク化

レコードのリスト(例:{{namae:”Piyomaru”,age:16}, {namae:”Piyoko”, age:13}})で、重複データ項目があった場合にそなえ、重複項目を削除する「ユニーク化」を行うAppleScriptObjCのScriptです。

BridgePlusを用いたバージョンと、ASObjCExtras.frameworkを用いたバージョンを掲載します。現在ではBridgePlusの使用が強く推奨されています。

AppleScript名:ASOCでレコードのリストをユニーク化(BridgePlus)
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
use script “BridgePlus”

load framework

set msRecList to {{msName:“格 陸戦型ジム 獲得済 COST: 120″, sortieTimes:12}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}}

set newMsList to uniquefyList(msRecList)
–>  {{sortieTimes:6, msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″}, {sortieTimes:12, msName:”格 陸戦型ジム 獲得済 COST: 120″}}

–レコードのリストをユニーク化
on uniquefyList(aList)
  set msArray to Cocoaify aList
  
set aRes to current application’s NSSet’s setWithArray:(msArray’s allObjects())
  
set bRes to aRes’s allObjects()
  
set cRes to ASify from bRes as list
  
return cRes
end uniquefyList

★Click Here to Open This Script 

AppleScript名:ASOCでレコードのリストをユニーク化(ASObjCExtras.framework)
use AppleScript version “2.4″
use framework “Foundation”
use framework “ASObjCExtras”
use scripting additions

set msRecList to {{msName:“格 陸戦型ジム 獲得済 COST: 120″, sortieTimes:12}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}, {msName:“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, sortieTimes:6}}

set newMsList to uniquefyList(msRecList)
–>  {{sortieTimes:6, msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″}, {sortieTimes:12, msName:”格 陸戦型ジム 獲得済 COST: 120″}}

–レコードのリストをユニーク化
on uniquefyList(aList)
  set msArray to current application’s SMSFord’s Cocoaify:aList
  
set aRes to current application’s NSSet’s setWithArray:(msArray’s allObjects())
  
set bRes to aRes’s allObjects()
  
set cRes to bRes’s ASify() as list
  
return cRes
end uniquefyList

★Click Here to Open This Script 

2015/07/10 ASOCでDict書き込み_2

アーケードゲーム「戦場の絆」では、PC/携帯電話などで会員ページにログインすると、各MSの出撃回数を調べられるようになっています。この出撃回数を取得するAppleScriptで、出撃回数ランキングの中に出撃回数が加算されたMSについて、「▲」表記を行う処理を作成してみました。

ms1.png

ms2.png

■1位 近 装甲強化型ジム COST: 200 = 66回
▲2位 近 ザクII(F2) COST: 160 = 50回
■3位 遠 ジム・キャノン COST: 160 = 43回
■4位 近 ジム・コマンド COST: 200 = 32回
■5位 近 ジム(WD隊) COST: 160 = 28回
■6位 近 陸戦型ガンダム COST: 220 = 24回
■7位 近 ジム改 COST: 240 = 22回
■7位 遠 ガンタンク COST: 200 = 22回
■9位 格 ジム(指揮官機) COST: 160 = 20回
■10位 近 ジム COST: 120 = 19回
■11位 遠 量産型ガンタンク COST: 160 = 14回
■12位 格 陸戦型ジム COST: 120 = 12回
■13位 格 ガンダム COST: 280 = 11回
■14位 近 ジム・トレーナー COST: 120 = 9回
■14位 射 ジム・スナイパーII(WD隊) COST: 220 = 9回
■16位 射 陸戦型ガンダム(ジム頭) COST: 200 = 7回
■17位 格 ガンダムEz8 COST: 240 = 6回
■17位 近 ジム・寒冷地仕様 COST: 200 = 6回
■17位 狙 ジム・スナイパーカスタム COST: 200 = 6回
■20位 格 ジム・ストライカー COST: 180 = 4回
■21位 格 ガンキャノン重装型 COST: 160 = 3回
■22位 近 アクア・ジム COST: 160 = 2回
■22位 射 ガンキャノン COST: 200 = 2回
■24位 近 ジム・コマンドライトアーマー COST: 160 = 1回

■25位 格 ボールK型 COST: 120 = 0回
■25位 格 B.D.2号機 COST: 260 = 0回
■25位 格 プロトタイプガンダム COST: 280 = 0回
■25位 近 パワード・ジム COST: 240 = 0回
■25位 射 デザート・ジム COST: 160 = 0回
■25位 遠 量産型ガンキャノン COST: 200 = 0回

このScriptの中で、AppleScriptのrecordをplistとして保存するルーチンを作成したので紹介します。そのまま実行すると、

~/Library/Application Support/戦場の絆/

ディレクトリ内にefsf.plistというplistファイルを作成します。

plist1.png

フォルダが存在しない場合には作成します。

plist2.png

いったん、かなりの数のサブルーチンをASObjC Extras.framework用に書いたので、なかなかBridgePlusライブラリ用に書き換えるということはできないところですが、このあたりの切り替えを柔軟に行うためにも自作のScriptの機能をライブラリ化しておくとよいのかもしれません。

ただ、AppleScript系の開発で毎回ターゲットOSがOS X 10.10.xになっているわけでもなくて、少し前のバージョンだったり(10.8とか)することもあるので、なかなかライブラリ化に踏み切れないところもあります。

AppleScript名:ASOCでDict書き込み_2
use AppleScript version “2.4″
use framework “Foundation”
use framework “ASObjCExtras”
use scripting additions

set a1List to {“msName”, “sortieTimes”}
set b1List to {{“近 装甲強化型ジム 獲得済 COST: 200″, 66}, {“遠 ジム・キャノン 獲得済 COST: 160″, 43}, {“近 ザクII(F2) 獲得済 COST: 160″, 42}, {“近 ジム・コマンド 獲得済 COST: 200″, 32}, {“近 ジム(WD隊) 獲得済 COST: 160″, 28}, {“近 陸戦型ガンダム 獲得済 COST: 220″, 24}, {“近 ジム改 獲得済 COST: 240″, 22}, {“遠 ガンタンク 獲得済 COST: 200″, 22}, {“格 ジム(指揮官機) 獲得済 COST: 160″, 20}, {“近 ジム 獲得済 COST: 120″, 19}, {“遠 量産型ガンタンク 獲得済 COST: 160″, 14}, {“格 陸戦型ジム 獲得済 COST: 120″, 12}, {“格 ガンダム 獲得済 COST: 280″, 11}, {“近 ジム・トレーナー 獲得済 COST: 120″, 9}, {“射 ジム・スナイパーII(WD隊) 獲得済 COST: 220″, 9}, {“射 陸戦型ガンダム(ジム頭) 獲得済 COST: 200″, 7}, {“格 ガンダムEz8 獲得済 COST: 240″, 6}, {“近 ジム・寒冷地仕様 獲得済 COST: 200″, 6}, {“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, 6}, {“格 ジム・ストライカー 獲得済 COST: 180″, 4}, {“格 ガンキャノン重装型 獲得済 COST: 160″, 3}, {“近 アクア・ジム 獲得済 COST: 160″, 2}, {“射 ガンキャノン 獲得済 COST: 200″, 2}, {“近 ジム・コマンドライトアーマー 獲得済 COST: 160″, 1}, {“格 ボールK型 獲得済 COST: 120″, 0}, {“格 B.D.2号機 獲得済 COST: 260″, 0}, {“格 プロトタイプガンダム 獲得済 COST: 280″, 0}, {“近 パワード・ジム 獲得済 COST: 240″, 0}, {“射 デザート・ジム 獲得済 COST: 160″, 0}, {“遠 量産型ガンキャノン 獲得済 COST: 200″, 0}}

set aArray to current application’s SMSFord’s subarraysIn:b1List asDictionariesUsingLabels:a1List |error|:(missing value)
set b1List to aArray’s ASify() as list

–>  {​​​​​{​​​​​​​sortieTimes:66, ​​​​​​​msName:”近 装甲強化型ジム 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:43, ​​​​​​​msName:”遠 ジム・キャノン 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:42, ​​​​​​​msName:”近 ザクII(F2) 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:32, ​​​​​​​msName:”近 ジム・コマンド 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:28, ​​​​​​​msName:”近 ジム(WD隊) 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:24, ​​​​​​​msName:”近 陸戦型ガンダム 獲得済 COST: 220″​​​​​}, ​​​​​{​​​​​​​sortieTimes:22, ​​​​​​​msName:”近 ジム改 獲得済 COST: 240″​​​​​}, ​​​​​{​​​​​​​sortieTimes:22, ​​​​​​​msName:”遠 ガンタンク 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:20, ​​​​​​​msName:”格 ジム(指揮官機) 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:19, ​​​​​​​msName:”近 ジム 獲得済 COST: 120″​​​​​}, ​​​​​{​​​​​​​sortieTimes:14, ​​​​​​​msName:”遠 量産型ガンタンク 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:12, ​​​​​​​msName:”格 陸戦型ジム 獲得済 COST: 120″​​​​​}, ​​​​​{​​​​​​​sortieTimes:11, ​​​​​​​msName:”格 ガンダム 獲得済 COST: 280″​​​​​}, ​​​​​{​​​​​​​sortieTimes:9, ​​​​​​​msName:”近 ジム・トレーナー 獲得済 COST: 120″​​​​​}, ​​​​​{​​​​​​​sortieTimes:9, ​​​​​​​msName:”射 ジム・スナイパーII(WD隊) 獲得済 COST: 220″​​​​​}, ​​​​​{​​​​​​​sortieTimes:7, ​​​​​​​msName:”射 陸戦型ガンダム(ジム頭) 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:6, ​​​​​​​msName:”格 ガンダムEz8 獲得済 COST: 240″​​​​​}, ​​​​​{​​​​​​​sortieTimes:6, ​​​​​​​msName:”近 ジム・寒冷地仕様 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:6, ​​​​​​​msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:4, ​​​​​​​msName:”格 ジム・ストライカー 獲得済 COST: 180″​​​​​}, ​​​​​{​​​​​​​sortieTimes:3, ​​​​​​​msName:”格 ガンキャノン重装型 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:2, ​​​​​​​msName:”近 アクア・ジム 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:2, ​​​​​​​msName:”射 ガンキャノン 獲得済 COST: 200″​​​​​}, ​​​​​{​​​​​​​sortieTimes:1, ​​​​​​​msName:”近 ジム・コマンドライトアーマー 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”格 ボールK型 獲得済 COST: 120″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”格 B.D.2号機 獲得済 COST: 260″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”格 プロトタイプガンダム 獲得済 COST: 280″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”近 パワード・ジム 獲得済 COST: 240″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”射 デザート・ジム 獲得済 COST: 160″​​​​​}, ​​​​​{​​​​​​​sortieTimes:0, ​​​​​​​msName:”遠 量産型ガンキャノン 獲得済 COST: 200″​​​​​}​​​}

set cRec to {msList:b1List, sortieDate:date string of (current date)}

–>  {​​​​​msList:{​​​​​​​{​​​​​​​​​sortieTimes:66, ​​​​​​​​​msName:”近 装甲強化型ジム 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:43, ​​​​​​​​​msName:”遠 ジム・キャノン 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:42, ​​​​​​​​​msName:”近 ザクII(F2) 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:32, ​​​​​​​​​msName:”近 ジム・コマンド 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:28, ​​​​​​​​​msName:”近 ジム(WD隊) 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:24, ​​​​​​​​​msName:”近 陸戦型ガンダム 獲得済 COST: 220″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:22, ​​​​​​​​​msName:”近 ジム改 獲得済 COST: 240″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:22, ​​​​​​​​​msName:”遠 ガンタンク 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:20, ​​​​​​​​​msName:”格 ジム(指揮官機) 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:19, ​​​​​​​​​msName:”近 ジム 獲得済 COST: 120″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:14, ​​​​​​​​​msName:”遠 量産型ガンタンク 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:12, ​​​​​​​​​msName:”格 陸戦型ジム 獲得済 COST: 120″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:11, ​​​​​​​​​msName:”格 ガンダム 獲得済 COST: 280″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:9, ​​​​​​​​​msName:”近 ジム・トレーナー 獲得済 COST: 120″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:9, ​​​​​​​​​msName:”射 ジム・スナイパーII(WD隊) 獲得済 COST: 220″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:7, ​​​​​​​​​msName:”射 陸戦型ガンダム(ジム頭) 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:6, ​​​​​​​​​msName:”格 ガンダムEz8 獲得済 COST: 240″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:6, ​​​​​​​​​msName:”近 ジム・寒冷地仕様 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:6, ​​​​​​​​​msName:”狙 ジム・スナイパーカスタム 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:4, ​​​​​​​​​msName:”格 ジム・ストライカー 獲得済 COST: 180″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:3, ​​​​​​​​​msName:”格 ガンキャノン重装型 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:2, ​​​​​​​​​msName:”近 アクア・ジム 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:2, ​​​​​​​​​msName:”射 ガンキャノン 獲得済 COST: 200″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:1, ​​​​​​​​​msName:”近 ジム・コマンドライトアーマー 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”格 ボールK型 獲得済 COST: 120″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”格 B.D.2号機 獲得済 COST: 260″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”格 プロトタイプガンダム 獲得済 COST: 280″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”近 パワード・ジム 獲得済 COST: 240″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”射 デザート・ジム 獲得済 COST: 160″​​​​​​​}, ​​​​​​​{​​​​​​​​​sortieTimes:0, ​​​​​​​​​msName:”遠 量産型ガンキャノン 獲得済 COST: 200″​​​​​​​}​​​​​}, ​​​​​sortieDate:”2015年7月10日金曜日”​​​}

set aName to “efsf.plist”
saveRecordToFolAsPlist(cRec, “戦場の絆”, aName) of me

on saveRecordToFolAsPlist(theRecord, folName, aName)
  
  
set myAppSupDir to (path to application support from user domain) as string
  
set myAppSupDir to myAppSupDir & folName & “:”
  
set aPath to (POSIX path of myAppSupDir)
  
try
    do shell script “mkdir -p” & space & (quoted form of aPath)
  end try
  
  
set theDict to current application’s NSDictionary’s dictionaryWithDictionary:theRecord
  
  
set thePath to aPath & aName –Full Path
  
set cPath to current application’s NSString’s stringWithString:thePath
  
–set cPath to cPath’s stringByExpandingTildeInPath()—(OSからフルパスを取得しているので)チルダなどの展開処理は省略
  
  
set aRes to theDict’s writeToFile:cPath atomically:true
  
  
return aRes as boolean
  
end saveRecordToFolAsPlist

★Click Here to Open This Script 

2015/05/29 BridgePlus v1.1.0 Readme日本語翻訳版

(Written By Shane Stanley、Translated By Takaaki Naganoya〜翻訳・掲載はShaneの許諾済み)

BridgePlusはAppleScriptで記述した「Script Library」で、バージョン10.9以降のOS Xで動作します。

典型的なScripterにとって、BridgePlusは「ASObjC Runner.app」の機能をもとにしたハンドラ群を含んだライブラリです。

AppleScriptObjCユーザーにとって、AppleScriptとCocoaオブジェクトの相互変換機能を向上させたコマンド群で、(AppleScript用語辞書によるラッピングを介さず)拡張機能に直接アクセスが可能なものです。

bridge.png

BridgePlusは、いずれかのScript Librariesフォルダ(~/Library/Script Libraries/ など)にインストールしておく必要があります。また、Scriptアプリケーションのバンドル内に直接埋め込むことも可能です(後述)。

基本的な利用方法

もし、あなたがAppleScriptObjCを使うつもりがない場合、BridgePlusは1つの適切なコマンドをAppleScript用語辞書の中に持っています。それが、「open lib description」コマンドです。本コマンドを実行すると、このReadme書類(英文)を自動でオープンします。

AppleScript名:sample1
use BridgePlus : script “BridgePlus”
open lib description

★Click Here to Open This Script 

BridgePlusライブラリ内のハンドラ(サブルーチン)を呼び出すためには、ライブラリ経由で呼び出すことになります。

たとえば、ソーティング(データ並べ替え)のハンドラ(サブルーチン)、

on sortListOfNumbers:listOfNumbers

を呼び出すためには、

AppleScript名:sample2
use AppleScript version “2.4″
use scripting additions
use BridgePlus : script “BridgePlus”
set sortedList to BridgePlus’s sortListOfNumbers:{9, 2, 7, 3, 6, 4}
–> {2, 3, 4, 6, 7, 9}

★Click Here to Open This Script 

のように書くことになります。もし、OS X 10.6.x上でのAppleScriptObjCハンドラ風に、

AppleScript名:sample3
use AppleScript version “2.4″
use scripting additions
use BridgePlus : script “BridgePlus”
set sortedList to BridgePlus’s sortListOfNumbers_({9, 2, 7, 3, 6, 4})

★Click Here to Open This Script 

と書いたとしても、コンパイル(構文確認)すると、

AppleScript名:sample4
use AppleScript version “2.4″
use scripting additions
use BridgePlus : script “BridgePlus”
set sortedList to BridgePlus’s sortListOfNumbers:{9, 2, 7, 3, 6, 4}

★Click Here to Open This Script 

のように書き換えられます。

(注記:オリジナルではここで各種ハンドラの実例紹介。サンプル部分をすべて日本語訳していると時間がかかりすぎるので、Shaneと協議の結果、まずは日本語訳も実例以外の部分を掲載ということで話がまとまった)

基本的な利用方法

BridgePlusは2つのメインコマンドを持っており、これらはAppleScriptObjC記述時に、CocoaとAppleScriptのオブジェクトの変換をシンプルにし、機能向上させるものです。

 Cocoaify:AppleScript側の値をCocoa側の等しい型の値(例:integer→NSInteger)に変換します
 ASify from:Cocoa側の値をAppleScript側の等しい型の値(例:NSInteger→integer)に変換します

BridgePlus Script LibraryのAppleScript用語辞書を見るには、

 スクリプトエディタ:BridgePlusを~/Library/Script Libraries.フォルダにコピーしたのちに、「ファイル」>「用語説明を開く…」を実行
 Script Debugger:Optionキーを押しながらScript Debuggerアイコンにドラッグ

と操作してください。

多くのケースにおいて、AppleScriptObjCによる処理は以下の3ステップから構成されます。

 AppleScript側の値をCocoa側の等しい型に変換
 Cocoaオブジェクトのinstance methodを呼び出す
 7覯漫Cocoaの値)をAppleScript側の値に変換して返す

たとえば、以下のようなAppleScriptObjCのコードがあったとして、

AppleScript名:sample5
use framework “Foundation”

set someList to {1, 3, 2} –I added :-)
set anArray to current application’s NSArray’s arrayWithArray:someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to anArray as list

★Click Here to Open This Script 

これはBridgePlusを使ってこのように書き換えられます。

AppleScript名:sample6
use framework “Foundation”
use script “BridgePlus”

set someList to {1, 3, 2} I added :-)
set anArray to Cocoaify someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to ASify from anArray

★Click Here to Open This Script 

ほんのちょっとシンプルになりましたが、劇的なほどではありませんね。しかしながら、「Cocoaify」「ASify from」コマンドを使うことによる利点は、AppleScriptとCocoaの間の型変換をより完全に行えることにあります。

・Cocoaifyコマンド:AppleScript側の値がdateオブジェクト、もしくはlist型やRecord型でdateオブジェクトを含む場合に、dateはNSDateに変換されます。alias型やfileはNSURLに変換されます

・ASify fromコマンド:Cocoa側の値がNSDateの場合、およびNSDateを含むNSArrayやNSDictionaryの場合、AppleScript側のdateに変換されます。同様に、NSURLはfile («class furl»)に変換されます。

Cocoa側の値がFloating Pointの数値を含む場合、それらはAppleScript側のrealに変換されますし、listやrecord内に含まれるrealとして変換されます。実際に、OS X 10.10.3上でCocoaのFloating Pointの数値1.2をAppleScript側のrealに変換すると1.200000047684になるなど、AppleScriptの標準機能を使うと精度が失われてしまいます。でも、BridgePlusの「ASify from」コマンドを使えば、こんな問題は起きません。Cocoaの1.2を変換しても、AppleScript側でも1.2が得られます。

なので、たとえば上記のサンプルScriptにAppleScriptのdate型のデータをlist型データに入れても、きちんとソートされます。

AppleScript名:sample7
use framework “Foundation”
use scripting additions
use script “BridgePlus”

set someList to {current date, (current date) - (2 * days), (current date) - (1 * days)} Today, The Day before Yesterday, Yesterday
set anArray to Cocoaify someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to ASify from anArray
–> {date “2015年5月28日木曜日 0:22:39″, date “2015年5月29日金曜日 0:22:39″, date “2015年5月30日土曜日 0:22:39″}

★Click Here to Open This Script 

BridgePlusなしでAppleScriptの標準機能を使った場合には、サブルーチンを用いてひとつひとつのdateの値をNSDateに変換してから並べ替える必要があります。さらに、並べ替えたあとに元の型に変換し直す必要も出てきます。そのさいのAppleScriptObjCのコードはより長く複雑なものになってしまいます。

高度なAppleScriptObjCでの利用方法

「BridgePlus.scptd」のバンドルは、多くのScripterにとって有用なフレームワーク(BridgePlus.framework)を含んでいます。本ライブラリBridgePlusはこの内部フレームワークが持つすべての機能をサポートする用語は持っていませんが、あなたのScriptに「use script “BridgePlus”」の1行を加えるだけで、フレームワークのmethodに直接アクセスできるようになります。

フレームワーク内のmethodのほとんどは、「SMSForder」クラスから呼び出せるmethodとして実装されており、これらは「ASObjC Runner.app」(現在では廃止)をもとに機能拡張されたものです。「SMSForder」クラスのヘッダーファイルを確認するには、「open framework header」コマンドを実行します。

AppleScript名:sample8
use script “BridgePlus”
open framework header

★Click Here to Open This Script 

BridgePlusのフレームワークは、実際のところ「ASObjCExtras.framework」のアップデート版であり、ASObjCExtras.frameworkがすでにインストールされている環境でのコンフリクトやクラッシュを避けるために名称変更されたものです。

SMSForder内のmethodを直接呼び出す前に、最低でも1つのBridgePlus.scptdライブラリ内のコマンドを実行する必要があります。それが「load framework」コマンドです(もしくは何かBridgePlusの持つコマンド・・・たとえば、Cocoaify “” を実行することでもOKです)。

かんたんなサンプル:

AppleScript名:sample9
use framework “Foundation”
use scripting additions
use script “BridgePlus”

load framework
set newList to ASify from (current application’s SMSForder’s colsToRowsIn:{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}} |error|:(missing value))
>  {{1, 4, 7, 10}, {2, 5, 8, 11}, {3, 6, 9, 12}}

★Click Here to Open This Script 

やってはいけないことがあります。たとえあなたがBridgePlusライブラリをインストールしてあって使っていても、Script中に「use framework “BridgePlus”」とは書いてはいけません。その書き方ではBridgePlusバンドル内部のフレームワークは見つかりません。「use script “BridgePlus” 」の行とBridgePlusの持つコマンドを1つ実行するとフレームワークが(自動で)読み込まれるようになっています。

SMSForderはCocoa的に0からはじまるインデックスを用います、一方でBridgePlusライブラリの「AppleScriptObjC」で直接内部機能を呼び出さないハンドラを呼び出した場合にはAppleScriptの世界で標準的な1からはじまるインデックスで値を返します。

実行環境へのインストール(Deployment)

「~/Library/Script Libraries」フォルダに「BridgePlus.scptd」ファイルを入れることで、あなたのすべてのAppleScript中でBridgePlusの機能を利用できるようになります。

BridgePlusライブラリをあなたの書いたScriptと一緒に配布する際には、BridgePlus.scptdファイルをあなたのScriptのBundle内の「/Contents/Resources/Script Libraries」フォルダに入れておけば大丈夫です(アプレットの場合でも、.scptdファイルの場合でも)。

もし、あなたがScript Bundle(AppleScriptアプレット/.scptd)をCodesignすることを検討している場合、まず最初にライブラリ中に入っているBridgePlus.frameworkをcodesignする必要があります。

BridgePlusをXcodeプロジェクト内でお使いの場合、「BridgePlus.framework」をBridgePlusライブラリのバンドル内から取り出して、他のframeworkと同様にXcodeプロジェクトに登録し、「BridgePlus.scptd」バンドル内から削除する必要があります。このようにすれば、BridgePlus.frameworkのcodesignはXcodeがめんどうを見てくれます。

BridgePlusのダウンロードはこちら!
http://www.macosxautomation.com/applescript/apps/BridgePlus.html

著名なScripterでありBlogerであるTakaaki Naganoyaによる(表現原文ママ)ASObjCExtras.frameworkの総合マニュアル(英文)はこちらです。
同マニュアルは、もしあなたがBridgePlusの上級者向けの(AppleScriptObjCの)機能を利用したい場合には有用なものです。

http://piyocast.com/as/asinyaye/free-asobjcextras-scripting-guide/

本ライブラリの利用にあたって、ライブラリ全体、内部フレームワークのみの場合の両方で自由に再配布できます(再配布時の料金は発生しません)。
利用料金は発生しませんが、動作保証もいたしません。「At your own risk」でご利用ください。

2015/05/22 BridgePlusがv1.0からv1.1にバージョンアップ

Shane StanleyによるOSのScripting Bridgeのバグを回避しさまざまな高度な型変換機能や計算機能をAppleScriptにもたらす「ASObjCExtras.framework」の後継ソフトウェア、「BridgePlus」の登場から間もないですが、早くもバージョンアップ!

バージョン1.0から1.1になりました。

基本的な機能については、さほど変更はなく・・・AppleScriptObjCをさわっていないAppleScriptユーザーに便利で簡単に感じられるように、AppleScript用語辞書が補われているという方向で機能強化されています。FrameworkではAppleScript用語辞書がついていないので、そこを補うために「見た目のファイル形状」(Framework単体からFramework入りScript Librariesへ)を変更したということです。

BridgePlusのAppleScript用語辞書を用いて記述するかぎりは、結果などすべてAppleScriptのオブジェクトに変換して返してくれるので、いきなりNSArrayなどが返ってきて面食らうようなことはないはずです。Arrayのindexも0ベースではなくAppleScriptの1ベースのindexが返ってくるため、違和感をおぼえないようになっています。

ただ、これはつまり・・・値を返すときにかならず毎回CocoaオブジェクトからAppleScriptオブジェクトへの再変換を行っているわけで、高速なScriptを組むときにはこのオーバーヘッドを回避できるよう、内部機能を直接呼び出す方向でScriptを組んだほうがメリットがあります。

上級スクリプター向けの機能を維持しつつ、一般スクリプター向けにわかりやすさと単純さを高めた・・・という感じでしょうか。

AppleScript名:BridgePlus v1.0の記述サンプル
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use script “BridgePlus” version “1.0″

set someList to {1, 3, 2}
set anArray to Cocoaify someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to ASify from anArray
–> {1, 2, 3}

★Click Here to Open This Script 

AppleScript名:BridgePlus v1.1の記述サンプル
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus” version “1.1″

set aList to BridgePlus’s sortListOfNumbers:{1, 3, 2}
–> {1, 2, 3}

★Click Here to Open This Script 

AppleScript名:BridgePlus v1.1の記述サンプル(上級者向け記述)
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus” version “1.1″

load framework –一応、念のため実行。初回呼び出し時のオーバーヘッド軽減のため
set someList to {1, 3, 2}
set anArray to Cocoaify someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to ASify from anArray
–> {1, 2, 3}

★Click Here to Open This Script 

2015/05/21 ASObjC Extras.frameworkからBridgePlus Script Libraryへ

Scripting Bridgeのバグを回避し、より手軽にCocoaオブジェクトとAppleScriptオブジェクトの相互変換が行えるようにしたのが、Shane StanleyのASObjCExtras.frameworkです。

日々、便利に使っていますし・・・いくつかのアプリケーションやシステムはすでにASObjCExtras.frameworkを用いて記述し、稼働しています。

ただ、ここまで気合いの入ったASObjCExtras.frameworkですが、まだ大々的に利用されるにはいたっていません。

理由は・・・

(1)ASObjC自体が、Scripterにそれほど理解・利用されていない(Appleがドキュメントを一切出していないので、事実上Shaneの電子ブック「AppleScriptObjC Explored」と「Everyday AppleScriptObjC」を読まずに使うのは無理!)

(2)ASObjCExtras.frameworkにかぎらず、Cocoaの機能を使おうとしてもAppleScript用語辞書が存在していないので、「用語辞書を見ながらScriptを書く」というやり方ができない

といったあたりだとShaneは分析しており、加えて自分は、

(3)CocoaのオンラインドキュメントがObjective-CとかSwift用であって、AppleScriptObjCの書き方が書かれていない

さらに、

(4)Apple純正のScript Editorの機能不足

といった点も問題だと思っています。CocoaのAPIを調べて記述するだけの機能はScript Editorには備わっていません。

そこでShaneはASObjCExstras.frameworkの後継Framework「BridgePlus.framework」を含んだAppleScript Libraries「BridgePlus Library」を発表。配布を開始しました

AppleScript Librariesなので、AppleScript用語辞書が見られるし、useコマンドでバージョン番号も指定できる(割と頻繁にバージョンアップするので)など、さまざまな問題が解決できる見込みです。

bridgep.png

えー、一応事前に「こういうのやりたいんだけど(ドキュメントが作り直しになっちゃうかもしれないけど)、どうかな?」という打診はもらっていまして(^ー^;; そりゃー、Shaneがやりたいと思うんなら「一番いいと思う方向でやっちゃってくださいよ。ドキュメントのことは気にしないで」とお答えしておきました。

AppleScript名:ASObjCExtrasの記述サンプル
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set aList to {1, 3, 2}
set aArray to current application’s SMSFord’s Cocoaify:aList
set aRes to aArray’s sortedArrayUsingSelector:“compare:”
set bList to aRes’s ASify() as list
–> {1, 2, 3}

★Click Here to Open This Script 

AppleScript名:BridgePlusの記述サンプル
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use script “BridgePlus” version “1.0″

set someList to {1, 3, 2}
set anArray to Cocoaify someList
set anArray to anArray’s sortedArrayUsingSelector:“compare:”
set aList to ASify from anArray
–> {1, 2, 3}

★Click Here to Open This Script 

2015/03/11 CSVファイルをListにParseする(ASOC)

Shane Stanley wrote me a simple but strong AppleScriptObjC (ASOC) Script. It is a perfect one!

I checked Objective-C version csv parser. But they are not so short as this.

And I understood that this method was made just for this purpose:-).

csv2.png
▲Test Data

AppleScript名:CSVのParse 4(ASOC)
– Created 2015-03-11 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set someString to read (choose file)

set theData to current application’s SMSFord’s arrayFromCSV:someString commaIs:“,”
set theData to (current application’s SMSFord’s subarraysIn:theData paddedWith:“” |error|:(missing value)) as list
–>  {​​​​​{​​​​​​​”cust1″, ​​​​​​​”prod,1″, ​​​​​​​”season 1″, ​​​​​​​”"​​​​​}, ​​​​​{​​​​​​​”cust1″, ​​​​​​​”prod1″, ​​​​​​​”season 2″, ​​​​​​​”"​​​​​}, ​​​​​{​​​​​​​”cust2″, ​​​​​​​”prod1″, ​​​​​​​”event1″, ​​​​​​​”season 1″​​​​​}, ​​​​​{​​​​​​​”cust2″, ​​​​​​​”prod2″, ​​​​​​​”event1″, ​​​​​​​”season 2″​​​​​}, ​​​​​{​​​​​​​”cust2″, ​​​​​​​”prod3″, ​​​​​​​”event1″, ​​​​​​​”season 1″​​​​​}​​​}

★Click Here to Open This Script 

2015/03/03 2点間の距離を求める

This AppleScript calculates the distance (km) between 2 places. Place data is a pair of Latitude and Longitude.

This Script requires ASObjCExtras Framework.

dist.png

2点間の距離を求めるAppleScriptです(単位:km)。位置情報は緯度と経度のペアで与えます。実行には、ASObjCExtras Frameworkのインストールが必要です。

AppleScript名:Calc Distance between 2 places v2
– Created 2015-03-03 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set aPlace to {latitude:35.737072, longitude:139.637826} –Seibu-Ikebukuro Line Nakamurabashi Station (My Nearest Station)
set bPlace to {latitude:35.753108, longitude:139.595123} –Amusium OSC (Game Center, Nearest Senjo-No-Kizuna POD)

set aDistance to calcDistanceBetweenPlaces(aPlace, bPlace)
–>  4.251157707731 (km)

–2点間の距離を計測する(km単位)
–参考:http://log.nissuk.info/2012/04/2.html
on calcDistanceBetweenPlaces(aPlace, bPlace)
  
  
set r to 6378.137 –Equatorial radius/赤道半径(km)
  
  
–Place A
  
set lat1 to (latitude of aPlace) * pi / 180
  
set lng1 to (longitude of aPlace) * pi / 180
  
  
–Place B
  
set lat2 to (latitude of bPlace) * pi / 180
  
set lng2 to (longitude of bPlace) * pi / 180
  
  
–Calculation
  
set calc1 to (current application’s SMSFord’s sinValueOf:lat1) as real
  
set calc2 to (current application’s SMSFord’s sinValueOf:lat2) as real
  
  
set calc3 to (current application’s SMSFord’s cosValueOf:lat1) as real
  
set calc4 to (current application’s SMSFord’s cosValueOf:lat2) as real
  
  
set calc5 to (current application’s SMSFord’s cosValueOf:(lng2 - lng1)) as real
  
  
set aDist to (current application’s SMSFord’s acosValueOf:(calc1 * calc2 + calc3 * calc4 * calc5)) as real
  
set aDist to aDist * r
  
  
return aDist
  
end calcDistanceBetweenPlaces

★Click Here to Open This Script 

2015/02/24 ASObjCExtras Scripting Guide v1.0 Erratta

I uploaded ASObjC Extras.framework Scripting Guide v1.0 Erratta.

The description and sample of

subarraysFrom: usingKeys: outKeys: error:

was wrong in Scripting Guide v1.0. So, I rewrote it.

New v1.1 document is in progress. It contains “Embedding” chapter. My work stops due to the business of some works…So I post the errata at first.

erratta.png

2015/02/09 Photoshop Action Setをインストールする(ASOC)

PhotoshopのAction SetをインストールするAppleScriptのASOC版です。

AppleScript名:指定ファイルを指定Bundle IDのアプリでオープンする(ASOC)
– Created 2015-02-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit”

set a to (choose file)
openFileWithApp(a, “com.adobe.photoshop”)

on openFileWithApp(aFileAlias as alias, aBundleID as string)
  set aURL to current application’s SMSFord’s URLFrom:aFileAlias
  
set aURLarray to current application’s NSArray’s arrayWithObject:aURL
  
set sharedWS to current application’s NSWorkspace’s sharedWorkspace()
  
  
sharedWS’s openURLs:aURLarray withAppBundleIdentifier:aBundleID options:(current application’s NSWorkspaceLaunchDefault) additionalEventParamDescriptor:(missing value) launchIdentifiers:(missing value)
end openFileWithApp

★Click Here to Open This Script 

2015/02/08 起動中のプロセスの存在確認

Bundle IDで指定したプロセスが起動しているかどうかを確認するAppleScriptです。

AppleScript的には、System Eventsを経由してプロセスの起動中確認を行います。

AppleScript名:指定Bundle IDのプロセス存在確認(AS)
use AppleScript version “2.4″
use scripting additions

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshop”)
–> true

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshopoo!”)
–> false

on chkAppProcesByBundleID(aBundleID as string)
  tell application “System Events”
    set a to every process whose bundle identifier is aBundleID
    
if length of a 1 then
      return true
    else
      return false
    end if
  end tell
end chkAppProcesByBundleID

★Click Here to Open This Script 

しかし、この方法ではもしもMac App Storeに申請するアプリケーションで、System Eventsへのアクセスが封じられたらおしまいです。一応、shell script経由でpsコマンドを実行するという手段もありますが・・・

そこで、ASOCでCocoaの機能を用いてプロセスの存在確認を行ってみました。もうちょっと短く書けそうな気配もするのですが、とりあえず。

AppleScript名:指定Bundle IDのプロセス存在確認(ASOC)
– Created 2015-02-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit”

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshop”)
–> true

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshopoo!”)
–> false

on chkAppProcesByBundleID(aBundleID as string)
  set appArray to current application’s NSWorkspace’s sharedWorkspace’s runningApplications()
  
set appList to appArray’s ASify() as list
  
  
repeat with i in appList
    set anID to (i’s bundleIdentifier()) as string
    
if anID = aBundleID then
      return true
    end if
  end repeat
  
  
return false
end chkAppProcesByBundleID

★Click Here to Open This Script 

2015/01/24 ASOC on Xcodeでアプリケーションに埋め込めるようASObjCExtrasを改修中

ASObjCExtras.frameworkを使って、Xcode上でASOCによるプログラム開発は行えますが、それを配布できるようアプリケーション中に埋め込めるようになっているのか?

ASObjCExtrasは再配布に制限を設けられておらず、アプリケーションやアプレットに埋め込んで配布できるよう、それ自体にコードサインされていません。むしろ、そのように使えるように仕様が定められ、作られているはずのものです。

実際に行ってみたところ、ASObjCExtrasのバージョン1.2では「そうなっていなかった」という衝撃の事実が発覚(1日悩んでしまいました)。コンピュータの業界的にというべきか、プログラミング全般というべきか、マニュアルやドキュメントのとおりに実際のモノが作られているかは、自分の手で地道に確認する必要があります。これ、本当。

即座にShane Stanleyにフィードバックし、対策ビルドの開発が行われ・・・今朝方確認した未リリースの最新ビルドではきちんと埋め込めるようになっています(埋め込みおよび埋め込んだアプリケーションバンドル内のフレームワークを正しく参照するようになった)。

現在、Xcode上でASOCでアプリケーション開発を行っている方は、外部に配布なりMac App Storeでの配布・販売を考えている場合には、バージョン1.2からアップデートされたASObjCExtras.frameworkがリリースされるまで「待つ」ことをおすすめします最新バージョンのv1.2.3を埋め込むことを強く推奨します。

# とか書いている間に、新バージョンv1.2.3が公開されました。変更点はここに書いているように、Xcodeプロジェクトへの埋め込み対応改善です

以下、実際にXcode上のASOCのプロジェクトにASObjCExtras.frameworkを組み込んで、アプリケーションに同frameworkを埋め込む手順です。

fra1.png

fra2.png

fra3.png

fra4.png

fra5.png

fra6.png

あとは、ビルドしてアプリケーションバンドル内に/Contents/Frameworks/ASObjcExtrasが存在していることを確認し、ASObjCExtrasなどのサードパーティ製フレームワークが一切含まれていない別ユーザーアカウントにて動作するかどうか確認をすれば大丈夫でしょう。

2015/01/22 指定したアプリケーションの各lproj内の各stringsファイルのパス一覧を取得する

指定したアプリケーションの各言語のlprojフォルダ内にある、各stringsファイルへのパスを取得するAppleScriptです。

各アプリのローカライズ情報を取り出すプログラムはいろいろと試してはいるものの、作り方とかローカライズ方法が全然違うアプリケーションが紛れていることがあり、イレギュラーを除去すべきなのかも(Apple純正でもSafariあたりは全然違うし)。

AppleScript名:指定したアプリケーションの各lproj内の各stringsファイルのパス一覧を取得する
– Created 2015-01-22 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set apPath1 to (path to applications folder) –dialog’s default directory
set anAlias to choose file of type "com.apple.application-bundle" default location apPath1 with prompt "ローカライズ情報を取得するアプリケーションを選択"
set aRes to getStringsPathWithinEachLanguageInApp(anAlias)
–> {{langStr:"English", stringsPath:{"/Applications/mi.app/Contents/Resources/English.lproj/Localizable.strings"}}, {langStr:"Japanese", stringsPath:{"/Applications/mi.app/Contents/Resources/Japanese.lproj/Localizable.strings"}}}

–指定したアプリケーションの各lproj内の各stringsファイルのパス一覧を取得する
on getStringsPathWithinEachLanguageInApp(anAlias)
  –アプリケーションのローカリゼーションを取得する(言語の重複を許容)
  
set locList to getSpecifiedAppFilesLocalizationListWithDuplication(anAlias) of me
  
  
set lprojList to {}
  
  
repeat with ii in locList
    
    
set jj to contents of ii
    
    
set appPath to POSIX path of anAlias
    
set appBundle to (current application’s NSBundle’s bundleWithPath:appPath)
    
set resPath to ((appBundle’s pathForResource:jj ofType:"lproj") as string) & "/"
    
    
if resPath is not equal to missing value then
      
      
set aLangBundle to (current application’s NSBundle’s bundleWithPath:resPath)
      
if aLangBundle is not equal to missing value then
        
        
set stringsList to (aLangBundle’s pathsForResourcesOfType:"strings" inDirectory:"") as list
        
        
if stringsList is not equal to {} then
          set the end of lprojList to {langStr:jj, stringsPath:stringsList}
        end if
        
      end if
    end if
    
  end repeat
  
  
return lprojList
  
end getStringsPathWithinEachLanguageInApp

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を許容
on getSpecifiedAppFilesLocalizationListWithDuplication(anAppAlias as alias)
  
  
set aURL to (current application’s SMSFord’s URLFrom:anAppAlias)
  
set aBundle to current application’s NSBundle’s bundleWithURL:aURL
  
  
set theNSLocale to current application’s NSLocale’s localeWithLocaleIdentifier:"en" –Output Locale Name in English (en)
  
  
–Get Localization Info
  
set locList to aBundle’s localizations()
  
–> {"de", "English", "fr", "French", "German", "ja", "Japanese"}
  
  
return locList as list
  
end getSpecifiedAppFilesLocalizationListWithDuplication

★Click Here to Open This Script