12A猫で学んだこと-Memoir-

...What are you learning now?

Powepoint + Python でスライドに色相環を配置してみる

こんにちは、StudentSです。
今月もレポート提出最終日のぎりぎりです。
これは、いけない習慣になっていますねー このままでは、 いつか単位を落としてしまいそう... 生活の見直しが必要です。

今月は、少しPowerpointで遊んでみました。

お題

comtypes のライブラリを使って 書いてみたコードが以下になります。

スクリプト

import os
import colorsys
import math
from comtypes import client


def make_hue_circle(seed_color, n_color=5):
    """ Make ``Hue Circle`` with ``seed``.
    Args:
        seed_color: 3-length tuple. (R, G, B) 
        n_color: the number of color.

    Returns:
        ``list`` of colors.
    """
    r, g, b = map(lambda x: x / 255, seed_color)
    h, l, s = colorsys.rgb_to_hls(r, g, b)
    hs = [(h + d / n_color) % 1.0 for d in range(n_color)]
    colors = [colorsys.hls_to_rgb(h, l, s) for h in hs]
    colors = [tuple(map(lambda x: round(x * 255), color)) for color in colors]
    return colors

""" Below, powerpoint specific functions.
"""

def _to_int(color):
    assert len(color) == 3
    value = sum((v << (i * 8)) for i, v in enumerate((color)))
    return value


def _get_application(path=None):
    app = client.CreateObject("Powerpoint.Application")
    app.Visible = True
    if path:
        app.open(os.path.abspath(path))
    return app

def _draw_circle(slide, cx, cy, radius, color):

    # https://docs.microsoft.com/en-us/office/vba/api/office.msoautoshapetype
    msoShapeOval = 9
    shape = slide.Shapes.AddShape(msoShapeOval,
                                  Left=cx - radius,
                                  Top=cy - radius,
                                  Width=2 * radius,
                                  Height=2 * radius)
    shape.Line.Visible = True
    shape.Fill.ForeColor.RGB = _to_int(color)
    return shape

def _draw_hue_circle(slide, cx, cy, radius, base_color, n_color, ring_radius=None):
    def _infer_ring_radius(radius, delta_theta):
        """ Based on the golden ratio, determine 
        the radius of small circle.
        """
        return radius * delta_theta * 2 / (5 + math.sqrt(5))

    colors = make_hue_circle(base_color, n_color)
    d_theta = 2 * math.pi / n_color
    if ring_radius is None:
        ring_radius = _infer_ring_radius(radius, d_theta)
    for i, color in enumerate(colors):
        x = cx + radius * math.sin(d_theta * i)
        y = cy - radius * math.cos(d_theta * i)
        _draw_circle(slide, x, y, ring_radius, color)
    return slide

if __name__ == "__main__":
    color = (0, 114, 114) # base color of ring.
    n_color = 12
    application = _get_application()
    presentation = application.ActivePresentation
    # Depending on the configuration, specify it.
    custom_layout = 9
    slide = presentation.Slides.Add(1, custom_layout)
    slide_height, slide_width = presentation.PageSetup.SlideHeight, presentation.PageSetup.SlideWidth
    cy, cx = slide_height / 2, slide_width / 2 
    _draw_hue_circle(slide, cx, cy, cy * 0.6, color, n_color)
  • 結果の例は以下の図のような感じです。

Bright Color Tone

Dark Color Tone

あとがき

  • pep8flake8も忘れていましたー
  • 強引にやったという感じがありますー

おまけ

ブログのネタを考えていたら、頭の中で生み出された妄想会話を残しておきます。

Conversationi