为什么在 GIF 上粘贴透明图像会扭曲它?

问题描述

我有一个带有 RGBA 代码 (0,0) 的透明图像,我在上面添加了一些图片文字。现在,我试图将其粘贴到 GIF 图像上,但它完全破坏了它。

这是我的透明图片

Transparent

这是我的 GIF:

Gif

而且,这就是我得到的:

final

这是我的代码

from PIL import ImageSequence
im = Image.open('newav.gif')
frames = []
for frame in ImageSequence.Iterator(im):
    frame = frame.copy()
    frame.paste(card,(0,0),card)
    frames.append(frame)
frames[0].save('rank_card_gif.gif',save_all=True,append_images=frames[1:],loop=0)

解决方法

将现有的动画 GIF 与具有透明度的静态 PNG 结合起来并不容易——至少仅使用 Pillow 是这样。您的 GIF 使用某些调色板最多只能存储 256 种不同的颜色,因此在使用 Pillow 打开时具有 mode P(或 PA)。现在,您的 PNG 可能有更多颜色。将 PNG 粘贴到 GIF 上时,GIF 的调色板用于转换一些 PNG 的颜色,这会产生意外或不需要的结果,参见。你的输出。

我的想法是,因为您已经在迭代每一帧:

  1. 将框架转换为 RGB,以从调色板中获取“显式”颜色。
  2. 将框架转换为某个 NumPy 数组,并使用其 alpha 通道手动 alpha blend 框架和 PNG。
  3. 将结果帧转换回 Pillow Image 对象。

因此,所有帧都存储为 RGB,所有帧的所有颜色都相同。所以,当现在保存一个新的 GIF 时,新的调色板是从这组图像中确定的。

这是我所描述过程的代码:

import cv2
from PIL import Image,ImageSequence
import numpy as np

# Read gif using Pillow
gif = Image.open('gif.gif')

# Read png using OpenCV
pngg = cv2.imread('png.png',cv2.IMREAD_UNCHANGED)

# Extract alpha channel,repeat for later alpha blending
alpha = np.repeat(pngg[...,3,np.newaxis],axis=2) / 255

frames = []
for frame in ImageSequence.Iterator(gif):
    frame = frame.copy()

    # Convert frame to RGB
    frame = frame.convert('RGB')

    # Convert frame to NumPy array; convert RGB to BGR for OpenCV
    frame = cv2.cvtColor(np.asarray(frame),cv2.COLOR_RGB2BGR)

    # Manual alpha blending
    frame = np.uint8(pngg[...,:3] * alpha + frame * (1 - alpha))

    # Convert BGR to RGB for Pillow; convert frame to Image object
    frame = Image.fromarray(cv2.cvtColor(frame,cv2.COLOR_BGR2RGB))

    frames.append(frame)
frames[0].save('output.gif',append_images=frames[1:],save_all=True,loop=0,duration=gif.info['duration'])

而且,这是结果:

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
NumPy:         1.20.1
OpenCV:        4.5.1
Pillow:        8.1.0
----------------------------------------