-
-
Notifications
You must be signed in to change notification settings - Fork 79
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
Fix Animated Sticker / TGS Sticker Transparency Issues #139
base: master
Are you sure you want to change the base?
Fix Animated Sticker / TGS Sticker Transparency Issues #139
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the contribution!
@@ -172,7 +188,7 @@ def export_gif(animation, fp, dpi=96, skip_frames=5): | |||
# Import only upon calling the method due to added binary dependencies | |||
# (libcairo) | |||
from lottie.exporters.cairo import export_png | |||
from lottie.exporters.gif import _png_gif_prepare | |||
# from lottie.exporters.gif import _png_gif_prepare # The code here have some problem, so I copy the function abo ve |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the forked code is already above, this line can be removed.
@@ -183,7 +199,7 @@ def export_gif(animation, fp, dpi=96, skip_frames=5): | |||
file.seek(0) | |||
frames.append(_png_gif_prepare(Image.open(file))) | |||
|
|||
duration = 1000 / animation.frame_rate * (1 + skip_frames) / 2 | |||
duration = 1000 / animation.frame_rate * (1 + skip_frames) # why /2 before? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The / 2
was brought over as a part of the original function. I’m not quite sure what it stands for though.
split = ( | ||
stream | ||
.split() | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplifed.
split = ( | |
stream | |
.split() | |
) | |
split = stream.split() |
stream_paletteuse = ( | ||
ffmpeg | ||
.filter( | ||
[ | ||
split[0], | ||
split[1] | ||
.filter( | ||
filter_name='palettegen', | ||
reserve_transparent='on', | ||
) | ||
], | ||
filter_name='paletteuse', | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified:
stream_paletteuse = ( | |
ffmpeg | |
.filter( | |
[ | |
split[0], | |
split[1] | |
.filter( | |
filter_name='palettegen', | |
reserve_transparent='on', | |
) | |
], | |
filter_name='paletteuse', | |
) | |
) | |
stream_paletteuse = ffmpeg.filter([ | |
split[0], | |
split[1].filter( | |
filter_name='palettegen', | |
reserve_transparent='on', | |
) | |
], filter_name='paletteuse')) |
# 检查视频编码类型是否为VP9 | ||
if metadata['streams'][0]['codec_name'] == 'vp9': | ||
stream = ffmpeg.input(file.name, vcodec='libvpx-vp9') # 只有这个能保持透明背景 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep code comments in English.
split = ( | ||
stream | ||
.split() | ||
) | ||
stream_paletteuse = ( | ||
ffmpeg | ||
.filter( | ||
[ | ||
split[0], | ||
split[1] | ||
.filter( | ||
filter_name='palettegen', | ||
reserve_transparent='on', | ||
) | ||
], | ||
filter_name='paletteuse', | ||
) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified. See above.
) | ||
stream_paletteuse.output(gif_file.name).overwrite_output().run() | ||
new_file_size = os.path.getsize(gif_file.name) | ||
print(f"file_size: {new_file_size/1024}KB") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use logging
for debug logs. Avoid using print
directly.
During the process of investigating the GIF size limits, I also discovered that even if a sticker has transparency, this transparency is lost when the sticker is sent to WeChat:
To address this transparency issue, I found that decoding the WEBM files from Telegram correctly and using palettegen with the reserve_transparent flag, then encoding to GIF can retain transparency in a way that WeChat recognizes.
This pull request also tried resolves the transparency loss issue when sending tgs stickers from Telegram to WeChat via EFB, but there might still be an issue with the first frame of some TGS stickers having a black background.
在研究 GIF 大小限制的过程中, 我还发现即使原始贴图有透明背景, 发送到微信后也会丢失透明度, 变成不透明的黑色背景:
为了解决这个透明度丢失的问题, 我发现正确解码 Telegram 的 WEBM 文件, 并在生成调色板时使用 reserve_transparent 标志, 然后编码成 GIF, 就能以微信可识别的方式保留透明背景。
该 Pull Request 还尝试解决了从 Telegram 通过 EFB 发送 tgs 格式的贴图到微信时透明度丢失的问题,但某些 TGS 贴图的第一帧可能仍然会有黑色背景。