ひとりぶろぐ

価値ある情報をユーザー視点で発信するブログ

iOS用Python開発環境Pythonista 3で外部ディスク上のファイルを扱う

   

working with external files in the pythonista 3 00011

直射日光下でもよく見える珍しいメモリ液晶を搭載したSHARPの電子ノートがお気に入りです。

working with external files in the pythonista 3 00001

SHARPの電子ノートには感圧式のタッチパネルが付いていて、付属のペンなどで手書きで絵図を書き込むことができます。

最後にいつ充電したのか忘れてしまうぐらいバッテリーが長持ちし、今の時代に希少な、文房具のような使い勝手が気に入っています。

電子ノートは考えを整理するためのメモ書きや、3Dプリンタで作るもののスケッチを描くのに使っています。

電子ノートに書き留めたものを再利用することはほとんどないのですが、iPhoneとの連携を強化すると新たな使い道が見えてくるのかなと思い、環境改善を考えてみました。

USB接続モードを使って連携を組む

電子ノートはPCなどとの連携のために、USBマスストレージとして動作するUSB接続モードを備えます。

working with external files in the pythonista 3 00002

Apple Lightning – USBカメラアダプタなどを使ってiPhoneとUSBケーブルで接続。

working with external files in the pythonista 3 00003

電子ノートをUSB接続モードにすると、iPhoneのファイル.appでも電子ノートの中身を見ることができます。

working with external files in the pythonista 3 00005

電子ノートからPCなどへの画像の受け渡しは一つずつに限られいささか面倒なのですが、逆を言うとUSB接続モードで受け渡しする画像は自ずと一つに決定されます。

このことを利用し、セミオートでiPhoneに持っていく方法を考えてみました。

外部ファイルを読み書きできるPythonista 3

使った道具はPythonista 3というアプリです。

Pythonista 3はiOS上で使えるPythonで、自由度の高いセルフ開発環境です。

最近のアップデートでこのPythonista 3から念願の外部ファイルが参照可能になったのです。

このことに気付き、喜んでいるのは筆者ぐらいのものかと思いますが、個人的には大きな可能性を感じています。

Pythonista 3は1,200円の有料アプリなので、iOS標準搭載のショートカット.appを使えば済む場合はブログを書いて広く世に問う都合上、最近はできるだけ使わないようにしているのですが(※)、ショートカット.appの場合、外部ファイルを扱う場合は最初にファイル.app上で手動で選択せざるを得ず、便利感が薄いのでPythonista 3を使いました。

Working with external files in the pythonista 3 00012

※導入の障壁が低いショートカットネタだと、記事の人気が高い傾向があるため

iPhoneにマウントした外部ディスク上のファイルをプログラマブルに扱う事例というのは希少かつ、こういうことができると分かれば応用可能なことが他にもたくさんあると思われるので紹介します。

使用するフォルダにアクセス権を与える

外部のフォルダやファイルにアクセスできるPythonista 3ですが、最初に一度だけ手動で対象のフォルダ、ファイルに読み書きのアクセス権を付与する手順が必要です。

  1. 電子ノートとiPhoneをUSBケーブルで接続し、電子ノートをUSB接続モードにします
  2. iPhone側でPythonista 3を起動しEXTERNAL FILESカテゴリ内の「Open…」をタップ
  3. 引き続き「Folder…」をタップ
  4. マウントされた電子ノートのボリューム(筆者の環境では「NO NAME」という名前)を選択して「完了」

フォルダを指定した場合は、そのフォルダ以下のフォルダ、ファイルにもアクセス権が与えられます。

これはiPhoneにマウントした外部ディスクに限らず、iCloud Drive上のフォルダも同様です。

つまり、iCloud Driveに対応した他のアプリで保存したファイルにアクセスすることも可能ということです。

例えばiA Writerで作ったMarkdownにPythonista 3側からアクセスして、 何らかの処理を施すことも可能です。

working with external files in the pythonista 3 00007

アクセス権を与えたフォルダにアクセスする方法

前述の手順でアクセス権を与えましたが、そのフォルダにPythoninsta 3側からアクセスする場合はどうすればいいのでしょうか。

