ラズパイでE-paperディスプレイを使う

AmazonでE-Inkのディスプレイを購入してみました。
200割引クーポンが付いていたので、2000円以下で購入できmした。

https://www.amazon.co.jp/gp/product/B08WZ21N7Q/


|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/eb6dd3c7-8db6-f25a-890d-c02117044ef7.png)|
|:-:|

# 動作テスト

メーカーのGeeekPiはGitHubにサンプルプログラムをアップしているので、それを利用して動作テストしてみます。

https://github.com/geeekpi/epaper

## SPIを有効にする

最初にSPIを有効にします。

```shell-session:
pi@raspberrypi:~ $ sudo raspi-config
```

raspi-configを実行すると以下の画面になります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/35d440d1-eddc-cad9-94b8-c30d41c89ba7.png)|
|:-:|

「3 Interface Options」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/06cb2623-a8ae-0871-357e-fad45789444a.png)|
|:-:|

「P4 SPI」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/9dd2512e-8841-5c9b-195a-099dab758696.png)|
|:-:|

SPIインターフェースを有効にするか聞かれるので「はい」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/bb6c3c95-2e22-7a7d-1709-8b3814b529b6.png)|
|:-:|

SPIインターフェースを有効にしましたと表示されるの「了解」を選択します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/efb117f7-1e44-faef-ff13-99fb1b536e2f.png)|
|:-:|

これで、SPIインターフェースは有効になりました。

## 必要なモジュールをインストール

Pillow,spidev,RPi.GPIOが必要なのですが、すでにインストールされていました。

```shell-session:
pi@raspberrypi:~/epaper $ sudo pip install Pillow spidev RPi.GPIO
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Requirement already satisfied: Pillow in /usr/lib/python2.7/dist-packages (5.4.1)
Requirement already satisfied: spidev in /usr/lib/python2.7/dist-packages (3.5)
Requirement already satisfied: RPi.GPIO in /usr/lib/python2.7/dist-packages (0.7.0)
```

### デモプログラムの取得

メーカー(Geeekpi)から提供されているデモプログラムをGitHubからダウンロードしてきます。

```shell-session:
pi@raspberrypi:~ $ git clone https://github.com/geeekpi/epaper.git
Cloning into 'epaper'...
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 29 (delta 9), reused 22 (delta 5), pack-reused 0
Unpacking objects: 100% (29/29), done.
```

### デモプログラムの実行

デモプログラムを実行すると、画面が赤→黒→白→画像と切り替わります。

```shell-session:
pi@raspberrypi:~ $ cd epaper/
pi@raspberrypi:~ $ python3 eink2.13_demo.py
Flash Red
Flash Black
Flash White
Flash Image
```

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/ce308542-3763-4af6-15c7-401d7bc889c1.png)|
|:-:|

今の接続の仕方だと画面がひっくり返って表示されるので、どうにかせねば。w

### 画像を回転

画像を180度回転させるためにデモプログラムを少し修正。

```python:修正前
f = f.convert('RGB')             # conversion to RGB
```

```python:修正後
f = f.convert('RGB').rotate(180) # conversion to RGB
```

180度回転されてちゃんと表示されました。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/0974d267-7aa0-50ee-8240-2c7b066b918b.png)|
|:-:|

## Pillowを使って描画する

### フォントのインストール

文字を描画する前の準備として、IPAフォントをインストールします。

