Skip to content
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

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

Ovler-Young
Copy link

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:
image

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.

image

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 大小限制的过程中, 我还发现即使原始贴图有透明背景, 发送到微信后也会丢失透明度, 变成不透明的黑色背景:
image

为了解决这个透明度丢失的问题, 我发现正确解码 Telegram 的 WEBM 文件, 并在生成调色板时使用 reserve_transparent 标志, 然后编码成 GIF, 就能以微信可识别的方式保留透明背景。

image
该 Pull Request 还尝试解决了从 Telegram 通过 EFB 发送 tgs 格式的贴图到微信时透明度丢失的问题,但某些 TGS 贴图的第一帧可能仍然会有黑色背景。

Copy link
Member

@blueset blueset left a 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
Copy link
Member

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?
Copy link
Member

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.

Comment on lines +279 to +282
split = (
stream
.split()
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplifed.

Suggested change
split = (
stream
.split()
)
split = stream.split()

Comment on lines +283 to +296
stream_paletteuse = (
ffmpeg
.filter(
[
split[0],
split[1]
.filter(
filter_name='palettegen',
reserve_transparent='on',
)
],
filter_name='paletteuse',
)
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified:

Suggested change
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'))

Comment on lines +329 to +331
# 检查视频编码类型是否为VP9
if metadata['streams'][0]['codec_name'] == 'vp9':
stream = ffmpeg.input(file.name, vcodec='libvpx-vp9') # 只有这个能保持透明背景
Copy link
Member

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.

Comment on lines +332 to +349
split = (
stream
.split()
)
stream_paletteuse = (
ffmpeg
.filter(
[
split[0],
split[1]
.filter(
filter_name='palettegen',
reserve_transparent='on',
)
],
filter_name='paletteuse',
)
)
Copy link
Member

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")
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants