New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reading GIF and saving it introduces artifacts #5307
Comments
Two comments for now -
from PIL import Image, ImageSequence
import urllib.request
url = "https://github.com/imageio/imageio-binaries/blob/master/images/newtonscradle.gif?raw=true"
response = urllib.request.urlopen(url)
with open("original.gif", "wb+") as file:
file.write(response.read())
response = urllib.request.urlopen(url)
pil_image = Image.open(response)
pil_frames = [frame for frame in ImageSequence.Iterator(pil_image)]
pil_frames[0].save("test.gif", loop=0, fps=60, save_all=True, append_images=pil_frames[1:])
|
And just for my future reference, I don't expect this has to do with saving, just reading, as even this simpler instance shows a broken image. from PIL import Image
import urllib.request
response = urllib.request.urlopen("https://github.com/imageio/imageio-binaries/blob/master/images/newtonscradle.gif?raw=true")
with open("original.gif", "wb+") as f:
f.write(response.read())
with Image.open("original.gif") as im:
im.seek(1)
im.save("out.png") |
Testing, I find this would be resolved by #5333 |
Will it still be possible to get the raw frame values containing transparent pixels? I like the idea of not replacing pixel values if the next pixel in the sequence is transparent, At the same time, it may still be useful to be able to just get the current frame without applying information from previous frames, e.g., for inspecting that writing worked as intended. Another question: How will this work with GIFs ability to have per-frame color pallets? If I understand #5333 correctly, then the pixel of the previous frame will be kept, which could effectively increase the number of colors in the image above 256. Couldn't this cause aliasing? How will the color pallet/conversion mechanism handle this? |
Without modifying Pillow, I wouldn't think that getting the raw frame with transparent pixels is even possible at the moment. If you'd like that as a new feature, please create a new issue. If you look through the issues tagged with GIF, you will find that there is already a problem with combining the palette between GIF frames. Looking at the code, when loading each frame, it defaults to the global palette, which can be overridden by the local palette. The matter of keeping colors from previous frames doesn't just apply to transparency, but also to each new tile that may not take up the entire width and height of the image. It doesn't solve everything, but I find that #5333 does fix the original problem that you posted here. |
Yes it does :) Thank you for addressing this issue with a PR so swiftly. |
What did you do?
I'm trying to read a
.gif
into a numpy array to obtain a sequence of frames and then write the result back to disk as a new gif.What did you expect to happen?
The image sequence loads and each frame contains a (fully rendered?) image. The created
.gif
and the original one look alike (minus FPS) upon visual inspection.What actually happened?
The written/created
.gif
contains artifacts, which (I suppose) come from either the writer not using the appropriate disposal method (1 - do not dispose), the reader only reading data from the current frame and disposing of the previous frame(s) each time, or the image containing transparent pixels which would then show the underlying frame/background.What are your OS, Python and Pillow versions?
Original Image:
Resulting Image:
It might be a user error on my part and I am simply missing an option. In either case, I don't think the default behavior should change, but it would be good to have the option to make a frame contain the same pixel values that a user would see once the frame is displayed (including non-disposed pixels of the previous frame(s)).
The text was updated successfully, but these errors were encountered: