ラベル Touchdown開発 の投稿を表示しています。 すべての投稿を表示
ラベル Touchdown開発 の投稿を表示しています。 すべての投稿を表示

Touchdown 1.3公開!

Touchdown 1.3を公開しました。



ダウンロードはこちらから。

Ver.1.3の変更点は以下の通りです。

新機能

  • macOS Mojave 10.13以降に対応
  • ダークモードに対応

ぜひお試しください。

Touchdown 1.2公開!

Touchdown 1.2を公開しました。



ダウンロードはこちらから。

Ver.1.2の変更点は以下の通りです。

新機能

  • macOS High Sierra 10.13以降に対応
  • コマンドキーを押しながら起動することで設定を保存しない機能を追加
    • 一時的な設定変更が可能です


不具合修正

  • テキストフィールドにフォーカスが合った状態で変換すると、設定が適用されないことがあった問題を修正
  • 多数のファイルをDockアイコンへドラッグ&ドロップした時に一部のファイルが変換できない問題を修正

ぜひお試しください。

ファイルをDockアイコンにドラッグすると「検証中」で遅い問題への対処

Touchdown 1.2を実装中に気がついたのですが、macOS 10.3 High Sierraから、ファイルのダブルクリックやDockアイコンへのドラッグ時にファイルの検証が実行されることがあるようです。

通常使用では問題ないのですが、巨大なファイルや大量のファイルをドラッグした時に問題が発生。

アプリアイコンへのファイルドラッグを受け付けるNSApplicationDelegateのfunc application(NSApplication, openFiles: [String])が呼び出されるのが非常に遅くなっています。

しかも、もともとこのopenFilesはファイル数が多いと複数回呼び出される謎仕様なので、Touchdownの「まとめて受け取って一括変換」という仕様と相性が悪く、ver.1.1までは短いタイマーを貼って全ファイルの受け取りを待つという残念な実装になっていました。

High Sierraからはかなり長い間隔をあけてopenFilesが複数回呼び出されるケースがあるため、適当な対応では対処しきれなくなったため、変換前に確認する場合の仕様を変更することにしました。

従来:最後にまとめてドラッグされたファイルを変換

Ver1.2:変換確認中にドラッグされたファイルをキューに追加していって変換

これに伴い変換するファイルの管理もArrayからSetに変更して、重複しないようにしました。

OSがバージョンアップするとやはり色々ありますね。

Touchdown ver.1.2向け追加予定機能

macOS High Sierraがリリースされて1ヶ月ほど経ちましたが、Touchdown も近日中にVer. 1.2へバージョンアップします。

変更予定箇所は以下の通り。
  • macOS High Sierra 10.13以降に対応
  • コマンドキーを押しながら起動すると、設定の変更が保存されないように
  • 設定で数値を変更しても、適用されない事がある不具合を修正

Swift 4に移行したらファイルのドラッグ時にパスが取り出せない?

TouchdownをSwift 4に変換した際に、フレームワーク側の変更に伴うコードの置換が発生していました。

ファイルのドラッグ&ドロップに関する部分ではドラッグ受付登録が、
register(forDraggedTypes: [NSFilenamesPboardType]);
から
registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL]);
になっています。

NSFilenamesPboardTypeの代わりにfileURLを使うようになったようです。

これに合わせてペーストボードから値を取得する部分が
sender.draggingPasteboard().propertyList(forType: NSPasteboard.PasteboardType.fileURL) as? [String]
のようなコードに置換されたのですが、ここでエラーが発生。

sender.draggingPasteboard().typesにfileURLが含まれているにも関わらず、どうも[String]にうまくキャストできていないようです。

色々調べたところ以下のコードがうまく動きました。
sender.draggingPasteboard().propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? [String]

フレームワーク側の不具合でしょうか?
ひとまずワークアラウンドとしてこの対応で進めることにします。

Swift 4に変換でNSKeyedUnarchiverがエラー

macOS High SierraになりSwiftも4にバージョンアップ。
TouchdownもSwift 3からSwift 4に移行します。

基本的にはXcodeの移行ツールに従うだけで、途中で聞かれる

  • Minimize Inference
  • Match Swift 3 Behavior

もせっかくなのでSwift 4推奨のMinimize Inferenceを選択しました。

ワーニングやエラーを手動で修正して実行したところ、以下のエラーが発生。