```shell-session:
pi@raspberrypi:~/epaper $ sudo apt install fonts-ipafont
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の追加パッケージがインストールされます:
  fonts-ipafont-gothic fonts-ipafont-mincho
以下のパッケージが新たにインストールされます:
  fonts-ipafont fonts-ipafont-gothic fonts-ipafont-mincho
アップグレード: 0 個、新規インストール: 3 個、削除: 0 個、保留: 13 個。
8,254 kB のアーカイブを取得する必要があります。
この操作後に追加で 28.7 MB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian buster/main armhf fonts-ipafont-gothic all 00303-18 [3,516 kB]
取得:2 http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian buster/main armhf fonts-ipafont-mincho all 00303-18 [4,726 kB]
取得:3 http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian buster/main armhf fonts-ipafont all 00303-18 [12.1 kB]
8,254 kB を 4秒 で取得しました (2,286 kB/s)
以前に未選択のパッケージ fonts-ipafont-gothic を選択しています。
(データベースを読み込んでいます ... 現在 104216 個のファイルとディレクトリがインストールされています。)
.../fonts-ipafont-gothic_00303-18_all.deb を展開する準備をしています ...
fonts-ipafont-gothic (00303-18) を展開しています...
以前に未選択のパッケージ fonts-ipafont-mincho を選択しています。
.../fonts-ipafont-mincho_00303-18_all.deb を展開する準備をしています ...
fonts-ipafont-mincho (00303-18) を展開しています...
以前に未選択のパッケージ fonts-ipafont を選択しています。
.../fonts-ipafont_00303-18_all.deb を展開する準備をしています ...
fonts-ipafont (00303-18) を展開しています...
fonts-ipafont-mincho (00303-18) を設定しています ...
update-alternatives: /usr/share/fonts/truetype/fonts-japanese-mincho.ttf (fonts-japanese-mincho.ttf) を提供するために自動モードで /usr/share/fonts/opentype/ipafont-mincho/ipam.ttf を使います
fonts-ipafont-gothic (00303-18) を設定しています ...
update-alternatives: /usr/share/fonts/truetype/fonts-japanese-gothic.ttf (fonts-japanese-gothic.ttf) を提供するために自動モードで /usr/share/fonts/opentype/ipafont-gothic/ipag.ttf を使います
fonts-ipafont (00303-18) を設定しています ...
fontconfig (2.13.1-2) のトリガを処理しています ...
pi@raspberrypi:~/epaper $ ls /usr/share/fonts/truetype/
dejavu  droid  fonts-japanese-gothic.ttf  fonts-japanese-mincho.ttf  freefont  liberation2  noto  piboto  quicksand
```

### 矩形と文字を表示させる。

Geeekpiのサンプルを利用して、ディスプレイに矩形と文字列を表示させます。

サンプルのred/black/whiteを表示していたところをバッサリ削除。
イメージを読み込んでいたところを
`Image.new( "RGB", X_PIXEL, X_PIXEL )`
として、イメージオブジェクトを新規作成します。
この時、ディスプレイを横長に使っているので、サンプルとは違い、幅を250、高さを128とします。

次に矩形を赤枠、白の塗りつぶしとして描画します。
``draw.rectangle([(0, 0), (X_PIXEL,122)], outline=color, fill=fillcolor, width=linewidth) ``

文字の描画は、フォントを指定
``font = ImageFont.truetype("fonts-japanese-gothic.ttf", 24)``
その後に文字列やサイズを指定して文字列の描画を行います。
``text = "test"
draw.text((10, 50), text, font=font, fill=color)``

あとは、Geeekpiのサンプルと同じようにバッファにデータを詰めて、Epaper.pyのメソッドを使ってディスプレイへの表示を行います。

```python:sample.py
import time
from Epaper import *
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

# Demo Configuration
#X_PIXEL = 128
#Y_PIXEL = 250
X_PIXEL = 250
Y_PIXEL = 128 

img = Image.new('RGB', (X_PIXEL, Y_PIXEL))
draw = ImageDraw.Draw(img)

color = (255, 0, 0) 
fillcolor = (255, 255, 255) 
linewidth = 4 
draw.rectangle([(0, 0), (X_PIXEL,122)], outline=color, fill=fillcolor, width=linewidth) 

font = ImageFont.truetype("fonts-japanese-gothic.ttf", 24)
text = "test"
draw.text((10, 50), text, font=font, fill=color)

img = img.rotate(270, expand=True)
data = img.load()

rBuf = [0] * 4000
bBuf = [0] * 4000

for y in range(250):
    for x in range(128):
       # Red CH
       if data[x,y] == (255,0,0):
           index = int(16 * y + (15 - (x - 7) / 8))
           tmp = rBuf[index]
           rBuf[index] = tmp | (1 << (x % 8))
       # Black CH
       elif data[x,y] == (255,255,255):
           index = int(16 * y + (15 - (x - 7) / 8))
           tmp = bBuf[index]
           bBuf[index] = tmp | (1 << (x % 8))

e = Epaper(Y_PIXEL,X_PIXEL)
e.flash_red(buf=rBuf)
e.flash_black(buf=bBuf)
e.update()
```

赤枠の中にtestの文字列が描画されました。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/23d86476-1d4b-fe0c-2d3e-9fc5b4572125.png)|
|:-:|

### 画面の書き換え動画

デモの画像を表示した状態から上のサンプルの「test」表示までの動画です。
思っていたよりも書き換えに時間がかかります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/0bsx5YEQX8U" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>