Skip to content

Instantly share code, notes, and snippets.

@nna774
Created May 12, 2026 09:27
Show Gist options
  • Select an option

  • Save nna774/3a21e1dcd15276e3f3c60735f3ebc176 to your computer and use it in GitHub Desktop.

Select an option

Save nna774/3a21e1dcd15276e3f3c60735f3ebc176 to your computer and use it in GitHub Desktop.
"""
CMYKテストパターン生成スクリプト
- output_no_profile.jpg : ICCプロファイルなし(Twitterが誤変換するやつ)
- output_with_profile.jpg: ICCプロファイルあり(正しく変換された場合)
"""
from PIL import Image, ImageDraw, ImageFont
import struct
W, H = 800, 1000
def make_cmyk_image():
img = Image.new("CMYK", (W, H), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# --- 各チャンネル単色スウォッチ ---
swatches = [
((255, 0, 0, 0 ), "C=100"),
((0, 255, 0, 0 ), "M=100"),
((0, 0, 255, 0 ), "Y=100"),
((0, 0, 0, 255), "K=100"),
((0, 255, 255, 0 ), "M+Y (赤系)"),
((255, 0, 255, 0 ), "C+Y (緑系)"),
((255, 255, 0, 0 ), "C+M (青系)"),
]
sw_w = W // len(swatches)
for i, (color, label) in enumerate(swatches):
x0 = i * sw_w
draw.rectangle([x0, 0, x0 + sw_w, 80], fill=color)
# ラベルは白で(K=0なので背景に対して見える)
draw.text((x0 + 4, 58), label, fill=(0, 0, 0, 200))
# --- Mチャンネル単独グラデーション ---
draw.text((10, 90), "M channel gradient (C=0,Y=0,K=0)", fill=(0, 0, 0, 200))
for x in range(W):
m = int(x / W * 255)
draw.line([(x, 110), (x, 170)], fill=(0, m, 0, 0))
# --- 肌色グラデーション(C低め、M/Y高め)---
draw.text((10, 180), "Skin tone gradient (C=5, M=20->60, Y=25->50, K=0)", fill=(0, 0, 0, 200))
steps = W
for x in range(steps):
t = x / steps
c = 5
m = int(20 + t * 40) # 20→60
y = int(25 + t * 25) # 25→50
k = 0
draw.line([(x, 200), (x, 260)], fill=(c, m, y, k))
# --- Kのみグレースケール ---
draw.text((10, 270), "K-only grayscale (C=M=Y=0)", fill=(0, 0, 0, 200))
for x in range(W):
k = int(x / W * 255)
draw.line([(x, 290), (x, 350)], fill=(0, 0, 0, k))
# --- シャドウ肌色(Kあり)---
draw.text((10, 360), "Shadow skin (C=10, M=40, Y=30, K=0->50)", fill=(0, 0, 0, 200))
for x in range(W):
t = x / W
k = int(t * 128)
draw.line([(x, 380), (x, 440)], fill=(26, 102, 77, k))
# --- CMYKスウォッチグリッド(細かい値)---
draw.text((10, 450), "CMYK swatches (肌色系)", fill=(0, 0, 0, 200))
skin_tones = [
(5, 15, 20, 0, "薄い肌"),
(5, 25, 30, 0, "標準肌"),
(5, 35, 40, 0, "濃い肌"),
(10, 40, 35, 10, "影肌1"),
(10, 50, 40, 20, "影肌2"),
(0, 60, 50, 0, "赤み肌"),
(0, 80, 60, 0, "強赤み"),
]
sw_w2 = W // len(skin_tones)
for i, (c, m, y, k, label) in enumerate(skin_tones):
x0 = i * sw_w2
draw.rectangle([x0, 470, x0 + sw_w2, 560], fill=(
int(c/100*255), int(m/100*255), int(y/100*255), int(k/100*255)
))
draw.text((x0 + 4, 538), label, fill=(0, 0, 0, 200))
# --- 全チャンネル段階グリッド(M vs Y)---
draw.text((10, 570), "M(縦) vs Y(横) grid, C=5, K=0", fill=(0, 0, 0, 200))
grid_steps = 8
cell_w = W // grid_steps
cell_h = 40
for row in range(grid_steps):
for col in range(grid_steps):
m = int(row / (grid_steps - 1) * 200)
y = int(col / (grid_steps - 1) * 200)
x0 = col * cell_w
y0 = 590 + row * cell_h
draw.rectangle([x0, y0, x0 + cell_w, y0 + cell_h],
fill=(13, m, y, 0))
# --- 白・グレー確認用 ---
draw.text((10, 920), "White / near-white check", fill=(0, 0, 0, 200))
whites = [
((0, 0, 0, 0), "Pure White\nC0M0Y0K0"),
((5, 5, 5, 0), "Near white\nC5M5Y5K0"),
((0, 5, 5, 0), "Warm white\nC0M5Y5K0"),
((5, 0, 0, 0), "Cool white\nC5M0Y0K0"),
((0, 0, 0, 10), "Light gray\nK10"),
((0, 0, 0, 30), "Gray K30"),
]
sw_w3 = W // len(whites)
for i, (color, label) in enumerate(whites):
x0 = i * sw_w3
draw.rectangle([x0, 940, x0 + sw_w3, H], fill=color)
draw.text((x0 + 4, H - 52), label, fill=(0, 0, 0, 180))
return img
img = make_cmyk_image()
# 1) ICCプロファイルなしで保存
img.save("/tmp/cmyk_test/output_no_profile.jpg", format="JPEG")
print("saved: output_no_profile.jpg")
# 2) ICCプロファイルあり(JapanColor2001Coated相当のプロファイルがない場合は
# sRGB変換してから保存するのが「正しく見える」側の代替)
rgb_img = img.convert("RGB")
rgb_img.save("/tmp/cmyk_test/output_rgb_converted.jpg", format="JPEG")
print("saved: output_rgb_converted.jpg (CMYK→RGB正変換済み)")
print("\n比較方法:")
print(" output_no_profile.jpg → Twitterにそのままアップ → 誤変換後の色")
print(" output_rgb_converted.jpg → 正しく変換した場合の色")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment