r_shibataの備忘録

大学院で研究したり,コーヒー入れたり,マジック勉強したり,ITの勉強したり...

PencilKitとSwiftUIでApplePencilの筆跡の情報(CGPoint)を取得管理する.

はじめに

最近iPadを買ってアプリ開発したいなと思って簡単なアプリを作ってみました.

検索してみたら,ApplePencilから情報を取得するプログラムや,ApplePencilKitを使ったプログラムは見つかったのですが, ApplePencilKitからswiftの一般的な座標情報であるCGPointを取得するプログラムがなかったのでいろいろ探してみました.

iOS: Apple Pencilから情報を取得する|TechRacho by BPS株式会社

たった3行のコードで PencilKit を導入して Apple Pencil 対応 - Qiita

PencilKitでApplePencilの筆跡情報を取得する

コードはGithubに挙げてあります.

github.com

PencilKitの筆跡情報は PKCanvasViewで管理されており, PKCanvasViewで作成したインスタンスのPKCanvasView.drawing.strokesにPKStrokeとしてストロークの配列が格納されています.

また,PKStrokeはPKStroke.pathプロパティを持っており,PKStrokePointとして1ストローク分の筆跡情報が格納されています.

そして,PKStrokePoint.locationが筆跡の1点を示すCGPointです.

これをコード(PKStroke2CGPoint.swift)ではfor in でパースしています.


func PKStroke2CGPoint (strokes: [PKStroke])->[[CGPoint]]{
    var cgpoints: [CGPoint] = []
    var cgpointList: [[CGPoint]] = []
    cgpoints = []

    for stroke in strokes {
        for strokePoint in stroke.path {
            cgpoints.append(strokePoint.location)
        }
        cgpointList.append(cgpoints)
        cgpoints = []
    }
    return cgpointList
}

動かしながら試してみてください.

CGPointで線を引く

これは,xy座標さえあれば線が引けるので,他の端末で描いたイラストなどを移すときに便利だと思います.

プログラムを作るにあたって,以下のサイトが参考になりました.

Convert UIBezierPath to PKStrokePath swift - Stack Overflow

詳しいことはあまり理解していませんが,ApplePencilの筆跡座標はBスプラインで保持されているらしく, CGPointをそのままpathとして渡してもうまく行かないらしいです.

func CGPint2PKStroke(canvasView: PKCanvasView, pointArrays: [[CGPoint]])->[PKStroke] {
    let ink = PKInk(.pen, color: .blue)
    var strokes: [PKStroke] = []
    for points in pointArrays where points.count > 1 {
        let strokePoints = points.enumerated().map { index, point in
            PKStrokePoint(location: point, timeOffset: 0.1 * TimeInterval(index), size: CGSize(width: 3, height: 3), opacity: 2, force: 1, azimuth: 0, altitude: 0)
        }

        var startStrokePoint = strokePoints.first!

        for strokePoint in strokePoints {
            let path = PKStrokePath(controlPoints: [startStrokePoint, strokePoint], creationDate: Date())
            strokes.append(PKStroke(ink: ink, path: path))
            startStrokePoint = strokePoint
        }
    }
    return strokes
}

なので変換するためのプログラムを挟んであります.

まとめ

簡単なプログラムですが,初めてswiftを書いたので少し手こずりました.個人的にSwiftUIは好きな書き方だなと思いました.

本当は筆跡情報をDeepLearingなどで加工するために,Pythonを使用することも検討していました. APIではなくSwiftにPythonスクリプトを埋め込む,KivyやBeewareが良いかなと思っていますが,なかなかうまく行かないです.

PythonとApplePencilの情報をうまく連携させる方法があればぜひコメントで書いてもらえれば幸いです.

また,コメントやいいねがいただけるとモチベになります.