sticker-convert 2.8.1__tar.gz → 2.8.3__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. {sticker-convert-2.8.1/src/sticker_convert.egg-info → sticker-convert-2.8.3}/PKG-INFO +18 -15
  2. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/README.md +17 -14
  3. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/cli.py +4 -0
  4. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/converter.py +96 -47
  5. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/download_telegram.py +1 -1
  6. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui.py +3 -1
  7. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/advanced_compression_window.py +117 -101
  8. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/job.py +9 -8
  9. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/job_option.py +3 -0
  10. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/compression.json +11 -0
  11. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/help.json +1 -0
  12. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/compress_wastickers.py +3 -3
  13. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/upload_telegram.py +1 -1
  14. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/metadata_handler.py +5 -0
  15. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/version.py +1 -1
  16. {sticker-convert-2.8.1 → sticker-convert-2.8.3/src/sticker_convert.egg-info}/PKG-INFO +18 -15
  17. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/LICENSE +0 -0
  18. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/MANIFEST.in +0 -0
  19. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/pyproject.toml +0 -0
  20. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/requirements.txt +0 -0
  21. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/setup.cfg +0 -0
  22. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/__init__.py +0 -0
  23. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/__main__.py +0 -0
  24. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/definitions.py +0 -0
  25. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/__init__.py +0 -0
  26. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/download_base.py +0 -0
  27. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/download_kakao.py +0 -0
  28. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/download_line.py +0 -0
  29. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/downloaders/download_signal.py +0 -0
  30. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/__init__.py +0 -0
  31. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/__init__.py +0 -0
  32. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/comp_frame.py +0 -0
  33. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/config_frame.py +0 -0
  34. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/control_frame.py +0 -0
  35. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/cred_frame.py +0 -0
  36. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/input_frame.py +0 -0
  37. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/output_frame.py +0 -0
  38. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/progress_frame.py +0 -0
  39. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/frames/right_clicker.py +0 -0
  40. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/gui_utils.py +0 -0
  41. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/__init__.py +0 -0
  42. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/base_window.py +0 -0
  43. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/kakao_get_auth_window.py +0 -0
  44. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/line_get_auth_window.py +0 -0
  45. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/gui_components/windows/signal_get_auth_window.py +0 -0
  46. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/.github/FUNDING.yml +0 -0
  47. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/.gitignore +0 -0
  48. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/README.md +0 -0
  49. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers/Info.plist +0 -0
  50. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Info.plist +0 -0
  51. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Contents.json +0 -0
  52. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json +0 -0
  53. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Contents.json +0 -0
  54. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Sticker 1.png +0 -0
  55. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Contents.json +0 -0
  56. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Sticker 2.png +0 -0
  57. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Contents.json +0 -0
  58. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Sticker 3.png +0 -0
  59. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/App-Store-1024x1024pt.png +0 -0
  60. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json +0 -0
  61. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-App-Store-1024x768pt.png +0 -0
  62. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPad-67x50pt@2x.png +0 -0
  63. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPad-Pro-74x55pt@2x.png +0 -0
  64. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPhone-60x45pt@2x.png +0 -0
  65. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages-iPhone-60x45pt@3x.png +0 -0
  66. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages27x20pt@2x.png +0 -0
  67. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages27x20pt@3x.png +0 -0
  68. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages32x24pt@2x.png +0 -0
  69. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Messages32x24pt@3x.png +0 -0
  70. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPad-Settings-29pt@2x.png +0 -0
  71. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPhone-Settings-29pt@3x.png +0 -0
  72. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/iPhone-settings-29pt@2x.png +0 -0
  73. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.pbxproj +0 -0
  74. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -0
  75. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -0
  76. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcuserdata/niklaspeterson.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  77. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/ios-message-stickers-template/stickers.xcodeproj/xcuserdata/niklaspeterson.xcuserdatad/xcschemes/xcschememanagement.plist +0 -0
  78. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/NotoColorEmoji.ttf +0 -0
  79. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/appicon.icns +0 -0
  80. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/appicon.ico +0 -0
  81. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/appicon.png +0 -0
  82. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/emoji.json +0 -0
  83. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/input.json +0 -0
  84. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/resources/output.json +0 -0
  85. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/__init__.py +0 -0
  86. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/upload_base.py +0 -0
  87. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/upload_signal.py +0 -0
  88. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/uploaders/xcode_imessage.py +0 -0
  89. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/auth/get_kakao_auth.py +0 -0
  90. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/auth/get_line_auth.py +0 -0
  91. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/auth/get_signal_auth.py +0 -0
  92. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/callback.py +0 -0
  93. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/cache_store.py +0 -0
  94. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/json_manager.py +0 -0
  95. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/json_resources_loader.py +0 -0
  96. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/run_bin.py +0 -0
  97. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/files/sanitize_filename.py +0 -0
  98. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/media/apple_png_normalize.py +0 -0
  99. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/media/codec_info.py +0 -0
  100. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/media/decrypt_kakao.py +0 -0
  101. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/media/format_verify.py +0 -0
  102. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert/utils/url_detect.py +0 -0
  103. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert.egg-info/SOURCES.txt +0 -0
  104. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert.egg-info/dependency_links.txt +0 -0
  105. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert.egg-info/entry_points.txt +0 -0
  106. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert.egg-info/requires.txt +0 -0
  107. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/src/sticker_convert.egg-info/top_level.txt +0 -0
  108. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/tests/test_compression.py +0 -0
  109. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/tests/test_download.py +0 -0
  110. {sticker-convert-2.8.1 → sticker-convert-2.8.3}/tests/test_export.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sticker-convert