以下のような方法で当該フォルダ、ファイルのフルパスを調べることができます。

  1. ファイル.appで外部ディスク上のファイルを選択し共有メニューを表示
    • working with external files in the pythonista 3 00008
  2. 共有メニューの「Run Pythonista Script」をタップ
    • working with external files in the pythonista 3 00009
  3. 「Console」をタップ
  4. プロンプトから以下を実行
    • import appex
    • appex.get_file_path()
    • working with external files in the pythonista 3 00010

すると、選択したファイルまでのフルパスが得られます。

接続した電子ノート上の書き出し画像を選択した場合、恐らくは、以下のようなパスが表示されるかと思います。

"/private/var/mobile/Library/LiveFiles/com.apple.filesystems.userfsd/NO NAME/EXPORT/Page0001.jpg"

ここを対象にPythonista 3で処理を組めばよいというわけです。

電子ノート連携スクリプト

ここまで説明したことを織り込んで作ったスクリプトが次に紹介するものです。

動作の概要は次のようなものです。

  1. 10秒間電子ノートの接続を待ち、その間カウントダウンのアラートを表示
  2. カウントダウン中に電子ノートが接続されて外部ディスクとしてマウントされたら、自動的に書き出しファイルを画像としてクリップボードにコピー
  3. クリップボードへのコピーが終わったら、完了通知を表示
  4. 指定アプリを起動(デフォルトではメモ)して処理終了
#!python3
import os, re, clipboard, console, time, shortcuts
from PIL import Image

# 電子ノートの書き出し画像を画像としてクリップボードにコピー
# moyashi ( @hitoriblog )
# 2020.07.10 Ver.0.0.1

# ----------設定-----------
# 電子ノートがマウントされる場所
mount_point = "/private/var/mobile/Library/LiveFiles/com.apple.filesystems.userfsd/"
# 電子ノートのボリューム名
volume_name = "NO NAME"
# 書き出し画像が保存されるフォルダ
export_dir = "EXPORT"
# 画像をコピーした後で起動するアプリのURL Scheme
app_to_launch = "mobilenotes://"
# ------------------------

# ボリュームのフルパス
target_volume = os.path.join(mount_point, volume_name)
# 書き出し画像が保存されるフォルダのフルパス
target_path = os.path.join(mount_point, volume_name, export_dir)

def copyImage():
	# 電子ノートがマウントされている?
	if os.path.exists(target_path):
		# 書き出し画像のファイルを走査
		files = os.scandir(target_path)
		# 書き出し画像のファイル名の正規表現(Page0001.jpg等)
		reobj = re.compile("Page\d{4}\.jpg")
		# 書き出しフォルダの内容を一つずつ精査
		for file in files:
			# 書き出し画像のファイル名形式と一致したら
			if (reobj.match(file.name)):
				# 書き出し画像からPILのイメージを生成
				im = Image.open(file.path)
				# イメージが生成できたら
				if (im):
					# iOSのクリップボードにコピー
					clipboard.set_image(im, format='png')
					# コピー完了を表示
					console.hud_alert(file.name + " をクリップボードにコピー")
				return 

# 主処理
def main():
	# 10回ループ(インデックス付き)
	for i, cnt in enumerate(range(10)):
		# まだ電子ノートがマウントされていなかったら
		if not os.path.exists(target_volume):
			# 待機のアラートを表示
			console.hud_alert("電子ノートの接続を待機... あと" + str(10 - i) + "秒")
			# 1秒待つ
			time.sleep(1)
		else:
			# 電子ノートがマウントされていたら
			# 画像をクリップボードにコピー
			copyImage()
			# 画像をペーストするアプリを起動
			# (クリップボードにコピーした画像をどう扱うするかは毎回違いそうなので以降は手動がよいと思いました)
			shortcuts.open_url(app_to_launch)
			break

main()

電子ノートをiPhoneに接続後、このスクリプトを起動すると電子ノート側で書き出した画像をクリップボードにコピーしてメモアプリを起動するので、あとは新規ページを作成してペーストするだけで電子ノートからの受け渡しが完了します。

 - iOS, iPad, iPhone, Python