You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIL循环粘贴图片异常:仅首个主题色板成功添加的问题排查

问题

我写了一段脚本,遍历一组JSON配色主题文件,用seaborn和matplotlib生成带标签的色板并保存到缓冲区,再把缓冲区内容粘贴到新的PIL.Image里,但只有首个主题的色板被添加到PIL.Image中。

代码如下:

sw_width = 1084
sw_height = 100

theme_list = listdir('themes')

width = sw_width
height = sw_height*len(theme_list)
swatches = Image.new('RGB', (width, height))
y_offset = 0

# Loop through all themes, drawing a swatch for each theme
for theme_file in theme_list:
    with open('themes/' + theme_file) as th:
        # load theme
        theme = json.load(th)
    # extract theme name and delete
    theme_name = theme.pop('name')
    theme_description = theme.pop('description')

    # Draw swatch
    sns.palplot(theme.values())

    # Add title to swatch
    plt.title(theme_name)
    # Add key and hexadecimal color
    for i, key in enumerate(theme):
        plt.text(
            i, 0.2,
            key+'\n'+theme[key],
            ha='center',
            va='bottom',
            color=invert_hex(theme[key]),
            fontsize=7
        )
    plt.tight_layout()
    buf = BytesIO()
    buf.seek(0)
    plt.savefig(buf)

    sw = Image.open(buf)
    swatches.paste(sw, (0,y_offset))
    y_offset += height
swatches.save('theme_swatches.png')

其中invert_hex函数用于设置文本反色,每个色板在Jupyter Notebook里都能正确生成,请问我哪里操作错了?

解决方法
  • 错误1:Matplotlib绘图未重置
    每次循环调用sns.palplot()和plt.title()后,Matplotlib的当前绘图对象没有被清空,后续的绘图会直接叠加在之前的图上,导致从缓冲区读取的始终是包含所有主题的叠加图,而非单个主题的独立色板。

  • 错误2:y_offset累加逻辑错误
    你写的y_offset += height,但height是最终合成图的总高度(sw_height*len(theme_list)),这会导致第一次循环后y_offset直接跳到超出图片范围的位置,后续的粘贴操作根本不会显示在画布上。应该改成每次累加单个色板的高度sw_height。

修正后的代码:

import os
import json
import seaborn as sns
import matplotlib.pyplot as plt
from PIL import Image
from io import BytesIO

sw_width = 1084
sw_height = 100

theme_list = os.listdir('themes')

width = sw_width
height = sw_height * len(theme_list)
swatches = Image.new('RGB', (width, height))
y_offset = 0

# 遍历所有主题,生成单个色板并拼接
for theme_file in theme_list:
    with open(os.path.join('themes', theme_file)) as th:
        theme = json.load(th)
    
    theme_name = theme.pop('name')
    theme_description = theme.pop('description')

    # 每次循环创建新画布,避免绘图叠加
    plt.figure(figsize=(sw_width/100, sw_height/100))  # 按像素设置画布尺寸(dpi默认100)
    sns.palplot(list(theme.values()))

    plt.title(theme_name)
    for i, key in enumerate(theme):
        plt.text(
            i, 0.2,
            f'{key}\n{theme[key]}',
            ha='center',
            va='bottom',
            color=invert_hex(theme[key]),
            fontsize=7
        )
    plt.tight_layout()
    
    buf = BytesIO()
    plt.savefig(buf, format='png')
    buf.seek(0)
    
    sw = Image.open(buf)
    swatches.paste(sw, (0, y_offset))
    y_offset += sw_height  # 累加单个色板的高度
    
    plt.close()  # 关闭当前画布,释放内存资源

swatches.save('theme_swatches.png')

补充说明:

  • 用plt.figure()每次创建独立画布,确保每个主题的色板互不干扰;
  • 用plt.close()及时关闭画布,避免内存占用过高;
  • 改用os.path.join()拼接文件路径,适配不同操作系统的路径规则。

内容的提问来源于stack exchange,提问作者zoof

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 10:36:06