[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (ConvertSetting) for key (NS.objects); the class may be defined in source code or a library that is not linked

Swift 3版でConvertSettingというクラスをarchiveして保存していたのですが、Swift 4版では互換性がなくなり復元できなくなってしまいました。

原因を調べてみたところ、Swift 3では自動で付与されていた@objcが、Swift 4では自動で付与されなくなり、今後は明示的に記述する必要があるようです。

つまり、もともとCocoa BindingのためConvertSettingには暗黙で@objcが付いていたのが、Swift 4以降のタイミングで付与されなくなったと予想。

クラス定義の部分に
@objc(ConvertSetting)
を追記することで解決しました。
Cocoa Bindingのため@objcMembersも記載してあります。

というわけで、Swift 4(macOS High Sierra)版Touchdownは既知の不具合などを修正してからリリース予定です。

TouchdownをHigh Sierraで動作確認

macOS High Sierraがリリースされたため、Touchdown ver.1.1の動作を確認しました。

今のところ大きな不具合はなさそうです。

NSTableViewの行をドラッグ&ドロップ

やり方を理解するのに結構手間取ったのがNSArrayControllerのビューになっているNSTableViewの行をドラッグ&ドロップで入れ替える実装方法。

詳細な説明は省きますが、概念さえわかれば中身は意外とシンプルです。
NSTableViewDataSourceとして以下の3つを実装すればOK。

func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool

ドラッグ&ドロップの実態は、コピー&ペーストに近いものがあります。
ここでやるべきことはNSPastboardにユーザーが移動しようとしている行のIndexSet(複数行ドラッグの可能性があるためIndexSetが渡ってきます)をセットするだけ。
(コピーに相当。)

func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation

.moveを返せばドラッグ可能になります。

func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool

NSPasteboardから取り出した(ペーストに相当)IndexSetと、移動先として渡ってきた行番号を手がかりにNSArrayControllerが管理している配列を並び替えるだけです。

わかってしまえばシンプルで泥臭い実装をするだけですね。

Touchdown 1.1公開!

Touchdown 1.1を公開しました。



ダウンロードはこちらから。

Ver.1.1の変更点は以下の通りです。

新機能

  • プリセットの並べ替え
    • プリセットリストの項目をドラッグで並べ替えられるようにしました
  • 「新規プリセット」メニュー項目追加
    • ファイルメニューに「新規プリセット」を追加しました
    • コマンド+Nでプリセットを追加できます


不具合修正

  • 一部文言を修正しました
  • Touch Barが適切に切り替わらないことがある不具合を修正しました


ぜひお試しください。

Touchdown ver.1.1向け追加予定機能

Touchdown ver.1.0としてリリースし便利に使っているものの、実装したかったけどまだできていない機能がいくつかあるため、今後のリリースで拡張して行く予定です。

優先度が高いものとしては

  • プリセットの並び替え
  • リネーム

の2点。

次期ver.1.1に向けてはまず「プリセットの並び替え」を実装したいですが、細かな改善と合わせて気長に対応していく予定です。

MacBook Proのための機能 その2

MacBook Proに長らく搭載されていて革新的でありながらイマイチ活用されていない機能といえばForce Touchトラックパッド

実はTouchdownでも地味に対応しています。

ファイルをウィンドウにドラッグするとフォーカス枠が表示されますが、その際に指先にフィードバックが来るようにしています。
触覚フィードバックだけでなく、感圧を生かしたアプリも作ってみたいですね。

MacBook Proのための機能 その1

Touchdownを作ろうと思った最大のモチベーションは「MacBook Proをもっと活用したい」だったので、最初に注目したのはいうまでもなくTouch Bar。

まずはTouch Barに何か表示してみるところから始めて、プリセットの切り替えという無難な機能に落ち着きました。

しかし、ちょっと物足りないので、Touch Barジェスチャーにも対応し、ダブルタップでプリセットの選択と実行をまとめてできるようにしてみました。

なんでも表示できるのでもっと派手な感じにもしたかったのですが、Appleのガイドラインに従う限り、あまり目立つものは実装できないのが残念です。

Touch Barでダブルタップ検知

TouchdownではTouch Barの設定(NSSegmentedControl)をダブルタップで実行する機能を実装しています。

やり方は意外と簡単。
NSClickGestureRecognizerで検知したいジェスチャーを指定し、任意のControlに設定するだけです。

let gesture = NSClickGestureRecognizer() // NSClickGestureRecognizerのインスタンスを作成
gesture.target = self // 通知を受けるオブジェクトを設定
gesture.numberOfTouchesRequired = 1 // 検知する指の本数
gesture.numberOfClicksRequired = 2 // 検知するタップ回数
gesture.allowedTouchTypes = .direct // 指によるダイレクトタッチを検知
gesture.action = #selector(deferConvertFiles(_:)) // 通知を受けたときに実行するセレクタ
segmentedControl.addGestureRecognizer(gesture) // Controlにジェスチャーを設定

シンプルで強力な仕組みですね。



Touchdown 1.0公開!

Touchdown 1.0を公開しました!



Touch Barに対応した画像変換ユーティリティアプリです。
こちらからダウンロードしてお試しください。

JPEGに変換

画像をJPEGに変換するのはとっても簡単。

なんらかの方法でNSBitmapImageRepを作成。

let imgRep = NSBitmapImageRep(...)

あとは、NSBitmapImageFileType.NSJPEGFileType を指定して Data を取得するだけ。
 properties には圧縮率などを辞書として渡せます。

let data = imgRep.representation(using: NSBitmapImageFileType.NSJPEGFileType, properties: [NSImageCompressionFactor:Float(0.8)])

最後に data を適当な場所に書き出せばOKです。

data.write(to: pathString, options:[])

NSImageをリサイズ

意外と複雑な画像のリサイズ。
やり方は色々ありそうですが、今回使った方法を記録しておきます。

大まかな流れは

  1. CGImageを準備
  2. CGContextを準備
  3. リサイズ後のサイズを指定
  4. contextを使って書き込む
  5. NSImageに戻す


まずはあらかじめ準備したNSImageからNSBitmapImageRepを取り出し、さらにCGImageを取り出す。

guard let image = NSBitmapImageRep(data: sourceImage.tiffRepresentation!)?.cgImage else {
    //  エラー処理
}

次に各種パラメータを準備して、CGContextを作成。

let bitsPerComponent = 8
let bytesPerRow = 4 * newWidth
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

guard let bitmapContext = CGContext(data: nil, width: newWidth, height: newHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
    // エラー処理
}

サイズを指定して書き込む。

let bitmapSize = NSMakeSize(CGFloat(newWidth), CGFloat(newHeight))
let bitmapRect = NSMakeRect(0.0, 0.0, bitmapSize.width, bitmapSize.height)

bitmapContext.draw(image, in: bitmapRect)

最後にNSImageに戻す。

guard let newImageRef = bitmapContext.makeImage() else{
    // エラー処理
}
let newImage = NSImage(cgImage: newImageRef, size: bitmapSize)

NSArrayControllerでNSTableViewをBind!

Touchdownでは複数の設定を保存して切り替えられるようにするため、NSTableViewをUIとして使います。

基本的なとこだけど、何かと分かりにくいCocoa Binding。
iOSでは使えないらしく情報も少なめなので、簡単にまとめておきます。

StoryboardでNSTableViewとNSArrayControllerを配置


NSTableViewNSArrayControllerをドラッグで配置。


ViewControllerにArrayを定義


例えば文字列の配列なら
dynamic var items: [String] = ["a", "b", "c"]

バインドするためにdynamicを付けるのがポイント


NSTableViewは2箇所Bind


まずNSTableViewArrayControllerを2箇所バインド。
ContentとはarrangedObjectsSelection IndexesselectionIndexes



さらにTableViewCellValueTableCellViewobjectValueをバインド。



値を変更できるようにする


TableViewCellのBehaviorEditableにしておきます。



コンパイルして実行


これでArrayの中身を表示して編集することができるようになりました。



設計と実装

きっちり設計して後は実装するだけ、というのはある意味理想形の一つかもしれませんが、勉強しながら進めたいので今回は作りながら考えることにします。

とはいえ、気の向くままにコードを書くわけにもいかないので自分ルールは決めておきたいところ。

・Macアプリ設計/実装の流儀に従う
・Cocoa Bindingは積極的に使う
・重い処理はマルチスレッド化する

まずはこのくらいから始めることにします。

アプリの要件洗い出し

何か作ろうと思ったら、まずは要件を整理してみるのが完成への近道。
とはいえ、個人で開発するだけならそれほど厳密になる必要もなく、まずは「最低限これがあればアプリとして成立する」というところを狙います。

譲れないのは以下の点。

  • ドラッグ&ドロップで複数画像をまとめてJPEGに変換
  • リサイズに対応
  • 新規フォルダにまとめて保存
  • 同名のファイルがある場合はリネーム
  • 設定をプリセットとして保存し切り替えられること
  • TouchBar対応


あとはここから膨らませていく感じで。

ソースコード管理はローカルなgitで

Xcodeでは普通にプロジェクトを作成するとローカルのgitリポジトリを作成してくれます。

一人で開発しているだけなので、一通りの実装ができるまではmasterブランチに直接commitしちゃうことにします。
何かやらかした時にリバートできればとりあえず良いので。

メニューからcommitを選ぶと変更したファイルや追加したファイルが自動的にadd候補になるので、適当にコメント書いてcommitするお手軽さ。

commitボタンがTouch Barに表示されるのが地味ながら便利ですね。
こういう絶妙な使い方を見つけていきたいものです。

落ち着いたらbranch切って拡張していく予定です。

Touchdown 1.3公開!

Touchdown 1.3を公開しました。 ダウンロードは こちら から。 Ver.1.3の変更点は以下の通りです。 新機能 macOS Mojave 10.13以降に対応 ダークモードに対応 ぜひお試しください。