3
- Version: 2.8.1
3
+ Version: 2.8.3
4
4
  Summary: Convert (animated) stickers to/from WhatsApp, Telegram, Signal, Line, Kakao, iMessage. Written in Python.
5
5
  Author-email: laggykiller <chaudominic2@gmail.com>
6
6
  Maintainer-email: laggykiller <chaudominic2@gmail.com>
@@ -483,23 +483,24 @@ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--custom-presets CUST
483
483
  [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,imessage_small,imessage_medium,imessage_large,custom}]
484
484
  [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
485
485
  [--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
486
- [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
487
- [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
488
- [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
489
- [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--bg-color BG_COLOR]
490
- [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT]
491
- [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER]
492
- [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
493
- [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
494
- [--signal-data-dir SIGNAL_DATA_DIR] [--telegram-token TELEGRAM_TOKEN]
495
- [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth]
496
- [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
497
- [--kakao-country-code KAKAO_COUNTRY_CODE] [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth]
498
- [--line-cookies LINE_COOKIES] [--save-cred SAVE_CRED]
486
+ [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX]
487
+ [--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX]
488
+ [--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX]
489
+ [--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX]
490
+ [--padding-percent PADDING_PERCENT] [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX]
491
+ [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT] [--img-format IMG_FORMAT]
492
+ [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD]
493
+ [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID]
494
+ [--signal-password SIGNAL_PASSWORD] [--signal-get-auth] [--signal-data-dir SIGNAL_DATA_DIR]
495
+ [--telegram-token TELEGRAM_TOKEN] [--telegram-userid TELEGRAM_USERID]
496
+ [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth] [--kakao-username KAKAO_USERNAME]
497
+ [--kakao-password KAKAO_PASSWORD] [--kakao-country-code KAKAO_COUNTRY_CODE]
498
+ [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES]
499
+ [--save-cred SAVE_CRED]
499
500
 
500
501
  CLI for stickers-convert
501
502
 
502
- optional arguments:
503
+ options:
503
504
  -h, --help show this help message and exit
504
505
  --version show program's version number and exit
505
506
  --no-confirm Do not ask any questions.
@@ -585,6 +586,8 @@ Compression options:
585
586
  Set minimum output duration in miliseconds.
586
587
  --duration-max DURATION_MAX
587
588
  Set maximum output duration in miliseconds.
589
+ --padding-percent PADDING_PERCENT
590
+ Set percentage of space used as padding.
588
591
  --bg-color BG_COLOR Set custom background color.
589
592
  Example: 00ff00 for green.
590
593
  If this is not set, background color would be auto set to black if image is bright, or white if image is dark.
@@ -96,23 +96,24 @@ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--custom-presets CUST
96
96
  [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,imessage_small,imessage_medium,imessage_large,custom}]
97
97
  [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
98
98
  [--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
99
- [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
100
- [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
101
- [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
102
- [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--bg-color BG_COLOR]
103
- [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT]
104
- [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER]
105
- [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
106
- [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
107
- [--signal-data-dir SIGNAL_DATA_DIR] [--telegram-token TELEGRAM_TOKEN]
108
- [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth]
109
- [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
110
- [--kakao-country-code KAKAO_COUNTRY_CODE] [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth]
111
- [--line-cookies LINE_COOKIES] [--save-cred SAVE_CRED]
99
+ [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX]
100
+ [--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX]
101
+ [--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX]
102
+ [--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX]
103
+ [--padding-percent PADDING_PERCENT] [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX]
104
+ [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT] [--img-format IMG_FORMAT]
105
+ [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD]
106
+ [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID]
107
+ [--signal-password SIGNAL_PASSWORD] [--signal-get-auth] [--signal-data-dir SIGNAL_DATA_DIR]
108
+ [--telegram-token TELEGRAM_TOKEN] [--telegram-userid TELEGRAM_USERID]
109
+ [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth] [--kakao-username KAKAO_USERNAME]
110
+ [--kakao-password KAKAO_PASSWORD] [--kakao-country-code KAKAO_COUNTRY_CODE]
111
+ [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES]
112
+ [--save-cred SAVE_CRED]
112
113
 
113
114
  CLI for stickers-convert
114
115
 
115
- optional arguments:
116
+ options:
116
117
  -h, --help show this help message and exit
117
118
  --version show program's version number and exit
118
119
  --no-confirm Do not ask any questions.
@@ -198,6 +199,8 @@ Compression options:
198
199
  Set minimum output duration in miliseconds.
199
200
  --duration-max DURATION_MAX
200
201
  Set maximum output duration in miliseconds.
202
+ --padding-percent PADDING_PERCENT
203
+ Set percentage of space used as padding.
201
204
  --bg-color BG_COLOR Set custom background color.
202
205
  Example: 00ff00 for green.
203
206
  If this is not set, background color would be auto set to black if image is bright, or white if image is dark.
@@ -119,6 +119,7 @@ class CLI:
119
119
  "duration_max",
120
120
  "vid_size_max",
121
121
  "img_size_max",
122
+ "padding_percent",
122
123
  )
123
124
  flags_comp_float = ("fps_power", "res_power", "quality_power", "color_power")
124
125
  flags_comp_str = (
@@ -372,6 +373,9 @@ class CLI:
372
373
  bg_color=self.compression_presets[preset]["bg_color"]
373
374
  if args.bg_color is None
374
375
  else args.bg_color,
376
+ padding_percent=self.compression_presets[preset]["padding_percent"]
377
+ if args.padding_percent is None
378
+ else args.padding_percent,
375
379
  steps=self.compression_presets[preset]["steps"]
376
380
  if args.steps is None
377
381
  else args.steps,
@@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Tuple, Uni
9
9
  import numpy as np
10
10
  from PIL import Image
11
11
  from PIL import __version__ as PillowVersion
12
+ from PIL import features
12
13
 
13
14
  from sticker_convert.job_option import CompOption
14
15
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
@@ -32,6 +33,17 @@ MSG_FAIL_COMP = (
32
33
  "[F] Failed Compression {} -> {}, "
33
34
  "cannot get below limit {} with lowest quality under current settings (Best size: {})"
34
35
  )
36
+ MSG_PYWEBP_DUPFRAME = (
37
+ "[W] {} contains duplicated frame.\n"
38
+ " System WebP>=0.5.0 was not found, hence Pillow cannot be used\n"
39
+ " for creating animated webp. Using pywebp instead, which is known to\n"
40
+ " collapse same frames into single frame, causing problem with animation timing."
41
+ )
42
+ MSG_WEBP_PIL_DUPFRAME = (
43
+ "[W] {} contains duplicated frame.\n"
44
+ " Using Pillow to create animated webp to avoid same frames collapse\n"
45
+ " into single frame, but this is slower."
46
+ )
35
47
 
36
48
  YUV_RGB_MATRIX = np.array(
37
49
  [
@@ -41,6 +53,10 @@ YUV_RGB_MATRIX = np.array(
41
53
  ]
42
54
  )
43
55
 
56
+ # Whether animated WebP is supported
57
+ # See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#saving-sequences
58
+ PIL_WEBP_ANIM = cast(bool, features.check("webp_anim")) # type: ignore
59
+
44
60
 
45
61
  def get_step_value(
46
62
  max_step: Optional[int],
@@ -179,6 +195,8 @@ class StickerConvert:
179
195
  self.result_step: Optional[int] = None
180
196
 
181
197
  self.apngasm = None
198
+ self.msg_pywebp_dupframe_displayed = False
199
+ self.msg_webp_pil_dupframe_displayed = False
182
200
 
183
201
  @staticmethod
184
202
  def convert(
@@ -394,7 +412,7 @@ class StickerConvert:
394
412
  with open(self.out_f, "wb+") as f:
395
413
  f.write(data)
396
414
 
397
- if result_step:
415
+ if result_step is not None:
398
416
  msg = MSG_DONE_COMP.format(
399
417
  self.in_f_name, self.out_f_name, self.result_size, result_step
400
418
  )
@@ -597,12 +615,13 @@ class StickerConvert:
597
615
  if self.res_h is None:
598
616
  self.res_h = height
599
617
 
618
+ scaling = 1 - (self.opt_comp.padding_percent / 100)
600
619
  if width > height:
601
- width_new = self.res_w
602
- height_new = height * self.res_w // width
620
+ width_new = int(self.res_w * scaling)
621
+ height_new = int(height * self.res_w // width * scaling)
603
622
  else:
604
- height_new = self.res_h
605
- width_new = width * self.res_h // height
623
+ height_new = int(self.res_h * scaling)
624
+ width_new = int(width * self.res_h // height * scaling)
606
625
 
607
626
  with im.resize((width_new, height_new), resample=resample) as im_resized:
608
627
  with Image.new(
@@ -677,14 +696,51 @@ class StickerConvert:
677
696
  self._frames_export_apng()
678
697
  else:
679
698
  self._frames_export_png()
680
- elif self.out_f.suffix == ".webp" and is_animated:
699
+ elif self.out_f.suffix == ".webp":
681
700
  self._frames_export_webp()
682
701
  elif self.out_f.suffix == ".gif":
683
- self._frames_export_gif()
702
+ self._frames_export_pil_anim()
684
703
  elif self.out_f.suffix in (".webm", ".mp4", ".mkv") or is_animated:
685
704
  self._frames_export_pyav()
686
705
  else:
687
706
  self._frames_export_pil()
707
+
708
+ def _check_dup(self) -> bool:
709
+ if len(self.frames_processed) == 1:
710
+ return False
711
+
712
+ prev_frame = self.frames_processed[0]
713
+ for frame in self.frames_processed[1:]:
714
+ if np.array_equal(frame, prev_frame):
715
+ return True
716
+ prev_frame = frame
717
+
718
+ return False
719
+
720
+ def _frames_export_webp(self) -> None:
721
+ has_dup_frames = self._check_dup()
722
+ if self.fps:
723
+ # It was noted that pywebp would collapse all frames.
724
+ # aed005b attempted to fix this by creating webp with
725
+ # variable frame duration. However, the webp created would
726
+ # not be accepted by WhatsApp.
727
+ # Therefore, we are preferring Pillow over pywebp.
728
+ if has_dup_frames:
729
+ if PIL_WEBP_ANIM:
730
+ # Warn that using Pillow is slower
731
+ if not self.msg_webp_pil_dupframe_displayed:
732
+ self.cb.put(MSG_WEBP_PIL_DUPFRAME.format(self.in_f_name))
733
+ self.msg_webp_pil_dupframe_displayed = True
734
+ self._frames_export_pil_anim()
735
+ else:
736
+ if not self.msg_pywebp_dupframe_displayed:
737
+ self.cb.put(MSG_PYWEBP_DUPFRAME.format(self.in_f_name))
738
+ self.msg_pywebp_dupframe_displayed = True
739
+ self._frames_export_pywebp()
740
+ else:
741
+ self._frames_export_pywebp()
742
+ else:
743
+ self._frames_export_pil()
688
744
 
689
745
  def _frames_export_pil(self) -> None:
690
746
  with Image.fromarray(self.frames_processed[0]) as im: # type: ignore
@@ -709,7 +765,7 @@ class StickerConvert:
709
765
  codec = "apng"
710
766
  pixel_format = "rgba"
711
767
  options["plays"] = "0"
712
- elif self.out_f.suffix in (".webp", ".webm", ".mkv"):
768
+ elif self.out_f.suffix in (".webm", ".mkv"):
713
769
  codec = "libvpx-vp9"
714
770
  pixel_format = "yuva420p"
715
771
  options["loop"] = "0"
@@ -733,7 +789,7 @@ class StickerConvert:
733
789
  output.mux(out_stream.encode(av_frame))
734
790
  output.mux(out_stream.encode())
735
791
 
736
- def _frames_export_gif(self) -> None:
792
+ def _frames_export_pil_anim(self) -> None:
737
793
  extra_kwargs: Dict[str, Any] = {}
738
794
 
739
795
  # disposal=2 on gif cause flicker in image with transparency
@@ -744,25 +800,34 @@ class StickerConvert:
744
800
  else:
745
801
  extra_kwargs["optimize"] = True
746
802
 
747
- # GIF can only have one alpha color
748
- # Change lowest alpha to alpha=0
749
- # Only keep alpha=0 and alpha=255, nothing in between
750
- frames_processed = np.array(self.frames_processed)
751
- alpha = frames_processed[:, :, :, 3]
752
- alpha_min = np.min(alpha) # type: ignore
753
- if alpha_min < 255:
754
- alpha[alpha > alpha_min] = 255
755
- alpha[alpha == alpha_min] = 0
756
-
757
- if 0 in alpha:
758
- extra_kwargs["transparency"] = 0
759
- extra_kwargs["disposal"] = 2
760
- im_out = [self.quantize(Image.fromarray(i)) for i in frames_processed] # type: ignore
803
+ if self.out_f.suffix == ".gif":
804
+ # GIF can only have one alpha color
805
+ # Change lowest alpha to alpha=0
806
+ # Only keep alpha=0 and alpha=255, nothing in between
807
+ frames_processed = np.array(self.frames_processed)
808
+ alpha = frames_processed[:, :, :, 3]
809
+ alpha_min = np.min(alpha) # type: ignore
810
+ if alpha_min < 255:
811
+ alpha[alpha > alpha_min] = 255
812
+ alpha[alpha == alpha_min] = 0
813
+
814
+ if 0 in alpha:
815
+ extra_kwargs["transparency"] = 0
816
+ extra_kwargs["disposal"] = 2
817
+ im_out = [self.quantize(Image.fromarray(i)) for i in frames_processed] # type: ignore
818
+ else:
819
+ im_out = [
820
+ self.quantize(Image.fromarray(i).convert("RGB")).convert("RGB") # type: ignore
821
+ for i in frames_processed
822
+ ]
823
+ extra_kwargs["format"] = "GIF"
824
+ elif self.out_f.suffix == ".webp":
825
+ im_out = [Image.fromarray(i) for i in self.frames_processed] # type: ignore
826
+ extra_kwargs["format"] = "WebP"
827
+ extra_kwargs["minimize_size"] = True
828
+ extra_kwargs["method"] = 6
761
829
  else:
762
- im_out = [
763
- self.quantize(Image.fromarray(i).convert("RGB")).convert("RGB") # type: ignore
764
- for i in frames_processed
765
- ]
830
+ raise RuntimeError(f"Invalid format {self.out_f.suffix}")
766
831
 
767
832
  if self.fps:
768
833
  extra_kwargs["save_all"] = True
@@ -772,12 +837,11 @@ class StickerConvert:
772
837
 
773
838
  im_out[0].save(
774
839
  self.tmp_f,
775
- format="GIF",
776
840
  quality=self.quality,
777
841
  **extra_kwargs,
778
842
  )
779
843
 
780
- def _frames_export_webp(self) -> None:
844
+ def _frames_export_pywebp(self) -> None:
781
845
  import webp # type: ignore
782
846
 
783
847
  assert self.fps
@@ -785,25 +849,10 @@ class StickerConvert:
785
849
  config = webp.WebPConfig.new(quality=self.quality) # type: ignore
786
850
  enc = webp.WebPAnimEncoder.new(self.res_w, self.res_h) # type: ignore
787
851
  timestamp_ms = 0
788
- timestamp_inc = int(1000 / self.fps)
789
-
790
- pic = webp.WebPPicture.from_numpy(self.frames_processed[0]) # type: ignore
791
- enc.encode_frame(pic, 0, config=config) # type: ignore
792
-
793
- frame_num = 1
794
- frame_num_prev = 1
795
- frame_total = len(self.frames_processed)
796
- while frame_num < frame_total - 1:
797
- while frame_num < frame_total - 1 and np.array_equal(
798
- self.frames_processed[frame_num_prev],
799
- self.frames_processed[frame_num],
800
- ):
801
- timestamp_ms += timestamp_inc
802
- frame_num += 1
803
- pic = webp.WebPPicture.from_numpy(self.frames_processed[frame_num]) # type: ignore
852
+ for frame in self.frames_processed:
853
+ pic = webp.WebPPicture.from_numpy(frame) # type: ignore
804
854
  enc.encode_frame(pic, timestamp_ms, config=config) # type: ignore
805
- frame_num_prev = frame_num
806
-
855
+ timestamp_ms += int(1000 / self.fps)
807
856
  anim_data = enc.assemble(timestamp_ms) # type: ignore
808
857
  self.tmp_f.write(anim_data.buffer()) # type: ignore
809
858
 
@@ -42,7 +42,7 @@ class DownloadTelegram(DownloadBase):
42
42
  application = ( # type: ignore
43
43
  ApplicationBuilder()
44
44
  .token(self.token)
45
- .rate_limiter(AIORateLimiter())
45
+ .rate_limiter(AIORateLimiter(max_retries=3))
46
46
  .connect_timeout(timeout)
47
47
  .pool_timeout(timeout)
48
48
  .read_timeout(timeout)
@@ -125,6 +125,7 @@ class GUI(Window):
125
125
  self.duration_min_var = IntVar(self)
126
126
  self.duration_max_var = IntVar(self)
127
127
  self.duration_disable_var = BooleanVar()
128
+ self.padding_percent_var = IntVar(self)
128
129
  self.img_size_max_var = IntVar(self)
129
130
  self.vid_size_max_var = IntVar(self)
130
131
  self.size_disable_var = BooleanVar()
@@ -519,6 +520,7 @@ class GUI(Window):
519
520
  if not self.duration_disable_var.get()
520
521
  else None,
521
522
  bg_color=self.bg_color_var.get(),
523
+ padding_percent=self.padding_percent_var.get(),
522
524
  steps=self.steps_var.get(),
523
525
  fake_vid=self.fake_vid_var.get(),
524
526
  scale_filter=self.scale_filter_var.get(),
@@ -642,10 +644,10 @@ class GUI(Window):
642
644
 
643
645
  def cb_bar(
644
646
  self,
645
- *args: Any,
646
647
  set_progress_mode: Optional[str] = None,
647
648
  steps: int = 0,
648
649
  update_bar: int = 0,
650
+ *args: Any,
649
651
  **kwargs: Any,
650
652
  ) -> None:
651
653
  self.progress_frame.update_progress_bar(