コンテンツにスキップ
quickthumb
すべてのドキュメント

基本的な考え方

キャンバスはレイヤーの集まり

Canvasはサイズと順序付きのレイヤー一覧を持ちます。レイヤーのメソッドは1枚追加してキャンバスを返すので、続けて呼び出せます。

from quickthumb import Canvas

canvas = (
    Canvas(1280, 720)
    .background(color="#0F172A")
    .text(content="Hello", size=64, color="#FFFFFF", align="center")
    .outline(width=8, color="#22D3EE")
)
canvas.render("hello.png")

レイヤーは追加した順に描かれます。最初が一番奥、最後が一番手前です。絵を描くときのように、背景から始めて細部を重ねていきます。

レイヤーの種類

メソッド 追加するもの リファレンス
.background() キャンバス全体の色、グラデーション、画像 背景
.text() 通常のテキスト、または書式付きのTextPart テキスト
.image() 配置した画像。背景除去も可能 画像
.shape() 長方形、楕円、カプセル、三角形、星、多角形 図形
.svg() アイコンやロゴなどのSVGファイル。svg追加機能が必要 SVG
.video() アニメーション出力用の動画クリップ 動画
.chart(), .qr_code() 棒・折れ線グラフ、QRコード データの可視化
.counter() ある値から別の値へ数える数字 Canvas
.group() 子を自動配置する行や列 グループ
.outline() キャンバスの縁の枠線 枠線
.custom(fn) Pillow画像へ描く独自の関数 Canvas

位置と整列

positionは(x, y)の組です。それぞれピクセルかキャンバスに対する百分率で指定でき、混在もできます。

canvas.shape(shape="rectangle", position=(64, 64), width=200, height=80, color="#CC0000")
canvas.text(content="Hello", size=72, color="#FFFFFF", position=("8%", 360))

alignは、レイヤーのどの点を指定位置に合わせるかを決めます。既定は左上です。align=("center", "middle")なら中心を合わせます。1280×720のキャンバスでalign=("right", "bottom")とposition=(1280, 720)を指定すると、レイヤーのサイズによらず右下に固定できます。

alignには、同じ意味を持ついくつかの書き方があります。

align=("center", "middle")      # (horizontal, vertical)
align="center"                  # same as ("center", "middle")
align="bottom-right"
align=Align.BOTTOM_RIGHT

横方向はleft、center、right、縦方向はtop、middle、bottomです。テキストにpositionがなくalignだけがある場合は、キャンバス内の対応する位置に配置します。つまりalign="center"なら中央です。

エフェクト

エフェクトはレイヤーの描き方を変えます。リストで渡してください。

from quickthumb import Shadow, Stroke

canvas.text(
    content="CLICK NOW",
    size=96,
    color="#FFFFFF",
    effects=[
        Stroke(width=4, color="#000000"),
        Shadow(offset_x=4, offset_y=4, color="#000000", blur_radius=8),
    ],
)

使えるエフェクトはレイヤーの種類によって異なります。

レイヤー エフェクト
背景 Filter、Grain
テキスト Stroke、Shadow、Glow、Background(文字の背後の枠)
図形 Stroke、Shadow、Glow、InnerShadow、BackdropBlur
画像、SVG、動画 Stroke、Shadow、Glow、Filter、Grain、Duotone、InnerShadow、BackdropBlur

レイヤーが対応していないエフェクトを渡すとValidationErrorになります。パラメーターはエフェクトリファレンスを参照してください。

リッチテキスト

すべて同じ書式なら通常の文字列で十分です。一部の書式を変えるにはTextPartのリストを渡します。

from quickthumb import TextPart

canvas.text(
    content=[
        TextPart(text="5 ", color="#FBBF24"),
        TextPart(text="WAYS TO WIN", color="#FFFFFF"),
    ],
    size=80,
    weight=900,
    position=("8%", "55%"),
    align=("left", "middle"),
)

レイヤーの設定(ここではsizeとweight)は、各パートで指定し直さない限り全体へ適用されます。パートごとにcolor、size、font、weight、bold、italic、letter_spacing、line_height、effectsを上書きできます。

グラデーション、ブレンド、画像のフィット

