カラー電子ペーパーでデジタルフォトフレームを作る

## Inky Impression - 7.3"

![IMG_1444 (大).JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3802709/10216c84-3b7c-4bf3-8fca-f21690231d3d.jpeg)

![無題の動画 ‐ Clipchampで作成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3802709/a682303a-31b3-438c-9954-2ab1286b89bc.gif)
(1.5倍速)

https://shop.pimoroni.com/products/inky-impression-7-3?variant=55186435244411

高精細で綺麗な表示が可能な7.3インチの電子ペーパー「Inky Impression」を購入したので、デジタルフォトフレームを作ってみました。写真より少し彩度が落ちますが、荒いピクセルも相まって味のある画になります。

裏面にはRaspberry Piシリーズをそのまま差せるピンヘッダがついています。

![IMG_1445.JPEG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3802709/0f01aa58-f3cc-48e2-b1bb-99f5dacd77dc.jpeg)

## 表示するもの

https://find47.jp/

日本の情景写真が掲載されているサイト。CC BY 4.0でライセンスされているので、クレジットを記載すれば自由に利用できます。

GitHubにリポジトリがあり、ここから写真とそれに関するデータを取得できます。
https://github.com/code4fukui/find47

## 完成したもの

Inky 2.1.0
<details><summary>main.py</summary>

``` main.py
import requests
import random
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
import json
from inky.auto import auto

def resize(img, target_size, background_color=(0, 0, 0)):
    target_w, target_h = target_size
    original_w, original_h = img.size

    # アスペクト比を維持したままリサイズ
    ratio = min(target_w / original_w, target_h / original_h)
    new_w = int(original_w * ratio)
    new_h = int(original_h * ratio)
    resized_img = img.resize((new_w, new_h))

    return resized_img


def main():
    images = None

    # 画像データのjsonを開く
    try:
        with open("/home/pi/impression73/inky/images.json", "r", encoding="utf-8") as f:
            images = json.load(f)
    except Exception as e:
        print("画像データの読み込みに失敗:", e)
        return

    # ランダムに1枚選択
    selected_image = random.choice(images.get("images"))
    title = selected_image.get("title", "No title")
    prefecture = selected_image.get("prefecture", {}).get("name_ja", "No prefecture")
    photographer = selected_image.get("phtotographer", {}).get("name", "Unknown")
    image_url = selected_image.get("url")

    print(title)
    print(prefecture)
    print(photographer)
    print(image_url)

    # ダウンロード
    try:
        image_response = requests.get(image_url)
        image_response.raise_for_status()
        image = Image.open(BytesIO(image_response.content))
    except Exception as e:
        print("画像の取得に失敗:", e)

    #Inkyで表示
    inky = auto(ask_user=True, verbose=True)
    resized_image = resize(image, inky.resolution)

    # 背景キャンバスを作成（黒）
    image = Image.new("RGB", inky.resolution, (0, 0, 0))
    image.paste(resized_image)

    dr = ImageDraw.Draw(image)

    fontFile = "/usr/share/fonts/opentype/note/NotoSansCJKjp-Regular.otf"
    fontSize = 16
    font = ImageFont.truetype(fontFile, fontSize)
    padding = (inky.resolution[1] - resized_image.size[1]) // 4
    dr.text((padding, inky.resolution[1] - padding // 2), title + "（" + prefecture + "）", anchor="ld", font=font)

    fontFile = "/usr/share/fonts/opentype/note/NotoSansCJKjp-Regular.otf"
    fontSize = 10
    font = ImageFont.truetype(fontFile, fontSize)
    dr.text((inky.resolution[0] - padding, inky.resolution[1]), "Photo by " + photographer + " / CC BY 4.0 / edited\n" + image_url, anchor="rd", spacing=2, font=font)

    inky.set_image(image)
    inky.show()

if __name__ == "__main__":
    main()

```
</details>

## 写真を表示する

### 写真の情報の取得
最初に電子ペーパーのセットアップをしておきます。
https://learn.pimoroni.com/article/getting-started-with-inky-impression

先ほどのリポジトリにimages.jsonというファイルがあります。中身はこんな感じ↓

``` images.json
{
    "images": [
        {
            "id": 1132,
            "code": "gy7lt",
            "url": "https://find47.jp/ja/i/gy7lt/image_file",
            "thumb_url": "https://find47.jp/ja/i/gy7lt/image_file?type=thumb",
            "page_url": "https://find47.jp/ja/i/gy7lt",
            "title": "生後１ヶ月の子鹿",
            "prefecture": {
                "code": 1,
                "dn": "hokkaido",
                "name_ja": "北海道",
                "name_en": "Hokkaido"
            },
            "phtotographer": {
                "name": "kkawamura"
            },
            "award": ""
        },
```

全ての写真のデータが入っているので、これをダウンロードしておきます。

``` terminal
cd ~/Downloads/
wget -O images.json https://raw.githubusercontent.com/code4fukui/find47/main/images.json
```

随時更新されているようなので、スクリプトを組んで定期的にダウンロードするようにしてもいいかもしれません。

### images.jsonを開く
``` python
images = None
try:
    with open("/home/pi/Scripts/impression73/inky/images.json", "r", encoding="utf-8") as f:
        images = json.load(f)
except Exception as e:
    print("画像データの読み込みに失敗:", e)
    return
```

パスは環境に合わせて修正してください。

### ランダムに1枚を選択する
``` python
selected_image = random.choice(images.get("images"))

title = selected_image.get("title", "No title")
prefecture = selected_image.get("prefecture", {}).get("name_ja", "No prefecture")
photographer = selected_image.get("phtotographer", {}).get("name", "Unknown")
image_url = selected_image.get("url")
```

random.choiceで画像を選び、データを取り出します。

### 写真をダウンロード
``` python
try:
    image_response = requests.get(image_url)
    image_response.raise_for_status()
    image = Image.open(BytesIO(image_response.content))
except Exception as e:
    print("画像の取得に失敗:", e)
```

urlから写真をダウンロードします。

### 写真をリサイズ
``` python 
inky = auto(ask_user=True, verbose=True)
resized_image = resize_and_pad(image, inky.resolution)
```

inkyの初期化で解像度が取得できるので、それに合わせてリサイズします。

写真のアスペクト比は16:9ですが、電子ペーパーは5:3なのでピッタリとはいきません。
そこで余ったスペースにタイトルと県名、ライセンスを表記するようにしました。

### 表示
``` python
inky.set_image(image)
inky.show()
```

これで表示されます。

## 定期的に写真を変える
cronで定期的にスクリプトを実行することで、表示する写真を変更します。

https://qiita.com/gdate/items/bdf6c620404679063211

こちらを参考に、6時間で1回実行するようにしました。
inkyのライブラリを利用するため、pimoroniの仮想環境のパスを指定します。
```
0 */6 * * * /home/pi/.virtualenvs/pimoroni/bin/python /home/pi/impression73/inky/main.py
```

## まとめ
カレンダーとかタスクの表示、ガジェット的な運用ができそうで楽しいです。用途にもよりますがRaspberry Pi Zero系の方がかさばらなくてよさそうです。色々遊びつつ、3Dプリンターで筐体を作って飾ろうと思います。