为什么在 GIF 上粘贴透明图像会扭曲它?
Why does pasting a transparent image on a GIF distort it?
我有一张RGBA代码的透明图片(0, 0, 0, 0)
,我在上面添加了一些图片和文字。现在,我试图将它粘贴到 GIF 图像上,但它完全毁了它。
这是我的透明图片:
这是我的 GIF:
而且,这就是我得到的:
这是我的代码:
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 是这样。使用 Pillow 打开时,您的 GIF can only store upto 256 different colors using some color palette, thus has mode P
(或 PA
)。现在,您的 PNG 可能有更多的颜色。将 PNG 粘贴到 GIF 上时,GIF 的调色板用于转换 PNG 的某些颜色,这会产生意外或不需要的结果,请参见。你的输出。
我的想法是,因为您已经在迭代每一帧:
- 将框架转换为
RGB
,以从调色板中获取“显式”颜色。
- 将框架转换为某个 NumPy 数组,并使用其 Alpha 通道手动 alpha blend 框架和 PNG。
- 将生成的帧转换回 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], 3, 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
----------------------------------------
我有一张RGBA代码的透明图片(0, 0, 0, 0)
,我在上面添加了一些图片和文字。现在,我试图将它粘贴到 GIF 图像上,但它完全毁了它。
这是我的透明图片:
这是我的 GIF:
而且,这就是我得到的:
这是我的代码:
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 是这样。使用 Pillow 打开时,您的 GIF can only store upto 256 different colors using some color palette, thus has mode P
(或 PA
)。现在,您的 PNG 可能有更多的颜色。将 PNG 粘贴到 GIF 上时,GIF 的调色板用于转换 PNG 的某些颜色,这会产生意外或不需要的结果,请参见。你的输出。
我的想法是,因为您已经在迭代每一帧:
- 将框架转换为
RGB
,以从调色板中获取“显式”颜色。 - 将框架转换为某个 NumPy 数组,并使用其 Alpha 通道手动 alpha blend 框架和 PNG。
- 将生成的帧转换回 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], 3, 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
----------------------------------------