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: error in sending sticker to wechat #138

Closed
wants to merge 11 commits into from
96 changes: 89 additions & 7 deletions efb_telegram_master/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,22 @@ def chat_id_str_to_id(s: EFBChannelChatIDStr) -> Tuple[ModuleID, ChatID, Optiona
group_id = ChatID(ids[2])
return channel_id, chat_uid, group_id

def _png_gif_prepare(image):
""" Fork of lottie.exporters.gif.export_gif
Adapted from eltiempoes/python-lottie
https://github.com/eltiempoes/python-lottie/blob/a9f8be4858adb7eb0bc0e406a870b19c309c8a36/lib/lottie/exporters/gif.py#L10
License:
AGPL 3.0 (Python Lottie)
"""
if image.mode not in ["RGBA", "RGBa"]:
image = image.convert("RGBA")
alpha = image.getchannel("A")
image = image.convert(image.mode[:-1]) \
.convert('P', palette=Image.ADAPTIVE, colors=255) # changed
mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
image.paste(255, mask=mask)
image.info['transparency'] = 255 # added
return image

def export_gif(animation, fp, dpi=96, skip_frames=5):
""" Fork of lottie.exporters.gif.export_gif
Expand All @@ -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

start = int(animation.in_point)
end = int(animation.out_point)
Expand Down Expand Up @@ -258,12 +274,35 @@ def gif_conversion(file: IO[bytes], channel_id: str) -> IO[bytes]:

# Set input/output of ffmpeg to stream
stream = ffmpeg.input("pipe:")
if channel_id.startswith("blueset.wechat") and metadata.get('width', 0) > 600:
if metadata['streams'][0]['codec_name'] == 'vp9':
stream = ffmpeg.input(file.name, vcodec='libvpx-vp9')
if channel_id.startswith("blueset.wechat"):
# Workaround: Compress GIF for slave channel `blueset.wechat`
# TODO: Move this logic to `blueset.wechat` in the future
stream = stream.filter("scale", 600, -2)
if metadata.get('width', 0) > 600:
stream = stream.filter("scale", 600, -2)
if metadata.get('fps', 0) > 12:
stream = stream.filter("fps", 12, round='up')
split = (
stream
.split()
)
stream_paletteuse = (
ffmpeg
.filter(
[
split[0],
split[1]
.filter(
filter_name='palettegen',
reserve_transparent='on',
)
],
filter_name='paletteuse',
)
)
# Need to specify file format here as no extension hint presents.
args = stream.output("pipe:", format="gif").compile()
args = stream_paletteuse.output("pipe:", format="gif").compile()
file.seek(0)

# subprocess.Popen would still try to access the file handle instead of
Expand Down Expand Up @@ -294,11 +333,54 @@ def gif_conversion(file: IO[bytes], channel_id: str) -> IO[bytes]:
file.seek(0)
metadata = ffmpeg.probe(file.name)
stream = ffmpeg.input(file.name)
if channel_id.startswith("blueset.wechat") and metadata.get('width', 0) > 600:
# 检查视频编码类型是否为VP9
if metadata['streams'][0]['codec_name'] == 'vp9':
stream = ffmpeg.input(file.name, vcodec='libvpx-vp9') # 只有这个能保持透明背景
if channel_id.startswith("blueset.wechat"):
# Workaround: Compress GIF for slave channel `blueset.wechat`
# TODO: Move this logic to `blueset.wechat` in the future
stream = stream.filter("scale", 600, -2)
stream.output(gif_file.name).overwrite_output().run()
if metadata.get('fps', 0) > 12:
stream = stream.filter("fps", 12, round='up') # 限制帧率
if metadata.get('width', 0) > 600:
stream = stream.filter("scale", 600, -2) # 限制宽度
split = (
stream
.split()
)
stream_paletteuse = (
ffmpeg
.filter(
[
split[0],
split[1]
.filter(
filter_name='palettegen',
reserve_transparent='on',
)
],
filter_name='paletteuse',
)
)
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")
if new_file_size > 1024 * 1024 and channel_id.startswith("blueset.wechat"):
# try to use gifsicle lossy compression
compress_file = NamedTemporaryFile(suffix='.gif')
subprocess.run(["gifsicle", "--resize-method=catrom", "--lossy=100", "-O2", "-o", compress_file.name, gif_file.name], check=True)
new_file_size = os.path.getsize(compress_file.name)
if new_file_size > 1024 * 1024:
scales = [600, 512, 480, 400, 360, 300, 256, 250, 200, 150, 100]
scales = [scale for scale in scales if scale < metadata['streams'][0]['width']]
scales = sorted(scales, reverse=True)
for scale in scales:
subprocess.run(["gifsicle", "--resize-method=catrom", "--resize-fit", f"{scale}x{scale}", "--lossy=100", "-O2", "-o", compress_file.name, gif_file.name], check=True)
new_file_size = os.path.getsize(compress_file.name)
print(f"new_file_size: {new_file_size/1024}KB after resize to {scale}x{scale}")
if new_file_size < 1024 * 1024:
break
gif_file.close()
gif_file = compress_file
file.close()
gif_file.seek(0)
return gif_file