Python による画像生成で Mac のクソダサデスクトップにさよなら

[進化しました。](https://qiita.com/nu_no_kehai/items/6b1d13bb4e3ade743bc2)

### 前置き

Mac使いの方。
マルチデスクトップを駆使していろんな作業を同時並行で進めていると、苦労することがありませんか……？

* どのデスクトップでどの作業をしているのか分からなくなる。
* 付箋アプリで作業内容を貼っておくのも鬱陶しい。
* かっこいいMacの壁紙の情報量が逆に邪魔。
* どんな壁紙を使っていてもそのうち飽きてくる。

ここで欲しくなってくるのは、
「任意のテキストが入れられた壁紙をさくっと作る」
プログラムです。そうですね。

というわけで作りました。

### 要するに、何がやりたいの？

![Screen Shot 2022-02-15 at 4.24.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351420/fef7f9f8-85f8-ad61-3cae-739873a24002.png)
![Screen Shot 2022-02-15 at 4.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351420/3151261c-ec31-93a8-9848-817a84ca9f13.png)
![Screen Shot 2022-02-15 at 4.24.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351420/cc41a9bc-c2ee-d660-9f67-8a4195c6474f.png)

こんな壁紙を手軽に作りたいわけです。
一目で何をやりたいかわかるデスクトップ。

![Screen Shot 2022-02-15 at 4.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351420/c20042ba-8ca1-c595-8ef6-e930cce289fd.png)

マルチデスクトップ間の移動をするときも、どこに行けばいいのか一目で分かります。

そしてシンプルでかっこいい。飽きてもすぐに配色が変えられる。

### 環境整備

まずは必要ライブラリをダウンロード。

```
pip3 install pillow
pip3 install pyautogui
pip3 install opencv-python
```

これらがインストールできたら、下記（一番下の項目『プログラム本文』にあります）の python コード run.py を叩いて実行できます。ただし、フォントが適切に指定されている必要があるので注意。

```
python3 run.py
```

また、下記の color.py が同じフォルダに入っている必要があります。

### 使い方

まず run.py 中、利用フォントを適切に設定します。

```
font_dir = '/Users/(your username)/Library/Fonts/'
font_file = 'sawarabi-gothic/sawarabi-gothic-medium.ttf'
```

この箇所を好きなフォントファイルに指定してください。

そうしたら、次はどんな文字を何色で入れるかです。

```
out_file_name = "desktop_01.png"
string_txt =  "デスクトップ01"
rgb_txt=find_color("茜色").rgb
rgb_bg=find_color("LightSalmon").rgb
```

改行を入れたければ\nで入れてください。
これでほぼ全てです。

### 配色
毎回実行の度に利用可能な色一覧が表示されますが、それでも配色の妙が一目で分からないのが目下の課題。とりあえず、アリな色の組み合わせを記載しておきます。

- ウォームピンク
 - どんな気分にも馴染む

```
rgb_txt=find_color("茜色").rgb
rgb_bg=find_color("LightSalmon").rgb
```

- 空色
 - ツイッターっぽさ

```
rgb_txt=find_color("White").rgb
rgb_bg=find_color("DeepSkyBlue").rgb
```

- オリーブグリーン
 - 落ち着いた雰囲気に

```
rgb_txt=find_color("DarkOliveGreen").rgb
rgb_bg=find_color("OliveDrab").rgb
```

- 濃い紫にベージュ
 - デザイナーチックな色合い

```
rgb_txt=find_color("Beige").rgb
rgb_bg=find_color("DarkMagenta").rgb
```

- 紺染め
 - 和風の佇まい

```
rgb_txt=find_color("灰汁色").rgb
rgb_bg=find_color("紺色").rgb
```

- ビタミンカラー
 - ビビッドでハイセンス

```
rgb_txt=find_color("Tomato").rgb
rgb_bg=find_color("Yellow").rgb
```

### その他

* デスクトップの順番が入れ替わると不便なので入れ替え機能は外しておきましょう。

https://jinnaitakumi.com/multi-desktop-fixed-sort-order/

* 「システム環境設定>デスクトップとスクリーンセーバー」のフォルダの項目に、生成画像が入っているフォルダを追加しておいた方がいいようです。
* カラーコードの一覧は以下のサイトを参考にさせていただきました。

https://itsakura.com/html-color-codes

* このページの記載内容について、改変して公開などはご自由に。

### プログラム本文

```python:run.py
import pyautogui as pag
from PIL import Image, ImageFont, ImageDraw
import cv2
import numpy as np
from color import *

out_file_name = "desktop_06.png"
string_txt =  "デスクトップ06"
rgb_txt=find_color("Tomato").rgb
rgb_bg=find_color("Yellow").rgb

print("Available colors:")
show_color_name() #利用可能な色名一覧を表示

rate_font_size = 0.1
rate_pos_txt = [0.05, 0.05]
font_dir = '/Users/(your username)/Library/Fonts/'
font_file = 'sawarabi-gothic/sawarabi-gothic-medium.ttf'

screen = pag.size()

print(" screen width = ",screen.width)
print("screen height = ",screen.height)

img = np.zeros((screen.height, screen.width, 3), np.uint8)
for i in range(0,3):
    img[:, :, i] = rgb_bg[2-i]

if ( font_dir == "" ):
    font_dir = "/System/Library/Fonts/"
font_path = font_dir + font_file
font_size = int(rate_font_size*screen.width)
font = ImageFont.truetype(font_path, font_size)
img = Image.fromarray(img) # cv2(NumPy)型の画像をPIL型に変換
draw = ImageDraw.Draw(img)

pos_txt = ( int(screen.height*rate_pos_txt[1]),int(screen.width*rate_pos_txt[0]) )
color_txt =(rgb_txt[2],rgb_txt[1],rgb_txt[0],0)
draw.text(pos_txt, string_txt, font=font, fill=color_txt)
img = np.array(img) # PIL型の画像をcv2(NumPy)型に変換

cv2.imwrite(out_file_name, img)
```

```python:color.py
def rgb_to_colorcode(rgb):

    red_str=str(hex(rgb[0]))
    red_str=red_str[2:]
    if len(red_str)==1:
        red_str="0"+red_str
    green_str=str(hex(rgb[1]))
    green_str=green_str[2:]
    if len(green_str)==1:
        green_str="0"+green_str
    blue_str=str(hex(rgb[2]))
    blue_str=blue_str[2:]
    if len(blue_str)==1:
        blue_str="0"+blue_str
    colorcode="#"+red_str+green_str+blue_str
    return colorcode

class Color:
  def __init__(self, name, rgb):
    self.name = name
    self.rgb = rgb
    self.r = rgb[0]
    self.g = rgb[1]
    self.b = rgb[2]
    self.code = rgb_to_colorcode(rgb)

def color_table_full():

    color_table=[]
    color_table.append(Color("IndianRed",(205,92,92)))
    color_table.append(Color("LightCoral",(240,128,128)))
    color_table.append(Color("Salmon",(250,128,114)))
    color_table.append(Color("DarkSalmon",(233,150,122)))
    color_table.append(Color("LightSalmon",(255,160,122)))
    color_table.append(Color("Crimson",(220,20,60)))
    color_table.append(Color("Red",(255,0,0)))
    color_table.append(Color("FireBrick",(178,34,34)))
    color_table.append(Color("DarkRed",(139,0,0)))
    color_table.append(Color("Pink",(255,192,203)))
    color_table.append(Color("LightPink",(255,182,193)))
    color_table.append(Color("HotPink",(255,105,180)))
    color_table.append(Color("DeepPink",(255,20,147)))
    color_table.append(Color("MediumVioletRed",(199,21,133)))
    color_table.append(Color("PaleVioletRed",(219,112,147)))
    color_table.append(Color("Coral",(255,127,80)))
    color_table.append(Color("Tomato",(255,99,71)))
    color_table.append(Color("OrangeRed",(255,69,0)))
    color_table.append(Color("DarkOrange",(255,140,0)))
    color_table.append(Color("Orange",(255,165,0)))
    color_table.append(Color("Gold",(255,215,0)))
    color_table.append(Color("Yellow",(255,255,0)))
    color_table.append(Color("LightYellow",(255,255,224)))
    color_table.append(Color("LemonChiffon",(255,250,205)))
    color_table.append(Color("LightGoldenrodYellow",(250,250,210)))
    color_table.append(Color("PapayaWhip",(255,239,213)))
    color_table.append(Color("Moccasin",(255,228,181)))
    color_table.append(Color("PeachPuff",(255,218,185)))
    color_table.append(Color("PaleGoldenrod",(238,232,170)))
    color_table.append(Color("Khaki" ,(240,230,140)))
    color_table.append(Color("DarkKhaki",(189,183,107)))
    color_table.append(Color("Lavender",(230,230,250)))
    color_table.append(Color("Thistle",(216,191,216)))
    color_table.append(Color("Plum",(221,160,221)))
    color_table.append(Color("Violet" ,(238,130,238)))
    color_table.append(Color("Orchid",(218,112,214)))
    color_table.append(Color("Fuchsia",(255,0,255)))
    color_table.append(Color("Magenta",(255,0,255)))
    color_table.append(Color("MediumOrchid",(186,85,211)))
    color_table.append(Color("MediumPurple",(147,112,219)))
    color_table.append(Color("Amethyst",(153,102,204)))
    color_table.append(Color("BlueViolet",(138,43,226)))
    color_table.append(Color("DarkViolet",(148,0,211)))
    color_table.append(Color("DarkOrchid",(153,50,204)))
    color_table.append(Color("DarkMagenta",(139,0,139)))
    color_table.append(Color("Purple",(128,0,128)))
    color_table.append(Color("Indigo",(75,0,130)))
    color_table.append(Color("SlateBlue",(106,90,205)))
    color_table.append(Color("DarkSlateBlue",(72,61,139)))
    color_table.append(Color("GreenYellow",(173,255,47)))
    color_table.append(Color("Chartreuse",(127,255,0)))
    color_table.append(Color("LawnGreen",(124,252,0)))
    color_table.append(Color("Lime",(0,255,0)))
    color_table.append(Color("LimeGreen",(50,205,50)))
    color_table.append(Color("PaleGreen",(152,251,152)))
    color_table.append(Color("LightGreen",(144,238,144)))
    color_table.append(Color("MediumSpringGreen",(0,250,154)))
    color_table.append(Color("SpringGreen",(0,255,127)))
    color_table.append(Color("MediumSeaGreen",(60,179,113)))
    color_table.append(Color("SeaGreen",(46,139,87)))
    color_table.append(Color("ForestGreen",(34,139,34)))
    color_table.append(Color("Green",(0,128,0)))
    color_table.append(Color("DarkGreen",(0,100,0)))
    color_table.append(Color("YellowGreen",(154,205,50)))
    color_table.append(Color("OliveDrab",(107,142,35)))
    color_table.append(Color("Olive",(128,128,0)))
    color_table.append(Color("DarkOliveGreen",(85,107,47)))
    color_table.append(Color("MediumAquamarine",(102,205,170)))
    color_table.append(Color("DarkSeaGreen",(143,188,143)))
    color_table.append(Color("LightSeaGreen",(32,178,170)))
    color_table.append(Color("DarkCyan",(0,139,139)))
    color_table.append(Color("Teal",(0,128,128)))
    color_table.append(Color("Aqua",(0,255,255)))
    color_table.append(Color("Cyan" ,(0,255,255)))
    color_table.append(Color("LightCyan",(224,255,255)))
    color_table.append(Color("PaleTurquoise",(175,238,238)))
    color_table.append(Color("Aquamarine",(127,255,212)))
    color_table.append(Color("Turquoise",(64,224,208)))
    color_table.append(Color("MediumTurquoise",(72,209,204)))
    color_table.append(Color("DarkTurquoise",(0,206,209)))
    color_table.append(Color("CadetBlue",(95,158,160)))
    color_table.append(Color("SteelBlue",(70,130,180)))
    color_table.append(Color("LightSteelBlue",(176,196,222)))
    color_table.append(Color("PowderBlue",(176,224,230)))
    color_table.append(Color("LightBlue",(173,216,230)))
    color_table.append(Color("SkyBlue",(135,206,235)))
    color_table.append(Color("LightSkyBlue",(135,206,250)))
    color_table.append(Color("DeepSkyBlue",(0,191,255)))
    color_table.append(Color("DodgerBlue",(30,144,255)))
    color_table.append(Color("CornflowerBlue",(100,149,237)))
    color_table.append(Color("MediumSlateBlue",(123,104,238)))
    color_table.append(Color("RoyalBlue",(65,105,225)))
    color_table.append(Color("Blue",(0,0,255)))
    color_table.append(Color("MediumBlue",(0,0,205)))
    color_table.append(Color("DarkBlue",(0,0,139)))
    color_table.append(Color("Navy",(0,0,128)))
    color_table.append(Color("MidnightBlue",(25,25,112)))
    color_table.append(Color("Cornsilk",(255,248,220)))
    color_table.append(Color("BlanchedAlmond",(255,235,205)))
    color_table.append(Color("BlanchedAlmond",(255,228,196)))
    color_table.append(Color("NavajoWhite",(255,222,173)))
    color_table.append(Color("Wheat",(245,222,179)))
    color_table.append(Color("BurlyWood",(222,184,135)))
    color_table.append(Color("Tan",(210,180,140)))
    color_table.append(Color("RosyBrown",(188,143,143)))
    color_table.append(Color("SandyBrown",(244,164,96)))
    color_table.append(Color("Goldenrod",(218,165,32)))
    color_table.append(Color("DarkGoldenrod",(184,134,11)))
    color_table.append(Color("Peru",(205,133,63)))
    color_table.append(Color("Chocolate",(210,105,30)))
    color_table.append(Color("SaddleBrown",(139,69,19)))
    color_table.append(Color("Sienna",(160,82,45)))
    color_table.append(Color("Brown",(165,42,42)))
    color_table.append(Color("Maroon",(128,0,0)))
    color_table.append(Color("White",(255,255,255)))
    color_table.append(Color("Snow",(255,250,250)))
    color_table.append(Color("Honeydew",(240,255,240)))
    color_table.append(Color("MintCream",(245,255,250)))
    color_table.append(Color("Azure",(240,255,255)))
    color_table.append(Color("AliceBlue",(240,248,255)))
    color_table.append(Color("GhostWhite",(248,248,255)))
    color_table.append(Color("WhiteSmoke",(245,245,245)))
    color_table.append(Color("Seashell",(255,245,238)))
    color_table.append(Color("Beige",(245,245,220)))
    color_table.append(Color("OldLace",(253,245,230)))
    color_table.append(Color("FloralWhite",(255,250,240)))
    color_table.append(Color("Ivory",(255,255,240)))
    color_table.append(Color("AntiqueWhite",(250,235,215)))
    color_table.append(Color("Linen",(250,240,230)))
    color_table.append(Color("LavenderBlush",(255,240,245)))
    color_table.append(Color("MistyRose",(255,228,225)))
    color_table.append(Color("Gainsboro",(220,220,220)))
    color_table.append(Color("LightGrey",(211,211,211)))
    color_table.append(Color("Silver",(192,192,192)))
    color_table.append(Color("DarkGray",(169,169,169)))
    color_table.append(Color("Gray",(128,128,128)))
    color_table.append(Color("DimGray",(105,105,105)))
    color_table.append(Color("LightSlateGray",(119,136,153)))
    color_table.append(Color("SlateGray",(112,128,144)))
    color_table.append(Color("DarkSlateGray",(47,79,79)))
    color_table.append(Color("Black",(0,0,0)))
    color_table.append(Color("紺色",(35,59,108)))
    color_table.append(Color("藍色",(22,94,131)))
    color_table.append(Color("桔梗色",(106,76,156)))
    color_table.append(Color("江戸紫",(116,83,153)))
    color_table.append(Color("鶯色",(145,141,64)))
    color_table.append(Color("灰汁色",(188,176,156)))
    color_table.append(Color("亜麻色",(214,198,175)))
    color_table.append(Color("山吹色",(248,180,0)))
    color_table.append(Color("小豆色",(152,81,75)))
    color_table.append(Color("えんじ色",(179,66,74)))
    color_table.append(Color("茜色",(177,53,70)))

    return color_table

def find_color(name_color):

    color_table = color_table_full()

    result = None

    for i in range(0,len(color_table)):
        if name_color.casefold() == color_table[i].name.casefold():
            result = color_table[i]
            break

    return result

def show_color_name():

    color_table = color_table_full()

    for i in range(0,len(color_table)):
        print(color_table[i].name, end =" ")

    print("")
```

### 追記

@shiracamus 様からの指摘で、color.py は辞書データにした方がいいようです。以下そのまま転載させていただきますが、見比べると面白いので以前のバージョンも残しておきます。後半のコードの綺麗さが比較になりませんね。

```python:color.py
COLORS = {
    "IndianRed": (205,92,92),
    "LightCoral": (240,128,128),
    "Salmon": (250,128,114),
    "DarkSalmon": (233,150,122),
    "LightSalmon": (255,160,122),
    "Crimson": (220,20,60),
    "Red": (255,0,0),
    "FireBrick": (178,34,34),
    "DarkRed": (139,0,0),
    "Pink": (255,192,203),
    "LightPink": (255,182,193),
    "HotPink": (255,105,180),
    "DeepPink": (255,20,147),
    "MediumVioletRed": (199,21,133),
    "PaleVioletRed": (219,112,147),
    "Coral": (255,127,80),
    "Tomato": (255,99,71),
    "OrangeRed": (255,69,0),
    "DarkOrange": (255,140,0),
    "Orange": (255,165,0),
    "Gold": (255,215,0),
    "Yellow": (255,255,0),
    "LightYellow": (255,255,224),
    "LemonChiffon": (255,250,205),
    "LightGoldenrodYellow": (250,250,210),
    "PapayaWhip": (255,239,213),
    "Moccasin": (255,228,181),
    "PeachPuff": (255,218,185),
    "PaleGoldenrod": (238,232,170),
    "Khaki" : (240,230,140),
    "DarkKhaki": (189,183,107),
    "Lavender": (230,230,250),
    "Thistle": (216,191,216),
    "Plum": (221,160,221),
    "Violet" : (238,130,238),
    "Orchid": (218,112,214),
    "Fuchsia": (255,0,255),
    "Magenta": (255,0,255),
    "MediumOrchid": (186,85,211),
    "MediumPurple": (147,112,219),
    "Amethyst": (153,102,204),
    "BlueViolet": (138,43,226),
    "DarkViolet": (148,0,211),
    "DarkOrchid": (153,50,204),
    "DarkMagenta": (139,0,139),
    "Purple": (128,0,128),
    "Indigo": (75,0,130),
    "SlateBlue": (106,90,205),
    "DarkSlateBlue": (72,61,139),
    "GreenYellow": (173,255,47),
    "Chartreuse": (127,255,0),
    "LawnGreen": (124,252,0),
    "Lime": (0,255,0),
    "LimeGreen": (50,205,50),
    "PaleGreen": (152,251,152),
    "LightGreen": (144,238,144),
    "MediumSpringGreen": (0,250,154),
    "SpringGreen": (0,255,127),
    "MediumSeaGreen": (60,179,113),
    "SeaGreen": (46,139,87),
    "ForestGreen": (34,139,34),
    "Green": (0,128,0),
    "DarkGreen": (0,100,0),
    "YellowGreen": (154,205,50),
    "OliveDrab": (107,142,35),
    "Olive": (128,128,0),
    "DarkOliveGreen": (85,107,47),
    "MediumAquamarine": (102,205,170),
    "DarkSeaGreen": (143,188,143),
    "LightSeaGreen": (32,178,170),
    "DarkCyan": (0,139,139),
    "Teal": (0,128,128),
    "Aqua": (0,255,255),
    "Cyan" : (0,255,255),
    "LightCyan": (224,255,255),
    "PaleTurquoise": (175,238,238),
    "Aquamarine": (127,255,212),
    "Turquoise": (64,224,208),
    "MediumTurquoise": (72,209,204),
    "DarkTurquoise": (0,206,209),
    "CadetBlue": (95,158,160),
    "SteelBlue": (70,130,180),
    "LightSteelBlue": (176,196,222),
    "PowderBlue": (176,224,230),
    "LightBlue": (173,216,230),
    "SkyBlue": (135,206,235),
    "LightSkyBlue": (135,206,250),
    "DeepSkyBlue": (0,191,255),
    "DodgerBlue": (30,144,255),
    "CornflowerBlue": (100,149,237),
    "MediumSlateBlue": (123,104,238),
    "RoyalBlue": (65,105,225),
    "Blue": (0,0,255),
    "MediumBlue": (0,0,205),
    "DarkBlue": (0,0,139),
    "Navy": (0,0,128),
    "MidnightBlue": (25,25,112),
    "Cornsilk": (255,248,220),
    "BlanchedAlmond": (255,235,205),
    "BlanchedAlmond": (255,228,196),
    "NavajoWhite": (255,222,173),
    "Wheat": (245,222,179),
    "BurlyWood": (222,184,135),
    "Tan": (210,180,140),
    "RosyBrown": (188,143,143),
    "SandyBrown": (244,164,96),
    "Goldenrod": (218,165,32),
    "DarkGoldenrod": (184,134,11),
    "Peru": (205,133,63),
    "Chocolate": (210,105,30),
    "SaddleBrown": (139,69,19),
    "Sienna": (160,82,45),
    "Brown": (165,42,42),
    "Maroon": (128,0,0),
    "White": (255,255,255),
    "Snow": (255,250,250),
    "Honeydew": (240,255,240),
    "MintCream": (245,255,250),
    "Azure": (240,255,255),
    "AliceBlue": (240,248,255),
    "GhostWhite": (248,248,255),
    "WhiteSmoke": (245,245,245),
    "Seashell": (255,245,238),
    "Beige": (245,245,220),
    "OldLace": (253,245,230),
    "FloralWhite": (255,250,240),
    "Ivory": (255,255,240),
    "AntiqueWhite": (250,235,215),
    "Linen": (250,240,230),
    "LavenderBlush": (255,240,245),
    "MistyRose": (255,228,225),
    "Gainsboro": (220,220,220),
    "LightGrey": (211,211,211),
    "Silver": (192,192,192),
    "DarkGray": (169,169,169),
    "Gray": (128,128,128),
    "DimGray": (105,105,105),
    "LightSlateGray": (119,136,153),
    "SlateGray": (112,128,144),
    "DarkSlateGray": (47,79,79),
    "Black": (0,0,0),
    "紺色": (35,59,108),
    "藍色": (22,94,131),
    "桔梗色": (106,76,156),
    "江戸紫": (116,83,153),
    "鶯色": (145,141,64),
    "灰汁色": (188,176,156),
    "亜麻色": (214,198,175),
    "山吹色": (248,180,0),
    "小豆色": (152,81,75),
    "えんじ色": (179,66,74),
    "茜色": (177,53,70),
}


class Color:
  def __init__(self, name, rgb):
    self.name = name
    self.r, self.g, self.b = self.rgb = rgb
    self.code = f'#{self.r:02x}{self.g:02x}{self.b:02x}'


def color_table_full():
    return [Color(name, rgb) for name, rgb in COLORS.items()]


def find_color(name):
    return Color(name, COLORS[name]) if name in COLORS else None


def show_color_names():
    print(*COLORS)
```