背景には色や画像に加えてgradientも指定できます。

from quickthumb import LinearGradient, RadialGradient

canvas.background(gradient=LinearGradient(angle=135, stops=[("#FF5733", 0.0), ("#3333FF", 1.0)]))
canvas.background(gradient=RadialGradient(center=(0.5, 0.5), stops=[("#FF5733", 0.0), ("#3333FF", 1.0)]))

停止点の色にはアルファ("#00000080")を含められます。これにより、文字の背後にある写真の一部を暗くできます。

背景や画像のblend_modeは、下の内容との合成方法を決めます。normal、multiply、screen、overlay、darken、lightenが使えます。

fitは画像を枠に収める方法です。coverは枠を埋めて余分な部分を切り取り、背景ではこれが既定です。containは画像全体を枠内に収め、fillは引き伸ばします。

自動レイアウト

手で座標を指定したテキストは、文言が長くなるとレイアウトが崩れがちです。groupは子のサイズを測り、行や列に並べます。グループを一度配置すれば、子の位置は自動で決まります。

canvas.group(
    children=[
        {"type": "shape", "shape": "pill", "width": 120, "height": 36, "color": "#E94560"},
        {"type": "text", "content": "AUTO LAYOUT", "size": 96, "color": "#FFFFFF", "weight": 900},
        {"type": "text", "content": "Longer copy pushes the rest down", "size": 40, "color": "#A2A8D3"},
    ],
    direction="column",
    gap=24,
    position=("8%", "50%"),
    align=("left", "middle"),
)

子にはpositionを指定しません。グループを入れ子にもできます。グループを参照してください。

JSON仕様

ここまでの内容はPythonだけでなくJSONでも書け、キャンバスと相互に変換できます。

spec = canvas.to_json()
same_canvas = Canvas.from_json(spec)

例外は.custom(fn)です。Python関数はJSONに保存できません。

JSONのthemeブロックで色やサイズを一度定義し、$theme.<path>で参照することもできます。

{
  "kind": "canvas",
  "width": 1280,
  "height": 720,
  "theme": { "colors": { "primary": "#B8FF00" }, "sizes": { "title": 96 } },
  "layers": [
    { "type": "text", "content": "Hello", "size": "$theme.sizes.title", "color": "$theme.colors.primary" }
  ]
}

JSON SchemaとAIワークフローを参照してください。

パスのモーション

Canvas.path()はSVGパスデータ、グラデーションを含む塗り、破線に対応します。固定されたwidth/heightのビューポートがローカルの描画を切り取り、回転や拡大縮小中も正規化されたanchorの基準となります。

from quickthumb import AnimationSpec, Canvas, KeyframeSpec, ScaleTrack, TimingSpec

canvas = Canvas(320, 240).path(
    "M2 20C2 2 38 2 38 20C38 38 2 38 2 20Z", (100, 80), 40, 40,
    "#38B6A080", anchor=(0.5, 0.5),
    animation=AnimationSpec.timeline(
        ScaleTrack(keyframes=[KeyframeSpec(time=0, value=1), KeyframeSpec(time=1, value=4)]),
        timing=TimingSpec(duration=1), easing="linear",
    ),
)
frame = canvas.render_frame(0.75)

パスのアニメーションにはトラックタイムラインを使います。対応範囲は出力形式によって異なります。パスではプリセット、stagger、Groupの子、変換の親子関係をサポートしていません。詳細はPath APIを参照してください。

エラーと検査

描画前のレイヤー追加時に引数を検証します。

from quickthumb import ValidationError

try:
    canvas.text(content="Hello", size=64, color="#FFF")
except ValidationError as error:
    print(error)  # /color: invalid hex color: #FFF

ダウンロードの失敗など、描画中に分かる問題はRenderingError、存在しないローカルファイルはMissingAssetErrorになります。どのエラーも構造化されたdetailsを持ちます。構造化エラーを参照してください。

有効なキャンバスでも見た目に問題がある場合はあります。canvas.diagnose()はファイルを出力せず、小さすぎる文字、はみ出し、低いコントラスト、他のレイヤーに隠れたレイヤーなどを調べます。診断とCLIを参照してください。