So this GIF looks perfectly fine before opening:
But, when opened using Pillow using
imageObject = Image.open(path.join(petGifs, f"{pokemonName}.gif"))
it bugs out, adding various boxes that have colors similar to that of the source image. This is an example frame, but almost every frame is different, and it's in different spots depending on the GIF:
The only thing, that has worked to fix this, is ezgif's unoptimize option (found in their optimize page). But, I'd need to do that on each GIF, and there's a lot of them.
I need either a way to bulk unoptimize, or a new way to open the GIF in Python (currently using Pillow), that will handle this.
At least for extracting proper single frames there might be a solution.
The disposal
method for all frames (except the first) is set to 2
, which is "restore to background color".
Diving through Pillow's source code, you'll find the according line where the disposal method 2
is considered, and, in the following, you'll find:
# by convention, attempt to use transparency first
color = (
frame_transparency
if frame_transparency is not None
else self.info.get("background", 0)
)
self.dispose = Image.core.fill("P", dispose_size, color)
If you check the faulty frames, you'll notice that this dark green color of the unwanted boxes is located at position 0
of the palette. So, it seems, the wrong color is picked for the disposal, because – I don't know why, yet – the above else
case is picked instead of using the transparency information – which would be there!
So, let's just override the possibly faulty stuff:
from PIL import Image, ImageSequence
# Open GIF
gif = Image.open('223vK.gif')
# Initialize list of extracted frames
frames = []
for frame in ImageSequence.Iterator(gif):
# If dispose is set, and color is set to 0, use transparency information
if frame.dispose is not None and frame.dispose[0] == 0:
frame.dispose = Image.core.fill('P', frame.dispose.size,
frame.info['transparency'])
# Convert frame to RGBA
frames.append(frame.convert('RGBA'))
# Visualization overhead
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 8))
for i, f in enumerate(frames, start=1):
plt.subplot(8, 8, i), plt.imshow(f), plt.axis('off')
plt.tight_layout(), plt.show()
The extracted frames look like this:
That seems fine to me.
If, by chance, the transparency information is actually set to 0
, no harm should be done here, since we (re)set with the still correct transparency information.
I don't know, if (re)saving to GIF will work, since frames are now in RGBA
mode, and saving to GIF from there is tricky as well.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.19041-SP0
Python: 3.9.1
PyCharm: 2021.1.3
Matplotlib: 3.4.2
Pillow: 8.3.1
----------------------------------------