【问题标题】:Why does the GIF colour palette get corrupted in my code?为什么我的代码中的 GIF 调色板损坏了?
【发布时间】:2021-07-09 16:36:37
【问题描述】:

我制作了一个为 GIF 或图像添加字幕的函数:

import textwrap
from io import BytesIO

from PIL import Image, ImageDraw, ImageFont, ImageOps, ImageSequence


def caption(fn: str, text: str):
    old_im = Image.open(fn)
    ft = old_im.format
    W = old_im.size[0]
    font = ImageFont.truetype('BebasNeue.ttf', 50) # replace with your own font

    width = 10
    while True:
        lines = textwrap.wrap(text, width=width)
        if (font.getsize(max(lines, key=len))[0]) > (0.9 * W):
            break
        width += 1

    # amount of lines * height of one line
    bar_height = len(lines) * (font.getsize(lines[0])[1])
    frames = []
    for frame in ImageSequence.Iterator(old_im):
        frame = ImageOps.expand(
            frame,
            border=(0, bar_height, 0, 0),
            fill='white'
        )
        draw = ImageDraw.Draw(frame)
        for i, line in enumerate(lines):
            w, h = draw.multiline_textsize(line, font=font)
            # Position is x: centered, y: line number * height of line
            draw.text(
                ((W - w) / 2, i * h),
                line,
                font=font,
                fill='black'
            )

        del draw
        b = BytesIO()
        frame.save(b, format=ft)
        b.seek(0)
        frames.append(Image.open(b))

    frames[0].save(
        f'out.{ft}',
        save_all=True,
        append_images=frames[1:],
        format=ft,
        loop=0,
        optimize=True
    )


caption(
    'in.gif',
    'this is a test message this is a test message this is a test message this is a test message this is a test message this is a test message'
)

这会产生一些奇怪的结果,但结果并不理想。

这是in.gif

  1. 以上代码不变:

  1. palette=old_im.palette 传递到frames[0].save()

  1. 在展开后立即将帧转换为“RGB”(.convert('RGB'))):

  1. palette=old_im.palette 传递到frames[0].save(...) 并且帧在展开后立即转换为“RGB”(.convert('RGB'))):

  1. palette=old_im.getpalette() 传递到frames[0].save(...)

  1. palette=old_im.getpalette() 传递到frames[0].save(...) 并且帧在展开后立即转换为“RGB”(.convert('RGB'))):

正如您所见,没有一个选项具有所需的输出,尽管数字 5 似乎有最好的结果,除了白色画布上的黑色文本现在突然变成红色画布上的深红色文本。这是什么原因造成的,我怎样才能得到正常的输出?

【问题讨论】:

    标签: python python-3.x python-imaging-library gif


    【解决方案1】:

    在扩展frame之前转换为'RGB'

    # [...]
    for frame in ImageSequence.Iterator(old_im):
        frame = frame.convert('RGB')                # <--
        frame = ImageOps.expand(
            frame,
            border=(0, bar_height, 0, 0),
            fill='white'
        )
        draw = ImageDraw.Draw(frame)
    # [...]
    

    这就是我得到的输出:

    我认为,用white 填充会以某种方式破坏现有的调色板。如果你在展开之前转换为'RGB',我猜“白色”将是“正确的白色”。

    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.16299-SP0
    Python:        3.9.1
    Pillow:        8.1.2
    ----------------------------------------
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-10
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多