-
-
Notifications
You must be signed in to change notification settings - Fork 78
Fix Animated Sticker / TGS Sticker Transparency Issues #139
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
base: master
Are you sure you want to change the base?
Changes from all commits
805ee0a
b101fc5
af53983
951d789
6c6c440
426da3c
2a01b03
cc14084
bd648dd
eeaaaf5
e61d809
9f7c656
49140d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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) | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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? | ||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||||||||||||||||||||||||||||||||||||||||||||
| frames[0].save( | ||||||||||||||||||||||||||||||||||||||||||||
| fp, | ||||||||||||||||||||||||||||||||||||||||||||
| format='GIF', | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -207,7 +223,7 @@ def convert_tgs_to_gif(tgs_file: BinaryIO, gif_file: BinaryIO) -> bool: | |||||||||||||||||||||||||||||||||||||||||||
| # heavy_strip(animation) | ||||||||||||||||||||||||||||||||||||||||||||
| # heavy_strip(animation) | ||||||||||||||||||||||||||||||||||||||||||||
| # animation.tgs_sanitize() | ||||||||||||||||||||||||||||||||||||||||||||
| export_gif(animation, gif_file, skip_frames=5, dpi=48) | ||||||||||||||||||||||||||||||||||||||||||||
| export_gif(animation, gif_file, skip_frames=5, dpi=48) # skip_frames = 5 means select one frame in every 5 frames | ||||||||||||||||||||||||||||||||||||||||||||
| return True | ||||||||||||||||||||||||||||||||||||||||||||
| except Exception: | ||||||||||||||||||||||||||||||||||||||||||||
| logging.exception("Error occurred while converting TGS to GIF.") | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -258,12 +274,28 @@ 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: | ||||||||||||||||||||||||||||||||||||||||||||
| # 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['streams'][0]['codec_name'] == 'vp9': | ||||||||||||||||||||||||||||||||||||||||||||
| stream = ffmpeg.input(file.name, vcodec='libvpx-vp9') | ||||||||||||||||||||||||||||||||||||||||||||
| split = ( | ||||||||||||||||||||||||||||||||||||||||||||
| stream | ||||||||||||||||||||||||||||||||||||||||||||
| .split() | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+279
to
+282
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be simplifed.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| stream_paletteuse = ( | ||||||||||||||||||||||||||||||||||||||||||||
| ffmpeg | ||||||||||||||||||||||||||||||||||||||||||||
| .filter( | ||||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||||
| split[0], | ||||||||||||||||||||||||||||||||||||||||||||
| split[1] | ||||||||||||||||||||||||||||||||||||||||||||
| .filter( | ||||||||||||||||||||||||||||||||||||||||||||
| filter_name='palettegen', | ||||||||||||||||||||||||||||||||||||||||||||
| reserve_transparent='on', | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||
| filter_name='paletteuse', | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+283
to
+296
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be simplified:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
| # 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 | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -294,11 +326,30 @@ 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: | ||||||||||||||||||||||||||||||||||||||||||||
| # 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() | ||||||||||||||||||||||||||||||||||||||||||||
| # 检查视频编码类型是否为VP9 | ||||||||||||||||||||||||||||||||||||||||||||
| if metadata['streams'][0]['codec_name'] == 'vp9': | ||||||||||||||||||||||||||||||||||||||||||||
| stream = ffmpeg.input(file.name, vcodec='libvpx-vp9') # 只有这个能保持透明背景 | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+329
to
+331
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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', | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+332
to
+349
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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") | ||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||||||||||||||||||||||||||||||||||||||||||||
| file.close() | ||||||||||||||||||||||||||||||||||||||||||||
| gif_file.seek(0) | ||||||||||||||||||||||||||||||||||||||||||||
| return gif_file | ||||||||||||||||||||||||||||||||||||||||||||
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.